withruntime 0.5.0 → 0.6.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.
Files changed (56) hide show
  1. package/DAYTONA.md +25 -25
  2. package/E2B.md +1 -1
  3. package/LICENSE +55 -0
  4. package/README.md +3 -2
  5. package/dist/cli-extras.d.ts +24 -0
  6. package/dist/cli-extras.js +205 -0
  7. package/dist/cli.d.ts +20 -0
  8. package/dist/cli.js +430 -37
  9. package/dist/daytona/context.d.ts +5 -0
  10. package/dist/daytona/context.js +3 -0
  11. package/dist/daytona/filesystem.js +2 -2
  12. package/dist/daytona/process.js +3 -1
  13. package/dist/e2b/commands.js +6 -2
  14. package/dist/e2b/filesystem.d.ts +26 -1
  15. package/dist/e2b/filesystem.js +30 -2
  16. package/dist/e2b/index.d.ts +1 -1
  17. package/dist/e2b/index.js +1 -1
  18. package/dist/errors.js +2 -0
  19. package/dist/identity.d.ts +27 -0
  20. package/dist/identity.js +56 -0
  21. package/dist/index.d.ts +14 -0
  22. package/dist/index.js +7 -0
  23. package/dist/mcp.js +16 -3
  24. package/dist/network-cli.d.ts +15 -0
  25. package/dist/network-cli.js +323 -0
  26. package/dist/products/desktop.d.ts +41 -4
  27. package/dist/products/desktop.js +73 -3
  28. package/dist/products/index.d.ts +12 -0
  29. package/dist/products/index.js +12 -0
  30. package/dist/products/interpreter.d.ts +5 -3
  31. package/dist/products/interpreter.js +2 -1
  32. package/dist/products/mcp.d.ts +79 -0
  33. package/dist/products/mcp.js +37 -0
  34. package/dist/products/mounts.d.ts +49 -0
  35. package/dist/products/mounts.js +21 -0
  36. package/dist/products/network-products.d.ts +167 -0
  37. package/dist/products/network-products.js +82 -0
  38. package/dist/products/network.d.ts +1 -1
  39. package/dist/products/sso.d.ts +44 -0
  40. package/dist/products/sso.js +8 -0
  41. package/dist/products/switching.d.ts +7 -0
  42. package/dist/products/volumes.d.ts +68 -5
  43. package/dist/products/volumes.js +52 -4
  44. package/dist/products/watch.d.ts +91 -0
  45. package/dist/products/watch.js +135 -0
  46. package/dist/sandbox.d.ts +32 -2
  47. package/dist/sandbox.js +93 -16
  48. package/dist/snapshots.d.ts +11 -1
  49. package/dist/ssh.js +13 -1
  50. package/dist/transport.d.ts +1 -1
  51. package/dist/transport.js +4 -1
  52. package/dist/tunnel.d.ts +4 -1
  53. package/dist/tunnel.js +8 -3
  54. package/dist/wireguard.d.ts +7 -0
  55. package/dist/wireguard.js +13 -0
  56. package/package.json +7 -3
@@ -0,0 +1,79 @@
1
+ import type { Sandbox } from "../sandbox.js";
2
+ import type { RequestOptions, Transport } from "../transport.js";
3
+ export type McpCatalogEntry = {
4
+ id: string;
5
+ title: string;
6
+ description: string;
7
+ license: string;
8
+ source: string;
9
+ version: string;
10
+ env: {
11
+ name: string;
12
+ description: string;
13
+ required: boolean;
14
+ secret: boolean;
15
+ hosts?: string[];
16
+ }[];
17
+ options: {
18
+ name: string;
19
+ description: string;
20
+ required: boolean;
21
+ }[];
22
+ egress: string[];
23
+ checked: string;
24
+ };
25
+ export type McpServerRequest = {
26
+ /** A catalog id, e.g. "github". */
27
+ id: string;
28
+ name?: string;
29
+ /** A secret setting to the Runtime secret that fills it. */
30
+ secrets?: Record<string, string>;
31
+ env?: Record<string, string>;
32
+ options?: Record<string, string>;
33
+ } | {
34
+ name: string;
35
+ command: string[];
36
+ env?: Record<string, string>;
37
+ };
38
+ export type McpGateway = {
39
+ running: boolean;
40
+ port: number | null;
41
+ /** Send it as `Authorization: Bearer <token>`. */
42
+ token?: string | null;
43
+ headers?: Record<string, string>;
44
+ urlExpiresAt?: string | null;
45
+ servers: {
46
+ name: string;
47
+ status: "installing" | "ready" | "failed";
48
+ message?: string | null;
49
+ /** Its Streamable HTTP endpoint. */
50
+ url: string | null;
51
+ }[];
52
+ warnings: string[];
53
+ };
54
+ /** `runtime.mcp`: the catalog of MCP servers a sandbox can run. */
55
+ export declare function mcp(t: Transport): {
56
+ catalog: (options?: RequestOptions) => Promise<McpCatalogEntry[]>;
57
+ };
58
+ /** `sbx.mcp`: catalog MCP servers running inside the sandbox, at URLs an
59
+ * agent connects to.
60
+ *
61
+ * const gw = await sbx.mcp.start([{ id: "github", secrets: { GITHUB_PERSONAL_ACCESS_TOKEN: "GITHUB_TOKEN" } }]);
62
+ * // gw.servers[0].url with gw.headers, in any MCP client
63
+ */
64
+ export declare function sandboxMcp(t: Transport, sandbox: Sandbox): {
65
+ start: (servers: McpServerRequest[], input?: {
66
+ port?: number;
67
+ replace?: boolean;
68
+ }, options?: RequestOptions) => Promise<McpGateway>;
69
+ /** Their state, and fresh URLs. */
70
+ get: (options?: RequestOptions) => Promise<McpGateway>;
71
+ /** Wait until every server is ready (or one failed). */
72
+ ready(input?: {
73
+ timeoutMs?: number;
74
+ intervalMs?: number;
75
+ }): Promise<McpGateway>;
76
+ stop: (options?: RequestOptions) => Promise<{
77
+ stopped: boolean;
78
+ }>;
79
+ };
@@ -0,0 +1,37 @@
1
+ /** `runtime.mcp`: the catalog of MCP servers a sandbox can run. */
2
+ export function mcp(t) {
3
+ return {
4
+ catalog: async (options) => (await t.json({
5
+ method: "GET",
6
+ path: "/v1/mcp/catalog",
7
+ ...options,
8
+ })).data,
9
+ };
10
+ }
11
+ /** `sbx.mcp`: catalog MCP servers running inside the sandbox, at URLs an
12
+ * agent connects to.
13
+ *
14
+ * const gw = await sbx.mcp.start([{ id: "github", secrets: { GITHUB_PERSONAL_ACCESS_TOKEN: "GITHUB_TOKEN" } }]);
15
+ * // gw.servers[0].url with gw.headers, in any MCP client
16
+ */
17
+ export function sandboxMcp(t, sandbox) {
18
+ const path = () => `/v1/sandboxes/${encodeURIComponent(sandbox.id)}/mcp`;
19
+ return {
20
+ start: (servers, input = {}, options) => t.json({ method: "POST", path: path(), body: { servers, ...input }, ...options }),
21
+ /** Their state, and fresh URLs. */
22
+ get: (options) => t.json({ method: "GET", path: path(), ...options }),
23
+ /** Wait until every server is ready (or one failed). */
24
+ async ready(input = {}) {
25
+ const deadline = Date.now() + (input.timeoutMs ?? 600_000);
26
+ for (;;) {
27
+ const state = await t.json({ method: "GET", path: path() });
28
+ if (!state.running || state.servers.every((server) => server.status !== "installing"))
29
+ return state;
30
+ if (Date.now() > deadline)
31
+ return state;
32
+ await new Promise((resolve) => setTimeout(resolve, input.intervalMs ?? 2_000));
33
+ }
34
+ },
35
+ stop: (options) => t.json({ method: "DELETE", path: path(), ...options }),
36
+ };
37
+ }
@@ -0,0 +1,49 @@
1
+ import type { Sandbox } from "../sandbox.js";
2
+ import type { RequestOptions, Transport } from "../transport.js";
3
+ /** A bucket mounted in a sandbox. */
4
+ export type Mount = {
5
+ path: string;
6
+ provider: "s3" | "r2" | "gcs";
7
+ bucket: string;
8
+ prefix: string | null;
9
+ /** The endpoint host the sandbox reaches the bucket at. */
10
+ endpoint: string;
11
+ /** The secret whose key the egress proxy signs with; null for a public bucket. */
12
+ secret: string | null;
13
+ readOnly: boolean;
14
+ /** Whether it is mounted right now. */
15
+ mounted: boolean;
16
+ mountedAt?: string;
17
+ };
18
+ export type MountBucket = {
19
+ /** s3 for Amazon S3, or any S3-compatible store with `endpoint`; r2 for
20
+ * Cloudflare R2 (with `accountId`); gcs for Google Cloud Storage (HMAC keys). */
21
+ provider: "s3" | "r2" | "gcs";
22
+ bucket: string;
23
+ /** Where it appears in the sandbox, such as /data. */
24
+ path: string;
25
+ prefix?: string;
26
+ region?: string;
27
+ endpoint?: string;
28
+ accountId?: string;
29
+ /** A secret stored with header `Authorization`, format
30
+ * `AWS4-HMAC-SHA256 {value}` and value `ACCESS_KEY_ID:SECRET_KEY`, naming
31
+ * the endpoint host. The sandbox never sees the key. Omit for a public bucket. */
32
+ secret?: string;
33
+ readOnly?: boolean;
34
+ };
35
+ /** `sbx.mounts`: your own S3, R2 or Google Cloud Storage bucket as a
36
+ * directory in this sandbox.
37
+ *
38
+ * await sbx.mounts.add({ provider: "s3", bucket: "data", region: "eu-west-1",
39
+ * path: "/data", secret: "DATA_BUCKET" });
40
+ *
41
+ * A mount lasts through a pause and a wake, and ends when the sandbox stops. */
42
+ export declare function sandboxMounts(t: Transport, sandbox: Sandbox): {
43
+ add: (input: MountBucket, options?: RequestOptions) => Promise<Mount>;
44
+ list: (options?: RequestOptions) => Promise<Mount[]>;
45
+ remove: (path: string, options?: RequestOptions) => Promise<{
46
+ path: string;
47
+ mounted: false;
48
+ }>;
49
+ };
@@ -0,0 +1,21 @@
1
+ const enc = encodeURIComponent;
2
+ /** `sbx.mounts`: your own S3, R2 or Google Cloud Storage bucket as a
3
+ * directory in this sandbox.
4
+ *
5
+ * await sbx.mounts.add({ provider: "s3", bucket: "data", region: "eu-west-1",
6
+ * path: "/data", secret: "DATA_BUCKET" });
7
+ *
8
+ * A mount lasts through a pause and a wake, and ends when the sandbox stops. */
9
+ export function sandboxMounts(t, sandbox) {
10
+ const base = () => `/v1/sandboxes/${enc(sandbox.id)}/mounts`;
11
+ return {
12
+ add: (input, options) => t.json({ method: "POST", path: base(), body: input, ...options }),
13
+ list: async (options) => (await t.json({ method: "GET", path: base(), ...options })).data,
14
+ remove: (path, options) => t.json({
15
+ method: "POST",
16
+ path: `${base()}:unmount`,
17
+ body: { path },
18
+ ...options,
19
+ }),
20
+ };
21
+ }
@@ -0,0 +1,167 @@
1
+ import type { RequestOptions, Transport } from "../transport.js";
2
+ export type DnsRecord = {
3
+ type: string;
4
+ name: string;
5
+ value: string;
6
+ purpose: string;
7
+ };
8
+ export type Domain = {
9
+ id: string;
10
+ hostname: string;
11
+ sandboxId: string;
12
+ port: number;
13
+ /** pending until the TXT record proves the name is yours, then active. */
14
+ state: "pending" | "active" | "released";
15
+ url: string;
16
+ /** Turned off by Runtime after a report. */
17
+ disabled: boolean;
18
+ /** The TXT record that proves the name, and the CNAME (or A) that sends visitors here. */
19
+ records: DnsRecord[];
20
+ verifiedAt: string | null;
21
+ checkedAt: string | null;
22
+ checkError: string | null;
23
+ createdAt: string;
24
+ };
25
+ export type CheckedDomain = Domain & {
26
+ /** The name resolves to Runtime's edge now. */
27
+ pointed: boolean | null;
28
+ hint: string;
29
+ };
30
+ export type TcpPort = {
31
+ id: string;
32
+ sandboxId: string;
33
+ /** The port inside the sandbox. */
34
+ port: number;
35
+ address: string;
36
+ publicPort: number;
37
+ /** address:publicPort, for a client's host and port. */
38
+ connect: string;
39
+ protocol: "tcp";
40
+ disabled: boolean;
41
+ createdAt: string;
42
+ };
43
+ export type NetworkFunding = {
44
+ /** False disables traffic; the reservation remains until explicitly released. */
45
+ funded: boolean;
46
+ /** Last funded-through ISO timestamp, possibly past. Null means no meter exists. */
47
+ fundedUntil: string | null;
48
+ /** Immutable monthly quote in millionths of a US dollar. */
49
+ rateMicros: number;
50
+ rateUnit: "unit_month";
51
+ };
52
+ export type EgressAddress = NetworkFunding & {
53
+ id: string;
54
+ address: string;
55
+ family: 4 | 6;
56
+ createdAt: string;
57
+ };
58
+ export type TunnelPeer = {
59
+ id: string;
60
+ name: string;
61
+ publicKey: string;
62
+ /** The peer's address inside the tunnel's subnet. */
63
+ address: string;
64
+ /** Your own ranges behind the peer that sandboxes may reach through it. */
65
+ routes: string[];
66
+ createdAt: string;
67
+ rotatedAt: string | null;
68
+ };
69
+ export type Tunnel = NetworkFunding & {
70
+ id: string;
71
+ subnet: string;
72
+ gatewayAddress: string;
73
+ /** Where peers send WireGuard: address:udpPort. */
74
+ endpoint: string;
75
+ /** Null for a few seconds after creation. */
76
+ gatewayPublicKey: string | null;
77
+ disabled: boolean;
78
+ peers: TunnelPeer[];
79
+ /** Each sandbox's address in the tunnel. */
80
+ sandboxes: {
81
+ sandboxId: string;
82
+ name: string | null;
83
+ address: string;
84
+ state: string;
85
+ }[];
86
+ createdAt: string;
87
+ };
88
+ export type TunnelPeerCreated = {
89
+ tunnel: Tunnel;
90
+ peer: TunnelPeer;
91
+ /** A wg-quick file. It holds the private key only when Runtime generated it. */
92
+ config: string | null;
93
+ /** False means config is a draft preserving the private key; fill its gateway PublicKey before use. */
94
+ configReady: boolean;
95
+ hint: string;
96
+ };
97
+ /** `runtime.domains`: serve a sandbox's port at your own hostname, with HTTPS. */
98
+ export declare function domains(t: Transport): {
99
+ /** Claims the hostname and answers the DNS records to set. Calling it again
100
+ * with another sandbox or port points the name there. */
101
+ add: (input: {
102
+ hostname: string;
103
+ sandboxId: string;
104
+ port: number;
105
+ }, options?: RequestOptions) => Promise<CheckedDomain>;
106
+ /** Checks the TXT record now; the name goes live when it matches. */
107
+ verify: (hostname: string, options?: RequestOptions) => Promise<CheckedDomain>;
108
+ get: (hostname: string, options?: RequestOptions) => Promise<Domain>;
109
+ list: (options?: RequestOptions) => Promise<Domain[]>;
110
+ remove: (hostname: string, options?: RequestOptions) => Promise<{
111
+ hostname: string;
112
+ deleted: true;
113
+ }>;
114
+ };
115
+ /** `runtime.ports`: a public TCP port to a port of a sandbox. */
116
+ export declare function ports(t: Transport): {
117
+ /** Returns the same public port when called again for the same sandbox and port. */
118
+ open: (input: {
119
+ sandboxId: string;
120
+ port: number;
121
+ }, options?: RequestOptions) => Promise<TcpPort & {
122
+ hint: string;
123
+ }>;
124
+ list: (filter?: {
125
+ sandboxId?: string;
126
+ }, options?: RequestOptions) => Promise<TcpPort[]>;
127
+ close: (portId: string, options?: RequestOptions) => Promise<{
128
+ id: string;
129
+ deleted: true;
130
+ }>;
131
+ };
132
+ /** `runtime.addresses`: a dedicated outbound address every sandbox of the
133
+ * account sends from, for allow-lists. */
134
+ export declare function addresses(t: Transport): {
135
+ reserve: (input?: {
136
+ family?: 4 | 6;
137
+ }, options?: RequestOptions) => Promise<EgressAddress>;
138
+ list: (options?: RequestOptions) => Promise<EgressAddress[]>;
139
+ release: (addressId: string, options?: RequestOptions) => Promise<{
140
+ id: string;
141
+ address: string;
142
+ deleted: true;
143
+ }>;
144
+ };
145
+ /** `runtime.tunnel`: a WireGuard tunnel from your own network into your sandboxes. */
146
+ export declare function tunnel(t: Transport): {
147
+ get: (options?: RequestOptions) => Promise<Tunnel>;
148
+ /** Idempotent: returns the tunnel you have. */
149
+ create: (input?: {
150
+ subnet?: string;
151
+ }, options?: RequestOptions) => Promise<Tunnel>;
152
+ delete: (options?: RequestOptions) => Promise<{
153
+ id: string;
154
+ deleted: true;
155
+ }>;
156
+ /** Leave publicKey out and Runtime generates the pair; the private key is
157
+ * then in `config`, shown once. */
158
+ addPeer: (input: {
159
+ name: string;
160
+ publicKey?: string;
161
+ routes?: string[];
162
+ }, options?: RequestOptions) => Promise<TunnelPeerCreated>;
163
+ rotatePeer: (peerId: string, input?: {
164
+ publicKey?: string;
165
+ }, options?: RequestOptions) => Promise<TunnelPeerCreated>;
166
+ removePeer: (peerId: string, options?: RequestOptions) => Promise<Tunnel>;
167
+ };
@@ -0,0 +1,82 @@
1
+ const enc = encodeURIComponent;
2
+ /** `runtime.domains`: serve a sandbox's port at your own hostname, with HTTPS. */
3
+ export function domains(t) {
4
+ return {
5
+ /** Claims the hostname and answers the DNS records to set. Calling it again
6
+ * with another sandbox or port points the name there. */
7
+ add: (input, options) => t.json({ method: "POST", path: "/v1/domains", body: input, ...options }),
8
+ /** Checks the TXT record now; the name goes live when it matches. */
9
+ verify: (hostname, options) => t.json({
10
+ method: "POST",
11
+ path: `/v1/domains/${enc(hostname)}:verify`,
12
+ ...options,
13
+ }),
14
+ get: (hostname, options) => t.json({ method: "GET", path: `/v1/domains/${enc(hostname)}`, ...options }),
15
+ list: async (options) => (await t.json({ method: "GET", path: "/v1/domains", ...options })).data,
16
+ remove: (hostname, options) => t.json({
17
+ method: "DELETE",
18
+ path: `/v1/domains/${enc(hostname)}`,
19
+ ...options,
20
+ }),
21
+ };
22
+ }
23
+ /** `runtime.ports`: a public TCP port to a port of a sandbox. */
24
+ export function ports(t) {
25
+ return {
26
+ /** Returns the same public port when called again for the same sandbox and port. */
27
+ open: (input, options) => t.json({
28
+ method: "POST",
29
+ path: "/v1/ports",
30
+ body: input,
31
+ ...options,
32
+ }),
33
+ list: async (filter = {}, options) => (await t.json({
34
+ method: "GET",
35
+ path: `/v1/ports${filter.sandboxId ? `?sandboxId=${enc(filter.sandboxId)}` : ""}`,
36
+ ...options,
37
+ })).data,
38
+ close: (portId, options) => t.json({
39
+ method: "DELETE",
40
+ path: `/v1/ports/${enc(portId)}`,
41
+ ...options,
42
+ }),
43
+ };
44
+ }
45
+ /** `runtime.addresses`: a dedicated outbound address every sandbox of the
46
+ * account sends from, for allow-lists. */
47
+ export function addresses(t) {
48
+ return {
49
+ reserve: (input = {}, options) => t.json({ method: "POST", path: "/v1/addresses", body: input, ...options }),
50
+ list: async (options) => (await t.json({ method: "GET", path: "/v1/addresses", ...options }))
51
+ .data,
52
+ release: (addressId, options) => t.json({
53
+ method: "DELETE",
54
+ path: `/v1/addresses/${enc(addressId)}`,
55
+ ...options,
56
+ }),
57
+ };
58
+ }
59
+ /** `runtime.tunnel`: a WireGuard tunnel from your own network into your sandboxes. */
60
+ export function tunnel(t) {
61
+ return {
62
+ get: (options) => t.json({ method: "GET", path: "/v1/tunnel", ...options }),
63
+ /** Idempotent: returns the tunnel you have. */
64
+ create: (input = {}, options) => t.json({ method: "POST", path: "/v1/tunnel", body: input, ...options }),
65
+ delete: (options) => t.json({ method: "DELETE", path: "/v1/tunnel", ...options }),
66
+ /** Leave publicKey out and Runtime generates the pair; the private key is
67
+ * then in `config`, shown once. */
68
+ addPeer: (input, options) => t.json({
69
+ method: "POST",
70
+ path: "/v1/tunnel/peers",
71
+ body: input,
72
+ ...options,
73
+ }),
74
+ rotatePeer: (peerId, input = {}, options) => t.json({
75
+ method: "POST",
76
+ path: `/v1/tunnel/peers/${enc(peerId)}:rotate`,
77
+ body: input,
78
+ ...options,
79
+ }),
80
+ removePeer: (peerId, options) => t.json({ method: "DELETE", path: `/v1/tunnel/peers/${enc(peerId)}`, ...options }),
81
+ };
82
+ }
@@ -24,7 +24,7 @@ export type NetworkPolicy = Required<NetworkRules> & {
24
24
  /** Ports reachable without a connect entry. */
25
25
  ports: number[];
26
26
  connectAllowed: boolean;
27
- /** paid, granted, not_paid, revoked or suspended. */
27
+ /** paid, granted, not_paid, revoked, suspended, or trial (a trial sandbox reaches ports 80 and 443 only). */
28
28
  connectReason: string;
29
29
  forbiddenPorts: number[];
30
30
  updatedAt: string | null;
@@ -0,0 +1,44 @@
1
+ import type { RequestOptions, Transport } from "../transport.js";
2
+ /** One identity provider of the account. */
3
+ export type SsoConnection = {
4
+ id: string;
5
+ /** Names the connection in its sign-in URLs. */
6
+ providerId: string;
7
+ protocol: "oidc" | "saml";
8
+ provider: "okta" | "entra" | "google" | "other";
9
+ /** The email domain it answers for. */
10
+ domain: string;
11
+ /** When DNS proved the domain; null until then, and nobody signs in until then. */
12
+ domainVerifiedAt: string | null;
13
+ /** The TXT record that proves the domain. */
14
+ verification: {
15
+ type: "TXT";
16
+ name: string;
17
+ value: string;
18
+ };
19
+ defaultRole: "admin" | "developer" | "billing";
20
+ /** Members other than owners sign in only through it. API keys are unaffected. */
21
+ requireSso: boolean;
22
+ createdAt: string;
23
+ };
24
+ export type SsoStatus = {
25
+ connections: SsoConnection[];
26
+ scim: {
27
+ tokens: number;
28
+ users: number;
29
+ activeUsers: number;
30
+ groups: {
31
+ id: string;
32
+ displayName: string;
33
+ role: string | null;
34
+ }[];
35
+ };
36
+ /** Where an owner changes single sign-on. */
37
+ manage: string;
38
+ };
39
+ /** `runtime.sso.get()`: the account's single sign-on and SCIM directory sync.
40
+ * Read only; an owner changes it on the website. Needs a key made by an owner
41
+ * or admin. */
42
+ export declare function sso(t: Transport): {
43
+ get: (options?: RequestOptions) => Promise<SsoStatus>;
44
+ };
@@ -0,0 +1,8 @@
1
+ /** `runtime.sso.get()`: the account's single sign-on and SCIM directory sync.
2
+ * Read only; an owner changes it on the website. Needs a key made by an owner
3
+ * or admin. */
4
+ export function sso(t) {
5
+ return {
6
+ get: (options) => t.json({ method: "GET", path: "/v1/sso", ...options }),
7
+ };
8
+ }
@@ -52,7 +52,14 @@ export type UsageComparison = {
52
52
  runSeconds: number;
53
53
  activeCpuSeconds: number;
54
54
  unpricedSandboxes: number;
55
+ /** Of `sandboxes`, how many the free trial paid for, and their running
56
+ * time. The trial charged nothing for them; `runtimeMicros` prices them at
57
+ * Runtime's standard rates, what the same work costs on paid credit. */
58
+ trialSandboxes: number;
59
+ trialRunSeconds: number;
55
60
  };
61
+ /** What the usage costs on Runtime on paid credit: each paid sandbox at the
62
+ * rates it was quoted, a trial sandbox at the standard rates. */
56
63
  runtimeMicros: string;
57
64
  rivalMicros: string;
58
65
  /** Rival less Runtime: negative when the rival would cost less. */
@@ -13,8 +13,16 @@ export type Volume = {
13
13
  filesystem: "ext4";
14
14
  usedMiB: number | null;
15
15
  measuredAt: string | null;
16
- /** Always false: a volume lives on one host and is not copied off it. */
17
- backedUp: false;
16
+ /** True once a backup of it has been copied off its host and checked. */
17
+ backedUp: boolean;
18
+ /** Daily backups, how long each is kept, and when the newest was taken. */
19
+ backups: {
20
+ daily: boolean;
21
+ retentionDays: number;
22
+ lastReadyAt: string | null;
23
+ };
24
+ /** The backup this volume was restored from, if any. */
25
+ restoredFrom: string | null;
18
26
  attachments: {
19
27
  sandboxId: string;
20
28
  mode: "rw" | "snapshot";
@@ -26,15 +34,42 @@ export type Volume = {
26
34
  readyAt: string | null;
27
35
  };
28
36
  export type CreateVolume = {
29
- sizeMiB: number;
37
+ /** Required unless restoring: a restore is the backup's size. */
38
+ sizeMiB?: number;
39
+ /** A ready backup to restore into the new volume, on any host in its region. */
40
+ fromBackup?: string;
30
41
  name?: string;
31
42
  labels?: Record<string, string>;
32
43
  region?: string;
33
44
  };
45
+ export type VolumeBackupState = "pending" | "ready" | "failed" | "deleting" | "deleted";
46
+ /** A point-in-time copy of a volume, kept off its host. */
47
+ export type VolumeBackup = {
48
+ id: string;
49
+ kind: "volume-backup";
50
+ status: string;
51
+ state: VolumeBackupState;
52
+ name: string | null;
53
+ labels: Record<string, string>;
54
+ region: string;
55
+ volumeId: string;
56
+ sizeMiB: number;
57
+ trigger: "manual" | "daily";
58
+ retentionDays: number;
59
+ logicalBytes: number | null;
60
+ storedBytes: number | null;
61
+ meteredBytes: number | null;
62
+ error: string | null;
63
+ createdAt: string;
64
+ readyAt: string | null;
65
+ expiresAt: string;
66
+ };
34
67
  /** Persistent disks: create once, attach when creating a sandbox with
35
- * `volumes: [{ volumeId: v.id, path: "/data" }]`. Not backed up off its host. */
68
+ * `volumes: [{ volumeId: v.id, path: "/data" }]`. Backed up off their host
69
+ * daily unless that is turned off; restore one with `create({ fromBackup })`. */
36
70
  export declare function volumes(t: Transport): {
37
- /** Create and wait (up to 10 s) until it is ready. */
71
+ /** Create and wait (up to 10 s) until it is ready. With `fromBackup`, a
72
+ * restore; it is ready once the backup is downloaded and checked. */
38
73
  create: (input: CreateVolume, options?: RequestOptions) => Promise<Volume>;
39
74
  get: (id: string, options?: RequestOptions) => Promise<Volume>;
40
75
  list: (query?: {
@@ -44,4 +79,32 @@ export declare function volumes(t: Transport): {
44
79
  cursor?: string;
45
80
  }, options?: RequestOptions) => Promise<Page<Volume>>;
46
81
  delete: (id: string, options?: RequestOptions) => Promise<Volume>;
82
+ /** Back a volume up now, off its host, and wait (up to a minute, or
83
+ * `wait` seconds) for it to be ready. */
84
+ backup: (id: string, input?: {
85
+ name?: string;
86
+ labels?: Record<string, string>;
87
+ retentionDays?: number;
88
+ }, options?: RequestOptions & {
89
+ wait?: number;
90
+ }) => Promise<VolumeBackup>;
91
+ /** Daily backups on or off, and how many days each is kept. */
92
+ setBackupPolicy: (id: string, input: {
93
+ daily?: boolean;
94
+ retentionDays?: number;
95
+ }, options?: RequestOptions) => Promise<Volume>;
96
+ /** Backups, newest first; `{ volumeId }` for one volume's. */
97
+ backups: (query?: {
98
+ volumeId?: string;
99
+ state?: Exclude<VolumeBackupState, "deleted">;
100
+ limit?: number;
101
+ cursor?: string;
102
+ }, options?: RequestOptions) => Promise<Page<VolumeBackup>>;
103
+ getBackup: (id: string, options?: RequestOptions) => Promise<VolumeBackup>;
104
+ deleteBackup: (id: string, options?: RequestOptions) => Promise<VolumeBackup>;
105
+ /** A new volume from a backup: `create({ fromBackup: id })`. */
106
+ restore: (backupId: string, input?: {
107
+ name?: string;
108
+ labels?: Record<string, string>;
109
+ }, options?: RequestOptions) => Promise<Volume>;
47
110
  };