withruntime 0.11.1 → 0.12.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 +3 -3
- package/COMPATIBILITY.md +74 -9
- package/DAYTONA.md +33 -5
- package/E2B.md +137 -48
- package/README.md +11 -9
- package/README.src.md +11 -9
- package/VERCEL.md +43 -5
- package/compatibility-lock.json +58 -49
- package/dist/billing-cli.d.ts +1 -1
- package/dist/billing-cli.js +77 -1
- package/dist/blaxel/errors.d.ts +14 -0
- package/dist/blaxel/errors.js +33 -4
- package/dist/blaxel/index.d.ts +2 -2
- package/dist/blaxel/index.js +4 -4
- package/dist/blaxel/interpreter.d.ts +2 -5
- package/dist/blaxel/sandbox.d.ts +15 -7
- package/dist/blaxel/sandbox.js +64 -9
- package/dist/blaxel/snapshot.d.ts +4 -0
- package/dist/blaxel/snapshot.js +4 -0
- package/dist/cli/logs.d.ts +21 -0
- package/dist/cli/logs.js +188 -0
- package/dist/cli/logs.test.d.ts +1 -0
- package/dist/cli/logs.test.js +272 -0
- package/dist/cli-extras.d.ts +3 -3
- package/dist/cli-extras.js +17 -12
- package/dist/cli-words.d.ts +10 -1
- package/dist/cli-words.js +18 -0
- package/dist/cli.d.ts +6 -2
- package/dist/cli.js +468 -219
- package/dist/client.d.ts +13 -63
- package/dist/client.js +35 -124
- package/dist/cloudflare/errors.d.ts +143 -0
- package/dist/cloudflare/errors.js +167 -0
- package/dist/cloudflare/index.d.ts +175 -6
- package/dist/cloudflare/index.js +416 -26
- package/dist/cloudflare/interpreter.d.ts +119 -0
- package/dist/cloudflare/interpreter.js +223 -0
- package/dist/cloudflare/streams.d.ts +38 -0
- package/dist/cloudflare/streams.js +145 -0
- package/dist/cloudflare/watch.d.ts +9 -0
- package/dist/cloudflare/watch.js +24 -0
- package/dist/codesandbox/index.d.ts +216 -28
- package/dist/codesandbox/index.js +478 -78
- package/dist/compat/core.d.ts +18 -0
- package/dist/compat/core.js +29 -0
- package/dist/compat/files.d.ts +1 -0
- package/dist/compat/files.js +25 -5
- package/dist/daytona/computer-use.d.ts +13 -4
- package/dist/daytona/computer-use.js +66 -8
- package/dist/daytona/daytona.d.ts +7 -2
- package/dist/daytona/daytona.js +31 -5
- package/dist/daytona/errors.d.ts +11 -0
- package/dist/daytona/errors.js +18 -0
- package/dist/daytona/filesystem.js +2 -1
- package/dist/daytona/image.d.ts +13 -9
- package/dist/daytona/image.js +18 -12
- package/dist/daytona/index.d.ts +1 -1
- package/dist/daytona/sandbox.d.ts +9 -3
- package/dist/daytona/sandbox.js +17 -3
- package/dist/domains/index.d.ts +9 -0
- package/dist/domains/index.js +10 -0
- package/dist/e2b/client.d.ts +15 -2
- package/dist/e2b/client.js +61 -7
- package/dist/e2b/commands.d.ts +4 -1
- package/dist/e2b/commands.js +17 -7
- package/dist/e2b/errors.d.ts +43 -2
- package/dist/e2b/errors.js +78 -6
- package/dist/e2b/filesystem.d.ts +1 -1
- package/dist/e2b/filesystem.js +82 -16
- package/dist/e2b/index.d.ts +3 -3
- package/dist/e2b/index.js +2 -2
- package/dist/e2b/sandbox.d.ts +50 -35
- package/dist/e2b/sandbox.js +228 -185
- package/dist/e2b/unsupported.d.ts +19 -0
- package/dist/e2b/unsupported.js +22 -1
- package/dist/e2b/users.d.ts +9 -0
- package/dist/e2b/users.js +22 -0
- package/dist/errors.d.ts +14 -5
- package/dist/errors.js +28 -14
- package/dist/freestyle/index.d.ts +285 -37
- package/dist/freestyle/index.js +656 -144
- package/dist/identity.d.ts +3 -0
- package/dist/identity.js +27 -0
- package/dist/images/index.d.ts +9 -0
- package/dist/images/index.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/ips/index.d.ts +9 -0
- package/dist/ips/index.js +10 -0
- package/dist/jobs/index.d.ts +9 -0
- package/dist/jobs/index.js +10 -0
- package/dist/keys.js +2 -0
- package/dist/login.js +2 -0
- package/dist/machine.d.ts +189 -0
- package/dist/machine.js +521 -0
- package/dist/mcp.js +1 -1
- package/dist/modal/index.d.ts +339 -61
- package/dist/modal/index.js +781 -121
- package/dist/network-cli.d.ts +3 -1
- package/dist/network-cli.js +78 -36
- package/dist/networks/index.d.ts +11 -0
- package/dist/networks/index.js +10 -0
- package/dist/openai-agents/index.d.ts +1 -1
- package/dist/openai-agents/index.js +1 -1
- package/dist/ports/index.d.ts +9 -0
- package/dist/ports/index.js +10 -0
- package/dist/product-names.d.ts +52 -0
- package/dist/product-names.js +164 -0
- package/dist/product-renames.d.ts +103 -0
- package/dist/product-renames.js +189 -0
- package/dist/products/apps.d.ts +176 -0
- package/dist/products/apps.js +165 -0
- package/dist/products/billing.d.ts +41 -0
- package/dist/products/billing.js +13 -0
- package/dist/products/browser.d.ts +10 -0
- package/dist/products/browsers.d.ts +71 -0
- package/dist/products/browsers.js +102 -0
- package/dist/products/builds.d.ts +126 -0
- package/dist/products/builds.js +221 -0
- package/dist/products/index.d.ts +3 -16
- package/dist/products/index.js +3 -14
- package/dist/products/jobs.d.ts +19 -3
- package/dist/products/jobs.js +28 -12
- package/dist/products/limits.d.ts +4 -10
- package/dist/products/logs.d.ts +245 -0
- package/dist/products/logs.js +274 -0
- package/dist/products/logs.test.d.ts +1 -0
- package/dist/products/logs.test.js +343 -0
- package/dist/products/network-products.d.ts +38 -7
- package/dist/products/network-products.js +31 -18
- package/dist/products/network.d.ts +1 -1
- package/dist/products/observability.d.ts +3 -2
- package/dist/products/private-network.js +1 -1
- package/dist/products/queues.d.ts +149 -0
- package/dist/products/queues.js +213 -0
- package/dist/products/referrals.d.ts +21 -7
- package/dist/products/referrals.js +3 -3
- package/dist/products/secrets.d.ts +8 -4
- package/dist/products/secrets.js +39 -18
- package/dist/products/signed-requests.d.ts +21 -0
- package/dist/products/signed-requests.js +11 -0
- package/dist/products/streams.d.ts +73 -0
- package/dist/products/streams.js +17 -0
- package/dist/products/switching.d.ts +37 -10
- package/dist/products/switching.js +4 -3
- package/dist/products/volumes.d.ts +3 -0
- package/dist/record-cli.d.ts +23 -0
- package/dist/record-cli.js +308 -0
- package/dist/renamed-products.d.ts +38 -0
- package/dist/renamed-products.js +34 -0
- package/dist/runloop/index.d.ts +9 -2
- package/dist/runloop/index.js +29 -8
- package/dist/runloop/sdk.d.ts +131 -0
- package/dist/runloop/sdk.js +167 -0
- package/dist/sandbox.d.ts +10 -94
- package/dist/sandbox.js +22 -371
- package/dist/sandboxes/index.d.ts +11 -0
- package/dist/sandboxes/index.js +12 -0
- package/dist/snapshots/index.d.ts +9 -0
- package/dist/snapshots/index.js +11 -0
- package/dist/snapshots.d.ts +7 -4
- package/dist/sprites/index.d.ts +343 -31
- package/dist/sprites/index.js +866 -84
- package/dist/ssh.d.ts +1 -1
- package/dist/ssh.js +11 -11
- package/dist/terminal.d.ts +24 -0
- package/dist/terminal.js +32 -0
- package/dist/transport.d.ts +18 -2
- package/dist/transport.js +61 -6
- package/dist/tunnel.js +1 -1
- package/dist/types.d.ts +116 -8
- package/dist/vercel/sandbox.d.ts +1 -2
- package/dist/vercel/sandbox.js +6 -5
- package/dist/vercel/snapshot.js +10 -2
- package/dist/volumes/index.d.ts +9 -0
- package/dist/volumes/index.js +10 -0
- package/package.json +48 -2
package/dist/blaxel/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type Config } from "./client.js";
|
|
2
|
-
export { SandboxInstance, DEFAULT_IMAGE, DEFAULT_MEMORY, MEMORY_PER_VCPU, durationMs, imageRef, lifetimeOf, networkRules, type SandboxListQuery, type SandboxForkOptions, type SandboxArchiveOptions, } from "./sandbox.js";
|
|
2
|
+
export { SandboxInstance, DEFAULT_IMAGE, DEFAULT_MEMORY, MEMORY_PER_VCPU, durationMs, imageRef, lifetimeOf, networkRules, type SandboxListQuery, type SandboxForkOptions, type SandboxArchiveOptions, MAX_CREATION_TIMEOUT_SECONDS, type SandboxCreateOptions, } from "./sandbox.js";
|
|
3
3
|
export { CodeInterpreter } from "./interpreter.js";
|
|
4
4
|
export { SandboxFileSystem, retryOnTransient, type File, type FileWithContent, type Subdirectory, type Directory, type SuccessResponse, type FindMatch, type FindResponse, type FuzzySearchMatch, type FuzzySearchResponse, type ContentSearchMatch, type ContentSearchResponse, type CopyResponse, type WatchEvent, type SandboxFilesystemFile, type FilesystemSearchOptions, type FilesystemFindOptions, type FilesystemGrepOptions, } from "./filesystem.js";
|
|
5
5
|
export { SandboxProcess, type ProcessRequest, type ProcessResponse, type ProcessRequestWithLog, type ProcessResponseWithLog, type PostProcessResponse, type GetProcessResponse, type GetProcessByIdentifierResponse, type DeleteProcessByIdentifierResponse, type DeleteProcessByIdentifierKillResponse, type ProcessLogs, } from "./process.js";
|
|
6
6
|
export { SandboxPreview, SandboxPreviews, SandboxPreviewToken, SandboxPreviewTokens, type Preview, type PreviewMetadata, type PreviewSpec, type PreviewToken, } from "./preview.js";
|
|
7
7
|
export { Snapshot, SandboxSnapshotsResource, type Env, type SandboxSnapshot, type SandboxSnapshotSource, type SandboxSnapshotSpec, type SandboxForkResponse, type SandboxRestoreResponse, type SnapshotCreateConfiguration, type SnapshotForkOptions, type SnapshotListQuery, } from "./snapshot.js";
|
|
8
|
-
export { ResponseError, SandboxGatewayError, isGatewayError, isGatewayTimeout, CredentialsError, NotSupportedError, } from "./errors.js";
|
|
8
|
+
export { ResponseError, SandboxCreationTimeoutError, isCreationTimeoutError, SandboxGatewayError, isGatewayError, isGatewayTimeout, CredentialsError, NotSupportedError, } from "./errors.js";
|
|
9
9
|
export { createPaginatedList, unwrapListData, type PaginatedList, type PaginatedListMeta, type ListResponse, type CursorPaginationQuery, type AutoPagingEachCallback, type AutoPagingToArrayOptions, } from "./pagination.js";
|
|
10
10
|
export { normalizePorts, normalizeEnvs, normalizeVolumes, type Status, type Port, type EnvVar, type ExpirationPolicy, type SandboxLifecycle, type SandboxNetwork, type VolumeBinding, type VolumeAttachment, type Metadata, type SandboxRuntime, type SandboxSpec, type CoreEvent, type Sandbox, type SandboxConfiguration, type SandboxCreateConfiguration, type SandboxUpdateMetadata, type SandboxUpdateNetwork, type SessionCreateOptions, type SessionWithToken, } from "./types.js";
|
|
11
11
|
export { initialize, type Config, type WithRuntime, type RuntimeOptions } from "./client.js";
|
package/dist/blaxel/index.js
CHANGED
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
* import { SandboxInstance } from "withruntime/blaxel"; // was: from "@blaxel/core"
|
|
5
5
|
*
|
|
6
6
|
* and set RUNTIME_API_KEY, or run `npx withruntime login` once. A Blaxel key
|
|
7
|
-
* (BL_API_KEY) is never sent anywhere. Every name `@blaxel/core` 0.3.
|
|
7
|
+
* (BL_API_KEY) is never sent anywhere. Every name `@blaxel/core` 0.3.25
|
|
8
8
|
* exports can be imported; what Runtime cannot do the way Blaxel does throws
|
|
9
9
|
* NotSupportedError, naming what to use. */
|
|
10
10
|
import { RuntimeError } from "../errors.js";
|
|
11
11
|
import { initialize } from "./client.js";
|
|
12
12
|
import { NotSupportedError } from "./errors.js";
|
|
13
13
|
import { CODEGEN, DRIVES, SCHEDULES, SYSTEM, unsupportedExport } from "./unsupported.js";
|
|
14
|
-
export { SandboxInstance, DEFAULT_IMAGE, DEFAULT_MEMORY, MEMORY_PER_VCPU, durationMs, imageRef, lifetimeOf, networkRules, } from "./sandbox.js";
|
|
14
|
+
export { SandboxInstance, DEFAULT_IMAGE, DEFAULT_MEMORY, MEMORY_PER_VCPU, durationMs, imageRef, lifetimeOf, networkRules, MAX_CREATION_TIMEOUT_SECONDS, } from "./sandbox.js";
|
|
15
15
|
export { CodeInterpreter } from "./interpreter.js";
|
|
16
16
|
export { SandboxFileSystem, retryOnTransient, } from "./filesystem.js";
|
|
17
17
|
export { SandboxProcess, } from "./process.js";
|
|
18
18
|
export { SandboxPreview, SandboxPreviews, SandboxPreviewToken, SandboxPreviewTokens, } from "./preview.js";
|
|
19
19
|
export { Snapshot, SandboxSnapshotsResource, } from "./snapshot.js";
|
|
20
|
-
export { ResponseError, SandboxGatewayError, isGatewayError, isGatewayTimeout, CredentialsError, NotSupportedError, } from "./errors.js";
|
|
20
|
+
export { ResponseError, SandboxCreationTimeoutError, isCreationTimeoutError, SandboxGatewayError, isGatewayError, isGatewayTimeout, CredentialsError, NotSupportedError, } from "./errors.js";
|
|
21
21
|
export { createPaginatedList, unwrapListData, } from "./pagination.js";
|
|
22
22
|
export { normalizePorts, normalizeEnvs, normalizeVolumes, } from "./types.js";
|
|
23
23
|
export { initialize } from "./client.js";
|
|
@@ -88,7 +88,7 @@ const MODELS = "Call your model provider's SDK directly; Runtime does not proxy
|
|
|
88
88
|
const TOOLS = "Give your agent Runtime's sandbox tools: `import { tools } from \"withruntime/tools\"`, or Runtime's MCP server (`npx withruntime mcp`).";
|
|
89
89
|
const MCP = "Serve MCP from a sandbox and share its port with sandbox.previews.create, or use Runtime's own MCP server (`npx withruntime mcp`).";
|
|
90
90
|
const JOBS = "Run the batch as processes in sandboxes: SandboxInstance.create, then sandbox.process.exec for each task.";
|
|
91
|
-
const IMAGES = "Build a Runtime image and create sandboxes from it by name: `npx withruntime
|
|
91
|
+
const IMAGES = "Build a Runtime image and create sandboxes from it by name: `npx withruntime images build --dockerfile Dockerfile --name <image>` or runtime.images.build({ name, dockerfile | image }).";
|
|
92
92
|
const VOLUMES = 'Use Runtime volumes: runtime.volumes.create({ name }) (`import { Runtime } from "withruntime"`), then pass volumes: [{ name, mountPath }] at create.';
|
|
93
93
|
const HOSTING = "Serve it from a sandbox and share its port with sandbox.previews.create.";
|
|
94
94
|
const TELEMETRY = "Send your own traces; Runtime exports sandbox metrics and events with runtime.otel (OpenTelemetry).";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SandboxInstance } from "./sandbox.js";
|
|
1
|
+
import { SandboxInstance, type SandboxCreateOptions } from "./sandbox.js";
|
|
2
2
|
import type { Port, Sandbox as SandboxModel, SandboxCreateConfiguration, SandboxLifecycle } from "./types.js";
|
|
3
3
|
declare class OutputMessage {
|
|
4
4
|
text: string;
|
|
@@ -45,10 +45,7 @@ export declare class CodeInterpreter extends SandboxInstance {
|
|
|
45
45
|
static readonly Context: typeof Context;
|
|
46
46
|
/** Blaxel's defaults for a code interpreter: its image, port 8888, and
|
|
47
47
|
* deletion after 30 idle minutes (a paused sandbox kept one day). */
|
|
48
|
-
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel | Record<string, unknown> | null, options?:
|
|
49
|
-
safe?: boolean;
|
|
50
|
-
createIfNotExist?: boolean;
|
|
51
|
-
}): Promise<InstanceType<T>>;
|
|
48
|
+
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel | Record<string, unknown> | null, options?: SandboxCreateOptions): Promise<InstanceType<T>>;
|
|
52
49
|
get _jupyterUrl(): string;
|
|
53
50
|
/** Runs code in a stateful context. Errors in the code come back in
|
|
54
51
|
* `execution.error`; a run past `timeout` seconds (default 60, 0 for none)
|
package/dist/blaxel/sandbox.d.ts
CHANGED
|
@@ -40,6 +40,18 @@ export type SandboxArchiveOptions = {
|
|
|
40
40
|
maxWait?: number;
|
|
41
41
|
interval?: number;
|
|
42
42
|
};
|
|
43
|
+
/** The longest creation `timeout` Blaxel accepts, in seconds. */
|
|
44
|
+
export declare const MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
45
|
+
/** Options of SandboxInstance.create / createIfNotExists, as Blaxel's. */
|
|
46
|
+
export type SandboxCreateOptions = {
|
|
47
|
+
/** List `/` once it runs, and delete it if that fails. */
|
|
48
|
+
safe?: boolean;
|
|
49
|
+
/** Answer the sandbox already holding the name instead of a 409. */
|
|
50
|
+
createIfNotExist?: boolean;
|
|
51
|
+
/** Give up after this many whole seconds (1 to 50): the sandbox is deleted
|
|
52
|
+
* and the call rejects with SandboxCreationTimeoutError. */
|
|
53
|
+
timeout?: number;
|
|
54
|
+
};
|
|
43
55
|
/** What a create asked for that no label keeps: shown by `spec` in the
|
|
44
56
|
* client that created the sandbox. */
|
|
45
57
|
type Asked = {
|
|
@@ -127,16 +139,12 @@ export declare class SandboxInstance {
|
|
|
127
139
|
get expiresIn(): number | undefined;
|
|
128
140
|
/** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
|
|
129
141
|
* image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
|
|
130
|
-
* Funding is left to Runtime: the
|
|
131
|
-
* time, then prepaid credit. A name another live sandbox holds is refused
|
|
142
|
+
* Funding is left to Runtime: the included usage first, then prepaid credit. A name another live sandbox holds is refused
|
|
132
143
|
* with a 409, as in Blaxel. */
|
|
133
|
-
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel,
|
|
134
|
-
safe?: boolean;
|
|
135
|
-
createIfNotExist?: boolean;
|
|
136
|
-
}): Promise<InstanceType<T>>;
|
|
144
|
+
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel, options?: SandboxCreateOptions): Promise<InstanceType<T>>;
|
|
137
145
|
/** The named sandbox, or a new one when no live sandbox has the name.
|
|
138
146
|
* Runtime settles a race between two callers: both get the same sandbox. */
|
|
139
|
-
static createIfNotExists<T extends typeof SandboxInstance>(this: T, sandbox: SandboxCreateConfiguration | SandboxModel): Promise<InstanceType<T>>;
|
|
147
|
+
static createIfNotExists<T extends typeof SandboxInstance>(this: T, sandbox: SandboxCreateConfiguration | SandboxModel, options?: Omit<SandboxCreateOptions, "createIfNotExist">): Promise<InstanceType<T>>;
|
|
140
148
|
/** The live sandbox with this name (or Runtime id). It is not woken: the
|
|
141
149
|
* next call wakes it. */
|
|
142
150
|
static get<T extends typeof SandboxInstance>(this: T, sandboxName: string, options?: RuntimeOptions): Promise<InstanceType<T>>;
|
package/dist/blaxel/sandbox.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RuntimeError } from "../errors.js";
|
|
2
2
|
import { clientFor, defaultRegion, } from "./client.js";
|
|
3
3
|
import { checkEnvNames, envFileCommand, envFileLines, parseProcessLine, toRuntimePath, } from "./context.js";
|
|
4
|
-
import { codeOf, guard, NotSupportedError, responseError, translate } from "./errors.js";
|
|
4
|
+
import { codeOf, guard, NotSupportedError, responseError, SandboxCreationTimeoutError, translate, } from "./errors.js";
|
|
5
5
|
import { SandboxFileSystem } from "./filesystem.js";
|
|
6
6
|
import { ARCHIVED, DISPLAY_NAME, EXTERNAL_ID, IDLE_PAUSE, LABEL, findByExternalId, findSandbox, LEASE_SECONDS, ownLabels, STANDBY, userLabels, whenNameFree, } from "./lookup.js";
|
|
7
7
|
import { paginate } from "./pagination.js";
|
|
@@ -38,6 +38,56 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
38
38
|
const DAY_MS = 86_400_000;
|
|
39
39
|
/** The lease is renewed in the background once this little of it is left. */
|
|
40
40
|
const RENEW_BELOW_MS = 10 * 60_000;
|
|
41
|
+
/** The longest creation `timeout` Blaxel accepts, in seconds. */
|
|
42
|
+
export const MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
43
|
+
/** Blaxel's own check of `timeout`, with its words. */
|
|
44
|
+
function creationTimeout({ timeout }) {
|
|
45
|
+
if (timeout === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (!Number.isInteger(timeout) || timeout < 1 || timeout > MAX_CREATION_TIMEOUT_SECONDS)
|
|
48
|
+
throw new Error(`SandboxInstance.create: 'timeout' must be a whole number of seconds between 1 and ${MAX_CREATION_TIMEOUT_SECONDS}, got ${timeout}.`);
|
|
49
|
+
return timeout;
|
|
50
|
+
}
|
|
51
|
+
/** A create that must be running within `timeout` seconds of the call, the
|
|
52
|
+
* wait for capacity included. One that is not is deleted, so the name is
|
|
53
|
+
* free again, and the call rejects with SandboxCreationTimeoutError. */
|
|
54
|
+
async function createWithin(client, input, timeout) {
|
|
55
|
+
const deadline = performance.now() + timeout * 1000;
|
|
56
|
+
const runtime = await guard(() => whenNameFree(client, () => client.sandboxes.create({ ...input, wait: false }, { waitForCapacityMs: timeout * 1000 })));
|
|
57
|
+
// A sandbox the name already had is the caller's, whatever its state: it is
|
|
58
|
+
// answered as it is, as without a timeout, and never deleted here.
|
|
59
|
+
if (runtime.state === "running" || runtime.info.reused)
|
|
60
|
+
return runtime;
|
|
61
|
+
const left = deadline - performance.now();
|
|
62
|
+
if (left > 0)
|
|
63
|
+
try {
|
|
64
|
+
await runtime.waitFor("running", {
|
|
65
|
+
timeoutSeconds: Math.max(1, Math.ceil(left / 1000)),
|
|
66
|
+
timeoutMs: Math.ceil(left) + 5_000,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (!(error instanceof RuntimeError && error.code === "timeout")) {
|
|
71
|
+
await runtime.delete().catch(() => undefined);
|
|
72
|
+
throw translate(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// waitFor updated the state TypeScript narrowed above.
|
|
76
|
+
const state = runtime.state;
|
|
77
|
+
if (state === "running")
|
|
78
|
+
return runtime;
|
|
79
|
+
await runtime.delete().catch(() => undefined);
|
|
80
|
+
if (state !== "starting")
|
|
81
|
+
throw translate(new RuntimeError({
|
|
82
|
+
message: `Sandbox ${runtime.id} is ${runtime.state}, not running.`,
|
|
83
|
+
code: "start_failed",
|
|
84
|
+
status: 0,
|
|
85
|
+
hint: "Create it again; SandboxInstance.get(name) reads why it stopped.",
|
|
86
|
+
}));
|
|
87
|
+
throw new SandboxCreationTimeoutError(input.name, timeout, {
|
|
88
|
+
message: `It was still starting after ${timeout}s.`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
41
91
|
/** The labels a new sandbox carries: the caller's, and under `blaxel/` what
|
|
42
92
|
* Blaxel keeps and Runtime has no field for, so any client (the Python
|
|
43
93
|
* adapter too) reads the same `spec`. */
|
|
@@ -212,7 +262,7 @@ async function resolveImage(client, image) {
|
|
|
212
262
|
if (found && found.state === "ready")
|
|
213
263
|
return { image: found.id };
|
|
214
264
|
const feature = `The image ${image}, which is not a Runtime image`;
|
|
215
|
-
const alternative = `Build it as a Runtime image named ${name}: \`npx withruntime
|
|
265
|
+
const alternative = `Build it as a Runtime image named ${name}: \`npx withruntime images build --dockerfile Dockerfile --name ${name} -t ${name}:${tag}\`. The code can keep "${image}": the adapter starts from ${name}:${tag}.`;
|
|
216
266
|
throw new NotSupportedError(feature, alternative, `${feature}, is not supported on Runtime. ${alternative}`);
|
|
217
267
|
}
|
|
218
268
|
/** Blaxel volumes (by name) as Runtime volumes. */
|
|
@@ -228,7 +278,7 @@ async function resolveVolumes(client, volumes) {
|
|
|
228
278
|
return Promise.all(volumes.map(async (volume) => {
|
|
229
279
|
const found = (await guard(() => client.volumes.list({ name: volume.name }))).data[0];
|
|
230
280
|
if (!found)
|
|
231
|
-
throw new NotSupportedError(`The volume ${volume.name}, which is not a Runtime volume`, `Create it first: runtime.volumes.create({ name: "${volume.name}" }) or \`npx withruntime
|
|
281
|
+
throw new NotSupportedError(`The volume ${volume.name}, which is not a Runtime volume`, `Create it first: runtime.volumes.create({ name: "${volume.name}" }) or \`npx withruntime volumes create --name ${volume.name}\`.`);
|
|
232
282
|
return { volumeId: found.id, path: toRuntimePath(volume.mountPath) };
|
|
233
283
|
}));
|
|
234
284
|
}
|
|
@@ -523,10 +573,11 @@ export class SandboxInstance {
|
|
|
523
573
|
// ---- create, get, list ---------------------------------------------------
|
|
524
574
|
/** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
|
|
525
575
|
* image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
|
|
526
|
-
* Funding is left to Runtime: the
|
|
527
|
-
* time, then prepaid credit. A name another live sandbox holds is refused
|
|
576
|
+
* Funding is left to Runtime: the included usage first, then prepaid credit. A name another live sandbox holds is refused
|
|
528
577
|
* with a 409, as in Blaxel. */
|
|
529
|
-
static async create(sandbox,
|
|
578
|
+
static async create(sandbox, options = {}) {
|
|
579
|
+
const { createIfNotExist = false, safe = false } = options;
|
|
580
|
+
const timeout = creationTimeout(options);
|
|
530
581
|
const config = configOf(sandbox);
|
|
531
582
|
const region = config.region || defaultRegion();
|
|
532
583
|
checkRegion(region);
|
|
@@ -560,7 +611,9 @@ export class SandboxInstance {
|
|
|
560
611
|
...(createIfNotExist && config.name ? { getOrCreate: true } : {}),
|
|
561
612
|
...config.withruntime?.create,
|
|
562
613
|
};
|
|
563
|
-
const runtime =
|
|
614
|
+
const runtime = timeout === undefined
|
|
615
|
+
? await guard(() => whenNameFree(client, () => client.sandboxes.create(input)))
|
|
616
|
+
: await createWithin(client, input, timeout);
|
|
564
617
|
const asked = {
|
|
565
618
|
...(Object.keys(envs).length ? { envs } : {}),
|
|
566
619
|
...(config.network ? { network: config.network } : {}),
|
|
@@ -572,6 +625,8 @@ export class SandboxInstance {
|
|
|
572
625
|
const instance = new this({ runtime, client, asked });
|
|
573
626
|
try {
|
|
574
627
|
await instance.#setUp(envs, lifetime.days);
|
|
628
|
+
if (safe)
|
|
629
|
+
await instance.fs.ls("/");
|
|
575
630
|
}
|
|
576
631
|
catch (error) {
|
|
577
632
|
await runtime.stop({ wait: false }).catch(() => undefined);
|
|
@@ -581,8 +636,8 @@ export class SandboxInstance {
|
|
|
581
636
|
}
|
|
582
637
|
/** The named sandbox, or a new one when no live sandbox has the name.
|
|
583
638
|
* Runtime settles a race between two callers: both get the same sandbox. */
|
|
584
|
-
static async createIfNotExists(sandbox) {
|
|
585
|
-
return this.create(sandbox, { createIfNotExist: true });
|
|
639
|
+
static async createIfNotExists(sandbox, options = {}) {
|
|
640
|
+
return this.create(sandbox, { ...options, createIfNotExist: true });
|
|
586
641
|
}
|
|
587
642
|
/** The live sandbox with this name (or Runtime id). It is not woken: the
|
|
588
643
|
* next call wakes it. */
|
|
@@ -71,6 +71,10 @@ export declare function appendEnvs(runtime: RuntimeSandbox, envs: Record<string,
|
|
|
71
71
|
export declare function startFromSnapshot(client: Runtime, snapshotId: string, name: string, labels: Record<string, string>, envs: Record<string, string>): Promise<RuntimeSandbox>;
|
|
72
72
|
declare function refuseApplication(options?: {
|
|
73
73
|
targetType?: string;
|
|
74
|
+
port?: number;
|
|
75
|
+
traffic?: number;
|
|
76
|
+
customDomain?: string;
|
|
77
|
+
prefix?: string;
|
|
74
78
|
}): void;
|
|
75
79
|
/** A snapshot, as Blaxel's Snapshot class. */
|
|
76
80
|
export declare class Snapshot {
|
package/dist/blaxel/snapshot.js
CHANGED
|
@@ -63,6 +63,10 @@ export async function startFromSnapshot(client, snapshotId, name, labels, envs)
|
|
|
63
63
|
function refuseApplication(options = {}) {
|
|
64
64
|
if (options.targetType === "application")
|
|
65
65
|
throw new NotSupportedError("Forking into an application", "Fork into a sandbox and share its port with sandbox.previews.create.");
|
|
66
|
+
// Blaxel's application-fork routing: a sandbox fork has no use for them.
|
|
67
|
+
for (const key of ["port", "traffic", "customDomain", "prefix"])
|
|
68
|
+
if (options[key] !== undefined)
|
|
69
|
+
throw new NotSupportedError(`A fork's ${key}`, "Fork without it, then share a port of the copy with sandbox.previews.create({ metadata: { name }, spec: { port } }).");
|
|
66
70
|
}
|
|
67
71
|
/** A snapshot, as Blaxel's Snapshot class. */
|
|
68
72
|
export class Snapshot {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ObservabilityClient } from "../products/logs.js";
|
|
2
|
+
type Product = "logs" | "traces" | "alerts";
|
|
3
|
+
type Args = {
|
|
4
|
+
positional: string[];
|
|
5
|
+
flags: Map<string, string[]>;
|
|
6
|
+
};
|
|
7
|
+
type Out = {
|
|
8
|
+
json: boolean;
|
|
9
|
+
tty?: boolean;
|
|
10
|
+
drain?: () => Promise<void>;
|
|
11
|
+
write(text: string): void;
|
|
12
|
+
error(text: string): void;
|
|
13
|
+
};
|
|
14
|
+
export declare const LOGS_HELP = "runtime logs tail <selector|app> [--since 1h] [--grep text] [--json] [--raw]\nruntime logs query '<LogQL>' [--from <time>] [--to <time>] [--limit <n>]\nruntime logs labels | values <label>\nruntime logs views ls|get|create|update|delete [id] [--body '<JSON>']\nruntime traces get <id> | search '<TraceQL>' | tags\nruntime traces views ls|get|create|update|delete [id] [--body '<JSON>']\nruntime logs ingest --body '<OTLP JSON>'\nruntime traces ingest --body '<OTLP JSON>'\nruntime alerts ls|get|create|update|delete|test|silence [id]\n create/update: --body '<JSON: name, labels, query, condition, for, actions>'\n silence: --until <RFC3339> [--reason <text>]\nEvery command takes --json. Writes take --idempotency-key <key>.\nOn a terminal, control characters in logs show as \\uXXXX; --raw prints them as written.";
|
|
15
|
+
/** Same parsed argument and output ports as the existing CLI. No registration
|
|
16
|
+
* occurs here: the launch owner supplies a client only after launch. */
|
|
17
|
+
export declare function logsProductCommand(product: Product, argv: string[], args: Args, out: Out, client: () => Promise<ObservabilityClient>, options?: {
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
now?: number;
|
|
20
|
+
}): Promise<number>;
|
|
21
|
+
export {};
|
package/dist/cli/logs.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
2
|
+
import { terminalSafe } from "../terminal.js";
|
|
3
|
+
export const LOGS_HELP = `runtime logs tail <selector|app> [--since 1h] [--grep text] [--json] [--raw]
|
|
4
|
+
runtime logs query '<LogQL>' [--from <time>] [--to <time>] [--limit <n>]
|
|
5
|
+
runtime logs labels | values <label>
|
|
6
|
+
runtime logs views ls|get|create|update|delete [id] [--body '<JSON>']
|
|
7
|
+
runtime traces get <id> | search '<TraceQL>' | tags
|
|
8
|
+
runtime traces views ls|get|create|update|delete [id] [--body '<JSON>']
|
|
9
|
+
runtime logs ingest --body '<OTLP JSON>'
|
|
10
|
+
runtime traces ingest --body '<OTLP JSON>'
|
|
11
|
+
runtime alerts ls|get|create|update|delete|test|silence [id]
|
|
12
|
+
create/update: --body '<JSON: name, labels, query, condition, for, actions>'
|
|
13
|
+
silence: --until <RFC3339> [--reason <text>]
|
|
14
|
+
Every command takes --json. Writes take --idempotency-key <key>.
|
|
15
|
+
On a terminal, control characters in logs show as \\uXXXX; --raw prints them as written.`;
|
|
16
|
+
const usage = (message) => new RuntimeError({ code: "usage", status: 0, message, hint: LOGS_HELP });
|
|
17
|
+
function since(text, now) {
|
|
18
|
+
const match = /^(\d+)(s|m|h|d)$/.exec(text);
|
|
19
|
+
if (!match)
|
|
20
|
+
throw usage("Use --since with seconds, minutes, hours or days, such as 1h.");
|
|
21
|
+
const factors = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
22
|
+
const at = now - Number(match[1]) * factors[match[2]];
|
|
23
|
+
if (!Number.isSafeInteger(at) || at < 0)
|
|
24
|
+
throw usage("--since is outside the supported time range.");
|
|
25
|
+
return new Date(at).toISOString();
|
|
26
|
+
}
|
|
27
|
+
/** Same parsed argument and output ports as the existing CLI. No registration
|
|
28
|
+
* occurs here: the launch owner supplies a client only after launch. */
|
|
29
|
+
export async function logsProductCommand(product, argv, args, out, client, options = {}) {
|
|
30
|
+
const verb = argv[0];
|
|
31
|
+
const rest = args.positional.slice(1);
|
|
32
|
+
const flag = (name) => args.flags.get(name)?.at(-1);
|
|
33
|
+
const json = out.json || flag("json") === "true";
|
|
34
|
+
// On a terminal, what customers' programs wrote is shown escaped, JSON
|
|
35
|
+
// included (an escape is still valid JSON); --raw prints it as it is.
|
|
36
|
+
const safe = (text) => (out.tty && flag("raw") !== "true" ? terminalSafe(text) : text);
|
|
37
|
+
const lines = (text) => text.split("\n").map(safe).join("\n");
|
|
38
|
+
const print = (value, text) => out.write(json ? safe(JSON.stringify(value)) : lines(text ?? JSON.stringify(value, null, 2)));
|
|
39
|
+
const need = (value, name) => {
|
|
40
|
+
if (!value)
|
|
41
|
+
throw usage(`Give ${name}.`);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
const body = () => {
|
|
45
|
+
try {
|
|
46
|
+
const value = JSON.parse(need(flag("body"), "--body with a JSON object"));
|
|
47
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
48
|
+
throw usage("--body must be a JSON object.");
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error instanceof RuntimeError)
|
|
53
|
+
throw error;
|
|
54
|
+
throw usage("--body is not valid JSON.");
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const request = {
|
|
58
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
59
|
+
...(flag("idempotency-key") ? { idempotencyKey: flag("idempotency-key") } : {}),
|
|
60
|
+
};
|
|
61
|
+
if (!verb || verb === "help" || verb === "--help") {
|
|
62
|
+
print({ usage: LOGS_HELP }, LOGS_HELP);
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
const runtime = await client();
|
|
66
|
+
if ((product === "logs" || product === "traces") && verb === "views") {
|
|
67
|
+
const views = runtime[product].views;
|
|
68
|
+
const action = need(rest[0], "a views command");
|
|
69
|
+
if (action === "ls") {
|
|
70
|
+
const result = await views.list({}, request);
|
|
71
|
+
print({ data: result.data, nextCursor: result.nextCursor });
|
|
72
|
+
}
|
|
73
|
+
else if (action === "create")
|
|
74
|
+
print(await views.create(body(), request));
|
|
75
|
+
else {
|
|
76
|
+
const id = need(rest[1], "a view id");
|
|
77
|
+
if (action === "get")
|
|
78
|
+
print(await views.get(id, request));
|
|
79
|
+
else if (action === "update")
|
|
80
|
+
print(await views.update(id, body(), request));
|
|
81
|
+
else if (action === "delete") {
|
|
82
|
+
await views.delete(id, request);
|
|
83
|
+
print({ deleted: id });
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
throw usage(`Unknown views command: ${action}.`);
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if ((product === "logs" || product === "traces") && verb === "ingest") {
|
|
91
|
+
const input = body();
|
|
92
|
+
if (product === "logs") {
|
|
93
|
+
if (!Array.isArray(input.resourceLogs))
|
|
94
|
+
throw usage("OTLP logs need resourceLogs.");
|
|
95
|
+
const resourceLogs = input.resourceLogs;
|
|
96
|
+
print(await runtime.logs.ingest({ resourceLogs }, request));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (!Array.isArray(input.resourceSpans))
|
|
100
|
+
throw usage("OTLP spans need resourceSpans.");
|
|
101
|
+
const resourceSpans = input.resourceSpans;
|
|
102
|
+
print(await runtime.traces.ingest({ resourceSpans }, request));
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
if (product === "logs") {
|
|
107
|
+
if (verb === "tail") {
|
|
108
|
+
const selector = need(rest[0], "a selector or app name");
|
|
109
|
+
let query = selector.trim().startsWith("{") ? selector : `{app=${JSON.stringify(selector)}}`;
|
|
110
|
+
if (flag("grep") !== undefined)
|
|
111
|
+
query += ` |= ${JSON.stringify(flag("grep"))}`;
|
|
112
|
+
for await (const event of runtime.logs.tail(query, {
|
|
113
|
+
...request,
|
|
114
|
+
...(flag("since") ? { start: since(flag("since"), options.now ?? Date.now()) } : {}),
|
|
115
|
+
})) {
|
|
116
|
+
if (json)
|
|
117
|
+
out.write(safe(JSON.stringify(event)));
|
|
118
|
+
else if (event.gap) {
|
|
119
|
+
const text = safe(`Logs expired between ${event.from} and ${event.to}; continuing from retained logs.`);
|
|
120
|
+
out.write(out.tty ? `\x1b[2m${text}\x1b[0m` : text);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const time = safe(event.time);
|
|
124
|
+
const text = safe(typeof event.body === "string" ? event.body : JSON.stringify(event.body));
|
|
125
|
+
out.write(`${out.tty ? `\x1b[2m${time}\x1b[0m` : time} ${safe(event.severityText)} ${text}`);
|
|
126
|
+
}
|
|
127
|
+
await out.drain?.();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (verb === "query") {
|
|
131
|
+
const limit = flag("limit") === undefined ? undefined : Number(flag("limit"));
|
|
132
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 1))
|
|
133
|
+
throw usage("--limit must be a positive integer.");
|
|
134
|
+
print(await runtime.logs.queryRange({
|
|
135
|
+
query: need(rest[0], "a LogQL query"),
|
|
136
|
+
...(flag("from") ? { start: flag("from") } : {}),
|
|
137
|
+
...(flag("to") ? { end: flag("to") } : {}),
|
|
138
|
+
...(limit !== undefined ? { limit } : {}),
|
|
139
|
+
}, request));
|
|
140
|
+
}
|
|
141
|
+
else if (verb === "labels")
|
|
142
|
+
print(await runtime.logs.labels({}, request));
|
|
143
|
+
else if (verb === "values")
|
|
144
|
+
print(await runtime.logs.labelValues(need(rest[0], "a label name"), {}, request));
|
|
145
|
+
else
|
|
146
|
+
throw usage(`Unknown logs command: ${verb}.`);
|
|
147
|
+
}
|
|
148
|
+
else if (product === "traces") {
|
|
149
|
+
if (verb === "get")
|
|
150
|
+
print(await runtime.traces.get(need(rest[0], "a trace id"), request));
|
|
151
|
+
else if (verb === "search")
|
|
152
|
+
print(await runtime.traces.search(need(rest[0], "a TraceQL query"), request));
|
|
153
|
+
else if (verb === "tags")
|
|
154
|
+
print(await runtime.traces.tags(request));
|
|
155
|
+
else
|
|
156
|
+
throw usage(`Unknown traces command: ${verb}.`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
if (verb === "ls") {
|
|
160
|
+
const result = await runtime.alerts.list({}, request);
|
|
161
|
+
print({ data: result.data, nextCursor: result.nextCursor });
|
|
162
|
+
}
|
|
163
|
+
else if (verb === "create")
|
|
164
|
+
print(await runtime.alerts.create(body(), request));
|
|
165
|
+
else {
|
|
166
|
+
const id = need(rest[0], "an alert id");
|
|
167
|
+
if (verb === "get")
|
|
168
|
+
print(await runtime.alerts.get(id, request));
|
|
169
|
+
else if (verb === "update")
|
|
170
|
+
print(await runtime.alerts.update(id, body(), request));
|
|
171
|
+
else if (verb === "delete") {
|
|
172
|
+
await runtime.alerts.delete(id, request);
|
|
173
|
+
print({ deleted: id });
|
|
174
|
+
}
|
|
175
|
+
else if (verb === "test")
|
|
176
|
+
print(await runtime.alerts.test(id, request));
|
|
177
|
+
else if (verb === "silence") {
|
|
178
|
+
const until = need(flag("until"), "--until with an RFC3339 time");
|
|
179
|
+
if (!/T.*(?:Z|[+-]\d\d:\d\d)$/.test(until) || !Number.isFinite(Date.parse(until)))
|
|
180
|
+
throw usage("--until must be an RFC3339 time with timezone.");
|
|
181
|
+
print(await runtime.alerts.silence(id, { until, ...(flag("reason") ? { reason: flag("reason") } : {}) }, request));
|
|
182
|
+
}
|
|
183
|
+
else
|
|
184
|
+
throw usage(`Unknown alerts command: ${verb}.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|