withruntime 0.14.0 → 0.16.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/BLAXEL.md +97 -32
- package/COMPATIBILITY.md +120 -5
- package/DAYTONA.md +34 -3
- package/E2B.md +34 -5
- package/README.md +33 -0
- package/README.src.md +33 -0
- package/VERCEL.md +52 -5
- package/compatibility-lock.json +71 -111
- package/dist/blaxel/client.d.ts +11 -0
- package/dist/blaxel/client.js +28 -0
- package/dist/blaxel/errors.d.ts +65 -0
- package/dist/blaxel/errors.js +114 -0
- package/dist/blaxel/index.d.ts +10 -3
- package/dist/blaxel/index.js +23 -4
- package/dist/blaxel/preview.d.ts +29 -4
- package/dist/blaxel/preview.js +79 -5
- package/dist/blaxel/sandbox.js +1 -0
- package/dist/blaxel/session.js +4 -2
- package/dist/cli-extras.js +2 -1
- package/dist/cli-words.js +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +54 -21
- package/dist/client.d.ts +1 -1
- package/dist/daytona/client.d.ts +4 -0
- package/dist/daytona/client.js +8 -3
- package/dist/daytona/daytona.d.ts +3 -0
- package/dist/daytona/daytona.js +2 -1
- package/dist/e2b/sandbox.d.ts +6 -5
- package/dist/e2b/sandbox.js +9 -12
- package/dist/freestyle/index.d.ts +77 -5
- package/dist/freestyle/index.js +380 -48
- package/dist/identity.js +36 -18
- package/dist/index.d.ts +2 -2
- package/dist/machine.d.ts +24 -12
- package/dist/machine.js +46 -14
- package/dist/mcp.js +16 -3
- package/dist/modal/index.d.ts +15 -0
- package/dist/modal/index.js +35 -7
- package/dist/morph/index.d.ts +255 -0
- package/dist/morph/index.js +641 -0
- package/dist/network-cli.js +2 -2
- package/dist/product-names.d.ts +2 -2
- package/dist/product-names.js +2 -2
- package/dist/products/limits.d.ts +16 -2
- package/dist/products/limits.js +2 -2
- package/dist/products/mcp.d.ts +5 -0
- package/dist/products/network-products.d.ts +21 -3
- package/dist/products/network-products.js +3 -1
- package/dist/products/previews.d.ts +6 -3
- package/dist/products/previews.js +1 -1
- package/dist/snapshots.d.ts +4 -0
- package/dist/ssh.d.ts +35 -0
- package/dist/ssh.js +93 -1
- package/dist/transport.d.ts +11 -8
- package/dist/transport.js +46 -12
- package/dist/types.d.ts +24 -0
- package/dist/vercel/command.d.ts +48 -1
- package/dist/vercel/command.js +237 -6
- package/dist/vercel/sandbox-user.js +2 -1
- package/dist/vercel/sandbox.d.ts +16 -2
- package/dist/vercel/sandbox.js +45 -2
- package/package.json +6 -1
package/dist/machine.js
CHANGED
|
@@ -41,7 +41,7 @@ export function machinePage(product, t, wrap, body, query, options = {}) {
|
|
|
41
41
|
}
|
|
42
42
|
/** One machine: its record and the verbs every machine product shares. */
|
|
43
43
|
/** Machines `create` made, which the end of an `await using` block deletes
|
|
44
|
-
* (
|
|
44
|
+
* (6 October 2026: deleted unless the code passes `keep: true`). One
|
|
45
45
|
* from `get`, or an existing one `getOrCreate` found, is only stopped. */
|
|
46
46
|
const deleteAtBlockEnd = new WeakSet();
|
|
47
47
|
export class Machine {
|
|
@@ -111,7 +111,9 @@ export class Machine {
|
|
|
111
111
|
return deleteMachine(this.#product, this.#t, this.id, options);
|
|
112
112
|
}
|
|
113
113
|
/** Carries on a paused sandbox; for one with a time limit,
|
|
114
|
-
* `timeoutSeconds` is its new one.
|
|
114
|
+
* `timeoutSeconds` is its new one. A wake stays on its server; when that
|
|
115
|
+
* server is full for now (`no_capacity`) it waits for room as `create`
|
|
116
|
+
* does, up to `waitForCapacityMs` (the client's, two minutes by default). */
|
|
115
117
|
async wake(options = {}) {
|
|
116
118
|
const { timeoutSeconds, ...rest } = options;
|
|
117
119
|
try {
|
|
@@ -128,15 +130,17 @@ export class Machine {
|
|
|
128
130
|
return this;
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
|
-
/** More time before its time limit ends (at most
|
|
133
|
+
/** More time before its time limit ends (at most 24 hours ahead of now). A
|
|
132
134
|
* sandbox with no time limit needs none: the call answers at once and
|
|
133
|
-
* changes nothing.
|
|
135
|
+
* changes nothing. To set the end sooner, or give one with no limit a limit,
|
|
136
|
+
* `update({ timeoutSeconds })`. */
|
|
134
137
|
async extend(seconds, options = {}) {
|
|
135
138
|
return this.#lifecycle("extend", { ...options, wait: false }, { seconds });
|
|
136
139
|
}
|
|
137
|
-
/** Changes its name, labels, automatic wake, idle pause
|
|
138
|
-
* fields left out stay as they are. `persistent:
|
|
139
|
-
* while credit lasts (paid only).
|
|
140
|
+
/** Changes its name, labels, automatic wake, idle pause, time limit, end
|
|
141
|
+
* action or persistence; fields left out stay as they are. `persistent:
|
|
142
|
+
* true` keeps it running while credit lasts (paid only). `timeoutSeconds`
|
|
143
|
+
* ends it that long from now, sooner or later than before (0: no limit). */
|
|
140
144
|
async update(settings, options = {}) {
|
|
141
145
|
return this.#lifecycle("update", { ...options, wait: false }, { ...settings });
|
|
142
146
|
}
|
|
@@ -277,20 +281,26 @@ export class Machine {
|
|
|
277
281
|
await this.refresh(request());
|
|
278
282
|
// Straight after a fork or a wake the sandbox is still `resuming`, and
|
|
279
283
|
// after a pause still `pausing`: wait for where it is going, or a
|
|
280
|
-
// snapshot of it is refused as not paused (
|
|
284
|
+
// snapshot of it is refused as not paused (23 September 2026).
|
|
281
285
|
if (this.state === "resuming" || this.state === "starting")
|
|
282
286
|
await this.waitFor("running", request());
|
|
283
287
|
else if (this.state === "pausing")
|
|
284
288
|
await this.waitFor("paused", request());
|
|
285
289
|
running = this.state === "running";
|
|
286
290
|
// Check before entering cleanup: an abort during refresh must not pause or wake.
|
|
287
|
-
|
|
291
|
+
request();
|
|
288
292
|
let captured;
|
|
289
293
|
let primary;
|
|
290
294
|
let failed = false;
|
|
295
|
+
/** Whether the server may have left a running source paused: it answered
|
|
296
|
+
* before the capture was over, or not at all. */
|
|
297
|
+
let leftPaused = running;
|
|
291
298
|
try {
|
|
292
|
-
|
|
293
|
-
|
|
299
|
+
// One call: the server pauses a running source for the capture, and
|
|
300
|
+
// wakes it before it answers a capture that is over (ready or failed).
|
|
301
|
+
// Pausing, snapshotting and waking it from here took four calls: a
|
|
302
|
+
// repeat snapshot of a 4 GiB sandbox took 1.96 s at the median against
|
|
303
|
+
// 1.19 s for this one (15 October 2026).
|
|
294
304
|
let snapshot = await this.#t.json({
|
|
295
305
|
method: "POST",
|
|
296
306
|
path: this.#path(":snapshot"),
|
|
@@ -300,6 +310,7 @@ export class Machine {
|
|
|
300
310
|
...request(),
|
|
301
311
|
});
|
|
302
312
|
captured = snapshot;
|
|
313
|
+
leftPaused = running && snapshot.state === "capturing";
|
|
303
314
|
// Prefer: wait is bounded on the server. A capture still in progress
|
|
304
315
|
// must keep its source paused, or the worker refuses it after we wake.
|
|
305
316
|
while (snapshot.state === "capturing") {
|
|
@@ -337,9 +348,17 @@ export class Machine {
|
|
|
337
348
|
}
|
|
338
349
|
// A capture still running needs its source paused: the worker fails one
|
|
339
350
|
// whose source woke. The timeout says so and leaves the wake to the caller.
|
|
340
|
-
if (
|
|
351
|
+
if (leftPaused && !late) {
|
|
341
352
|
try {
|
|
342
|
-
|
|
353
|
+
// A call that failed may have been refused before anything paused
|
|
354
|
+
// (pausable: false, volumes): only a source that is paused is woken.
|
|
355
|
+
if (failed && captured === undefined)
|
|
356
|
+
await this.refresh();
|
|
357
|
+
if (!failed ||
|
|
358
|
+
captured !== undefined ||
|
|
359
|
+
this.state === "paused" ||
|
|
360
|
+
this.state === "pausing")
|
|
361
|
+
await this.wake();
|
|
343
362
|
}
|
|
344
363
|
catch (wakeError) {
|
|
345
364
|
const recovery = {
|
|
@@ -365,17 +384,30 @@ export class Machine {
|
|
|
365
384
|
throw primary;
|
|
366
385
|
return captured;
|
|
367
386
|
}
|
|
368
|
-
/** Starts a stopped persistent sandbox again from its disk (memory is not
|
|
387
|
+
/** Starts a stopped persistent sandbox again from its disk (memory is not
|
|
388
|
+
* kept), waiting for room on a full server as `wake` does. Its image's
|
|
389
|
+
* start command runs again, reported in `info.start`. */
|
|
369
390
|
async restart(options = {}) {
|
|
370
391
|
return this.#lifecycle("restart", options);
|
|
371
392
|
}
|
|
372
393
|
async #lifecycle(verb, options, body = {}) {
|
|
394
|
+
// A wake or restart refused for room ran nothing and is sent again with
|
|
395
|
+
// the same key (api.md, "A refusal is not kept"). Until 17 October 2026
|
|
396
|
+
// only create waited: the product check's wake was refused no_capacity
|
|
397
|
+
// in 36 ms on 16 October, where a create would have waited for room.
|
|
398
|
+
const room = verb === "wake" || verb === "restart"
|
|
399
|
+
? {
|
|
400
|
+
waitForCapacityMs: options.waitForCapacityMs ?? this.#t.waitForCapacityMs,
|
|
401
|
+
...(options.onCapacityWait ? { onCapacityWait: options.onCapacityWait } : {}),
|
|
402
|
+
}
|
|
403
|
+
: {};
|
|
373
404
|
this.#keep(await this.#t.json({
|
|
374
405
|
method: "POST",
|
|
375
406
|
path: this.#path(`:${verb}`),
|
|
376
407
|
body,
|
|
377
408
|
wait: options.wait === false ? 0 : 60,
|
|
378
409
|
...requestOnly(options),
|
|
410
|
+
...room,
|
|
379
411
|
}));
|
|
380
412
|
return this;
|
|
381
413
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -212,11 +212,16 @@ export async function serveMcp(env = process.env, options = {}) {
|
|
|
212
212
|
await new Promise((resolve) => setTimeout(resolve, 10_000));
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
-
/** Starts forwarding with this key and tells the client its tools changed.
|
|
215
|
+
/** Starts forwarding with this key and tells the client its tools changed.
|
|
216
|
+
* The client read CONNECT_INSTRUCTIONS on its own initialize and will not
|
|
217
|
+
* read instructions again, so the hosted server's (limits, safe writes,
|
|
218
|
+
* cleanup, the task) come back in this answer, or an agent's first session
|
|
219
|
+
* never sees them. Not every client re-lists tools when told; a restart of
|
|
220
|
+
* this server finds the saved key and serves them at once. */
|
|
216
221
|
async function connected(found, agentName) {
|
|
217
222
|
key = found;
|
|
218
223
|
pending = undefined;
|
|
219
|
-
await post(JSON.stringify({
|
|
224
|
+
const { messages } = await post(JSON.stringify({
|
|
220
225
|
jsonrpc: "2.0",
|
|
221
226
|
id: "runtime-connect",
|
|
222
227
|
method: "initialize",
|
|
@@ -224,7 +229,15 @@ export async function serveMcp(env = process.env, options = {}) {
|
|
|
224
229
|
}));
|
|
225
230
|
await post(JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }));
|
|
226
231
|
write({ jsonrpc: "2.0", method: "notifications/tools/list_changed" });
|
|
227
|
-
|
|
232
|
+
const instructions = messages
|
|
233
|
+
.map((reply) => reply.result?.instructions)
|
|
234
|
+
.find((words) => typeof words === "string" && words.length > 0);
|
|
235
|
+
return [
|
|
236
|
+
`Connected${agentName ? ` as ${agentName}` : ""}. Runtime's tools are available now: list the tools again, then start with runtime_sandboxes_create. If they do not appear, restart this MCP server (or the client): the connection is saved, so it connects at once.`,
|
|
237
|
+
...(instructions
|
|
238
|
+
? ["", "Runtime's instructions, to follow from here:", "", instructions]
|
|
239
|
+
: []),
|
|
240
|
+
].join("\n");
|
|
228
241
|
}
|
|
229
242
|
/** Not connected yet: answer the client here, with the tools that connect. */
|
|
230
243
|
async function connectMode(message, id) {
|
package/dist/modal/index.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export declare class App {
|
|
|
47
47
|
readonly name?: string | undefined;
|
|
48
48
|
readonly environmentName?: string | undefined;
|
|
49
49
|
constructor(appId: string, name?: string | undefined, environmentName?: string | undefined);
|
|
50
|
+
readonly info: RefusedAsync;
|
|
50
51
|
}
|
|
51
52
|
export declare class AppService {
|
|
52
53
|
private readonly client;
|
|
@@ -90,6 +91,7 @@ export declare class VolumeService {
|
|
|
90
91
|
fromName(name: string, params?: {
|
|
91
92
|
createIfMissing?: boolean;
|
|
92
93
|
environment?: string;
|
|
94
|
+
version?: 1 | 2;
|
|
93
95
|
}): Promise<Volume>;
|
|
94
96
|
delete(name: string, params?: {
|
|
95
97
|
allowMissing?: boolean;
|
|
@@ -211,6 +213,14 @@ export declare class SandboxSnapshotService {
|
|
|
211
213
|
constructor(client: ModalClient);
|
|
212
214
|
fromId(snapshotId: string): Promise<SandboxSnapshot>;
|
|
213
215
|
}
|
|
216
|
+
/** `client.environments` (modal 0.11.1): refused, as `environment` options are. */
|
|
217
|
+
export declare class EnvironmentService {
|
|
218
|
+
readonly fromName: RefusedAsync;
|
|
219
|
+
readonly objects: Refused;
|
|
220
|
+
}
|
|
221
|
+
export declare const Environment: Refused;
|
|
222
|
+
export declare const EnvironmentAppsService: Refused;
|
|
223
|
+
export declare const EnvironmentObjectsService: Refused;
|
|
214
224
|
export type ModalClientParams = ClientOptions & {
|
|
215
225
|
tokenId?: string;
|
|
216
226
|
tokenSecret?: string;
|
|
@@ -237,6 +247,7 @@ export declare class ModalClient {
|
|
|
237
247
|
readonly cloudBucketMounts: CloudBucketMountService;
|
|
238
248
|
readonly sandboxSnapshots: SandboxSnapshotService;
|
|
239
249
|
readonly proxies: ProxyService;
|
|
250
|
+
readonly environments: EnvironmentService;
|
|
240
251
|
constructor(options?: ModalClientParams);
|
|
241
252
|
/** Throws once close() was called, as Modal's client does. */
|
|
242
253
|
open(): void;
|
|
@@ -292,11 +303,15 @@ export declare class SandboxService {
|
|
|
292
303
|
create(app: App, image: Image, params?: SandboxCreateParams): Promise<Sandbox>;
|
|
293
304
|
experimentalCreate(app: App, image: Image, params?: SandboxCreateParams): Promise<Sandbox>;
|
|
294
305
|
fromId(id: string): Promise<Sandbox>;
|
|
306
|
+
/** The running sandbox of that name; with includeTerminated, when none
|
|
307
|
+
* runs, the one that stopped last (modal 0.11.1). */
|
|
295
308
|
fromName(appName: string, name: string, params?: {
|
|
296
309
|
environment?: string;
|
|
310
|
+
includeTerminated?: boolean;
|
|
297
311
|
}): Promise<Sandbox>;
|
|
298
312
|
experimentalFromName(appName: string, name: string, params?: {
|
|
299
313
|
environment?: string;
|
|
314
|
+
includeTerminated?: boolean;
|
|
300
315
|
}): Promise<Sandbox>;
|
|
301
316
|
/** A new sandbox continuing a memory snapshot: its files, memory and
|
|
302
317
|
* running entrypoint, under the snapshot's app and tags. */
|
package/dist/modal/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConflictError as NativeConflictError, InvalidRequestError, NotFoundError as NativeNotFoundError, RateLimitError, RuntimeError, ServiceUnavailableError, } from "../errors.js";
|
|
2
|
-
import { all, client, CompatibilityError, create, destroy, execOptions, only, refuse, region, } from "../compat/core.js";
|
|
2
|
+
import { all, client, CompatibilityError, create, destroy, execOptions, only, refuse, refusal, refused, region, } from "../compat/core.js";
|
|
3
3
|
import { GuestFiles } from "../compat/files.js";
|
|
4
4
|
export { CompatibilityError };
|
|
5
5
|
// Errors ----------------------------------------------------------------------
|
|
@@ -104,6 +104,9 @@ export class App {
|
|
|
104
104
|
this.environmentName = environmentName;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
refuse("Modal", "App", App, {
|
|
108
|
+
info: "a Runtime app is a label on its sandboxes, with no lifecycle, Functions or Servers: list them with client.sandboxes.list({ appId: app.appId })",
|
|
109
|
+
});
|
|
107
110
|
export class AppService {
|
|
108
111
|
client;
|
|
109
112
|
constructor(client) {
|
|
@@ -183,9 +186,11 @@ export class VolumeService {
|
|
|
183
186
|
}
|
|
184
187
|
async fromName(name, params = {}) {
|
|
185
188
|
this.client.open();
|
|
186
|
-
only("Modal volume", params, ["createIfMissing", "environment"]);
|
|
189
|
+
only("Modal volume", params, ["createIfMissing", "environment", "version"]);
|
|
187
190
|
if (params.environment)
|
|
188
191
|
throw new CompatibilityError("Modal", "named Modal environments");
|
|
192
|
+
if (params.version !== undefined)
|
|
193
|
+
throw new CompatibilityError("Modal", "VolumeFS versions; a Runtime volume has one format, so omit version");
|
|
189
194
|
const found = await this.find(name);
|
|
190
195
|
if (found)
|
|
191
196
|
return new Volume(found.id, name);
|
|
@@ -402,6 +407,21 @@ export class SandboxSnapshotService {
|
|
|
402
407
|
return new SandboxSnapshot(snapshot.id);
|
|
403
408
|
}
|
|
404
409
|
}
|
|
410
|
+
// Environments ------------------------------------------------------------------
|
|
411
|
+
const NO_ENVIRONMENTS = "Runtime has no Modal environments: an account's sandboxes share one namespace, grouped by app name (client.apps.fromName) and tags";
|
|
412
|
+
/** `client.environments` (modal 0.11.1): refused, as `environment` options are. */
|
|
413
|
+
export class EnvironmentService {
|
|
414
|
+
}
|
|
415
|
+
refuse("Modal", "EnvironmentService", EnvironmentService, { fromName: NO_ENVIRONMENTS });
|
|
416
|
+
Object.defineProperty(EnvironmentService.prototype, "objects", {
|
|
417
|
+
configurable: true,
|
|
418
|
+
get() {
|
|
419
|
+
throw refusal("Modal", "EnvironmentService.objects", NO_ENVIRONMENTS);
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
export const Environment = refused("Modal", "Environment", NO_ENVIRONMENTS);
|
|
423
|
+
export const EnvironmentAppsService = refused("Modal", "EnvironmentAppsService", NO_ENVIRONMENTS);
|
|
424
|
+
export const EnvironmentObjectsService = refused("Modal", "EnvironmentObjectsService", NO_ENVIRONMENTS);
|
|
405
425
|
export class ModalClient {
|
|
406
426
|
runtime;
|
|
407
427
|
apps;
|
|
@@ -412,6 +432,7 @@ export class ModalClient {
|
|
|
412
432
|
cloudBucketMounts = new CloudBucketMountService();
|
|
413
433
|
sandboxSnapshots;
|
|
414
434
|
proxies = new ProxyService();
|
|
435
|
+
environments = new EnvironmentService();
|
|
415
436
|
#closed = false;
|
|
416
437
|
constructor(options = {}) {
|
|
417
438
|
if (options.endpoint !== undefined ||
|
|
@@ -458,7 +479,7 @@ export class ModalClient {
|
|
|
458
479
|
}
|
|
459
480
|
/** The Modal SDK version whose interface this adapter implements. */
|
|
460
481
|
version() {
|
|
461
|
-
return "0.11.
|
|
482
|
+
return "0.11.1";
|
|
462
483
|
}
|
|
463
484
|
close() {
|
|
464
485
|
// The transport owns no background connection; later calls fail as Modal's do.
|
|
@@ -619,14 +640,21 @@ export class SandboxService {
|
|
|
619
640
|
throw new NotFoundError("Sandbox is not a Modal-compatible sandbox");
|
|
620
641
|
return new Sandbox(s, new ContainerProcess(await modal(() => s.processes.get(p)), "text"), this.client);
|
|
621
642
|
}
|
|
643
|
+
/** The running sandbox of that name; with includeTerminated, when none
|
|
644
|
+
* runs, the one that stopped last (modal 0.11.1). */
|
|
622
645
|
async fromName(appName, name, params = {}) {
|
|
623
646
|
this.client?.open();
|
|
624
|
-
only("Modal sandbox name", params, ["environment"]);
|
|
647
|
+
only("Modal sandbox name", params, ["environment", "includeTerminated"]);
|
|
625
648
|
if (params.environment)
|
|
626
649
|
throw new CompatibilityError("Modal", ENVIRONMENTS);
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
650
|
+
const named = (await all(this.runtime, "modal")).filter((s) => s.info.labels["modal.app"] === appName && s.info.labels["modal.name"] === name);
|
|
651
|
+
const ended = (s) => s.info.endedAt ?? s.info.createdAt ?? "";
|
|
652
|
+
const s = named.find((s) => s.state === "running") ??
|
|
653
|
+
(params.includeTerminated
|
|
654
|
+
? named
|
|
655
|
+
.filter((s) => s.state === "stopped")
|
|
656
|
+
.sort((a, b) => ended(b).localeCompare(ended(a)))[0]
|
|
657
|
+
: undefined);
|
|
630
658
|
if (!s)
|
|
631
659
|
throw new NotFoundError(`Sandbox ${name} not found`);
|
|
632
660
|
return this.fromId(s.id);
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import type { Runtime } from "../client.js";
|
|
2
|
+
import type { Preview } from "../products/previews.js";
|
|
3
|
+
import { Sandbox } from "../sandbox.js";
|
|
4
|
+
import type { Snapshot as NativeSnapshot } from "../snapshots.js";
|
|
5
|
+
import { CompatibilityError, type ClientOptions, type RefusedAsync } from "../compat/core.js";
|
|
6
|
+
export { CompatibilityError };
|
|
7
|
+
/** Morph's base image; on Runtime, the default image. */
|
|
8
|
+
export declare const MORPH_DEFAULT_IMAGE = "morphvm-minimal";
|
|
9
|
+
export declare enum SnapshotStatus {
|
|
10
|
+
PENDING = "pending",
|
|
11
|
+
READY = "ready",
|
|
12
|
+
FAILED = "failed",
|
|
13
|
+
DELETING = "deleting",
|
|
14
|
+
DELETED = "deleted"
|
|
15
|
+
}
|
|
16
|
+
export declare enum InstanceStatus {
|
|
17
|
+
PENDING = "pending",
|
|
18
|
+
READY = "ready",
|
|
19
|
+
PAUSED = "paused",
|
|
20
|
+
SAVING = "saving",
|
|
21
|
+
ERROR = "error"
|
|
22
|
+
}
|
|
23
|
+
export interface ResourceSpec {
|
|
24
|
+
vcpus: number;
|
|
25
|
+
/** MiB. */
|
|
26
|
+
memory: number;
|
|
27
|
+
/** MiB. */
|
|
28
|
+
diskSize: number;
|
|
29
|
+
}
|
|
30
|
+
export interface SnapshotRefs {
|
|
31
|
+
imageId: string;
|
|
32
|
+
}
|
|
33
|
+
export interface InstanceHttpService {
|
|
34
|
+
name: string;
|
|
35
|
+
port: number;
|
|
36
|
+
url: string;
|
|
37
|
+
}
|
|
38
|
+
export interface InstanceNetworking {
|
|
39
|
+
internalIp?: string;
|
|
40
|
+
httpServices: InstanceHttpService[];
|
|
41
|
+
auth_mode?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface InstanceRefs {
|
|
44
|
+
snapshotId: string;
|
|
45
|
+
imageId: string;
|
|
46
|
+
}
|
|
47
|
+
export interface InstanceExecResponse {
|
|
48
|
+
exit_code: number;
|
|
49
|
+
stdout: string;
|
|
50
|
+
stderr: string;
|
|
51
|
+
}
|
|
52
|
+
export interface InstanceTTL {
|
|
53
|
+
ttlSeconds?: number;
|
|
54
|
+
ttlExpireAt?: number;
|
|
55
|
+
ttlAction?: "stop" | "pause";
|
|
56
|
+
}
|
|
57
|
+
export interface InstanceWakeOn {
|
|
58
|
+
wakeOnSsh?: boolean;
|
|
59
|
+
wakeOnHttp?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface ExecOptions {
|
|
62
|
+
/** Seconds; default 24 hours, as Morph's. */
|
|
63
|
+
timeout?: number;
|
|
64
|
+
onStdout?: (content: string) => void;
|
|
65
|
+
onStderr?: (content: string) => void;
|
|
66
|
+
}
|
|
67
|
+
export interface InstanceSshKey {
|
|
68
|
+
object: "instance_ssh_key";
|
|
69
|
+
private_key: string;
|
|
70
|
+
public_key: string;
|
|
71
|
+
password: string;
|
|
72
|
+
}
|
|
73
|
+
export interface MorphCloudClientOptions extends ClientOptions {
|
|
74
|
+
/** A Runtime key (`rtcloud_...`); a Morph key is never sent anywhere. */
|
|
75
|
+
apiKey?: string;
|
|
76
|
+
baseUrl?: string;
|
|
77
|
+
verbose?: boolean;
|
|
78
|
+
}
|
|
79
|
+
export type ImageListOptions = Record<string, never>;
|
|
80
|
+
export interface SnapshotListOptions {
|
|
81
|
+
digest?: string;
|
|
82
|
+
metadata?: Record<string, string>;
|
|
83
|
+
}
|
|
84
|
+
export interface SnapshotCreateOptions {
|
|
85
|
+
imageId?: string;
|
|
86
|
+
vcpus?: number;
|
|
87
|
+
memory?: number;
|
|
88
|
+
diskSize?: number;
|
|
89
|
+
digest?: string;
|
|
90
|
+
metadata?: Record<string, string>;
|
|
91
|
+
}
|
|
92
|
+
export interface SnapshotGetOptions {
|
|
93
|
+
snapshotId: string;
|
|
94
|
+
}
|
|
95
|
+
export interface InstanceListOptions {
|
|
96
|
+
metadata?: Record<string, string>;
|
|
97
|
+
}
|
|
98
|
+
export interface InstanceStartOptions {
|
|
99
|
+
snapshotId: string;
|
|
100
|
+
metadata?: Record<string, string>;
|
|
101
|
+
ttlSeconds?: number;
|
|
102
|
+
ttlAction?: "stop" | "pause";
|
|
103
|
+
/** Seconds to wait until it runs. */
|
|
104
|
+
timeout?: number;
|
|
105
|
+
}
|
|
106
|
+
export interface InstanceSnapshotOptions {
|
|
107
|
+
digest?: string;
|
|
108
|
+
metadata?: Record<string, string>;
|
|
109
|
+
}
|
|
110
|
+
export interface InstanceGetOptions {
|
|
111
|
+
instanceId: string;
|
|
112
|
+
}
|
|
113
|
+
export interface InstanceStopOptions {
|
|
114
|
+
instanceId: string;
|
|
115
|
+
}
|
|
116
|
+
export interface InstanceBootOptions {
|
|
117
|
+
snapshotId: string;
|
|
118
|
+
vcpus?: number;
|
|
119
|
+
memory?: number;
|
|
120
|
+
diskSize?: number;
|
|
121
|
+
metadata?: Record<string, string>;
|
|
122
|
+
ttlSeconds?: number;
|
|
123
|
+
ttlAction?: "stop" | "pause";
|
|
124
|
+
}
|
|
125
|
+
export interface SyncOptions {
|
|
126
|
+
delete?: boolean;
|
|
127
|
+
dryRun?: boolean;
|
|
128
|
+
verbose?: boolean;
|
|
129
|
+
respectGitignore?: boolean;
|
|
130
|
+
}
|
|
131
|
+
export declare class Image {
|
|
132
|
+
readonly id: string;
|
|
133
|
+
readonly name: string;
|
|
134
|
+
readonly diskSize: number;
|
|
135
|
+
readonly created: number;
|
|
136
|
+
readonly description?: string | undefined;
|
|
137
|
+
readonly object: "image";
|
|
138
|
+
constructor(id: string, name: string, diskSize: number, created: number, description?: string | undefined);
|
|
139
|
+
}
|
|
140
|
+
export declare class Snapshot {
|
|
141
|
+
#private;
|
|
142
|
+
readonly native: NativeSnapshot;
|
|
143
|
+
readonly id: string;
|
|
144
|
+
readonly object: "snapshot";
|
|
145
|
+
readonly created: number;
|
|
146
|
+
readonly status: SnapshotStatus;
|
|
147
|
+
readonly spec: ResourceSpec;
|
|
148
|
+
readonly refs: SnapshotRefs;
|
|
149
|
+
readonly digest?: string;
|
|
150
|
+
metadata?: Record<string, string>;
|
|
151
|
+
constructor(native: NativeSnapshot, morph: MorphCloudClient);
|
|
152
|
+
delete(): Promise<void>;
|
|
153
|
+
/** Morph's chain hash: SHA-256 of the parent's hash, a newline and the effect. */
|
|
154
|
+
static computeChainHash(parentChainHash: string, effectIdentifier: string): string;
|
|
155
|
+
/** Runs `command` on a copy of this snapshot and snapshots the result, once:
|
|
156
|
+
* a later setup of the same command on the same snapshot answers the
|
|
157
|
+
* snapshot made the first time. A command that fails throws, and the copy
|
|
158
|
+
* is stopped either way. */
|
|
159
|
+
setup(command: string): Promise<Snapshot>;
|
|
160
|
+
/** Adds or changes these metadata keys; the others stay. */
|
|
161
|
+
setMetadata(metadata: Record<string, string>): Promise<void>;
|
|
162
|
+
}
|
|
163
|
+
export declare class Instance {
|
|
164
|
+
#private;
|
|
165
|
+
readonly id: string;
|
|
166
|
+
readonly object: "instance";
|
|
167
|
+
readonly created: number;
|
|
168
|
+
status: InstanceStatus;
|
|
169
|
+
readonly spec: ResourceSpec;
|
|
170
|
+
readonly refs: InstanceRefs;
|
|
171
|
+
networking: InstanceNetworking;
|
|
172
|
+
ttl: InstanceTTL;
|
|
173
|
+
wakeOn: InstanceWakeOn;
|
|
174
|
+
metadata?: Record<string, string>;
|
|
175
|
+
readonly ssh: RefusedAsync;
|
|
176
|
+
readonly sshKey: RefusedAsync;
|
|
177
|
+
readonly sshKeyRotate: RefusedAsync;
|
|
178
|
+
readonly reboot: RefusedAsync;
|
|
179
|
+
readonly setTTL: RefusedAsync;
|
|
180
|
+
constructor(sandbox: Sandbox, morph: MorphCloudClient, previews?: Preview[]);
|
|
181
|
+
/** The Runtime sandbox behind it, for what Morph has no call for. */
|
|
182
|
+
get native(): Sandbox;
|
|
183
|
+
/** Deletes it, with its disk and memory, as Morph's stop does; its snapshots stay. */
|
|
184
|
+
stop(): Promise<void>;
|
|
185
|
+
/** Keeps memory and disk, and stops compute charges. */
|
|
186
|
+
pause(): Promise<void>;
|
|
187
|
+
resume(): Promise<void>;
|
|
188
|
+
/** Adds or changes these metadata keys; the others stay. */
|
|
189
|
+
setMetadata(metadata: Record<string, string>): Promise<void>;
|
|
190
|
+
/** Runtime wakes a paused sandbox on any request (an API call, SSH, a
|
|
191
|
+
* visit to a shared port) or on none: both values must agree. */
|
|
192
|
+
setWakeOn(wakeOnSsh?: boolean, wakeOnHttp?: boolean): Promise<void>;
|
|
193
|
+
/** Files, memory and running processes; a running instance pauses for the
|
|
194
|
+
* moment it takes, then runs on. */
|
|
195
|
+
snapshot(options?: InstanceSnapshotOptions): Promise<Snapshot>;
|
|
196
|
+
/** `count` running copies, with its files, memory and processes, and the
|
|
197
|
+
* snapshot they were started from, which is kept. */
|
|
198
|
+
branch(count: number): Promise<{
|
|
199
|
+
snapshot: Snapshot;
|
|
200
|
+
instances: Instance[];
|
|
201
|
+
}>;
|
|
202
|
+
/** Shares `port` at an HTTPS address. With no auth_mode, anyone with the
|
|
203
|
+
* address reaches it (Runtime's public preview, which needs a kept
|
|
204
|
+
* top-up); with auth_mode "api_key", a request needs the preview's token
|
|
205
|
+
* in `x-runtime-preview-token` (native.previews.get(port)). */
|
|
206
|
+
exposeHttpService(name: string, port: number, auth_mode?: string): Promise<InstanceHttpService>;
|
|
207
|
+
hideHttpService(name: string): Promise<void>;
|
|
208
|
+
/** A string, or a one-item array, runs in a shell; a longer array runs as
|
|
209
|
+
* its arguments. Output streams to onStdout and onStderr as it comes. */
|
|
210
|
+
exec(command: string | string[], options?: ExecOptions): Promise<InstanceExecResponse>;
|
|
211
|
+
/** Seconds; waits until it runs, waking it if paused. */
|
|
212
|
+
waitUntilReady(timeout?: number): Promise<void>;
|
|
213
|
+
/** Copies a local file or folder into the instance, or out of it: the
|
|
214
|
+
* instance's side is written `<instance id>:<path>`. Without delete, dry
|
|
215
|
+
* runs or .gitignore, which refuse. */
|
|
216
|
+
sync(source: string, dest: string, options?: SyncOptions): Promise<void>;
|
|
217
|
+
}
|
|
218
|
+
/** Morph's client, on Runtime. `new MorphCloudClient()` reads RUNTIME_API_KEY
|
|
219
|
+
* (or a saved login), never MORPH_API_KEY. */
|
|
220
|
+
export declare class MorphCloudClient {
|
|
221
|
+
readonly runtime: Runtime;
|
|
222
|
+
readonly baseUrl: string;
|
|
223
|
+
readonly apiKey: string;
|
|
224
|
+
readonly verbose: boolean;
|
|
225
|
+
readonly GET: RefusedAsync;
|
|
226
|
+
readonly POST: RefusedAsync;
|
|
227
|
+
readonly streamPOST: RefusedAsync;
|
|
228
|
+
readonly DELETE: RefusedAsync;
|
|
229
|
+
constructor(options?: MorphCloudClientOptions);
|
|
230
|
+
images: {
|
|
231
|
+
/** Morph's base image, which is Runtime's default image. Build others with runtime.images. */
|
|
232
|
+
list: (_options?: ImageListOptions) => Promise<Image[]>;
|
|
233
|
+
};
|
|
234
|
+
snapshots: {
|
|
235
|
+
list: (options?: SnapshotListOptions) => Promise<Snapshot[]>;
|
|
236
|
+
/** A bootable snapshot of an image at a size: Runtime boots a sandbox from
|
|
237
|
+
* the image, snapshots its disk and stops it. With a digest, a snapshot
|
|
238
|
+
* already made with it is answered instead. */
|
|
239
|
+
create: (options?: SnapshotCreateOptions) => Promise<Snapshot>;
|
|
240
|
+
get: (options: SnapshotGetOptions) => Promise<Snapshot>;
|
|
241
|
+
};
|
|
242
|
+
instances: {
|
|
243
|
+
/** Running and paused instances whose metadata match. */
|
|
244
|
+
list: (options?: InstanceListOptions) => Promise<Instance[]>;
|
|
245
|
+
/** A running copy of a snapshot: files, and memory and processes when the
|
|
246
|
+
* snapshot kept them. */
|
|
247
|
+
start: (options: InstanceStartOptions) => Promise<Instance>;
|
|
248
|
+
/** As start; a different vcpus or memory restarts it at that size (its
|
|
249
|
+
* files kept, its programs started afresh). The disk keeps the snapshot's size. */
|
|
250
|
+
boot: (options: InstanceBootOptions) => Promise<Instance>;
|
|
251
|
+
get: (options: InstanceGetOptions) => Promise<Instance>;
|
|
252
|
+
/** Deletes it, with its disk and memory, as Morph's stop does; its snapshots stay. */
|
|
253
|
+
stop: (options: InstanceStopOptions) => Promise<void>;
|
|
254
|
+
};
|
|
255
|
+
}
|