@schemavaults/sandbox-management-sdk 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +295 -2
- package/dist/commands.d.ts +16 -0
- package/dist/commands.js +99 -0
- package/dist/dbh/index.d.ts +4 -0
- package/dist/dbh/index.js +2 -0
- package/dist/dbh/migration.d.ts +18 -0
- package/dist/dbh/migration.js +41 -0
- package/dist/dbh/store.d.ts +42 -0
- package/dist/dbh/store.js +105 -0
- package/dist/docker/egress-proxy/config.d.ts +20 -0
- package/dist/docker/egress-proxy/config.js +29 -0
- package/dist/docker/egress-proxy/main.d.ts +1 -0
- package/dist/docker/egress-proxy/main.js +19 -0
- package/dist/docker/egress-proxy/policy.d.ts +49 -0
- package/dist/docker/egress-proxy/policy.js +89 -0
- package/dist/docker/egress-proxy/server.d.ts +25 -0
- package/dist/docker/egress-proxy/server.js +225 -0
- package/dist/docker/egress.d.ts +41 -0
- package/dist/docker/egress.js +67 -0
- package/dist/docker/index.d.ts +3 -0
- package/dist/docker/index.js +2 -0
- package/dist/docker/provider.d.ts +101 -0
- package/dist/docker/provider.js +373 -0
- package/dist/docker/tar.d.ts +20 -0
- package/dist/docker/tar.js +124 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.js +67 -0
- package/dist/in-memory-store.d.ts +11 -0
- package/dist/in-memory-store.js +40 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +8 -0
- package/dist/internal/base64.d.ts +7 -0
- package/dist/internal/base64.js +20 -0
- package/dist/internal/output.d.ts +6 -0
- package/dist/internal/output.js +25 -0
- package/dist/internal/posix-path.d.ts +8 -0
- package/dist/internal/posix-path.js +38 -0
- package/dist/manager.d.ts +126 -0
- package/dist/manager.js +477 -0
- package/dist/network.d.ts +27 -0
- package/dist/network.js +128 -0
- package/dist/provider.d.ts +77 -0
- package/dist/provider.js +1 -0
- package/dist/shell-main-process.d.ts +27 -0
- package/dist/shell-main-process.js +94 -0
- package/dist/store.d.ts +36 -0
- package/dist/store.js +19 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/mock-provider.d.ts +99 -0
- package/dist/testing/mock-provider.js +181 -0
- package/dist/types.d.ts +158 -0
- package/dist/types.js +21 -0
- package/dist/vercel/index.d.ts +2 -0
- package/dist/vercel/index.js +1 -0
- package/dist/vercel/provider.d.ts +125 -0
- package/dist/vercel/provider.js +190 -0
- package/dist/web-storage/index.d.ts +2 -0
- package/dist/web-storage/index.js +1 -0
- package/dist/web-storage/store.d.ts +53 -0
- package/dist/web-storage/store.js +118 -0
- package/package.json +117 -4
package/dist/errors.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export class SandboxError extends Error {
|
|
2
|
+
constructor(message, options) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = new.target.name;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class SandboxNotFoundError extends SandboxError {
|
|
8
|
+
sandboxId;
|
|
9
|
+
constructor(sandboxId) {
|
|
10
|
+
super(`Sandbox "${sandboxId}" not found`);
|
|
11
|
+
this.sandboxId = sandboxId;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class ProviderNotFoundError extends SandboxError {
|
|
15
|
+
providerName;
|
|
16
|
+
constructor(providerName) {
|
|
17
|
+
super(`No sandbox provider registered under the name "${providerName}"`);
|
|
18
|
+
this.providerName = providerName;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** The operation is not allowed while the sandbox is in its current status. */
|
|
22
|
+
export class SandboxStateError extends SandboxError {
|
|
23
|
+
sandboxId;
|
|
24
|
+
status;
|
|
25
|
+
constructor(sandboxId, status, operation) {
|
|
26
|
+
super(`Cannot ${operation} sandbox "${sandboxId}" while it is ${status}`);
|
|
27
|
+
this.sandboxId = sandboxId;
|
|
28
|
+
this.status = status;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The sandbox stayed in a transitional status for longer than the manager waits. */
|
|
32
|
+
export class SandboxBusyError extends SandboxError {
|
|
33
|
+
sandboxId;
|
|
34
|
+
status;
|
|
35
|
+
constructor(sandboxId, status) {
|
|
36
|
+
super(`Timed out waiting for sandbox "${sandboxId}" to leave status ${status}`);
|
|
37
|
+
this.sandboxId = sandboxId;
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** A lifecycle command (git clone or a setup step) exited non-zero. */
|
|
42
|
+
export class SandboxCommandError extends SandboxError {
|
|
43
|
+
step;
|
|
44
|
+
result;
|
|
45
|
+
constructor(step, result) {
|
|
46
|
+
const output = (result.stderr || result.stdout).trim().slice(-2000);
|
|
47
|
+
super(`${step} exited with code ${result.exitCode}${output ? `: ${output}` : ""}`);
|
|
48
|
+
this.step = step;
|
|
49
|
+
this.result = result;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Thrown by providers when an operation needs a running sandbox but it is stopped. */
|
|
53
|
+
export class ProviderSandboxStoppedError extends SandboxError {
|
|
54
|
+
providerRef;
|
|
55
|
+
constructor(providerRef) {
|
|
56
|
+
super(`Provider sandbox "${providerRef}" is not running`);
|
|
57
|
+
this.providerRef = providerRef;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Thrown by providers when the sandbox no longer exists on the provider. */
|
|
61
|
+
export class ProviderSandboxMissingError extends SandboxError {
|
|
62
|
+
providerRef;
|
|
63
|
+
constructor(providerRef) {
|
|
64
|
+
super(`Provider sandbox "${providerRef}" no longer exists`);
|
|
65
|
+
this.providerRef = providerRef;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SandboxListFilter, SandboxRecordPatch, SandboxStore } from "./store.js";
|
|
2
|
+
import type { SandboxRecord } from "./types.js";
|
|
3
|
+
/** A process-local store for tests and single-process development. */
|
|
4
|
+
export declare class InMemorySandboxStore implements SandboxStore {
|
|
5
|
+
private readonly records;
|
|
6
|
+
insert(record: SandboxRecord): Promise<void>;
|
|
7
|
+
get(id: string): Promise<SandboxRecord | null>;
|
|
8
|
+
list(filter?: SandboxListFilter): Promise<SandboxRecord[]>;
|
|
9
|
+
update(id: string, expectedVersion: number, patch: SandboxRecordPatch): Promise<SandboxRecord | null>;
|
|
10
|
+
delete(id: string): Promise<boolean>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { matchesFilter } from "./store.js";
|
|
2
|
+
/** A process-local store for tests and single-process development. */
|
|
3
|
+
export class InMemorySandboxStore {
|
|
4
|
+
records = new Map();
|
|
5
|
+
async insert(record) {
|
|
6
|
+
if (this.records.has(record.id)) {
|
|
7
|
+
throw new Error(`Sandbox record "${record.id}" already exists`);
|
|
8
|
+
}
|
|
9
|
+
this.records.set(record.id, structuredClone(record));
|
|
10
|
+
}
|
|
11
|
+
async get(id) {
|
|
12
|
+
const record = this.records.get(id);
|
|
13
|
+
return record ? structuredClone(record) : null;
|
|
14
|
+
}
|
|
15
|
+
async list(filter = {}) {
|
|
16
|
+
const matches = [...this.records.values()]
|
|
17
|
+
.filter((record) => matchesFilter(record, filter))
|
|
18
|
+
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
19
|
+
const offset = filter.offset ?? 0;
|
|
20
|
+
const end = filter.limit === undefined ? undefined : offset + filter.limit;
|
|
21
|
+
return matches.slice(offset, end).map((record) => structuredClone(record));
|
|
22
|
+
}
|
|
23
|
+
async update(id, expectedVersion, patch) {
|
|
24
|
+
const current = this.records.get(id);
|
|
25
|
+
if (!current || current.version !== expectedVersion)
|
|
26
|
+
return null;
|
|
27
|
+
const defined = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined));
|
|
28
|
+
const next = {
|
|
29
|
+
...current,
|
|
30
|
+
...structuredClone(defined),
|
|
31
|
+
version: current.version + 1,
|
|
32
|
+
updatedAt: new Date(),
|
|
33
|
+
};
|
|
34
|
+
this.records.set(id, next);
|
|
35
|
+
return structuredClone(next);
|
|
36
|
+
}
|
|
37
|
+
async delete(id) {
|
|
38
|
+
return this.records.delete(id);
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { SandboxManager, generateSandboxId } from "./manager.js";
|
|
2
|
+
export type { CreateSandboxOptions, LogsOptions, SandboxManagerOptions } from "./manager.js";
|
|
3
|
+
export { InMemorySandboxStore } from "./in-memory-store.js";
|
|
4
|
+
export { matchesFilter } from "./store.js";
|
|
5
|
+
export type { SandboxListFilter, SandboxRecordPatch, SandboxStore } from "./store.js";
|
|
6
|
+
export type { MainLogChunk, ProviderCreateInput, ProviderCreateResult, ProviderSandbox, ProviderSandboxStatus, ResolvedSandboxFile, SandboxProvider, } from "./provider.js";
|
|
7
|
+
export { ProviderNotFoundError, ProviderSandboxMissingError, ProviderSandboxStoppedError, SandboxBusyError, SandboxCommandError, SandboxError, SandboxNotFoundError, SandboxStateError, } from "./errors.js";
|
|
8
|
+
export { gitCloneCommand, normalizeCommand, resolveSandboxPath, shellQuote, toShellCommandLine, validateSpec, } from "./commands.js";
|
|
9
|
+
export { MAIN_PROCESS_DIR, mainProcessLauncher, shellGetMainProcess, shellReadMainLog, shellStartMainProcess, } from "./shell-main-process.js";
|
|
10
|
+
export { assertNetworkPolicySupported, networkPolicyKind, normalizeCidr } from "./network.js";
|
|
11
|
+
export { SANDBOX_STATUSES, TRANSITIONAL_STATUSES } from "./types.js";
|
|
12
|
+
export type { ArgvCommand, CommandInput, ExecOptions, ExecResult, GitSource, MainProcessInfo, NormalizedCommand, SandboxFile, SandboxNetworkAllowlist, SandboxNetworkPolicy, SandboxNetworkPolicyKind, SandboxProviderOptions, SandboxRecord, SandboxResources, SandboxSpec, SandboxStatus, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { SandboxManager, generateSandboxId } from "./manager.js";
|
|
2
|
+
export { InMemorySandboxStore } from "./in-memory-store.js";
|
|
3
|
+
export { matchesFilter } from "./store.js";
|
|
4
|
+
export { ProviderNotFoundError, ProviderSandboxMissingError, ProviderSandboxStoppedError, SandboxBusyError, SandboxCommandError, SandboxError, SandboxNotFoundError, SandboxStateError, } from "./errors.js";
|
|
5
|
+
export { gitCloneCommand, normalizeCommand, resolveSandboxPath, shellQuote, toShellCommandLine, validateSpec, } from "./commands.js";
|
|
6
|
+
export { MAIN_PROCESS_DIR, mainProcessLauncher, shellGetMainProcess, shellReadMainLog, shellStartMainProcess, } from "./shell-main-process.js";
|
|
7
|
+
export { assertNetworkPolicySupported, networkPolicyKind, normalizeCidr } from "./network.js";
|
|
8
|
+
export { SANDBOX_STATUSES, TRANSITIONAL_STATUSES } from "./types.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 without `Buffer`, so the core also runs in browsers. `btoa` and
|
|
3
|
+
* `atob` are globals in Node.js, Bun and every browser.
|
|
4
|
+
*/
|
|
5
|
+
export declare function encodeBase64(bytes: Uint8Array): string;
|
|
6
|
+
/** Whitespace in `text` is ignored. */
|
|
7
|
+
export declare function decodeBase64(text: string): Uint8Array;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 without `Buffer`, so the core also runs in browsers. `btoa` and
|
|
3
|
+
* `atob` are globals in Node.js, Bun and every browser.
|
|
4
|
+
*/
|
|
5
|
+
const CHUNK = 0x8000;
|
|
6
|
+
export function encodeBase64(bytes) {
|
|
7
|
+
let binary = "";
|
|
8
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
9
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
10
|
+
}
|
|
11
|
+
return btoa(binary);
|
|
12
|
+
}
|
|
13
|
+
/** Whitespace in `text` is ignored. */
|
|
14
|
+
export function decodeBase64(text) {
|
|
15
|
+
const binary = atob(text.replace(/\s+/g, ""));
|
|
16
|
+
const bytes = new Uint8Array(binary.length);
|
|
17
|
+
for (let i = 0; i < binary.length; i += 1)
|
|
18
|
+
bytes[i] = binary.charCodeAt(i);
|
|
19
|
+
return bytes;
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Writable } from "node:stream";
|
|
2
|
+
/** A Writable that decodes UTF-8 output, forwards each chunk and keeps the full text. */
|
|
3
|
+
export function outputCollector(onChunk) {
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
let text = "";
|
|
6
|
+
const push = (chunk) => {
|
|
7
|
+
if (!chunk)
|
|
8
|
+
return;
|
|
9
|
+
text += chunk;
|
|
10
|
+
onChunk?.(chunk);
|
|
11
|
+
};
|
|
12
|
+
const writable = new Writable({
|
|
13
|
+
write(chunk, _encoding, callback) {
|
|
14
|
+
push(typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true }));
|
|
15
|
+
callback();
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
writable,
|
|
20
|
+
finish: () => {
|
|
21
|
+
push(decoder.decode());
|
|
22
|
+
return text;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The POSIX path helpers the core needs, without `node:path`, so the core
|
|
3
|
+
* also runs in browsers. Same results as `posix.isAbsolute`,
|
|
4
|
+
* `posix.normalize` and `posix.join` from `node:path`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isAbsolute(path: string): boolean;
|
|
7
|
+
export declare function normalize(path: string): string;
|
|
8
|
+
export declare function join(...paths: string[]): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The POSIX path helpers the core needs, without `node:path`, so the core
|
|
3
|
+
* also runs in browsers. Same results as `posix.isAbsolute`,
|
|
4
|
+
* `posix.normalize` and `posix.join` from `node:path`.
|
|
5
|
+
*/
|
|
6
|
+
export function isAbsolute(path) {
|
|
7
|
+
return path.startsWith("/");
|
|
8
|
+
}
|
|
9
|
+
export function normalize(path) {
|
|
10
|
+
if (path === "")
|
|
11
|
+
return ".";
|
|
12
|
+
const absolute = isAbsolute(path);
|
|
13
|
+
const trailingSlash = path.endsWith("/");
|
|
14
|
+
const segments = [];
|
|
15
|
+
for (const segment of path.split("/")) {
|
|
16
|
+
if (segment === "" || segment === ".")
|
|
17
|
+
continue;
|
|
18
|
+
if (segment !== "..") {
|
|
19
|
+
segments.push(segment);
|
|
20
|
+
}
|
|
21
|
+
else if (segments.length > 0 && segments.at(-1) !== "..") {
|
|
22
|
+
segments.pop();
|
|
23
|
+
}
|
|
24
|
+
else if (!absolute) {
|
|
25
|
+
segments.push("..");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let result = segments.join("/");
|
|
29
|
+
if (result === "")
|
|
30
|
+
return absolute ? "/" : trailingSlash ? "./" : ".";
|
|
31
|
+
if (trailingSlash)
|
|
32
|
+
result += "/";
|
|
33
|
+
return absolute ? `/${result}` : result;
|
|
34
|
+
}
|
|
35
|
+
export function join(...paths) {
|
|
36
|
+
const joined = paths.filter((path) => path !== "").join("/");
|
|
37
|
+
return joined === "" ? "." : normalize(joined);
|
|
38
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { SandboxProvider } from "./provider.js";
|
|
2
|
+
import type { SandboxListFilter, SandboxStore } from "./store.js";
|
|
3
|
+
import type { CommandInput, ExecOptions, ExecResult, MainProcessInfo, SandboxFile, SandboxRecord, SandboxSpec } from "./types.js";
|
|
4
|
+
export interface SandboxManagerOptions {
|
|
5
|
+
providers: SandboxProvider[];
|
|
6
|
+
store: SandboxStore;
|
|
7
|
+
/** Provider used by `create` when none is given. Defaults to the only provider, if there is one. */
|
|
8
|
+
defaultProvider?: string;
|
|
9
|
+
/** Resume stopped sandboxes automatically when they are accessed. Default `true`. */
|
|
10
|
+
autoResume?: boolean;
|
|
11
|
+
/** How long to wait for another caller's in-flight transition. Default 10 minutes. */
|
|
12
|
+
transitionTimeoutMs?: number;
|
|
13
|
+
/** Poll interval while waiting for a transition. Default 250ms. */
|
|
14
|
+
pollIntervalMs?: number;
|
|
15
|
+
/** ID generator for new sandboxes. */
|
|
16
|
+
generateId?: () => string;
|
|
17
|
+
/** Clock, for tests. */
|
|
18
|
+
now?: () => Date;
|
|
19
|
+
}
|
|
20
|
+
export interface CreateSandboxOptions extends Pick<ExecOptions, "onStdout" | "onStderr"> {
|
|
21
|
+
spec: SandboxSpec;
|
|
22
|
+
/** Provider name. Defaults to `defaultProvider`. */
|
|
23
|
+
provider?: string;
|
|
24
|
+
ownerId?: string | null;
|
|
25
|
+
labels?: Record<string, string>;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export interface LogsOptions {
|
|
29
|
+
/** Keep polling for new output until `signal` aborts. Default `false`. */
|
|
30
|
+
follow?: boolean;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
/** Poll interval when following. Default 1000ms. */
|
|
33
|
+
pollIntervalMs?: number;
|
|
34
|
+
}
|
|
35
|
+
export declare function generateSandboxId(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Creates, lists and drives sandboxes across providers, keeping their state in
|
|
38
|
+
* a `SandboxStore`. Safe to use from many processes at once: every status
|
|
39
|
+
* change is a compare-and-set on the record's version.
|
|
40
|
+
*/
|
|
41
|
+
export declare class SandboxManager {
|
|
42
|
+
private readonly providers;
|
|
43
|
+
private readonly store;
|
|
44
|
+
private readonly defaultProvider;
|
|
45
|
+
private readonly autoResume;
|
|
46
|
+
private readonly transitionTimeoutMs;
|
|
47
|
+
private readonly pollIntervalMs;
|
|
48
|
+
private readonly generateId;
|
|
49
|
+
private readonly now;
|
|
50
|
+
constructor(options: SandboxManagerOptions);
|
|
51
|
+
/**
|
|
52
|
+
* Create a sandbox, clone `spec.git`, run `spec.setup` and launch
|
|
53
|
+
* `spec.start`. Resolves once the sandbox is running. On failure the record
|
|
54
|
+
* is marked `failed` and the provider sandbox is kept for inspection; call
|
|
55
|
+
* `destroy` to remove it.
|
|
56
|
+
*/
|
|
57
|
+
create(options: CreateSandboxOptions): Promise<SandboxRecord>;
|
|
58
|
+
/** Resolves the record, or throws `SandboxNotFoundError`. */
|
|
59
|
+
get(id: string): Promise<SandboxRecord>;
|
|
60
|
+
/** Resolves the record, or `null` if it does not exist. */
|
|
61
|
+
find(id: string): Promise<SandboxRecord | null>;
|
|
62
|
+
list(filter?: SandboxListFilter): Promise<SandboxRecord[]>;
|
|
63
|
+
/** Run a one-shot command and wait for it to finish. A non-zero exit does not throw. */
|
|
64
|
+
exec(id: string, command: CommandInput, options?: ExecOptions): Promise<ExecResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Wake a stopped sandbox and relaunch `spec.resume` (or `spec.start`) as its
|
|
67
|
+
* main process. Also retries a `failed` sandbox that still has a provider
|
|
68
|
+
* sandbox; `setup` is not re-run. No-op if it is already running.
|
|
69
|
+
*/
|
|
70
|
+
resume(id: string): Promise<SandboxRecord>;
|
|
71
|
+
/** Stop a running sandbox, keeping its filesystem. No-op if it is already stopped. */
|
|
72
|
+
stop(id: string): Promise<SandboxRecord>;
|
|
73
|
+
/** Delete the provider sandbox. The record is kept with status `destroyed`. */
|
|
74
|
+
destroy(id: string): Promise<SandboxRecord>;
|
|
75
|
+
/** A URL that reaches `port` (which must be listed in `spec.ports`). */
|
|
76
|
+
getUrl(id: string, port: number): Promise<string>;
|
|
77
|
+
writeFiles(id: string, files: SandboxFile[]): Promise<void>;
|
|
78
|
+
/** Resolves the file's bytes, or `null` if it does not exist. */
|
|
79
|
+
readFile(id: string, path: string): Promise<Uint8Array | null>;
|
|
80
|
+
readTextFile(id: string, path: string): Promise<string | null>;
|
|
81
|
+
/** State of the detached main process, or `null` if none was launched. */
|
|
82
|
+
getMainProcess(id: string): Promise<MainProcessInfo | null>;
|
|
83
|
+
/** The main process's full log so far. */
|
|
84
|
+
readLogs(id: string): Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Stream the main process's log, from the beginning. Only the first read
|
|
87
|
+
* auto-resumes a stopped sandbox; when following, the stream ends once the
|
|
88
|
+
* sandbox stops or `signal` aborts.
|
|
89
|
+
*/
|
|
90
|
+
logs(id: string, options?: LogsOptions): AsyncGenerator<string, void, void>;
|
|
91
|
+
/** Reads the log without resuming; `null` once the sandbox is no longer running. */
|
|
92
|
+
private readMainLogIfRunning;
|
|
93
|
+
/** Push back the sandbox's expiry (and the provider's own timeout, if it has one). */
|
|
94
|
+
extendTimeout(id: string, durationMs: number): Promise<SandboxRecord>;
|
|
95
|
+
/**
|
|
96
|
+
* Stop every running sandbox whose `expiresAt` has passed. Run this
|
|
97
|
+
* periodically (e.g. from a cron job) for providers without native
|
|
98
|
+
* timeouts, such as Docker.
|
|
99
|
+
*/
|
|
100
|
+
stopExpired(): Promise<SandboxRecord[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Bring records in line with what the providers report: running sandboxes
|
|
103
|
+
* the provider has stopped become `stopped`, vanished ones become `failed`,
|
|
104
|
+
* and transitions abandoned for longer than the transition timeout (e.g. a
|
|
105
|
+
* crashed process) are settled. Defaults to every non-destroyed sandbox;
|
|
106
|
+
* sandboxes on unregistered providers, or whose provider errors, are
|
|
107
|
+
* skipped. Resolves the records that changed.
|
|
108
|
+
*/
|
|
109
|
+
reconcile(ids?: string[]): Promise<SandboxRecord[]>;
|
|
110
|
+
private reconcilePatch;
|
|
111
|
+
/** Runs `fn` against a running sandbox, auto-resuming it if it is (or turns out to be) stopped. */
|
|
112
|
+
private withRunning;
|
|
113
|
+
private ensureRunning;
|
|
114
|
+
/** Claims the record for resuming. Resolves `null` if another caller claimed it first. */
|
|
115
|
+
private tryResume;
|
|
116
|
+
/** Waits until the record is not in a transitional status. */
|
|
117
|
+
private settle;
|
|
118
|
+
private runStep;
|
|
119
|
+
/** Update that must succeed because this caller holds the record's transitional status. */
|
|
120
|
+
private mustUpdate;
|
|
121
|
+
private markFailed;
|
|
122
|
+
private getProvider;
|
|
123
|
+
private workdirFor;
|
|
124
|
+
private toProviderSandbox;
|
|
125
|
+
private expiryFor;
|
|
126
|
+
}
|