@computesdk/uno 0.0.0-stage → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 computesdk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,86 @@
1
- # Temporary Holding Version
1
+ # @computesdk/uno
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [Uno](https://uno.place) provider for [ComputeSDK](https://www.computesdk.com).
4
+
5
+ Every Uno machine is a full Linux microVM on Firecracker, not a container: systemd, `apt`, passwordless `sudo` and a real disk. It boots from a warm snapshot in seconds. Machines in the **US region run on High-end servers**, on our fastest processors.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @computesdk/uno
11
+ ```
12
+
13
+ ## Setup
14
+
15
+ Create an API key in the Uno console (**Settings → API keys**) and add it to your environment:
16
+
17
+ ```bash
18
+ UNO_API_KEY=your_uno_api_key
19
+ UNO_REGION=us # optional: 'us' (High-end) or 'nl'; defaults to your account's region
20
+ ```
21
+
22
+ Creating machines needs an Uno plan. Machine sizes fit inside your plan's limits (for example, 8 vCPU / 16 GiB needs Pro or Max).
23
+
24
+ ## Usage
25
+
26
+ ```typescript
27
+ import { uno } from '@computesdk/uno'
28
+
29
+ const compute = uno({ apiKey: process.env.UNO_API_KEY, region: 'us' })
30
+
31
+ const sandbox = await compute.sandbox.create({ vcpus: 8, memoryMiB: 16384 })
32
+
33
+ const result = await sandbox.runCommand('uname -a && nproc')
34
+ console.log(result.stdout)
35
+
36
+ await sandbox.filesystem.writeFile('/tmp/hello.txt', 'Hello from Uno')
37
+ console.log(await sandbox.filesystem.readFile('/tmp/hello.txt'))
38
+
39
+ await sandbox.destroy()
40
+ ```
41
+
42
+ ## Configuration
43
+
44
+ ```typescript
45
+ interface UnoConfig {
46
+ /** API key. Falls back to UNO_API_KEY. */
47
+ apiKey?: string
48
+ /** API base URL. Falls back to UNO_API_URL, then https://console.uno4.dev. */
49
+ baseUrl?: string
50
+ /** 'us' (High-end) or 'nl'. Falls back to UNO_REGION, then your account's region. */
51
+ region?: string
52
+ /** OS template: 'ubuntu-24.04' (default), 'ubuntu-22.04', 'debian-12'. */
53
+ template?: string
54
+ /** Defaults when create() does not say: 2 vCPU, 2048 MiB, 10 GB disk. */
55
+ vcpu?: number
56
+ ramMb?: number
57
+ diskGb?: number
58
+ /** How long create() waits for the machine to boot. Default 120 000 ms. */
59
+ readyTimeoutMs?: number
60
+ }
61
+ ```
62
+
63
+ `create()` reads the size from `vcpus` / `cpus` / `cpu`, `memoryMiB` / `memMiB` / `memoryMb` / `memory` and `diskMiB` / `diskMb`. Memory is rounded up to a multiple of 256 MiB. `templateId` selects the OS template.
64
+
65
+ ## How commands run
66
+
67
+ - Commands run as user `uno` in a login `bash` shell, in the home directory. Use `sudo` for root.
68
+ - A command can run for up to 1 hour (`timeout`, default 5 minutes). Long commands are long-polled, so no single HTTP response hangs on proxy time limits. Retries use an idempotency key, so a dropped connection never starts a command twice.
69
+ - Up to 256 KiB of stdout and 64 KiB of stderr are returned per command; if either was cut, `stderr` ends with an `[uno] … truncated` line. Command text is limited to 64 KiB: write bigger inputs with `filesystem.writeFile` first.
70
+ - `filesystem.readFile`, `writeFile` and `readdir` have no size limit: they move data in chunks, and `writeFile` renames a temp file into place only after every chunk landed.
71
+ - One command runs on a machine at a time. A concurrent `runCommand` on the same machine is retried for a few seconds, then fails with `BOX_BUSY`: use one machine per parallel job, or `background: true`.
72
+
73
+ ## Supported
74
+
75
+ | Feature | |
76
+ |---|---|
77
+ | create / getById / list / destroy | ✅ |
78
+ | runCommand (cwd, env, timeout, background) | ✅ |
79
+ | filesystem (read, write, mkdir, readdir, exists, remove) | ✅ via shell |
80
+ | getUrl | port 80 only, at `https://<name>.uno4.dev` |
81
+ | live output streaming, snapshots, templates API | not yet |
82
+
83
+ ## Links
84
+
85
+ - Uno: https://uno.place
86
+ - API reference: `GET https://console.uno4.dev/api/v1/openapi.yaml`
@@ -0,0 +1,154 @@
1
+ import * as _computesdk_provider from '@computesdk/provider';
2
+ import * as computesdk from 'computesdk';
3
+
4
+ /**
5
+ * Minimal HTTP client for the Uno box API.
6
+ *
7
+ * The API is a small JSON surface (`/api/v1/boxes`), so this talks to it with
8
+ * `fetch` and has no dependencies. Everything that touches the network lives
9
+ * here; `./index` only maps ComputeSDK's interface onto these calls.
10
+ *
11
+ * @see https://uno.place/docs/api
12
+ */
13
+ declare const DEFAULT_BASE_URL = "https://console.uno4.dev";
14
+ /** Box JSON as returned by `GET /api/v1/boxes/{id}` (fields this package reads). */
15
+ interface UnoBox {
16
+ id: number;
17
+ name: string;
18
+ status: string;
19
+ provision_state?: string;
20
+ provision_error?: string;
21
+ vcpu: number;
22
+ ram_mb: number;
23
+ disk_gb: number;
24
+ created_at: string;
25
+ hostname?: string;
26
+ url?: string;
27
+ ssh_command?: string;
28
+ network_region?: string;
29
+ max_lifetime_s?: number;
30
+ comment?: string;
31
+ [key: string]: unknown;
32
+ }
33
+ interface UnoCreateBoxRequest {
34
+ template: string;
35
+ vcpu: number;
36
+ ram_mb: number;
37
+ disk_gb: number;
38
+ name?: string;
39
+ region?: string;
40
+ ssh_key?: string;
41
+ comment?: string;
42
+ }
43
+ /** A run as returned by `POST /boxes/{id}/run` (200) or `GET /boxes/{id}/runs/{rid}`. */
44
+ interface UnoRun {
45
+ run_id?: string;
46
+ id?: string;
47
+ status: 'running' | 'finished' | 'error';
48
+ exit_code?: number;
49
+ stdout?: string;
50
+ stderr?: string;
51
+ stdout_truncated?: boolean;
52
+ stderr_truncated?: boolean;
53
+ duration_ms?: number;
54
+ error_code?: string;
55
+ command_started?: boolean | null;
56
+ retry_safe?: boolean;
57
+ }
58
+ interface UnoClientOptions {
59
+ /** Account API key or a token with `boxes:read`, `boxes:write` and `infra:purchase`. Falls back to `UNO_API_KEY`. */
60
+ apiKey?: string;
61
+ /** API base URL. Falls back to `UNO_API_URL`, then {@link DEFAULT_BASE_URL}. */
62
+ baseUrl?: string;
63
+ /** Per-request timeout for plain API calls, in ms. Default 30 000. */
64
+ requestTimeoutMs?: number;
65
+ }
66
+ declare class UnoError extends Error {
67
+ readonly status: number;
68
+ readonly code?: string | undefined;
69
+ readonly body?: Record<string, unknown> | undefined;
70
+ constructor(message: string, status: number, code?: string | undefined, body?: Record<string, unknown> | undefined);
71
+ }
72
+ declare class UnoClient {
73
+ readonly baseUrl: string;
74
+ private readonly apiKey;
75
+ private readonly requestTimeoutMs;
76
+ constructor(options?: UnoClientOptions);
77
+ /**
78
+ * One HTTP call. Returns status + parsed JSON body; throws {@link UnoError}
79
+ * for any status not listed in `accept`.
80
+ */
81
+ request<T = Record<string, unknown>>(method: string, path: string, body?: unknown, opts?: {
82
+ accept?: number[];
83
+ timeoutMs?: number;
84
+ signal?: AbortSignal;
85
+ }): Promise<{
86
+ status: number;
87
+ body: T;
88
+ headers: Headers;
89
+ }>;
90
+ createBox(req: UnoCreateBoxRequest, signal?: AbortSignal): Promise<UnoBox>;
91
+ /**
92
+ * The box whose `comment` is exactly `marker` (a per-request UUID), created
93
+ * at or after `since` (ms epoch). Looks up to `attempts` times, 2 s apart: a
94
+ * create the connection lost may show up in the list a moment later.
95
+ */
96
+ findBoxByMarker(marker: string, since: number, attempts?: number): Promise<UnoBox | null>;
97
+ getBox(id: string | number): Promise<UnoBox | null>;
98
+ listBoxes(): Promise<UnoBox[]>;
99
+ /** Delete a box; a box that is already gone is not an error. */
100
+ deleteBox(id: string | number): Promise<void>;
101
+ /**
102
+ * Poll until the box is running and provisioned. Create returns at once with
103
+ * `status: "provisioning"`; the machine boots from a warm snapshot in seconds.
104
+ */
105
+ waitReady(id: string | number, timeoutMs: number, signal?: AbortSignal): Promise<UnoBox>;
106
+ /**
107
+ * Run a command and wait for its result.
108
+ *
109
+ * The server holds the request for up to `waitS` seconds; longer commands
110
+ * come back as 202 + run id and are long-polled, so no single HTTP response
111
+ * outlives proxy idle limits (~100 s). Every attempt carries the same
112
+ * idempotency key, so a retry after a dropped connection returns the run
113
+ * already recorded instead of starting the command twice.
114
+ */
115
+ run(id: string | number, payload: {
116
+ cmd: string;
117
+ env?: Record<string, string>;
118
+ timeout_s: number;
119
+ }, opts?: {
120
+ waitS?: number;
121
+ idempotencyKey?: string;
122
+ }): Promise<UnoRun>;
123
+ }
124
+
125
+ interface UnoConfig extends UnoClientOptions {
126
+ /**
127
+ * Region for new machines: `'us'` (High-end) or `'nl'`. Falls back to
128
+ * `UNO_REGION`; omitted means the account's default region.
129
+ */
130
+ region?: string;
131
+ /** OS template slug (see `GET /api/v1/box-templates`). Default `'ubuntu-24.04'`. */
132
+ template?: string;
133
+ /** Default vCPUs when `create` does not say. Default 2. */
134
+ vcpu?: number;
135
+ /** Default memory in MiB when `create` does not say. Default 2048. */
136
+ ramMb?: number;
137
+ /** Default disk in GB when `create` does not say. Default 10. */
138
+ diskGb?: number;
139
+ /** How long `create` waits for the machine to boot, in ms. Default 120 000. */
140
+ readyTimeoutMs?: number;
141
+ }
142
+ interface UnoSandbox {
143
+ id: string;
144
+ box: UnoBox;
145
+ client: UnoClient;
146
+ /** Environment from `create({ envs })`, applied to every command. */
147
+ envs?: Record<string, string>;
148
+ }
149
+ type ConfigWithClient = UnoConfig & {
150
+ __client?: UnoClient;
151
+ };
152
+ declare const uno: (config: ConfigWithClient) => _computesdk_provider.Provider<UnoSandbox, any, any, computesdk.Volume>;
153
+
154
+ export { DEFAULT_BASE_URL, type UnoBox, UnoClient, type UnoClientOptions, type UnoConfig, type UnoCreateBoxRequest, UnoError, type UnoRun, type UnoSandbox, uno as default, uno };
@@ -0,0 +1,154 @@
1
+ import * as _computesdk_provider from '@computesdk/provider';
2
+ import * as computesdk from 'computesdk';
3
+
4
+ /**
5
+ * Minimal HTTP client for the Uno box API.
6
+ *
7
+ * The API is a small JSON surface (`/api/v1/boxes`), so this talks to it with
8
+ * `fetch` and has no dependencies. Everything that touches the network lives
9
+ * here; `./index` only maps ComputeSDK's interface onto these calls.
10
+ *
11
+ * @see https://uno.place/docs/api
12
+ */
13
+ declare const DEFAULT_BASE_URL = "https://console.uno4.dev";
14
+ /** Box JSON as returned by `GET /api/v1/boxes/{id}` (fields this package reads). */
15
+ interface UnoBox {
16
+ id: number;
17
+ name: string;
18
+ status: string;
19
+ provision_state?: string;
20
+ provision_error?: string;
21
+ vcpu: number;
22
+ ram_mb: number;
23
+ disk_gb: number;
24
+ created_at: string;
25
+ hostname?: string;
26
+ url?: string;
27
+ ssh_command?: string;
28
+ network_region?: string;
29
+ max_lifetime_s?: number;
30
+ comment?: string;
31
+ [key: string]: unknown;
32
+ }
33
+ interface UnoCreateBoxRequest {
34
+ template: string;
35
+ vcpu: number;
36
+ ram_mb: number;
37
+ disk_gb: number;
38
+ name?: string;
39
+ region?: string;
40
+ ssh_key?: string;
41
+ comment?: string;
42
+ }
43
+ /** A run as returned by `POST /boxes/{id}/run` (200) or `GET /boxes/{id}/runs/{rid}`. */
44
+ interface UnoRun {
45
+ run_id?: string;
46
+ id?: string;
47
+ status: 'running' | 'finished' | 'error';
48
+ exit_code?: number;
49
+ stdout?: string;
50
+ stderr?: string;
51
+ stdout_truncated?: boolean;
52
+ stderr_truncated?: boolean;
53
+ duration_ms?: number;
54
+ error_code?: string;
55
+ command_started?: boolean | null;
56
+ retry_safe?: boolean;
57
+ }
58
+ interface UnoClientOptions {
59
+ /** Account API key or a token with `boxes:read`, `boxes:write` and `infra:purchase`. Falls back to `UNO_API_KEY`. */
60
+ apiKey?: string;
61
+ /** API base URL. Falls back to `UNO_API_URL`, then {@link DEFAULT_BASE_URL}. */
62
+ baseUrl?: string;
63
+ /** Per-request timeout for plain API calls, in ms. Default 30 000. */
64
+ requestTimeoutMs?: number;
65
+ }
66
+ declare class UnoError extends Error {
67
+ readonly status: number;
68
+ readonly code?: string | undefined;
69
+ readonly body?: Record<string, unknown> | undefined;
70
+ constructor(message: string, status: number, code?: string | undefined, body?: Record<string, unknown> | undefined);
71
+ }
72
+ declare class UnoClient {
73
+ readonly baseUrl: string;
74
+ private readonly apiKey;
75
+ private readonly requestTimeoutMs;
76
+ constructor(options?: UnoClientOptions);
77
+ /**
78
+ * One HTTP call. Returns status + parsed JSON body; throws {@link UnoError}
79
+ * for any status not listed in `accept`.
80
+ */
81
+ request<T = Record<string, unknown>>(method: string, path: string, body?: unknown, opts?: {
82
+ accept?: number[];
83
+ timeoutMs?: number;
84
+ signal?: AbortSignal;
85
+ }): Promise<{
86
+ status: number;
87
+ body: T;
88
+ headers: Headers;
89
+ }>;
90
+ createBox(req: UnoCreateBoxRequest, signal?: AbortSignal): Promise<UnoBox>;
91
+ /**
92
+ * The box whose `comment` is exactly `marker` (a per-request UUID), created
93
+ * at or after `since` (ms epoch). Looks up to `attempts` times, 2 s apart: a
94
+ * create the connection lost may show up in the list a moment later.
95
+ */
96
+ findBoxByMarker(marker: string, since: number, attempts?: number): Promise<UnoBox | null>;
97
+ getBox(id: string | number): Promise<UnoBox | null>;
98
+ listBoxes(): Promise<UnoBox[]>;
99
+ /** Delete a box; a box that is already gone is not an error. */
100
+ deleteBox(id: string | number): Promise<void>;
101
+ /**
102
+ * Poll until the box is running and provisioned. Create returns at once with
103
+ * `status: "provisioning"`; the machine boots from a warm snapshot in seconds.
104
+ */
105
+ waitReady(id: string | number, timeoutMs: number, signal?: AbortSignal): Promise<UnoBox>;
106
+ /**
107
+ * Run a command and wait for its result.
108
+ *
109
+ * The server holds the request for up to `waitS` seconds; longer commands
110
+ * come back as 202 + run id and are long-polled, so no single HTTP response
111
+ * outlives proxy idle limits (~100 s). Every attempt carries the same
112
+ * idempotency key, so a retry after a dropped connection returns the run
113
+ * already recorded instead of starting the command twice.
114
+ */
115
+ run(id: string | number, payload: {
116
+ cmd: string;
117
+ env?: Record<string, string>;
118
+ timeout_s: number;
119
+ }, opts?: {
120
+ waitS?: number;
121
+ idempotencyKey?: string;
122
+ }): Promise<UnoRun>;
123
+ }
124
+
125
+ interface UnoConfig extends UnoClientOptions {
126
+ /**
127
+ * Region for new machines: `'us'` (High-end) or `'nl'`. Falls back to
128
+ * `UNO_REGION`; omitted means the account's default region.
129
+ */
130
+ region?: string;
131
+ /** OS template slug (see `GET /api/v1/box-templates`). Default `'ubuntu-24.04'`. */
132
+ template?: string;
133
+ /** Default vCPUs when `create` does not say. Default 2. */
134
+ vcpu?: number;
135
+ /** Default memory in MiB when `create` does not say. Default 2048. */
136
+ ramMb?: number;
137
+ /** Default disk in GB when `create` does not say. Default 10. */
138
+ diskGb?: number;
139
+ /** How long `create` waits for the machine to boot, in ms. Default 120 000. */
140
+ readyTimeoutMs?: number;
141
+ }
142
+ interface UnoSandbox {
143
+ id: string;
144
+ box: UnoBox;
145
+ client: UnoClient;
146
+ /** Environment from `create({ envs })`, applied to every command. */
147
+ envs?: Record<string, string>;
148
+ }
149
+ type ConfigWithClient = UnoConfig & {
150
+ __client?: UnoClient;
151
+ };
152
+ declare const uno: (config: ConfigWithClient) => _computesdk_provider.Provider<UnoSandbox, any, any, computesdk.Volume>;
153
+
154
+ export { DEFAULT_BASE_URL, type UnoBox, UnoClient, type UnoClientOptions, type UnoConfig, type UnoCreateBoxRequest, UnoError, type UnoRun, type UnoSandbox, uno as default, uno };