withruntime 0.4.0 → 0.5.1
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/DAYTONA.md +129 -0
- package/E2B.md +3 -3
- package/README.md +47 -9
- package/VERCEL.md +127 -0
- package/dist/ai/index.d.ts +33 -0
- package/dist/ai/index.js +38 -0
- package/dist/claude-agent-sdk/index.d.ts +7 -0
- package/dist/claude-agent-sdk/index.js +65 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +959 -102
- package/dist/client.d.ts +25 -2
- package/dist/client.js +14 -1
- package/dist/credentials.d.ts +10 -0
- package/dist/credentials.js +56 -1
- package/dist/daytona/client.d.ts +44 -0
- package/dist/daytona/client.js +40 -0
- package/dist/daytona/context.d.ts +31 -0
- package/dist/daytona/context.js +25 -0
- package/dist/daytona/daytona.d.ts +185 -0
- package/dist/daytona/daytona.js +416 -0
- package/dist/daytona/errors.d.ts +106 -0
- package/dist/daytona/errors.js +182 -0
- package/dist/daytona/filesystem.d.ts +84 -0
- package/dist/daytona/filesystem.js +206 -0
- package/dist/daytona/git.d.ts +33 -0
- package/dist/daytona/git.js +128 -0
- package/dist/daytona/image.d.ts +45 -0
- package/dist/daytona/image.js +140 -0
- package/dist/daytona/index.d.ts +50 -0
- package/dist/daytona/index.js +50 -0
- package/dist/daytona/process.d.ts +86 -0
- package/dist/daytona/process.js +341 -0
- package/dist/daytona/sandbox.d.ts +196 -0
- package/dist/daytona/sandbox.js +448 -0
- package/dist/e2b/commands.js +6 -2
- package/dist/e2b/sandbox.d.ts +22 -2
- package/dist/e2b/sandbox.js +39 -7
- package/dist/errors.d.ts +10 -4
- package/dist/errors.js +26 -6
- package/dist/image-context.d.ts +39 -0
- package/dist/image-context.js +176 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.js +17 -2
- package/dist/keys.d.ts +43 -0
- package/dist/keys.js +196 -0
- package/dist/login.js +14 -2
- package/dist/openai-agents/index.d.ts +132 -0
- package/dist/openai-agents/index.js +791 -0
- package/dist/products/audit.d.ts +48 -0
- package/dist/products/audit.js +10 -0
- package/dist/products/images.d.ts +113 -7
- package/dist/products/images.js +186 -27
- package/dist/products/index.d.ts +11 -0
- package/dist/products/index.js +17 -1
- package/dist/products/observability.d.ts +186 -0
- package/dist/products/observability.js +117 -0
- package/dist/products/secrets.d.ts +40 -0
- package/dist/products/secrets.js +24 -0
- package/dist/products/switching.d.ts +96 -0
- package/dist/products/switching.js +25 -0
- package/dist/sandbox.d.ts +26 -1
- package/dist/sandbox.js +101 -1
- package/dist/ssh.d.ts +21 -0
- package/dist/ssh.js +324 -0
- package/dist/tar.d.ts +1 -0
- package/dist/tar.js +4 -4
- package/dist/tools/index.d.ts +62 -0
- package/dist/tools/index.js +180 -0
- package/dist/transport.d.ts +12 -2
- package/dist/transport.js +31 -4
- package/dist/tunnel.d.ts +70 -0
- package/dist/tunnel.js +316 -0
- package/dist/types.d.ts +57 -1
- package/dist/vercel/client.d.ts +40 -0
- package/dist/vercel/client.js +39 -0
- package/dist/vercel/command.d.ts +70 -0
- package/dist/vercel/command.js +148 -0
- package/dist/vercel/errors.d.ts +53 -0
- package/dist/vercel/errors.js +113 -0
- package/dist/vercel/filesystem.d.ts +150 -0
- package/dist/vercel/filesystem.js +248 -0
- package/dist/vercel/index.d.ts +30 -0
- package/dist/vercel/index.js +38 -0
- package/dist/vercel/sandbox.d.ts +317 -0
- package/dist/vercel/sandbox.js +726 -0
- package/dist/vercel/snapshot.d.ts +93 -0
- package/dist/vercel/snapshot.js +123 -0
- package/package.json +56 -4
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
2
|
+
/** One entry of the account's audit log. */
|
|
3
|
+
export type AuditEvent = {
|
|
4
|
+
/** Position in the log. Pass the last page's `next` as `before`. */
|
|
5
|
+
seq: string;
|
|
6
|
+
id: string;
|
|
7
|
+
/** When, ISO 8601 UTC. */
|
|
8
|
+
at: string;
|
|
9
|
+
/** What happened, like `member.role_changed`, `key.created` or `credit.purchased`. */
|
|
10
|
+
action: string;
|
|
11
|
+
actor: {
|
|
12
|
+
/** `runtime` is Runtime itself: a payment, an expiry, a takedown. */
|
|
13
|
+
kind: "person" | "agent" | "app" | "group" | "runtime";
|
|
14
|
+
id: string | null;
|
|
15
|
+
name: string | null;
|
|
16
|
+
/** For an agent: the member whose key it is. */
|
|
17
|
+
person: string | null;
|
|
18
|
+
};
|
|
19
|
+
target: {
|
|
20
|
+
type: string | null;
|
|
21
|
+
id: string | null;
|
|
22
|
+
};
|
|
23
|
+
/** The facts that matter, such as an email, a role or an amount. Never a secret. */
|
|
24
|
+
detail: Record<string, unknown>;
|
|
25
|
+
/** The client address the request came from. */
|
|
26
|
+
ip: string | null;
|
|
27
|
+
requestId: string | null;
|
|
28
|
+
via: "web" | "api" | "mcp" | "runtime";
|
|
29
|
+
};
|
|
30
|
+
export type AuditPage = {
|
|
31
|
+
events: AuditEvent[];
|
|
32
|
+
next: string | null;
|
|
33
|
+
};
|
|
34
|
+
/** `runtime.audit`: the account's audit log, newest first. Needs a key for
|
|
35
|
+
* every product or a read-only key, made by an owner or admin.
|
|
36
|
+
*
|
|
37
|
+
* const { events, next } = await runtime.audit.list({ action: "member." });
|
|
38
|
+
*/
|
|
39
|
+
export declare function audit(t: Transport): {
|
|
40
|
+
list: (query?: {
|
|
41
|
+
/** An action (`key.created`), or a group ending in a dot (`member.`, `credit.`). */
|
|
42
|
+
action?: string;
|
|
43
|
+
/** 1 to 200; 50 by default. */
|
|
44
|
+
limit?: number;
|
|
45
|
+
/** The previous page's `next`. */
|
|
46
|
+
before?: string;
|
|
47
|
+
}, options?: RequestOptions) => Promise<AuditPage>;
|
|
48
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** `runtime.audit`: the account's audit log, newest first. Needs a key for
|
|
2
|
+
* every product or a read-only key, made by an owner or admin.
|
|
3
|
+
*
|
|
4
|
+
* const { events, next } = await runtime.audit.list({ action: "member." });
|
|
5
|
+
*/
|
|
6
|
+
export function audit(t) {
|
|
7
|
+
return {
|
|
8
|
+
list: (query = {}, options) => t.json({ method: "GET", path: "/v1/audit", query, ...options }),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Page } from "../page.js";
|
|
2
2
|
import type { RequestOptions, Transport } from "../transport.js";
|
|
3
|
-
/** A file for a
|
|
3
|
+
/** A file for a small build context sent inline, or a recipe. */
|
|
4
4
|
export type ImageFile = {
|
|
5
5
|
path: string;
|
|
6
6
|
content: string;
|
|
@@ -8,7 +8,7 @@ export type ImageFile = {
|
|
|
8
8
|
mode?: number;
|
|
9
9
|
};
|
|
10
10
|
export type ImageRecipe = {
|
|
11
|
-
/** "runtime" (the default) or
|
|
11
|
+
/** "runtime" (the default) or an image reference. */
|
|
12
12
|
base?: string;
|
|
13
13
|
apt?: string[];
|
|
14
14
|
pip?: string[];
|
|
@@ -24,22 +24,65 @@ export type ImageBuildLimits = {
|
|
|
24
24
|
diskMiB?: number;
|
|
25
25
|
maxImageMiB?: number;
|
|
26
26
|
timeoutSeconds?: number;
|
|
27
|
+
/** The most this build's layer cache may keep. */
|
|
28
|
+
cacheMiB?: number;
|
|
29
|
+
};
|
|
30
|
+
/** What a sandbox from the image runs as it starts, and when its create
|
|
31
|
+
* answers: once `readyPort` is listened on, or `readyCommand` exits 0. */
|
|
32
|
+
export type ImageStart = {
|
|
33
|
+
command?: string;
|
|
34
|
+
argv?: string[];
|
|
35
|
+
cwd?: string;
|
|
36
|
+
env?: Record<string, string>;
|
|
37
|
+
readyCommand?: string;
|
|
38
|
+
readyPort?: number;
|
|
39
|
+
readyTimeoutSeconds?: number;
|
|
40
|
+
};
|
|
41
|
+
/** An uploaded build context: its archive's chunks and the files it holds. */
|
|
42
|
+
export type ImageContext = {
|
|
43
|
+
archive: {
|
|
44
|
+
sha256: string;
|
|
45
|
+
size: number;
|
|
46
|
+
chunks: string[];
|
|
47
|
+
};
|
|
48
|
+
files: {
|
|
49
|
+
path: string;
|
|
50
|
+
sha256: string;
|
|
51
|
+
size: number;
|
|
52
|
+
mode?: number;
|
|
53
|
+
}[];
|
|
27
54
|
};
|
|
28
55
|
/** Exactly one of `image`, `dockerfile` or `recipe`. */
|
|
29
56
|
export type CreateImage = {
|
|
57
|
+
/** Each build of a name is its next version. */
|
|
30
58
|
name?: string;
|
|
59
|
+
/** Tags the build takes when ready; a named image with none takes `latest`. */
|
|
60
|
+
tags?: string[];
|
|
31
61
|
labels?: Record<string, string>;
|
|
32
62
|
region?: string;
|
|
33
63
|
build?: ImageBuildLimits;
|
|
34
64
|
env?: Record<string, string>;
|
|
65
|
+
/** Overrides a Dockerfile's CMD and HEALTHCHECK; null runs nothing. */
|
|
66
|
+
start?: ImageStart | null;
|
|
67
|
+
/** false: build every step afresh and keep no cache. */
|
|
68
|
+
cache?: boolean;
|
|
35
69
|
} & ({
|
|
36
70
|
image: string;
|
|
37
71
|
dockerfile?: never;
|
|
38
72
|
recipe?: never;
|
|
39
73
|
} | {
|
|
40
74
|
dockerfile: string;
|
|
75
|
+
/** A small context sent inline (1 MiB in all). */
|
|
41
76
|
files?: ImageFile[];
|
|
77
|
+
/** A folder to send as the context, with its .dockerignore; uploaded
|
|
78
|
+
* as chunks, and only the ones the server does not have. */
|
|
79
|
+
contextDir?: string;
|
|
80
|
+
/** An already uploaded context (`uploadContext`). */
|
|
81
|
+
context?: ImageContext;
|
|
82
|
+
dockerignore?: string;
|
|
42
83
|
buildArgs?: Record<string, string>;
|
|
84
|
+
/** Build this stage instead of the last. */
|
|
85
|
+
target?: string;
|
|
43
86
|
image?: never;
|
|
44
87
|
recipe?: never;
|
|
45
88
|
} | {
|
|
@@ -54,6 +97,9 @@ export type Image = {
|
|
|
54
97
|
status: string;
|
|
55
98
|
state: ImageState;
|
|
56
99
|
name: string | null;
|
|
100
|
+
version: number | null;
|
|
101
|
+
tags: string[];
|
|
102
|
+
pendingTags?: string[];
|
|
57
103
|
labels: Record<string, string>;
|
|
58
104
|
region: string;
|
|
59
105
|
source: {
|
|
@@ -61,6 +107,9 @@ export type Image = {
|
|
|
61
107
|
digest: string;
|
|
62
108
|
base: unknown;
|
|
63
109
|
steps: number;
|
|
110
|
+
planVersion?: number;
|
|
111
|
+
stages?: number;
|
|
112
|
+
contextBytes?: number | null;
|
|
64
113
|
};
|
|
65
114
|
build: ImageBuildLimits & {
|
|
66
115
|
startedAt: string | null;
|
|
@@ -68,6 +117,14 @@ export type Image = {
|
|
|
68
117
|
cachedSteps: number;
|
|
69
118
|
builderVersion: string | null;
|
|
70
119
|
};
|
|
120
|
+
cache?: {
|
|
121
|
+
enabled: boolean;
|
|
122
|
+
maxMiB: number;
|
|
123
|
+
from: string | null;
|
|
124
|
+
checkpoints: number;
|
|
125
|
+
bytes: number;
|
|
126
|
+
};
|
|
127
|
+
start?: ImageStart | null;
|
|
71
128
|
sizeBytes: number | null;
|
|
72
129
|
sizeMiB: number | null;
|
|
73
130
|
storedBytes: number | null;
|
|
@@ -98,24 +155,73 @@ export type ImageLogs = {
|
|
|
98
155
|
truncated: boolean;
|
|
99
156
|
done: boolean;
|
|
100
157
|
};
|
|
101
|
-
|
|
102
|
-
|
|
158
|
+
export type ImageRegistry = {
|
|
159
|
+
id: string;
|
|
160
|
+
registry: string;
|
|
161
|
+
kind: "basic" | "ecr";
|
|
162
|
+
username: string;
|
|
163
|
+
region: string | null;
|
|
164
|
+
createdAt: string;
|
|
165
|
+
};
|
|
166
|
+
/** Credentials for pulling private images: a user name and token or password
|
|
167
|
+
* (Docker Hub, GitHub, Google with username `_json_key`), or an AWS access
|
|
168
|
+
* key for Amazon ECR. Sealed for Runtime's hosts; never returned. */
|
|
169
|
+
export type SetImageRegistry = {
|
|
170
|
+
registry: string;
|
|
171
|
+
username: string;
|
|
172
|
+
password: string;
|
|
173
|
+
} | {
|
|
174
|
+
registry: string;
|
|
175
|
+
accessKeyId: string;
|
|
176
|
+
secretAccessKey: string;
|
|
177
|
+
};
|
|
178
|
+
/** Custom images: `runtime.images.build({ recipe: { pip: ["pandas"] } })`, or
|
|
179
|
+
* `runtime.images.build({ name: "app", dockerfile, contextDir: "." })`, then
|
|
180
|
+
* `runtime.sandboxes.create({ image: "app" })`. */
|
|
103
181
|
export declare function images(t: Transport): {
|
|
104
|
-
/** Queue a build and return at once, state "queued".
|
|
105
|
-
|
|
182
|
+
/** Queue a build and return at once, state "queued". With `contextDir`,
|
|
183
|
+
* the folder is packed and its missing chunks uploaded first. */
|
|
184
|
+
create(input: CreateImage, options?: RequestOptions): Promise<Image>;
|
|
106
185
|
/** Build and wait until the image is ready or failed, streaming log lines
|
|
107
186
|
* to `onLog`. Throws when the build fails, with the build's own error. */
|
|
108
187
|
build(input: CreateImage, options?: RequestOptions & {
|
|
109
188
|
onLog?: (line: ImageLogLine) => void;
|
|
110
189
|
pollMs?: number;
|
|
111
190
|
}): Promise<Image>;
|
|
191
|
+
uploadContext: (folder: string, options?: RequestOptions & {
|
|
192
|
+
dockerignore?: string;
|
|
193
|
+
dockerfile?: string;
|
|
194
|
+
}) => Promise<ImageContext & {
|
|
195
|
+
dockerignore?: string;
|
|
196
|
+
}>;
|
|
112
197
|
get: (id: string, options?: RequestOptions) => Promise<Image>;
|
|
198
|
+
resolve: (ref: string, options?: RequestOptions) => Promise<Image>;
|
|
113
199
|
logs: (id: string, after?: number, options?: RequestOptions) => Promise<ImageLogs>;
|
|
200
|
+
followLogs: (id: string, onLog: (line: ImageLogLine) => void, options?: RequestOptions & {
|
|
201
|
+
after?: number;
|
|
202
|
+
pollMs?: number;
|
|
203
|
+
}) => Promise<Image>;
|
|
114
204
|
list: (query?: {
|
|
115
205
|
state?: ImageState;
|
|
116
206
|
name?: string;
|
|
117
207
|
limit?: number;
|
|
118
208
|
cursor?: string;
|
|
119
209
|
}, options?: RequestOptions) => Promise<Page<Image>>;
|
|
120
|
-
|
|
210
|
+
/** Every version of a name, newest first. */
|
|
211
|
+
versions: (name: string, options?: RequestOptions) => Promise<Page<Image>>;
|
|
212
|
+
/** Point `tag` of the image's name at this version. */
|
|
213
|
+
tag(ref: string, tag: string, options?: RequestOptions): Promise<Image>;
|
|
214
|
+
untag(ref: string, tag: string, options?: RequestOptions): Promise<Image>;
|
|
215
|
+
/** Delete one version (by id, name:tag or name@version) and its tags. */
|
|
216
|
+
delete(ref: string, options?: RequestOptions): Promise<Image>;
|
|
217
|
+
/** Credentials for private registries. The secret is sealed on arrival
|
|
218
|
+
* and never returned. */
|
|
219
|
+
registries: {
|
|
220
|
+
list: (options?: RequestOptions) => Promise<ImageRegistry[]>;
|
|
221
|
+
set: (input: SetImageRegistry, options?: RequestOptions) => Promise<ImageRegistry>;
|
|
222
|
+
delete: (registry: string, options?: RequestOptions) => Promise<{
|
|
223
|
+
registry: string;
|
|
224
|
+
deleted: boolean;
|
|
225
|
+
}>;
|
|
226
|
+
};
|
|
121
227
|
};
|
package/dist/products/images.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { Page } from "../page.js";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
3
|
+
const PARALLEL_UPLOADS = 4;
|
|
4
|
+
/** Custom images: `runtime.images.build({ recipe: { pip: ["pandas"] } })`, or
|
|
5
|
+
* `runtime.images.build({ name: "app", dockerfile, contextDir: "." })`, then
|
|
6
|
+
* `runtime.sandboxes.create({ image: "app" })`. */
|
|
4
7
|
export function images(t) {
|
|
5
|
-
const
|
|
8
|
+
const enc = encodeURIComponent;
|
|
9
|
+
const get = (id, options) => t.json({ method: "GET", path: `/v1/images/${enc(id)}`, ...options });
|
|
10
|
+
/** An image by id, name (its latest tag), name:tag or name@version. */
|
|
11
|
+
const resolve = (ref, options) => UUID.test(ref)
|
|
12
|
+
? get(ref, options)
|
|
13
|
+
: t.json({ method: "GET", path: "/v1/images/resolve", query: { ref }, ...options });
|
|
14
|
+
const idOf = async (ref, options) => UUID.test(ref) ? ref : (await resolve(ref, options)).id;
|
|
6
15
|
const logs = (id, after = 0, options) => t.json({
|
|
7
16
|
method: "GET",
|
|
8
|
-
path: `/v1/images/${
|
|
17
|
+
path: `/v1/images/${enc(id)}/logs`,
|
|
9
18
|
query: { after },
|
|
10
19
|
...options,
|
|
11
20
|
});
|
|
@@ -18,9 +27,123 @@ export function images(t) {
|
|
|
18
27
|
});
|
|
19
28
|
return new Page(page.data, page.nextCursor, (cursor) => list({ ...query, cursor }, options));
|
|
20
29
|
};
|
|
30
|
+
/** Pack a folder as a build context and upload the chunks the server does
|
|
31
|
+
* not have yet. Node and Bun. */
|
|
32
|
+
async function uploadContext(folder, options = {}) {
|
|
33
|
+
const { dockerignore, dockerfile, ...request } = options;
|
|
34
|
+
const { packContext, chunkArchive } = await import("../image-context.js");
|
|
35
|
+
const packed = await packContext(folder, {
|
|
36
|
+
...(dockerignore === undefined ? {} : { dockerignore }),
|
|
37
|
+
...(dockerfile === undefined ? {} : { dockerfile }),
|
|
38
|
+
});
|
|
39
|
+
const archive = await chunkArchive(packed.archive);
|
|
40
|
+
const { missing } = await t.json({
|
|
41
|
+
method: "POST",
|
|
42
|
+
path: "/v1/images/context/missing",
|
|
43
|
+
body: { digests: archive.chunks.map((c) => c.sha256) },
|
|
44
|
+
...request,
|
|
45
|
+
});
|
|
46
|
+
const wanted = new Set(missing);
|
|
47
|
+
const queue = archive.chunks.filter((chunk) => wanted.has(chunk.sha256));
|
|
48
|
+
const upload = async () => {
|
|
49
|
+
for (let chunk = queue.shift(); chunk; chunk = queue.shift())
|
|
50
|
+
await t.json({
|
|
51
|
+
method: "PUT",
|
|
52
|
+
path: `/v1/images/context/${chunk.sha256}`,
|
|
53
|
+
bytes: chunk.bytes,
|
|
54
|
+
...request,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
await Promise.all(Array.from({ length: PARALLEL_UPLOADS }, upload));
|
|
58
|
+
return {
|
|
59
|
+
archive: {
|
|
60
|
+
sha256: archive.sha256,
|
|
61
|
+
size: archive.size,
|
|
62
|
+
chunks: archive.chunks.map((c) => c.sha256),
|
|
63
|
+
},
|
|
64
|
+
files: packed.files,
|
|
65
|
+
...(packed.dockerignore === undefined ? {} : { dockerignore: packed.dockerignore }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** The request, with a context folder uploaded and named instead. */
|
|
69
|
+
async function prepare(input, options) {
|
|
70
|
+
if (!("contextDir" in input) || input.contextDir === undefined)
|
|
71
|
+
return input;
|
|
72
|
+
const { contextDir, ...rest } = input;
|
|
73
|
+
const uploaded = await uploadContext(contextDir, {
|
|
74
|
+
...(rest.dockerignore === undefined ? {} : { dockerignore: rest.dockerignore }),
|
|
75
|
+
...(options?.signal ? { signal: options.signal } : {}),
|
|
76
|
+
});
|
|
77
|
+
const { dockerignore, ...context } = uploaded;
|
|
78
|
+
return {
|
|
79
|
+
...rest,
|
|
80
|
+
context,
|
|
81
|
+
...(dockerignore === undefined ? {} : { dockerignore }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Build log lines as they are written, until the build ends. Streams when
|
|
85
|
+
* the server can, and polls when it cannot. */
|
|
86
|
+
async function followLogs(id, onLog, options = {}) {
|
|
87
|
+
const { after: from = 0, pollMs = 1000, ...request } = options;
|
|
88
|
+
let after = from;
|
|
89
|
+
try {
|
|
90
|
+
for (;;) {
|
|
91
|
+
let resume = false;
|
|
92
|
+
for await (const event of t.events({
|
|
93
|
+
method: "GET",
|
|
94
|
+
path: `/v1/images/${enc(id)}/logs`,
|
|
95
|
+
query: { after, follow: true },
|
|
96
|
+
...request,
|
|
97
|
+
})) {
|
|
98
|
+
if (event.type === "line") {
|
|
99
|
+
onLog(event);
|
|
100
|
+
after = event.seq;
|
|
101
|
+
}
|
|
102
|
+
else if (event.type === "done")
|
|
103
|
+
return event.image;
|
|
104
|
+
else if (event.type === "continue") {
|
|
105
|
+
after = event.after;
|
|
106
|
+
resume = true;
|
|
107
|
+
}
|
|
108
|
+
else if (event.type === "error")
|
|
109
|
+
throw new Error(event.error.message);
|
|
110
|
+
}
|
|
111
|
+
if (!resume)
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (request.signal?.aborted)
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
// A server without streamed logs, or a stream that broke: poll.
|
|
120
|
+
for (;;) {
|
|
121
|
+
const page = await logs(id, after, request);
|
|
122
|
+
for (const line of page.lines)
|
|
123
|
+
onLog(line);
|
|
124
|
+
after = page.nextAfter;
|
|
125
|
+
if (page.done)
|
|
126
|
+
return get(id, request);
|
|
127
|
+
const image = await get(id, request);
|
|
128
|
+
if (image.state !== "queued" && image.state !== "building") {
|
|
129
|
+
for (const line of (await logs(id, after, request)).lines)
|
|
130
|
+
onLog(line);
|
|
131
|
+
return image;
|
|
132
|
+
}
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
21
136
|
return {
|
|
22
|
-
/** Queue a build and return at once, state "queued".
|
|
23
|
-
|
|
137
|
+
/** Queue a build and return at once, state "queued". With `contextDir`,
|
|
138
|
+
* the folder is packed and its missing chunks uploaded first. */
|
|
139
|
+
async create(input, options) {
|
|
140
|
+
return t.json({
|
|
141
|
+
method: "POST",
|
|
142
|
+
path: "/v1/images",
|
|
143
|
+
body: await prepare(input, options),
|
|
144
|
+
...options,
|
|
145
|
+
});
|
|
146
|
+
},
|
|
24
147
|
/** Build and wait until the image is ready or failed, streaming log lines
|
|
25
148
|
* to `onLog`. Throws when the build fails, with the build's own error. */
|
|
26
149
|
async build(input, options = {}) {
|
|
@@ -28,37 +151,73 @@ export function images(t) {
|
|
|
28
151
|
let image = await t.json({
|
|
29
152
|
method: "POST",
|
|
30
153
|
path: "/v1/images",
|
|
31
|
-
body: input,
|
|
154
|
+
body: await prepare(input, request),
|
|
32
155
|
...request,
|
|
33
156
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const page = await logs(image.id, after, { signal: request.signal });
|
|
38
|
-
for (const line of page.lines)
|
|
39
|
-
onLog(line);
|
|
40
|
-
after = page.nextAfter;
|
|
41
|
-
}
|
|
42
|
-
image = await get(image.id, { signal: request.signal });
|
|
43
|
-
if (image.state !== "queued" && image.state !== "building")
|
|
44
|
-
break;
|
|
157
|
+
if (onLog)
|
|
158
|
+
image = await followLogs(image.id, onLog, { ...request, pollMs });
|
|
159
|
+
while (image.state === "queued" || image.state === "building") {
|
|
45
160
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
161
|
+
image = await get(image.id, { ...(request.signal ? { signal: request.signal } : {}) });
|
|
46
162
|
}
|
|
47
|
-
if (onLog)
|
|
48
|
-
for (const line of (await logs(image.id, after)).lines)
|
|
49
|
-
onLog(line);
|
|
50
163
|
if (image.state !== "ready")
|
|
51
164
|
throw new Error(`Image ${image.id} ${image.state}: ${image.error ?? "no error given"}`);
|
|
52
165
|
return image;
|
|
53
166
|
},
|
|
167
|
+
uploadContext,
|
|
54
168
|
get,
|
|
169
|
+
resolve,
|
|
55
170
|
logs,
|
|
171
|
+
followLogs,
|
|
56
172
|
list,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
173
|
+
/** Every version of a name, newest first. */
|
|
174
|
+
versions: (name, options) => list({ name, limit: 100 }, options),
|
|
175
|
+
/** Point `tag` of the image's name at this version. */
|
|
176
|
+
async tag(ref, tag, options) {
|
|
177
|
+
return t.json({
|
|
178
|
+
method: "POST",
|
|
179
|
+
path: `/v1/images/${enc(await idOf(ref, options))}:tag`,
|
|
180
|
+
body: { tag },
|
|
181
|
+
...options,
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
async untag(ref, tag, options) {
|
|
185
|
+
return t.json({
|
|
186
|
+
method: "POST",
|
|
187
|
+
path: `/v1/images/${enc(await idOf(ref, options))}:untag`,
|
|
188
|
+
body: { tag },
|
|
189
|
+
...options,
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
/** Delete one version (by id, name:tag or name@version) and its tags. */
|
|
193
|
+
async delete(ref, options) {
|
|
194
|
+
return t.json({
|
|
195
|
+
method: "POST",
|
|
196
|
+
path: `/v1/images/${enc(await idOf(ref, options))}:delete`,
|
|
197
|
+
body: {},
|
|
198
|
+
...options,
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
/** Credentials for private registries. The secret is sealed on arrival
|
|
202
|
+
* and never returned. */
|
|
203
|
+
registries: {
|
|
204
|
+
list: async (options) => (await t.json({
|
|
205
|
+
method: "GET",
|
|
206
|
+
path: "/v1/images/registries",
|
|
207
|
+
...options,
|
|
208
|
+
})).data,
|
|
209
|
+
set: (input, options) => t.json({
|
|
210
|
+
method: "POST",
|
|
211
|
+
path: "/v1/images/registries",
|
|
212
|
+
body: input,
|
|
213
|
+
...options,
|
|
214
|
+
}),
|
|
215
|
+
delete: (registry, options) => t.json({
|
|
216
|
+
method: "POST",
|
|
217
|
+
path: "/v1/images/registries:delete",
|
|
218
|
+
body: { registry },
|
|
219
|
+
...options,
|
|
220
|
+
}),
|
|
221
|
+
},
|
|
63
222
|
};
|
|
64
223
|
}
|
package/dist/products/index.d.ts
CHANGED
|
@@ -6,19 +6,30 @@ import { sandboxInterpreter } from "./interpreter.js";
|
|
|
6
6
|
import { sandboxNetwork } from "./network.js";
|
|
7
7
|
import { sandboxPreviews } from "./previews.js";
|
|
8
8
|
import { referrals } from "./referrals.js";
|
|
9
|
+
import { audit } from "./audit.js";
|
|
10
|
+
import { switching } from "./switching.js";
|
|
9
11
|
import { limits } from "./limits.js";
|
|
10
12
|
import { volumes } from "./volumes.js";
|
|
13
|
+
import { secrets } from "./secrets.js";
|
|
14
|
+
import { events, otel, sandboxMetrics, webhooks } from "./observability.js";
|
|
11
15
|
export declare const clientExtensions: {
|
|
12
16
|
images: typeof images;
|
|
13
17
|
volumes: typeof volumes;
|
|
14
18
|
referrals: typeof referrals;
|
|
15
19
|
limits: typeof limits;
|
|
20
|
+
switching: typeof switching;
|
|
21
|
+
secrets: typeof secrets;
|
|
22
|
+
webhooks: typeof webhooks;
|
|
23
|
+
otel: typeof otel;
|
|
24
|
+
events: typeof events;
|
|
25
|
+
audit: typeof audit;
|
|
16
26
|
};
|
|
17
27
|
export declare const sandboxExtensions: {
|
|
18
28
|
interpreter: typeof sandboxInterpreter;
|
|
19
29
|
previews: typeof sandboxPreviews;
|
|
20
30
|
network: typeof sandboxNetwork;
|
|
21
31
|
desktop: typeof sandboxDesktop;
|
|
32
|
+
metrics: typeof sandboxMetrics;
|
|
22
33
|
};
|
|
23
34
|
export type ClientExtensions = {
|
|
24
35
|
readonly [K in keyof typeof clientExtensions]: ReturnType<(typeof clientExtensions)[K]>;
|
package/dist/products/index.js
CHANGED
|
@@ -4,8 +4,12 @@ import { sandboxInterpreter } from "./interpreter.js";
|
|
|
4
4
|
import { sandboxNetwork } from "./network.js";
|
|
5
5
|
import { sandboxPreviews } from "./previews.js";
|
|
6
6
|
import { referrals } from "./referrals.js";
|
|
7
|
+
import { audit } from "./audit.js";
|
|
8
|
+
import { switching } from "./switching.js";
|
|
7
9
|
import { limits } from "./limits.js";
|
|
8
10
|
import { volumes } from "./volumes.js";
|
|
11
|
+
import { secrets } from "./secrets.js";
|
|
12
|
+
import { events, otel, sandboxMetrics, webhooks } from "./observability.js";
|
|
9
13
|
/* HOW A LANE ADDS A PRODUCT TO THE SDK
|
|
10
14
|
*
|
|
11
15
|
* 1. Write src/products/<name>.ts exporting a factory:
|
|
@@ -21,12 +25,24 @@ import { volumes } from "./volumes.js";
|
|
|
21
25
|
* 2. Add ONE line to the matching object below. The Runtime client and every
|
|
22
26
|
* Sandbox pick it up, typed, with the shared auth, retries, keys and errors.
|
|
23
27
|
*/
|
|
24
|
-
export const clientExtensions = {
|
|
28
|
+
export const clientExtensions = {
|
|
29
|
+
images,
|
|
30
|
+
volumes,
|
|
31
|
+
referrals,
|
|
32
|
+
limits,
|
|
33
|
+
switching,
|
|
34
|
+
secrets,
|
|
35
|
+
webhooks,
|
|
36
|
+
otel,
|
|
37
|
+
events,
|
|
38
|
+
audit,
|
|
39
|
+
};
|
|
25
40
|
export const sandboxExtensions = {
|
|
26
41
|
interpreter: sandboxInterpreter,
|
|
27
42
|
previews: sandboxPreviews,
|
|
28
43
|
network: sandboxNetwork,
|
|
29
44
|
desktop: sandboxDesktop,
|
|
45
|
+
metrics: sandboxMetrics,
|
|
30
46
|
};
|
|
31
47
|
/** The factories as plain pairs, for the constructors that install them. */
|
|
32
48
|
export function clientFactories() {
|