withruntime 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/DAYTONA.md +129 -0
  2. package/E2B.md +146 -0
  3. package/README.md +84 -12
  4. package/VERCEL.md +127 -0
  5. package/dist/ai/index.d.ts +33 -0
  6. package/dist/ai/index.js +38 -0
  7. package/dist/claude-agent-sdk/index.d.ts +7 -0
  8. package/dist/claude-agent-sdk/index.js +65 -0
  9. package/dist/cli.d.ts +6 -0
  10. package/dist/cli.js +949 -105
  11. package/dist/client.d.ts +25 -2
  12. package/dist/client.js +14 -1
  13. package/dist/credentials.d.ts +10 -0
  14. package/dist/credentials.js +56 -1
  15. package/dist/daytona/client.d.ts +44 -0
  16. package/dist/daytona/client.js +40 -0
  17. package/dist/daytona/context.d.ts +26 -0
  18. package/dist/daytona/context.js +22 -0
  19. package/dist/daytona/daytona.d.ts +185 -0
  20. package/dist/daytona/daytona.js +416 -0
  21. package/dist/daytona/errors.d.ts +106 -0
  22. package/dist/daytona/errors.js +182 -0
  23. package/dist/daytona/filesystem.d.ts +84 -0
  24. package/dist/daytona/filesystem.js +206 -0
  25. package/dist/daytona/git.d.ts +33 -0
  26. package/dist/daytona/git.js +128 -0
  27. package/dist/daytona/image.d.ts +45 -0
  28. package/dist/daytona/image.js +140 -0
  29. package/dist/daytona/index.d.ts +50 -0
  30. package/dist/daytona/index.js +50 -0
  31. package/dist/daytona/process.d.ts +86 -0
  32. package/dist/daytona/process.js +339 -0
  33. package/dist/daytona/sandbox.d.ts +196 -0
  34. package/dist/daytona/sandbox.js +448 -0
  35. package/dist/e2b/client.d.ts +58 -0
  36. package/dist/e2b/client.js +66 -0
  37. package/dist/e2b/code-interpreter.d.ts +144 -0
  38. package/dist/e2b/code-interpreter.js +244 -0
  39. package/dist/e2b/commands.d.ts +100 -0
  40. package/dist/e2b/commands.js +268 -0
  41. package/dist/e2b/errors.d.ts +72 -0
  42. package/dist/e2b/errors.js +151 -0
  43. package/dist/e2b/filesystem.d.ts +82 -0
  44. package/dist/e2b/filesystem.js +143 -0
  45. package/dist/e2b/index.d.ts +28 -0
  46. package/dist/e2b/index.js +61 -0
  47. package/dist/e2b/sandbox.d.ts +203 -0
  48. package/dist/e2b/sandbox.js +490 -0
  49. package/dist/e2b/unsupported.d.ts +19 -0
  50. package/dist/e2b/unsupported.js +27 -0
  51. package/dist/errors.d.ts +10 -4
  52. package/dist/errors.js +26 -6
  53. package/dist/image-context.d.ts +39 -0
  54. package/dist/image-context.js +176 -0
  55. package/dist/index.d.ts +19 -2
  56. package/dist/index.js +17 -2
  57. package/dist/keys.d.ts +43 -0
  58. package/dist/keys.js +196 -0
  59. package/dist/login.js +27 -6
  60. package/dist/mcp.d.ts +2 -2
  61. package/dist/mcp.js +4 -3
  62. package/dist/openai-agents/index.d.ts +132 -0
  63. package/dist/openai-agents/index.js +791 -0
  64. package/dist/products/audit.d.ts +48 -0
  65. package/dist/products/audit.js +10 -0
  66. package/dist/products/images.d.ts +113 -7
  67. package/dist/products/images.js +186 -27
  68. package/dist/products/index.d.ts +11 -0
  69. package/dist/products/index.js +17 -1
  70. package/dist/products/observability.d.ts +186 -0
  71. package/dist/products/observability.js +117 -0
  72. package/dist/products/secrets.d.ts +40 -0
  73. package/dist/products/secrets.js +24 -0
  74. package/dist/products/switching.d.ts +89 -0
  75. package/dist/products/switching.js +25 -0
  76. package/dist/proxy.d.ts +30 -0
  77. package/dist/proxy.js +178 -0
  78. package/dist/sandbox.d.ts +30 -2
  79. package/dist/sandbox.js +101 -1
  80. package/dist/ssh.d.ts +21 -0
  81. package/dist/ssh.js +312 -0
  82. package/dist/tar.d.ts +1 -0
  83. package/dist/tar.js +4 -4
  84. package/dist/tools/index.d.ts +62 -0
  85. package/dist/tools/index.js +180 -0
  86. package/dist/transport.d.ts +12 -2
  87. package/dist/transport.js +76 -16
  88. package/dist/tunnel.d.ts +67 -0
  89. package/dist/tunnel.js +311 -0
  90. package/dist/types.d.ts +57 -1
  91. package/dist/vercel/client.d.ts +40 -0
  92. package/dist/vercel/client.js +39 -0
  93. package/dist/vercel/command.d.ts +70 -0
  94. package/dist/vercel/command.js +148 -0
  95. package/dist/vercel/errors.d.ts +53 -0
  96. package/dist/vercel/errors.js +113 -0
  97. package/dist/vercel/filesystem.d.ts +150 -0
  98. package/dist/vercel/filesystem.js +248 -0
  99. package/dist/vercel/index.d.ts +30 -0
  100. package/dist/vercel/index.js +38 -0
  101. package/dist/vercel/sandbox.d.ts +317 -0
  102. package/dist/vercel/sandbox.js +726 -0
  103. package/dist/vercel/snapshot.d.ts +93 -0
  104. package/dist/vercel/snapshot.js +123 -0
  105. package/package.json +69 -5
@@ -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 Dockerfile's build context or a recipe. */
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 a public image reference. */
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
- /** Custom images: `runtime.images.build({ recipe: { pip: ["pandas"] } })`, then
102
- * `runtime.sandboxes.create({ image: image.id })`. */
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
- create: (input: CreateImage, options?: RequestOptions) => Promise<Image>;
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
- delete: (id: string, options?: RequestOptions) => Promise<Image>;
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
  };
@@ -1,11 +1,20 @@
1
1
  import { Page } from "../page.js";
2
- /** Custom images: `runtime.images.build({ recipe: { pip: ["pandas"] } })`, then
3
- * `runtime.sandboxes.create({ image: image.id })`. */
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 get = (id, options) => t.json({ method: "GET", path: `/v1/images/${encodeURIComponent(id)}`, ...options });
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/${encodeURIComponent(id)}/logs`,
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
- create: (input, options) => t.json({ method: "POST", path: "/v1/images", body: input, ...options }),
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
- let after = 0;
35
- for (;;) {
36
- if (onLog) {
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
- delete: (id, options) => t.json({
58
- method: "POST",
59
- path: `/v1/images/${encodeURIComponent(id)}:delete`,
60
- body: {},
61
- ...options,
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
  }
@@ -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]>;
@@ -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 = { images, volumes, referrals, limits };
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() {