@buddy-works/sandbox-sdk 0.1.0-rc.0 → 0.1.0-rc.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/dist/index.d.mts +1629 -0
- package/dist/index.mjs +2600 -0
- package/package.json +1 -1
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2600 @@
|
|
|
1
|
+
import { ZodError, prettifyError, z } from "zod";
|
|
2
|
+
import { inspect } from "node:util";
|
|
3
|
+
import pRetry from "p-retry";
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
|
|
6
|
+
//#region src/api/openapi/transformers.gen.ts
|
|
7
|
+
const projectViewSchemaResponseTransformer = (data) => {
|
|
8
|
+
if (data.create_date) data.create_date = new Date(data.create_date);
|
|
9
|
+
return data;
|
|
10
|
+
};
|
|
11
|
+
const sandboxResponseSchemaResponseTransformer = (data) => {
|
|
12
|
+
if (data.project) data.project = projectViewSchemaResponseTransformer(data.project);
|
|
13
|
+
return data;
|
|
14
|
+
};
|
|
15
|
+
const addSandboxResponseTransformer = async (data) => {
|
|
16
|
+
data = sandboxResponseSchemaResponseTransformer(data);
|
|
17
|
+
return data;
|
|
18
|
+
};
|
|
19
|
+
const getSandboxResponseTransformer = async (data) => {
|
|
20
|
+
data = sandboxResponseSchemaResponseTransformer(data);
|
|
21
|
+
return data;
|
|
22
|
+
};
|
|
23
|
+
const sandboxContentItemSchemaResponseTransformer = (data) => {
|
|
24
|
+
if (data.size) data.size = BigInt(data.size.toString());
|
|
25
|
+
return data;
|
|
26
|
+
};
|
|
27
|
+
const sandboxContentViewSchemaResponseTransformer = (data) => {
|
|
28
|
+
if (data.contents) data.contents = data.contents.map((item) => sandboxContentItemSchemaResponseTransformer(item));
|
|
29
|
+
return data;
|
|
30
|
+
};
|
|
31
|
+
const getSandboxContentResponseTransformer = async (data) => {
|
|
32
|
+
data = sandboxContentViewSchemaResponseTransformer(data);
|
|
33
|
+
return data;
|
|
34
|
+
};
|
|
35
|
+
const createSandboxDirectoryResponseTransformer = async (data) => {
|
|
36
|
+
data = sandboxContentItemSchemaResponseTransformer(data);
|
|
37
|
+
return data;
|
|
38
|
+
};
|
|
39
|
+
const uploadSandboxFileResponseTransformer = async (data) => {
|
|
40
|
+
data = sandboxContentItemSchemaResponseTransformer(data);
|
|
41
|
+
return data;
|
|
42
|
+
};
|
|
43
|
+
const restartSandboxResponseTransformer = async (data) => {
|
|
44
|
+
data = sandboxResponseSchemaResponseTransformer(data);
|
|
45
|
+
return data;
|
|
46
|
+
};
|
|
47
|
+
const startSandboxResponseTransformer = async (data) => {
|
|
48
|
+
data = sandboxResponseSchemaResponseTransformer(data);
|
|
49
|
+
return data;
|
|
50
|
+
};
|
|
51
|
+
const stopSandboxResponseTransformer = async (data) => {
|
|
52
|
+
data = sandboxResponseSchemaResponseTransformer(data);
|
|
53
|
+
return data;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/api/openapi/zod.gen.ts
|
|
58
|
+
const zUriBuilder = z.record(z.string(), z.unknown());
|
|
59
|
+
const zStatusType = z.object({
|
|
60
|
+
family: z.optional(z.enum([
|
|
61
|
+
"INFORMATIONAL",
|
|
62
|
+
"SUCCESSFUL",
|
|
63
|
+
"REDIRECTION",
|
|
64
|
+
"CLIENT_ERROR",
|
|
65
|
+
"SERVER_ERROR",
|
|
66
|
+
"OTHER"
|
|
67
|
+
])),
|
|
68
|
+
status_code: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
|
|
69
|
+
reason_phrase: z.optional(z.string())
|
|
70
|
+
});
|
|
71
|
+
const zEntityTag = z.object({
|
|
72
|
+
value: z.optional(z.string()),
|
|
73
|
+
weak: z.optional(z.boolean())
|
|
74
|
+
});
|
|
75
|
+
const zMediaType = z.object({
|
|
76
|
+
type: z.optional(z.string()),
|
|
77
|
+
subtype: z.optional(z.string()),
|
|
78
|
+
parameters: z.optional(z.record(z.string(), z.string())),
|
|
79
|
+
wildcard_type: z.optional(z.boolean()),
|
|
80
|
+
wildcard_subtype: z.optional(z.boolean())
|
|
81
|
+
});
|
|
82
|
+
const zLink = z.object({
|
|
83
|
+
uri: z.optional(z.url()),
|
|
84
|
+
uri_builder: z.optional(zUriBuilder),
|
|
85
|
+
rel: z.optional(z.string()),
|
|
86
|
+
rels: z.optional(z.array(z.string())),
|
|
87
|
+
type: z.optional(z.string()),
|
|
88
|
+
params: z.optional(z.record(z.string(), z.string())),
|
|
89
|
+
title: z.optional(z.string())
|
|
90
|
+
});
|
|
91
|
+
const zNewCookie = z.object({
|
|
92
|
+
name: z.optional(z.string()),
|
|
93
|
+
value: z.optional(z.string()),
|
|
94
|
+
version: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
|
|
95
|
+
path: z.optional(z.string()),
|
|
96
|
+
domain: z.optional(z.string()),
|
|
97
|
+
comment: z.optional(z.string()),
|
|
98
|
+
max_age: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
|
|
99
|
+
expiry: z.optional(z.iso.datetime()),
|
|
100
|
+
secure: z.optional(z.boolean()),
|
|
101
|
+
http_only: z.optional(z.boolean()),
|
|
102
|
+
same_site: z.optional(z.enum([
|
|
103
|
+
"NONE",
|
|
104
|
+
"LAX",
|
|
105
|
+
"STRICT"
|
|
106
|
+
]))
|
|
107
|
+
});
|
|
108
|
+
const zResponse = z.object({
|
|
109
|
+
status_info: z.optional(zStatusType),
|
|
110
|
+
cookies: z.optional(z.record(z.string(), zNewCookie)),
|
|
111
|
+
allowed_methods: z.optional(z.array(z.string())),
|
|
112
|
+
links: z.optional(z.array(zLink)),
|
|
113
|
+
media_type: z.optional(zMediaType),
|
|
114
|
+
entity_tag: z.optional(zEntityTag),
|
|
115
|
+
string_headers: z.optional(z.object({ empty: z.optional(z.boolean()) })),
|
|
116
|
+
closed: z.optional(z.boolean()),
|
|
117
|
+
length: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
|
|
118
|
+
location: z.optional(z.url()),
|
|
119
|
+
language: z.optional(z.object({
|
|
120
|
+
language: z.optional(z.string()),
|
|
121
|
+
display_name: z.optional(z.string()),
|
|
122
|
+
country: z.optional(z.string()),
|
|
123
|
+
variant: z.optional(z.string()),
|
|
124
|
+
script: z.optional(z.string()),
|
|
125
|
+
unicode_locale_attributes: z.optional(z.array(z.string())),
|
|
126
|
+
unicode_locale_keys: z.optional(z.array(z.string())),
|
|
127
|
+
display_language: z.optional(z.string()),
|
|
128
|
+
display_script: z.optional(z.string()),
|
|
129
|
+
display_country: z.optional(z.string()),
|
|
130
|
+
display_variant: z.optional(z.string()),
|
|
131
|
+
extension_keys: z.optional(z.array(z.string())),
|
|
132
|
+
iso3_language: z.optional(z.string()),
|
|
133
|
+
iso3_country: z.optional(z.string())
|
|
134
|
+
})),
|
|
135
|
+
date: z.optional(z.iso.datetime()),
|
|
136
|
+
last_modified: z.optional(z.iso.datetime()),
|
|
137
|
+
status: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" })),
|
|
138
|
+
metadata: z.optional(z.object({ empty: z.optional(z.boolean()) })),
|
|
139
|
+
entity: z.optional(z.record(z.string(), z.unknown())),
|
|
140
|
+
headers: z.optional(z.object({ empty: z.optional(z.boolean()) }))
|
|
141
|
+
});
|
|
142
|
+
/**
|
|
143
|
+
* Sandbox reference
|
|
144
|
+
*/
|
|
145
|
+
const zSandboxIdView = z.object({
|
|
146
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
147
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
148
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })),
|
|
149
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
150
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
151
|
+
status: z.optional(z.enum([
|
|
152
|
+
"STARTING",
|
|
153
|
+
"STOPPING",
|
|
154
|
+
"FAILED",
|
|
155
|
+
"RUNNING",
|
|
156
|
+
"STOPPED",
|
|
157
|
+
"RESTORING"
|
|
158
|
+
]).register(z.globalRegistry, { description: "The current status of the sandbox" }))
|
|
159
|
+
}).register(z.globalRegistry, { description: "Sandbox reference" });
|
|
160
|
+
/**
|
|
161
|
+
* Integration reference
|
|
162
|
+
*/
|
|
163
|
+
const zIntegrationIdView = z.object({
|
|
164
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
165
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
166
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID of the integration" })),
|
|
167
|
+
hash_id: z.optional(z.string().register(z.globalRegistry, { description: "The unique hash ID of the integration" })),
|
|
168
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the integration" })),
|
|
169
|
+
type: z.optional(z.enum([
|
|
170
|
+
"GIT_HUB",
|
|
171
|
+
"BITBUCKET",
|
|
172
|
+
"GOOGLE",
|
|
173
|
+
"DIGITAL_OCEAN",
|
|
174
|
+
"SLACK",
|
|
175
|
+
"MODULUS",
|
|
176
|
+
"HEROKU",
|
|
177
|
+
"AMAZON",
|
|
178
|
+
"GIT_LAB",
|
|
179
|
+
"SHOPIFY",
|
|
180
|
+
"GIT_HUB_ENTERPRISE",
|
|
181
|
+
"GIT_LAB_ENTERPRISE",
|
|
182
|
+
"PUSHOVER",
|
|
183
|
+
"PUSHBULLET",
|
|
184
|
+
"RACKSPACE",
|
|
185
|
+
"CUSTOM",
|
|
186
|
+
"CLOUDFLARE",
|
|
187
|
+
"NEW_RELIC",
|
|
188
|
+
"SENTRY",
|
|
189
|
+
"ROLLBAR",
|
|
190
|
+
"DATADOG",
|
|
191
|
+
"DO_SPACES",
|
|
192
|
+
"HONEYBADGER",
|
|
193
|
+
"VULTR",
|
|
194
|
+
"SENTRY_ENTERPRISE",
|
|
195
|
+
"LOGGLY",
|
|
196
|
+
"HIP_CHAT",
|
|
197
|
+
"FIREBASE",
|
|
198
|
+
"TELEGRAM",
|
|
199
|
+
"AZURE",
|
|
200
|
+
"UPCLOUD",
|
|
201
|
+
"GHOST_INSPECTOR",
|
|
202
|
+
"NETLIFY",
|
|
203
|
+
"AZURE_CLOUD",
|
|
204
|
+
"MICROSOFT_TEAMS",
|
|
205
|
+
"GOOGLE_SERVICE_ACCOUNT",
|
|
206
|
+
"GOOGLE_PLAY_STORE",
|
|
207
|
+
"DOCKER_HUB",
|
|
208
|
+
"APP_STORE",
|
|
209
|
+
"GIT_HUB_APP",
|
|
210
|
+
"GIT_HUB_APP_ENTERPRISE",
|
|
211
|
+
"GIT_HUB_API",
|
|
212
|
+
"ATOP",
|
|
213
|
+
"SNYK",
|
|
214
|
+
"STACK_HAWK",
|
|
215
|
+
"BLACKFIRE",
|
|
216
|
+
"BACKBLAZE",
|
|
217
|
+
"ONE_LOGIN",
|
|
218
|
+
"OKTA",
|
|
219
|
+
"CONTENTFUL"
|
|
220
|
+
]).register(z.globalRegistry, { description: "The type of integration" })),
|
|
221
|
+
auth_type: z.optional(z.enum([
|
|
222
|
+
"OAUTH",
|
|
223
|
+
"TOKEN",
|
|
224
|
+
"API_KEY",
|
|
225
|
+
"APP",
|
|
226
|
+
"APP_SPRYKER",
|
|
227
|
+
"TOKEN_APP_EXTENSION",
|
|
228
|
+
"DEFAULT",
|
|
229
|
+
"OIDC",
|
|
230
|
+
"TRUSTED",
|
|
231
|
+
"APP_RW"
|
|
232
|
+
]).register(z.globalRegistry, { description: "The authentication method used by the integration" })),
|
|
233
|
+
host_url: z.optional(z.string().register(z.globalRegistry, { description: "The host URL for custom integrations" })),
|
|
234
|
+
webhook_address: z.optional(z.string().register(z.globalRegistry, { description: "The webhook URL for receiving notifications" })),
|
|
235
|
+
atop_url: z.optional(z.string().register(z.globalRegistry, { description: "The ATOP service URL" })),
|
|
236
|
+
app_id: z.optional(z.string().register(z.globalRegistry, { description: "The application ID for Azure Cloud integrations" })),
|
|
237
|
+
google_project: z.optional(z.string().register(z.globalRegistry, { description: "The Google Cloud project ID" })),
|
|
238
|
+
audience: z.optional(z.string().register(z.globalRegistry, { description: "The JWT audience for token validation" }))
|
|
239
|
+
}).register(z.globalRegistry, { description: "Integration reference" });
|
|
240
|
+
/**
|
|
241
|
+
* User/member reference
|
|
242
|
+
*/
|
|
243
|
+
const zMemberView = z.object({
|
|
244
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
245
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
246
|
+
id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the user" })),
|
|
247
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the user" })),
|
|
248
|
+
avatar_url: z.optional(z.string().register(z.globalRegistry, { description: "The avatar URL of the user" })),
|
|
249
|
+
email: z.optional(z.string().register(z.globalRegistry, { description: "The email address of the user" })),
|
|
250
|
+
admin: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether the user has admin privileges" })),
|
|
251
|
+
workspace_owner: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether the user is workspace owner" }))
|
|
252
|
+
}).register(z.globalRegistry, { description: "User/member reference" });
|
|
253
|
+
const zProjectView = z.object({
|
|
254
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
255
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
256
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The human-readable ID of the project" })),
|
|
257
|
+
display_name: z.string().register(z.globalRegistry, { description: "The Name of the project" }),
|
|
258
|
+
status: z.optional(z.string().register(z.globalRegistry, { description: "The status of the project" })),
|
|
259
|
+
access: z.optional(z.enum(["PRIVATE", "PUBLIC"]).register(z.globalRegistry, { description: "Indicates if this is a public project" })),
|
|
260
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "The creation date of the project" })),
|
|
261
|
+
external_project_id: z.optional(z.string().register(z.globalRegistry, { description: "Repo slug of the Bitbucket, GitHub or GitLab project. Required when adding the integrated project" })),
|
|
262
|
+
git_lab_project_id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "ID of the project in GitLab" })),
|
|
263
|
+
custom_repo_url: z.optional(z.string().register(z.globalRegistry, { description: "SSH or HTTPS url of the git repository. Required when adding the project integrated with custom git repository" })),
|
|
264
|
+
custom_repo_user: z.optional(z.string().register(z.globalRegistry, { description: "Username used to authorize access to the git repository. Required when adding the project integrated with custom git repository" })),
|
|
265
|
+
custom_repo_pass: z.optional(z.string().register(z.globalRegistry, { description: "Password used to authorize access to the git repository. Required when adding the project integrated with custom git repository and the provided `custom_repo_url` is the HTTPS url" })),
|
|
266
|
+
custom_repo_ssh_key_id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the private SSH key used to authorize access to the git repository. Required when adding the project integrated with private git server by SSH url" })),
|
|
267
|
+
created_by: z.optional(zMemberView),
|
|
268
|
+
http_repository: z.optional(z.string().register(z.globalRegistry, { description: "The HTTP repository URL" })),
|
|
269
|
+
ssh_repository: z.optional(z.string().register(z.globalRegistry, { description: "The SSH repository URL" })),
|
|
270
|
+
default_branch: z.optional(z.string().register(z.globalRegistry, { description: "The default branch name" })),
|
|
271
|
+
integration: z.optional(zIntegrationIdView),
|
|
272
|
+
fetch_submodules: z.optional(z.boolean().register(z.globalRegistry, { description: "Defines whether the submodules are fetched during the runs in this project" })),
|
|
273
|
+
fetch_submodules_env_key: z.optional(z.string().register(z.globalRegistry, { description: "Name of the key that will be used to authorize while fetching the submodules. Required when `fetch_submodules` is set to `true`" })),
|
|
274
|
+
allow_pull_requests: z.optional(z.boolean().register(z.globalRegistry, { description: "Enables/disables pull requests in the project. Available only for projects synchronized with GitHub or GitHub Enterprise repository" })),
|
|
275
|
+
update_default_branch_from_external: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to true, the default branch will be updated from GitHub/GitLab/Bitbucket." })),
|
|
276
|
+
without_repository: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to true, the project is created without any repository attached." }))
|
|
277
|
+
});
|
|
278
|
+
/**
|
|
279
|
+
* The environment variables of the sandbox
|
|
280
|
+
*/
|
|
281
|
+
const zAddVariableInObjectRequest = z.object({
|
|
282
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
283
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
284
|
+
key: z.string().register(z.globalRegistry, { description: "The name of the variable" }),
|
|
285
|
+
value: z.optional(z.string().register(z.globalRegistry, { description: "The value of the variable" })),
|
|
286
|
+
settable: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value can be set by Buddy actions" })),
|
|
287
|
+
run_only_settable: z.optional(z.boolean().register(z.globalRegistry, { description: "Available only if `type=VAR`. If set to `true` the variable value can be set by Buddy actions only for execution time" })),
|
|
288
|
+
encrypted: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value will be encrypted and hidden" })),
|
|
289
|
+
description: z.optional(z.string().register(z.globalRegistry, { description: "The optional description of the variable" })),
|
|
290
|
+
init_path: z.optional(z.string().register(z.globalRegistry, { description: "Initial path for the variable" })),
|
|
291
|
+
defaults: z.optional(z.string().register(z.globalRegistry, { description: "Default value for the variable" })),
|
|
292
|
+
file_path: z.optional(z.string().register(z.globalRegistry, { description: "Specifies where to copy the file on each run. Set if `type` is `SSH_KEY`" })),
|
|
293
|
+
file_chmod: z.optional(z.string().register(z.globalRegistry, { description: "File permission set on copy to a container on each run. Set if `type` is `SSH_KEY`" })),
|
|
294
|
+
file_place: z.optional(z.enum(["NONE", "CONTAINER"]).register(z.globalRegistry, { description: "Set if `type` is `SSH_KEY`. If it's `NONE`, the variable can be used as a parameter in an action. For `CONTAINER`, the given key is additionally copied to an action container on each run" })),
|
|
295
|
+
password: z.optional(z.string().register(z.globalRegistry, { description: "Password for certificates" })),
|
|
296
|
+
passphrase: z.optional(z.string().register(z.globalRegistry, { description: "Passphrase for encrypted SSH keys" })),
|
|
297
|
+
key_identifier: z.optional(z.string().register(z.globalRegistry, { description: "GPG key identifier" })),
|
|
298
|
+
type: z.enum([
|
|
299
|
+
"VAR",
|
|
300
|
+
"FILE",
|
|
301
|
+
"SSH_KEY",
|
|
302
|
+
"IOS_KEYCHAIN",
|
|
303
|
+
"IOS_PROVISION_PROFILES",
|
|
304
|
+
"SSH_PUBLIC_KEY",
|
|
305
|
+
"GPG_KEY"
|
|
306
|
+
]).register(z.globalRegistry, { description: "The type of the added variable" })
|
|
307
|
+
}).register(z.globalRegistry, { description: "The environment variables of the sandbox" });
|
|
308
|
+
/**
|
|
309
|
+
* The TLS/SSL encryption settings of the tunnel
|
|
310
|
+
*/
|
|
311
|
+
const zTlsSettingsView = z.object({
|
|
312
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
313
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
314
|
+
terminate_at: z.optional(z.enum([
|
|
315
|
+
"REGION",
|
|
316
|
+
"AGENT",
|
|
317
|
+
"TARGET"
|
|
318
|
+
]).register(z.globalRegistry, { description: "Where to terminate TLS connection" }))
|
|
319
|
+
}).register(z.globalRegistry, { description: "The TLS/SSL encryption settings of the tunnel" });
|
|
320
|
+
/**
|
|
321
|
+
* The HTTP-specific settings of the tunnel
|
|
322
|
+
*/
|
|
323
|
+
const zHttpSettingsView = z.object({
|
|
324
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
325
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
326
|
+
verify_certificate: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether to verify SSL/TLS certificates" })),
|
|
327
|
+
compression: z.optional(z.boolean().register(z.globalRegistry, { description: "Enable HTTP compression" })),
|
|
328
|
+
http2: z.optional(z.boolean().register(z.globalRegistry, { description: "Enable HTTP/2 protocol support" })),
|
|
329
|
+
log_requests: z.optional(z.boolean().register(z.globalRegistry, { description: "Log incoming HTTP requests" })),
|
|
330
|
+
request_headers: z.optional(z.array(z.record(z.string(), z.string())).register(z.globalRegistry, { description: "Custom HTTP headers to add to requests" })),
|
|
331
|
+
whitelist_user_agents: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "List of allowed User-Agent strings" })),
|
|
332
|
+
rewrite_host_header: z.optional(z.string().register(z.globalRegistry, { description: "Rewrite the Host header to this value" })),
|
|
333
|
+
response_headers: z.optional(z.array(z.record(z.string(), z.string())).register(z.globalRegistry, { description: "Custom HTTP headers to add to responses" })),
|
|
334
|
+
login: z.optional(z.string().register(z.globalRegistry, { description: "Basic authentication username" })),
|
|
335
|
+
circuit_breaker: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Circuit breaker threshold (number of failed requests)" })),
|
|
336
|
+
serve_path: z.optional(z.string().register(z.globalRegistry, { description: "Base path for serving requests" })),
|
|
337
|
+
auth_type: z.optional(z.enum([
|
|
338
|
+
"NONE",
|
|
339
|
+
"BASIC",
|
|
340
|
+
"BUDDY"
|
|
341
|
+
]).register(z.globalRegistry, { description: "Type of authentication used" }))
|
|
342
|
+
}).register(z.globalRegistry, { description: "The HTTP-specific settings of the tunnel" });
|
|
343
|
+
const zTunnelView = z.object({
|
|
344
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
345
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
346
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the tunnel" }),
|
|
347
|
+
endpoint: z.string().register(z.globalRegistry, { description: "The endpoint URL of the tunnel" }),
|
|
348
|
+
type: z.enum([
|
|
349
|
+
"TCP",
|
|
350
|
+
"TLS",
|
|
351
|
+
"HTTP",
|
|
352
|
+
"SSH"
|
|
353
|
+
]).register(z.globalRegistry, { description: "The type of the tunnel" }),
|
|
354
|
+
region: z.enum([
|
|
355
|
+
"US",
|
|
356
|
+
"EU",
|
|
357
|
+
"AS"
|
|
358
|
+
]).register(z.globalRegistry, { description: "The region where the tunnel is deployed" }),
|
|
359
|
+
whitelist: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The IP addresses or domains allowed to access the tunnel" })),
|
|
360
|
+
timeout: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The connection timeout of the tunnel in seconds" })),
|
|
361
|
+
http: z.optional(zHttpSettingsView),
|
|
362
|
+
tls: z.optional(zTlsSettingsView),
|
|
363
|
+
endpoint_url: z.optional(z.string().register(z.globalRegistry, { description: "The url of the tunnel" }))
|
|
364
|
+
});
|
|
365
|
+
const zUpdateSandboxRequest = z.object({
|
|
366
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
367
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
368
|
+
resources: z.optional(z.enum([
|
|
369
|
+
"1x2",
|
|
370
|
+
"2x4",
|
|
371
|
+
"3x6",
|
|
372
|
+
"4x8",
|
|
373
|
+
"5x10",
|
|
374
|
+
"6x12",
|
|
375
|
+
"7x14",
|
|
376
|
+
"8x16",
|
|
377
|
+
"9x18",
|
|
378
|
+
"10x20",
|
|
379
|
+
"11x22",
|
|
380
|
+
"12x24",
|
|
381
|
+
"CUSTOM"
|
|
382
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
383
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
384
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
385
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
386
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
387
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
388
|
+
endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
389
|
+
variables: z.optional(z.array(zAddVariableInObjectRequest).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
390
|
+
});
|
|
391
|
+
const zSandboxesView = z.object({
|
|
392
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
393
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
394
|
+
sandboxes: z.optional(z.array(zSandboxIdView))
|
|
395
|
+
});
|
|
396
|
+
/**
|
|
397
|
+
* Content item in a sandbox
|
|
398
|
+
*/
|
|
399
|
+
const zSandboxContentItem = z.object({
|
|
400
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
401
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
402
|
+
type: z.optional(z.enum(["FILE", "DIR"]).register(z.globalRegistry, { description: "The content type (FILE or DIR)" })),
|
|
403
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the file or directory" })),
|
|
404
|
+
path: z.optional(z.string().register(z.globalRegistry, { description: "The path to the file or directory" })),
|
|
405
|
+
size: z.optional(z.coerce.bigint().min(BigInt("-9223372036854775808"), { error: "Invalid value: Expected int64 to be >= -9223372036854775808" }).max(BigInt("9223372036854775807"), { error: "Invalid value: Expected int64 to be <= 9223372036854775807" }).register(z.globalRegistry, { description: "The size of the file in bytes" }))
|
|
406
|
+
}).register(z.globalRegistry, { description: "Content item in a sandbox" });
|
|
407
|
+
/**
|
|
408
|
+
* Sandbox content listing
|
|
409
|
+
*/
|
|
410
|
+
const zSandboxContentView = z.object({
|
|
411
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
412
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
413
|
+
contents: z.optional(z.array(zSandboxContentItem).register(z.globalRegistry, { description: "List of content items in the directory" }))
|
|
414
|
+
}).register(z.globalRegistry, { description: "Sandbox content listing" });
|
|
415
|
+
const zSandboxCommandView = z.object({
|
|
416
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
417
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
418
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the command" })),
|
|
419
|
+
command: z.optional(z.string().register(z.globalRegistry, { description: "Command to execute in the sandbox" })),
|
|
420
|
+
runtime: z.optional(z.enum([
|
|
421
|
+
"BASH",
|
|
422
|
+
"JAVASCRIPT",
|
|
423
|
+
"TYPESCRIPT",
|
|
424
|
+
"PYTHON"
|
|
425
|
+
]).register(z.globalRegistry, { description: "Runtime environment for command execution (default: `BASH`)" })),
|
|
426
|
+
status: z.optional(z.enum([
|
|
427
|
+
"INPROGRESS",
|
|
428
|
+
"SUCCESSFUL",
|
|
429
|
+
"FAILED"
|
|
430
|
+
]).register(z.globalRegistry, { description: "Command execution status" })),
|
|
431
|
+
exit_code: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Command exit code" })),
|
|
432
|
+
logs_url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint URL to retrieve logs for this command" }))
|
|
433
|
+
});
|
|
434
|
+
const zSandboxCommandsView = z.object({
|
|
435
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
436
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
437
|
+
commands: z.optional(z.array(zSandboxCommandView))
|
|
438
|
+
});
|
|
439
|
+
const zSandboxCommandLog = z.object({
|
|
440
|
+
type: z.optional(z.enum(["STDOUT", "STDERR"]).register(z.globalRegistry, { description: "The type of command output stream" })),
|
|
441
|
+
data: z.optional(z.string().register(z.globalRegistry, { description: "The command execution logs." }))
|
|
442
|
+
});
|
|
443
|
+
const zSandboxAppLogsView = z.object({
|
|
444
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
445
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
446
|
+
cursor: z.optional(z.string().register(z.globalRegistry, { description: "Cursor for pagination" })),
|
|
447
|
+
logs: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "Application log entries" }))
|
|
448
|
+
});
|
|
449
|
+
const zShortSnapshotView = z.object({
|
|
450
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
451
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
452
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })),
|
|
453
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "Snapshot name" })),
|
|
454
|
+
size: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Snapshot size in GB" })),
|
|
455
|
+
status: z.optional(z.enum([
|
|
456
|
+
"CREATING",
|
|
457
|
+
"CREATED",
|
|
458
|
+
"DELETING",
|
|
459
|
+
"FAILED"
|
|
460
|
+
]).register(z.globalRegistry, { description: "Snapshot status" })),
|
|
461
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "Snapshot creation date" }))
|
|
462
|
+
});
|
|
463
|
+
const zSnapshotsView = z.object({
|
|
464
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
465
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
466
|
+
snapshots: z.optional(z.array(zShortSnapshotView).register(z.globalRegistry, { description: "Collection of snapshots" }))
|
|
467
|
+
});
|
|
468
|
+
const zExecuteSandboxCommandRequest = z.object({
|
|
469
|
+
command: z.string().register(z.globalRegistry, { description: "Command to execute in the sandbox" }),
|
|
470
|
+
runtime: z.optional(z.enum([
|
|
471
|
+
"BASH",
|
|
472
|
+
"JAVASCRIPT",
|
|
473
|
+
"TYPESCRIPT",
|
|
474
|
+
"PYTHON"
|
|
475
|
+
]).register(z.globalRegistry, { description: "Runtime environment for command execution (default: `BASH`)" }))
|
|
476
|
+
});
|
|
477
|
+
const zAddSnapshotRequest = z.object({ name: z.optional(z.string().register(z.globalRegistry, { description: "Snapshot name" })) });
|
|
478
|
+
const zSnapshotView = z.object({
|
|
479
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
480
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
481
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })),
|
|
482
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "Snapshot name" })),
|
|
483
|
+
size: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Snapshot size in GB" })),
|
|
484
|
+
status: z.optional(z.enum([
|
|
485
|
+
"CREATING",
|
|
486
|
+
"CREATED",
|
|
487
|
+
"DELETING",
|
|
488
|
+
"FAILED"
|
|
489
|
+
]).register(z.globalRegistry, { description: "Snapshot status" })),
|
|
490
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "Snapshot creation date" })),
|
|
491
|
+
created_by: z.optional(zMemberView)
|
|
492
|
+
});
|
|
493
|
+
const zSandboxYamlView = z.object({
|
|
494
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
495
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
496
|
+
yaml: z.optional(z.string().register(z.globalRegistry, { description: "The base64-encoded YAML configuration of the sandbox" }))
|
|
497
|
+
});
|
|
498
|
+
const zCreateNewSandboxRequest = z.object({
|
|
499
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the sandbox" }),
|
|
500
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
501
|
+
os: z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" }),
|
|
502
|
+
resources: z.optional(z.enum([
|
|
503
|
+
"1x2",
|
|
504
|
+
"2x4",
|
|
505
|
+
"3x6",
|
|
506
|
+
"4x8",
|
|
507
|
+
"5x10",
|
|
508
|
+
"6x12",
|
|
509
|
+
"7x14",
|
|
510
|
+
"8x16",
|
|
511
|
+
"9x18",
|
|
512
|
+
"10x20",
|
|
513
|
+
"11x22",
|
|
514
|
+
"12x24",
|
|
515
|
+
"CUSTOM"
|
|
516
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
517
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
518
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
519
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
520
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
521
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
522
|
+
endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
523
|
+
variables: z.optional(z.array(zAddVariableInObjectRequest).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
524
|
+
});
|
|
525
|
+
/**
|
|
526
|
+
* The list of variables you can use the action
|
|
527
|
+
*/
|
|
528
|
+
const zEnvironmentVariableView = z.object({
|
|
529
|
+
id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the variable" })),
|
|
530
|
+
key: z.optional(z.string().register(z.globalRegistry, { description: "The name of the variable" })),
|
|
531
|
+
value: z.optional(z.string().register(z.globalRegistry, { description: "The value of the variable" })),
|
|
532
|
+
type: z.optional(z.enum([
|
|
533
|
+
"VAR",
|
|
534
|
+
"FILE",
|
|
535
|
+
"SSH_KEY",
|
|
536
|
+
"IOS_KEYCHAIN",
|
|
537
|
+
"IOS_PROVISION_PROFILES",
|
|
538
|
+
"SSH_PUBLIC_KEY",
|
|
539
|
+
"GPG_KEY"
|
|
540
|
+
]).register(z.globalRegistry, { description: "The type of the added variable" })),
|
|
541
|
+
encrypted: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value will be encrypted and hidden" })),
|
|
542
|
+
settable: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value can be set by Buddy actions" })),
|
|
543
|
+
run_only_settable: z.optional(z.boolean().register(z.globalRegistry, { description: "Available only if `type=VAR`. If set to `true` the variable value can be set by Buddy actions only for execution time" })),
|
|
544
|
+
description: z.optional(z.string().register(z.globalRegistry, { description: "The optional description of the variable" })),
|
|
545
|
+
init_path: z.optional(z.string().register(z.globalRegistry, { description: "Initial path for the variable" })),
|
|
546
|
+
defaults: z.optional(z.string().register(z.globalRegistry, { description: "Default value for the variable" })),
|
|
547
|
+
file_path: z.optional(z.string().register(z.globalRegistry, { description: "Specifies where to copy the file on each run. Set if `type` is `SSH_KEY`" })),
|
|
548
|
+
file_chmod: z.optional(z.string().register(z.globalRegistry, { description: "File permission set on copy to a container on each run. Set if `type` is `SSH_KEY`" })),
|
|
549
|
+
file_place: z.optional(z.enum(["NONE", "CONTAINER"]).register(z.globalRegistry, { description: "Set if `type` is `SSH_KEY`. If it's `NONE`, the variable can be used as a parameter in an action. For `CONTAINER`, the given key is additionally copied to an action container on each run" })),
|
|
550
|
+
binary: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether the file is binary" })),
|
|
551
|
+
public_value: z.optional(z.string().register(z.globalRegistry, { description: "Public value for SSH key type variables" })),
|
|
552
|
+
key_fingerprint: z.optional(z.string().register(z.globalRegistry, { description: "Fingerprint of SSH key" })),
|
|
553
|
+
checksum: z.optional(z.string().register(z.globalRegistry, { description: "Checksum of the variable value" })),
|
|
554
|
+
password: z.optional(z.string().register(z.globalRegistry, { description: "Password for certificates" })),
|
|
555
|
+
passphrase: z.optional(z.string().register(z.globalRegistry, { description: "Passphrase for encrypted SSH keys" })),
|
|
556
|
+
key_identifier: z.optional(z.string().register(z.globalRegistry, { description: "GPG key identifier" }))
|
|
557
|
+
}).register(z.globalRegistry, { description: "The list of variables you can use the action" });
|
|
558
|
+
const zCreateFromSnapshotRequest = z.object({
|
|
559
|
+
snapshot_id: z.string().register(z.globalRegistry, { description: "The ID of the snapshot to create from" }),
|
|
560
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the sandbox" }),
|
|
561
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
562
|
+
os: z.optional(z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" })),
|
|
563
|
+
resources: z.optional(z.enum([
|
|
564
|
+
"1x2",
|
|
565
|
+
"2x4",
|
|
566
|
+
"3x6",
|
|
567
|
+
"4x8",
|
|
568
|
+
"5x10",
|
|
569
|
+
"6x12",
|
|
570
|
+
"7x14",
|
|
571
|
+
"8x16",
|
|
572
|
+
"9x18",
|
|
573
|
+
"10x20",
|
|
574
|
+
"11x22",
|
|
575
|
+
"12x24",
|
|
576
|
+
"CUSTOM"
|
|
577
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
578
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
579
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
580
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
581
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
582
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
583
|
+
endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
584
|
+
variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
585
|
+
});
|
|
586
|
+
const zCloneSandboxRequest = z.object({
|
|
587
|
+
source_sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox to clone" }),
|
|
588
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the sandbox" }),
|
|
589
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." }))
|
|
590
|
+
});
|
|
591
|
+
const zSandboxResponse = z.object({
|
|
592
|
+
url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint to GET this object" }).readonly()),
|
|
593
|
+
html_url: z.optional(z.string().register(z.globalRegistry, { description: "Web URL to view this object in Buddy.works" }).readonly()),
|
|
594
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })),
|
|
595
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
596
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
597
|
+
status: z.optional(z.enum([
|
|
598
|
+
"STARTING",
|
|
599
|
+
"STOPPING",
|
|
600
|
+
"FAILED",
|
|
601
|
+
"RUNNING",
|
|
602
|
+
"STOPPED",
|
|
603
|
+
"RESTORING"
|
|
604
|
+
]).register(z.globalRegistry, { description: "The current status of the sandbox" })),
|
|
605
|
+
os: z.optional(z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" })),
|
|
606
|
+
resources: z.optional(z.enum([
|
|
607
|
+
"1x2",
|
|
608
|
+
"2x4",
|
|
609
|
+
"3x6",
|
|
610
|
+
"4x8",
|
|
611
|
+
"5x10",
|
|
612
|
+
"6x12",
|
|
613
|
+
"7x14",
|
|
614
|
+
"8x16",
|
|
615
|
+
"9x18",
|
|
616
|
+
"10x20",
|
|
617
|
+
"11x22",
|
|
618
|
+
"12x24",
|
|
619
|
+
"CUSTOM"
|
|
620
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
621
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
622
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
623
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
624
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
625
|
+
tags: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
626
|
+
app_status: z.optional(z.enum([
|
|
627
|
+
"NONE",
|
|
628
|
+
"RUNNING",
|
|
629
|
+
"ENDED",
|
|
630
|
+
"FAILED"
|
|
631
|
+
]).register(z.globalRegistry, { description: "The current application status of the sandbox" })),
|
|
632
|
+
boot_logs: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The boot logs of the sandbox" })),
|
|
633
|
+
setup_status: z.optional(z.enum([
|
|
634
|
+
"INPROGRESS",
|
|
635
|
+
"SUCCESS",
|
|
636
|
+
"FAILED"
|
|
637
|
+
]).register(z.globalRegistry, { description: "The current setup status of the sandbox" })),
|
|
638
|
+
endpoints: z.optional(z.array(zTunnelView).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
639
|
+
project: z.optional(zProjectView),
|
|
640
|
+
variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
641
|
+
});
|
|
642
|
+
/**
|
|
643
|
+
* Sandbox reference
|
|
644
|
+
*/
|
|
645
|
+
const zSandboxIdViewWritable = z.object({
|
|
646
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })),
|
|
647
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
648
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
649
|
+
status: z.optional(z.enum([
|
|
650
|
+
"STARTING",
|
|
651
|
+
"STOPPING",
|
|
652
|
+
"FAILED",
|
|
653
|
+
"RUNNING",
|
|
654
|
+
"STOPPED",
|
|
655
|
+
"RESTORING"
|
|
656
|
+
]).register(z.globalRegistry, { description: "The current status of the sandbox" }))
|
|
657
|
+
}).register(z.globalRegistry, { description: "Sandbox reference" });
|
|
658
|
+
/**
|
|
659
|
+
* Integration reference
|
|
660
|
+
*/
|
|
661
|
+
const zIntegrationIdViewWritable = z.object({
|
|
662
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID of the integration" })),
|
|
663
|
+
hash_id: z.optional(z.string().register(z.globalRegistry, { description: "The unique hash ID of the integration" })),
|
|
664
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the integration" })),
|
|
665
|
+
type: z.optional(z.enum([
|
|
666
|
+
"GIT_HUB",
|
|
667
|
+
"BITBUCKET",
|
|
668
|
+
"GOOGLE",
|
|
669
|
+
"DIGITAL_OCEAN",
|
|
670
|
+
"SLACK",
|
|
671
|
+
"MODULUS",
|
|
672
|
+
"HEROKU",
|
|
673
|
+
"AMAZON",
|
|
674
|
+
"GIT_LAB",
|
|
675
|
+
"SHOPIFY",
|
|
676
|
+
"GIT_HUB_ENTERPRISE",
|
|
677
|
+
"GIT_LAB_ENTERPRISE",
|
|
678
|
+
"PUSHOVER",
|
|
679
|
+
"PUSHBULLET",
|
|
680
|
+
"RACKSPACE",
|
|
681
|
+
"CUSTOM",
|
|
682
|
+
"CLOUDFLARE",
|
|
683
|
+
"NEW_RELIC",
|
|
684
|
+
"SENTRY",
|
|
685
|
+
"ROLLBAR",
|
|
686
|
+
"DATADOG",
|
|
687
|
+
"DO_SPACES",
|
|
688
|
+
"HONEYBADGER",
|
|
689
|
+
"VULTR",
|
|
690
|
+
"SENTRY_ENTERPRISE",
|
|
691
|
+
"LOGGLY",
|
|
692
|
+
"HIP_CHAT",
|
|
693
|
+
"FIREBASE",
|
|
694
|
+
"TELEGRAM",
|
|
695
|
+
"AZURE",
|
|
696
|
+
"UPCLOUD",
|
|
697
|
+
"GHOST_INSPECTOR",
|
|
698
|
+
"NETLIFY",
|
|
699
|
+
"AZURE_CLOUD",
|
|
700
|
+
"MICROSOFT_TEAMS",
|
|
701
|
+
"GOOGLE_SERVICE_ACCOUNT",
|
|
702
|
+
"GOOGLE_PLAY_STORE",
|
|
703
|
+
"DOCKER_HUB",
|
|
704
|
+
"APP_STORE",
|
|
705
|
+
"GIT_HUB_APP",
|
|
706
|
+
"GIT_HUB_APP_ENTERPRISE",
|
|
707
|
+
"GIT_HUB_API",
|
|
708
|
+
"ATOP",
|
|
709
|
+
"SNYK",
|
|
710
|
+
"STACK_HAWK",
|
|
711
|
+
"BLACKFIRE",
|
|
712
|
+
"BACKBLAZE",
|
|
713
|
+
"ONE_LOGIN",
|
|
714
|
+
"OKTA",
|
|
715
|
+
"CONTENTFUL"
|
|
716
|
+
]).register(z.globalRegistry, { description: "The type of integration" })),
|
|
717
|
+
auth_type: z.optional(z.enum([
|
|
718
|
+
"OAUTH",
|
|
719
|
+
"TOKEN",
|
|
720
|
+
"API_KEY",
|
|
721
|
+
"APP",
|
|
722
|
+
"APP_SPRYKER",
|
|
723
|
+
"TOKEN_APP_EXTENSION",
|
|
724
|
+
"DEFAULT",
|
|
725
|
+
"OIDC",
|
|
726
|
+
"TRUSTED",
|
|
727
|
+
"APP_RW"
|
|
728
|
+
]).register(z.globalRegistry, { description: "The authentication method used by the integration" })),
|
|
729
|
+
host_url: z.optional(z.string().register(z.globalRegistry, { description: "The host URL for custom integrations" })),
|
|
730
|
+
webhook_address: z.optional(z.string().register(z.globalRegistry, { description: "The webhook URL for receiving notifications" })),
|
|
731
|
+
atop_url: z.optional(z.string().register(z.globalRegistry, { description: "The ATOP service URL" })),
|
|
732
|
+
app_id: z.optional(z.string().register(z.globalRegistry, { description: "The application ID for Azure Cloud integrations" })),
|
|
733
|
+
google_project: z.optional(z.string().register(z.globalRegistry, { description: "The Google Cloud project ID" })),
|
|
734
|
+
audience: z.optional(z.string().register(z.globalRegistry, { description: "The JWT audience for token validation" }))
|
|
735
|
+
}).register(z.globalRegistry, { description: "Integration reference" });
|
|
736
|
+
/**
|
|
737
|
+
* User/member reference
|
|
738
|
+
*/
|
|
739
|
+
const zMemberViewWritable = z.object({
|
|
740
|
+
id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the user" })),
|
|
741
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the user" })),
|
|
742
|
+
avatar_url: z.optional(z.string().register(z.globalRegistry, { description: "The avatar URL of the user" })),
|
|
743
|
+
email: z.optional(z.string().register(z.globalRegistry, { description: "The email address of the user" })),
|
|
744
|
+
admin: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether the user has admin privileges" })),
|
|
745
|
+
workspace_owner: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether the user is workspace owner" }))
|
|
746
|
+
}).register(z.globalRegistry, { description: "User/member reference" });
|
|
747
|
+
const zProjectViewWritable = z.object({
|
|
748
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The human-readable ID of the project" })),
|
|
749
|
+
display_name: z.string().register(z.globalRegistry, { description: "The Name of the project" }),
|
|
750
|
+
status: z.optional(z.string().register(z.globalRegistry, { description: "The status of the project" })),
|
|
751
|
+
access: z.optional(z.enum(["PRIVATE", "PUBLIC"]).register(z.globalRegistry, { description: "Indicates if this is a public project" })),
|
|
752
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "The creation date of the project" })),
|
|
753
|
+
external_project_id: z.optional(z.string().register(z.globalRegistry, { description: "Repo slug of the Bitbucket, GitHub or GitLab project. Required when adding the integrated project" })),
|
|
754
|
+
git_lab_project_id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "ID of the project in GitLab" })),
|
|
755
|
+
custom_repo_url: z.optional(z.string().register(z.globalRegistry, { description: "SSH or HTTPS url of the git repository. Required when adding the project integrated with custom git repository" })),
|
|
756
|
+
custom_repo_user: z.optional(z.string().register(z.globalRegistry, { description: "Username used to authorize access to the git repository. Required when adding the project integrated with custom git repository" })),
|
|
757
|
+
custom_repo_pass: z.optional(z.string().register(z.globalRegistry, { description: "Password used to authorize access to the git repository. Required when adding the project integrated with custom git repository and the provided `custom_repo_url` is the HTTPS url" })),
|
|
758
|
+
custom_repo_ssh_key_id: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The ID of the private SSH key used to authorize access to the git repository. Required when adding the project integrated with private git server by SSH url" })),
|
|
759
|
+
created_by: z.optional(zMemberViewWritable),
|
|
760
|
+
http_repository: z.optional(z.string().register(z.globalRegistry, { description: "The HTTP repository URL" })),
|
|
761
|
+
ssh_repository: z.optional(z.string().register(z.globalRegistry, { description: "The SSH repository URL" })),
|
|
762
|
+
default_branch: z.optional(z.string().register(z.globalRegistry, { description: "The default branch name" })),
|
|
763
|
+
integration: z.optional(zIntegrationIdViewWritable),
|
|
764
|
+
fetch_submodules: z.optional(z.boolean().register(z.globalRegistry, { description: "Defines whether the submodules are fetched during the runs in this project" })),
|
|
765
|
+
fetch_submodules_env_key: z.optional(z.string().register(z.globalRegistry, { description: "Name of the key that will be used to authorize while fetching the submodules. Required when `fetch_submodules` is set to `true`" })),
|
|
766
|
+
allow_pull_requests: z.optional(z.boolean().register(z.globalRegistry, { description: "Enables/disables pull requests in the project. Available only for projects synchronized with GitHub or GitHub Enterprise repository" })),
|
|
767
|
+
update_default_branch_from_external: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to true, the default branch will be updated from GitHub/GitLab/Bitbucket." })),
|
|
768
|
+
without_repository: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to true, the project is created without any repository attached." }))
|
|
769
|
+
});
|
|
770
|
+
/**
|
|
771
|
+
* The environment variables of the sandbox
|
|
772
|
+
*/
|
|
773
|
+
const zAddVariableInObjectRequestWritable = z.object({
|
|
774
|
+
key: z.string().register(z.globalRegistry, { description: "The name of the variable" }),
|
|
775
|
+
value: z.optional(z.string().register(z.globalRegistry, { description: "The value of the variable" })),
|
|
776
|
+
settable: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value can be set by Buddy actions" })),
|
|
777
|
+
run_only_settable: z.optional(z.boolean().register(z.globalRegistry, { description: "Available only if `type=VAR`. If set to `true` the variable value can be set by Buddy actions only for execution time" })),
|
|
778
|
+
encrypted: z.optional(z.boolean().register(z.globalRegistry, { description: "If set to `true` the variable value will be encrypted and hidden" })),
|
|
779
|
+
description: z.optional(z.string().register(z.globalRegistry, { description: "The optional description of the variable" })),
|
|
780
|
+
init_path: z.optional(z.string().register(z.globalRegistry, { description: "Initial path for the variable" })),
|
|
781
|
+
defaults: z.optional(z.string().register(z.globalRegistry, { description: "Default value for the variable" })),
|
|
782
|
+
file_path: z.optional(z.string().register(z.globalRegistry, { description: "Specifies where to copy the file on each run. Set if `type` is `SSH_KEY`" })),
|
|
783
|
+
file_chmod: z.optional(z.string().register(z.globalRegistry, { description: "File permission set on copy to a container on each run. Set if `type` is `SSH_KEY`" })),
|
|
784
|
+
file_place: z.optional(z.enum(["NONE", "CONTAINER"]).register(z.globalRegistry, { description: "Set if `type` is `SSH_KEY`. If it's `NONE`, the variable can be used as a parameter in an action. For `CONTAINER`, the given key is additionally copied to an action container on each run" })),
|
|
785
|
+
password: z.optional(z.string().register(z.globalRegistry, { description: "Password for certificates" })),
|
|
786
|
+
passphrase: z.optional(z.string().register(z.globalRegistry, { description: "Passphrase for encrypted SSH keys" })),
|
|
787
|
+
key_identifier: z.optional(z.string().register(z.globalRegistry, { description: "GPG key identifier" })),
|
|
788
|
+
type: z.enum([
|
|
789
|
+
"VAR",
|
|
790
|
+
"FILE",
|
|
791
|
+
"SSH_KEY",
|
|
792
|
+
"IOS_KEYCHAIN",
|
|
793
|
+
"IOS_PROVISION_PROFILES",
|
|
794
|
+
"SSH_PUBLIC_KEY",
|
|
795
|
+
"GPG_KEY"
|
|
796
|
+
]).register(z.globalRegistry, { description: "The type of the added variable" })
|
|
797
|
+
}).register(z.globalRegistry, { description: "The environment variables of the sandbox" });
|
|
798
|
+
/**
|
|
799
|
+
* The TLS/SSL encryption settings of the tunnel
|
|
800
|
+
*/
|
|
801
|
+
const zTlsSettingsViewWritable = z.object({
|
|
802
|
+
private_key: z.optional(z.string().register(z.globalRegistry, { description: "Private key for TLS certificate" })),
|
|
803
|
+
certificate: z.optional(z.string().register(z.globalRegistry, { description: "TLS certificate" })),
|
|
804
|
+
ca_certificate: z.optional(z.string().register(z.globalRegistry, { description: "Certificate Authority certificate" })),
|
|
805
|
+
terminate_at: z.optional(z.enum([
|
|
806
|
+
"REGION",
|
|
807
|
+
"AGENT",
|
|
808
|
+
"TARGET"
|
|
809
|
+
]).register(z.globalRegistry, { description: "Where to terminate TLS connection" }))
|
|
810
|
+
}).register(z.globalRegistry, { description: "The TLS/SSL encryption settings of the tunnel" });
|
|
811
|
+
/**
|
|
812
|
+
* The HTTP-specific settings of the tunnel
|
|
813
|
+
*/
|
|
814
|
+
const zHttpSettingsViewWritable = z.object({
|
|
815
|
+
verify_certificate: z.optional(z.boolean().register(z.globalRegistry, { description: "Whether to verify SSL/TLS certificates" })),
|
|
816
|
+
compression: z.optional(z.boolean().register(z.globalRegistry, { description: "Enable HTTP compression" })),
|
|
817
|
+
http2: z.optional(z.boolean().register(z.globalRegistry, { description: "Enable HTTP/2 protocol support" })),
|
|
818
|
+
log_requests: z.optional(z.boolean().register(z.globalRegistry, { description: "Log incoming HTTP requests" })),
|
|
819
|
+
request_headers: z.optional(z.array(z.record(z.string(), z.string())).register(z.globalRegistry, { description: "Custom HTTP headers to add to requests" })),
|
|
820
|
+
whitelist_user_agents: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "List of allowed User-Agent strings" })),
|
|
821
|
+
rewrite_host_header: z.optional(z.string().register(z.globalRegistry, { description: "Rewrite the Host header to this value" })),
|
|
822
|
+
response_headers: z.optional(z.array(z.record(z.string(), z.string())).register(z.globalRegistry, { description: "Custom HTTP headers to add to responses" })),
|
|
823
|
+
login: z.optional(z.string().register(z.globalRegistry, { description: "Basic authentication username" })),
|
|
824
|
+
password: z.optional(z.string().register(z.globalRegistry, { description: "Basic authentication password" })),
|
|
825
|
+
tls_ca: z.optional(z.string().register(z.globalRegistry, { description: "Custom TLS Certificate Authority" })),
|
|
826
|
+
circuit_breaker: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Circuit breaker threshold (number of failed requests)" })),
|
|
827
|
+
serve_path: z.optional(z.string().register(z.globalRegistry, { description: "Base path for serving requests" })),
|
|
828
|
+
auth_type: z.optional(z.enum([
|
|
829
|
+
"NONE",
|
|
830
|
+
"BASIC",
|
|
831
|
+
"BUDDY"
|
|
832
|
+
]).register(z.globalRegistry, { description: "Type of authentication used" }))
|
|
833
|
+
}).register(z.globalRegistry, { description: "The HTTP-specific settings of the tunnel" });
|
|
834
|
+
const zTunnelViewWritable = z.object({
|
|
835
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the tunnel" }),
|
|
836
|
+
endpoint: z.string().register(z.globalRegistry, { description: "The endpoint URL of the tunnel" }),
|
|
837
|
+
type: z.enum([
|
|
838
|
+
"TCP",
|
|
839
|
+
"TLS",
|
|
840
|
+
"HTTP",
|
|
841
|
+
"SSH"
|
|
842
|
+
]).register(z.globalRegistry, { description: "The type of the tunnel" }),
|
|
843
|
+
region: z.enum([
|
|
844
|
+
"US",
|
|
845
|
+
"EU",
|
|
846
|
+
"AS"
|
|
847
|
+
]).register(z.globalRegistry, { description: "The region where the tunnel is deployed" }),
|
|
848
|
+
whitelist: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The IP addresses or domains allowed to access the tunnel" })),
|
|
849
|
+
timeout: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "The connection timeout of the tunnel in seconds" })),
|
|
850
|
+
http: z.optional(zHttpSettingsViewWritable),
|
|
851
|
+
tls: z.optional(zTlsSettingsViewWritable),
|
|
852
|
+
endpoint_url: z.optional(z.string().register(z.globalRegistry, { description: "The url of the tunnel" }))
|
|
853
|
+
});
|
|
854
|
+
const zUpdateSandboxRequestWritable = z.object({
|
|
855
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
856
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
857
|
+
resources: z.optional(z.enum([
|
|
858
|
+
"1x2",
|
|
859
|
+
"2x4",
|
|
860
|
+
"3x6",
|
|
861
|
+
"4x8",
|
|
862
|
+
"5x10",
|
|
863
|
+
"6x12",
|
|
864
|
+
"7x14",
|
|
865
|
+
"8x16",
|
|
866
|
+
"9x18",
|
|
867
|
+
"10x20",
|
|
868
|
+
"11x22",
|
|
869
|
+
"12x24",
|
|
870
|
+
"CUSTOM"
|
|
871
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
872
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
873
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
874
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
875
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
876
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
877
|
+
endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
878
|
+
variables: z.optional(z.array(zAddVariableInObjectRequestWritable).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
879
|
+
});
|
|
880
|
+
const zSandboxesViewWritable = z.object({ sandboxes: z.optional(z.array(zSandboxIdViewWritable)) });
|
|
881
|
+
/**
|
|
882
|
+
* Content item in a sandbox
|
|
883
|
+
*/
|
|
884
|
+
const zSandboxContentItemWritable = z.object({
|
|
885
|
+
type: z.optional(z.enum(["FILE", "DIR"]).register(z.globalRegistry, { description: "The content type (FILE or DIR)" })),
|
|
886
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the file or directory" })),
|
|
887
|
+
path: z.optional(z.string().register(z.globalRegistry, { description: "The path to the file or directory" })),
|
|
888
|
+
size: z.optional(z.coerce.bigint().min(BigInt("-9223372036854775808"), { error: "Invalid value: Expected int64 to be >= -9223372036854775808" }).max(BigInt("9223372036854775807"), { error: "Invalid value: Expected int64 to be <= 9223372036854775807" }).register(z.globalRegistry, { description: "The size of the file in bytes" }))
|
|
889
|
+
}).register(z.globalRegistry, { description: "Content item in a sandbox" });
|
|
890
|
+
/**
|
|
891
|
+
* Sandbox content listing
|
|
892
|
+
*/
|
|
893
|
+
const zSandboxContentViewWritable = z.object({ contents: z.optional(z.array(zSandboxContentItemWritable).register(z.globalRegistry, { description: "List of content items in the directory" })) }).register(z.globalRegistry, { description: "Sandbox content listing" });
|
|
894
|
+
const zSandboxCommandViewWritable = z.object({
|
|
895
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the command" })),
|
|
896
|
+
command: z.optional(z.string().register(z.globalRegistry, { description: "Command to execute in the sandbox" })),
|
|
897
|
+
runtime: z.optional(z.enum([
|
|
898
|
+
"BASH",
|
|
899
|
+
"JAVASCRIPT",
|
|
900
|
+
"TYPESCRIPT",
|
|
901
|
+
"PYTHON"
|
|
902
|
+
]).register(z.globalRegistry, { description: "Runtime environment for command execution (default: `BASH`)" })),
|
|
903
|
+
status: z.optional(z.enum([
|
|
904
|
+
"INPROGRESS",
|
|
905
|
+
"SUCCESSFUL",
|
|
906
|
+
"FAILED"
|
|
907
|
+
]).register(z.globalRegistry, { description: "Command execution status" })),
|
|
908
|
+
exit_code: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Command exit code" })),
|
|
909
|
+
logs_url: z.optional(z.string().register(z.globalRegistry, { description: "API endpoint URL to retrieve logs for this command" }))
|
|
910
|
+
});
|
|
911
|
+
const zSandboxCommandsViewWritable = z.object({ commands: z.optional(z.array(zSandboxCommandViewWritable)) });
|
|
912
|
+
const zSandboxAppLogsViewWritable = z.object({
|
|
913
|
+
cursor: z.optional(z.string().register(z.globalRegistry, { description: "Cursor for pagination" })),
|
|
914
|
+
logs: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "Application log entries" }))
|
|
915
|
+
});
|
|
916
|
+
const zShortSnapshotViewWritable = z.object({
|
|
917
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })),
|
|
918
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "Snapshot name" })),
|
|
919
|
+
size: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Snapshot size in GB" })),
|
|
920
|
+
status: z.optional(z.enum([
|
|
921
|
+
"CREATING",
|
|
922
|
+
"CREATED",
|
|
923
|
+
"DELETING",
|
|
924
|
+
"FAILED"
|
|
925
|
+
]).register(z.globalRegistry, { description: "Snapshot status" })),
|
|
926
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "Snapshot creation date" }))
|
|
927
|
+
});
|
|
928
|
+
const zSnapshotsViewWritable = z.object({ snapshots: z.optional(z.array(zShortSnapshotViewWritable).register(z.globalRegistry, { description: "Collection of snapshots" })) });
|
|
929
|
+
const zSnapshotViewWritable = z.object({
|
|
930
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })),
|
|
931
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "Snapshot name" })),
|
|
932
|
+
size: z.optional(z.int().min(-2147483648, { error: "Invalid value: Expected int32 to be >= -2147483648" }).max(2147483647, { error: "Invalid value: Expected int32 to be <= 2147483647" }).register(z.globalRegistry, { description: "Snapshot size in GB" })),
|
|
933
|
+
status: z.optional(z.enum([
|
|
934
|
+
"CREATING",
|
|
935
|
+
"CREATED",
|
|
936
|
+
"DELETING",
|
|
937
|
+
"FAILED"
|
|
938
|
+
]).register(z.globalRegistry, { description: "Snapshot status" })),
|
|
939
|
+
create_date: z.optional(z.iso.datetime().register(z.globalRegistry, { description: "Snapshot creation date" })),
|
|
940
|
+
created_by: z.optional(zMemberViewWritable)
|
|
941
|
+
});
|
|
942
|
+
const zSandboxYamlViewWritable = z.object({ yaml: z.optional(z.string().register(z.globalRegistry, { description: "The base64-encoded YAML configuration of the sandbox" })) });
|
|
943
|
+
const zCreateNewSandboxRequestWritable = z.object({
|
|
944
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the sandbox" }),
|
|
945
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
946
|
+
os: z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" }),
|
|
947
|
+
resources: z.optional(z.enum([
|
|
948
|
+
"1x2",
|
|
949
|
+
"2x4",
|
|
950
|
+
"3x6",
|
|
951
|
+
"4x8",
|
|
952
|
+
"5x10",
|
|
953
|
+
"6x12",
|
|
954
|
+
"7x14",
|
|
955
|
+
"8x16",
|
|
956
|
+
"9x18",
|
|
957
|
+
"10x20",
|
|
958
|
+
"11x22",
|
|
959
|
+
"12x24",
|
|
960
|
+
"CUSTOM"
|
|
961
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
962
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
963
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
964
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
965
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
966
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
967
|
+
endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
968
|
+
variables: z.optional(z.array(zAddVariableInObjectRequestWritable).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
969
|
+
});
|
|
970
|
+
const zCreateFromSnapshotRequestWritable = z.object({
|
|
971
|
+
snapshot_id: z.string().register(z.globalRegistry, { description: "The ID of the snapshot to create from" }),
|
|
972
|
+
name: z.string().register(z.globalRegistry, { description: "The name of the sandbox" }),
|
|
973
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
974
|
+
os: z.optional(z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" })),
|
|
975
|
+
resources: z.optional(z.enum([
|
|
976
|
+
"1x2",
|
|
977
|
+
"2x4",
|
|
978
|
+
"3x6",
|
|
979
|
+
"4x8",
|
|
980
|
+
"5x10",
|
|
981
|
+
"6x12",
|
|
982
|
+
"7x14",
|
|
983
|
+
"8x16",
|
|
984
|
+
"9x18",
|
|
985
|
+
"10x20",
|
|
986
|
+
"11x22",
|
|
987
|
+
"12x24",
|
|
988
|
+
"CUSTOM"
|
|
989
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
990
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
991
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
992
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
993
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
994
|
+
tags: z.optional(z.array(z.string().register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
995
|
+
endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
996
|
+
variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
997
|
+
});
|
|
998
|
+
const zSandboxResponseWritable = z.object({
|
|
999
|
+
id: z.optional(z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })),
|
|
1000
|
+
identifier: z.optional(z.string().register(z.globalRegistry, { description: "A human-readable ID. Alphanumeric characters, underscores, and hyphens (hyphens cannot appear at the start or end)." })),
|
|
1001
|
+
name: z.optional(z.string().register(z.globalRegistry, { description: "The name of the sandbox" })),
|
|
1002
|
+
status: z.optional(z.enum([
|
|
1003
|
+
"STARTING",
|
|
1004
|
+
"STOPPING",
|
|
1005
|
+
"FAILED",
|
|
1006
|
+
"RUNNING",
|
|
1007
|
+
"STOPPED",
|
|
1008
|
+
"RESTORING"
|
|
1009
|
+
]).register(z.globalRegistry, { description: "The current status of the sandbox" })),
|
|
1010
|
+
os: z.optional(z.string().register(z.globalRegistry, { description: "The operating system of the sandbox [\"ubuntu:22.04\", \"ubuntu:24.04\"]" })),
|
|
1011
|
+
resources: z.optional(z.enum([
|
|
1012
|
+
"1x2",
|
|
1013
|
+
"2x4",
|
|
1014
|
+
"3x6",
|
|
1015
|
+
"4x8",
|
|
1016
|
+
"5x10",
|
|
1017
|
+
"6x12",
|
|
1018
|
+
"7x14",
|
|
1019
|
+
"8x16",
|
|
1020
|
+
"9x18",
|
|
1021
|
+
"10x20",
|
|
1022
|
+
"11x22",
|
|
1023
|
+
"12x24",
|
|
1024
|
+
"CUSTOM"
|
|
1025
|
+
]).register(z.globalRegistry, { description: "The resource configuration of the sandbox (CPU x RAM)" })),
|
|
1026
|
+
install_commands: z.optional(z.string().register(z.globalRegistry, { description: "The commands to run during setup of the sandbox" })),
|
|
1027
|
+
run_command: z.optional(z.string().register(z.globalRegistry, { description: "The run command of the sandbox" })),
|
|
1028
|
+
app_dir: z.optional(z.string().register(z.globalRegistry, { description: "The application directory of the sandbox" })),
|
|
1029
|
+
app_type: z.optional(z.enum(["CMD", "SERVICE"]).register(z.globalRegistry, { description: "The application type of the sandbox (passed command or existent service eg. apache2)" })),
|
|
1030
|
+
tags: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The list of tags associated with the sandbox" })),
|
|
1031
|
+
app_status: z.optional(z.enum([
|
|
1032
|
+
"NONE",
|
|
1033
|
+
"RUNNING",
|
|
1034
|
+
"ENDED",
|
|
1035
|
+
"FAILED"
|
|
1036
|
+
]).register(z.globalRegistry, { description: "The current application status of the sandbox" })),
|
|
1037
|
+
boot_logs: z.optional(z.array(z.string()).register(z.globalRegistry, { description: "The boot logs of the sandbox" })),
|
|
1038
|
+
setup_status: z.optional(z.enum([
|
|
1039
|
+
"INPROGRESS",
|
|
1040
|
+
"SUCCESS",
|
|
1041
|
+
"FAILED"
|
|
1042
|
+
]).register(z.globalRegistry, { description: "The current setup status of the sandbox" })),
|
|
1043
|
+
endpoints: z.optional(z.array(zTunnelViewWritable).register(z.globalRegistry, { description: "The tunnel endpoints of the sandbox" })),
|
|
1044
|
+
project: z.optional(zProjectViewWritable),
|
|
1045
|
+
variables: z.optional(z.array(zEnvironmentVariableView).register(z.globalRegistry, { description: "The environment variables of the sandbox" }))
|
|
1046
|
+
});
|
|
1047
|
+
const zGetSandboxesData = z.object({
|
|
1048
|
+
body: z.optional(z.never()),
|
|
1049
|
+
path: z.object({ workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }) }),
|
|
1050
|
+
query: z.object({ project_name: z.string().register(z.globalRegistry, { description: "The human-readable ID of the project to filter sandboxes" }) })
|
|
1051
|
+
});
|
|
1052
|
+
const zGetSandboxesResponse = zSandboxesView;
|
|
1053
|
+
const zAddSandboxData = z.object({
|
|
1054
|
+
body: z.optional(z.union([
|
|
1055
|
+
zCloneSandboxRequest,
|
|
1056
|
+
zCreateFromSnapshotRequestWritable,
|
|
1057
|
+
zCreateNewSandboxRequestWritable
|
|
1058
|
+
])),
|
|
1059
|
+
path: z.object({ workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }) }),
|
|
1060
|
+
query: z.object({ project_name: z.string().register(z.globalRegistry, { description: "The human-readable ID of the project to filter sandboxes" }) })
|
|
1061
|
+
});
|
|
1062
|
+
const zAddSandboxResponse = zSandboxResponse;
|
|
1063
|
+
const zDeleteSandboxData = z.object({
|
|
1064
|
+
body: z.optional(z.never()),
|
|
1065
|
+
path: z.object({
|
|
1066
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1067
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1068
|
+
}),
|
|
1069
|
+
query: z.optional(z.never())
|
|
1070
|
+
});
|
|
1071
|
+
/**
|
|
1072
|
+
* Sandbox deleted successfully
|
|
1073
|
+
*/
|
|
1074
|
+
const zDeleteSandboxResponse = z.void().register(z.globalRegistry, { description: "Sandbox deleted successfully" });
|
|
1075
|
+
const zGetSandboxData = z.object({
|
|
1076
|
+
body: z.optional(z.never()),
|
|
1077
|
+
path: z.object({
|
|
1078
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1079
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1080
|
+
}),
|
|
1081
|
+
query: z.optional(z.never())
|
|
1082
|
+
});
|
|
1083
|
+
const zGetSandboxResponse = zSandboxResponse;
|
|
1084
|
+
const zUpdateSandboxData = z.object({
|
|
1085
|
+
body: z.optional(zUpdateSandboxRequestWritable),
|
|
1086
|
+
path: z.object({
|
|
1087
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1088
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1089
|
+
}),
|
|
1090
|
+
query: z.optional(z.never())
|
|
1091
|
+
});
|
|
1092
|
+
const zGetSandboxAppLogsData = z.object({
|
|
1093
|
+
body: z.optional(z.never()),
|
|
1094
|
+
path: z.object({
|
|
1095
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1096
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1097
|
+
}),
|
|
1098
|
+
query: z.optional(z.object({ cursor: z.optional(z.string().register(z.globalRegistry, { description: "Cursor for pagination" })) }))
|
|
1099
|
+
});
|
|
1100
|
+
const zGetSandboxCommandsData = z.object({
|
|
1101
|
+
body: z.optional(z.never()),
|
|
1102
|
+
path: z.object({
|
|
1103
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1104
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1105
|
+
}),
|
|
1106
|
+
query: z.optional(z.never())
|
|
1107
|
+
});
|
|
1108
|
+
const zExecuteSandboxCommandData = z.object({
|
|
1109
|
+
body: z.optional(zExecuteSandboxCommandRequest),
|
|
1110
|
+
path: z.object({
|
|
1111
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1112
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1113
|
+
}),
|
|
1114
|
+
query: z.optional(z.never())
|
|
1115
|
+
});
|
|
1116
|
+
const zExecuteSandboxCommandResponse = zSandboxCommandView;
|
|
1117
|
+
const zGetSandboxCommandData = z.object({
|
|
1118
|
+
body: z.optional(z.never()),
|
|
1119
|
+
path: z.object({
|
|
1120
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1121
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1122
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the command" })
|
|
1123
|
+
}),
|
|
1124
|
+
query: z.optional(z.never())
|
|
1125
|
+
});
|
|
1126
|
+
const zGetSandboxCommandResponse = zSandboxCommandView;
|
|
1127
|
+
const zGetSandboxCommandLogsData = z.object({
|
|
1128
|
+
body: z.optional(z.never()),
|
|
1129
|
+
path: z.object({
|
|
1130
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1131
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1132
|
+
command_id: z.string().register(z.globalRegistry, { description: "The ID of the command" })
|
|
1133
|
+
}),
|
|
1134
|
+
query: z.optional(z.object({ follow: z.optional(z.boolean().register(z.globalRegistry, { description: "If true, streams logs until the command completes" })) }))
|
|
1135
|
+
});
|
|
1136
|
+
const zTerminateSandboxCommandData = z.object({
|
|
1137
|
+
body: z.optional(z.never()),
|
|
1138
|
+
path: z.object({
|
|
1139
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1140
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1141
|
+
command_id: z.string().register(z.globalRegistry, { description: "The ID of the command" })
|
|
1142
|
+
}),
|
|
1143
|
+
query: z.optional(z.never())
|
|
1144
|
+
});
|
|
1145
|
+
const zTerminateSandboxCommandResponse = zSandboxCommandView;
|
|
1146
|
+
const zDeleteSandboxFileData = z.object({
|
|
1147
|
+
body: z.optional(z.never()),
|
|
1148
|
+
path: z.object({
|
|
1149
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1150
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1151
|
+
path: z.string().regex(/.*/).register(z.globalRegistry, { description: "Absolute path to the file or directory to delete" })
|
|
1152
|
+
}),
|
|
1153
|
+
query: z.optional(z.never())
|
|
1154
|
+
});
|
|
1155
|
+
/**
|
|
1156
|
+
* File or directory deleted successfully
|
|
1157
|
+
*/
|
|
1158
|
+
const zDeleteSandboxFileResponse = z.void().register(z.globalRegistry, { description: "File or directory deleted successfully" });
|
|
1159
|
+
const zGetSandboxContentData = z.object({
|
|
1160
|
+
body: z.optional(z.never()),
|
|
1161
|
+
path: z.object({
|
|
1162
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1163
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1164
|
+
path: z.string().regex(/.*/).register(z.globalRegistry, { description: "Absolute path to the file or directory. Recommended directory is `/buddy`" })
|
|
1165
|
+
}),
|
|
1166
|
+
query: z.optional(z.never())
|
|
1167
|
+
});
|
|
1168
|
+
/**
|
|
1169
|
+
* Content retrieved successfully
|
|
1170
|
+
*/
|
|
1171
|
+
const zGetSandboxContentResponse = zSandboxContentView;
|
|
1172
|
+
const zCreateSandboxDirectoryData = z.object({
|
|
1173
|
+
body: z.optional(z.never()),
|
|
1174
|
+
path: z.object({
|
|
1175
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1176
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1177
|
+
path: z.string().regex(/.*/).register(z.globalRegistry, { description: "Absolute path where the directory should be created" })
|
|
1178
|
+
}),
|
|
1179
|
+
query: z.optional(z.never())
|
|
1180
|
+
});
|
|
1181
|
+
/**
|
|
1182
|
+
* Directory created successfully
|
|
1183
|
+
*/
|
|
1184
|
+
const zCreateSandboxDirectoryResponse = zSandboxContentItem;
|
|
1185
|
+
const zUploadSandboxFileData = z.object({
|
|
1186
|
+
body: z.optional(z.string().register(z.globalRegistry, { description: "File to upload" })),
|
|
1187
|
+
path: z.object({
|
|
1188
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1189
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1190
|
+
path: z.string().regex(/.*/).register(z.globalRegistry, { description: "Absolute path where the file should be uploaded. Recommended directory is `/buddy`" })
|
|
1191
|
+
}),
|
|
1192
|
+
query: z.optional(z.never())
|
|
1193
|
+
});
|
|
1194
|
+
/**
|
|
1195
|
+
* File uploaded successfully
|
|
1196
|
+
*/
|
|
1197
|
+
const zUploadSandboxFileResponse = zSandboxContentItem;
|
|
1198
|
+
const zDownloadSandboxContentData = z.object({
|
|
1199
|
+
body: z.optional(z.never()),
|
|
1200
|
+
path: z.object({
|
|
1201
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1202
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1203
|
+
path: z.string().regex(/.*/).register(z.globalRegistry, { description: "Absolute path to the file or directory to download" })
|
|
1204
|
+
}),
|
|
1205
|
+
query: z.optional(z.never())
|
|
1206
|
+
});
|
|
1207
|
+
const zRestartSandboxData = z.object({
|
|
1208
|
+
body: z.optional(z.never()),
|
|
1209
|
+
path: z.object({
|
|
1210
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1211
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1212
|
+
}),
|
|
1213
|
+
query: z.optional(z.never())
|
|
1214
|
+
});
|
|
1215
|
+
const zRestartSandboxResponse = zSandboxResponse;
|
|
1216
|
+
const zGetSandboxSnapshotsData = z.object({
|
|
1217
|
+
body: z.optional(z.never()),
|
|
1218
|
+
path: z.object({
|
|
1219
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1220
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1221
|
+
}),
|
|
1222
|
+
query: z.optional(z.never())
|
|
1223
|
+
});
|
|
1224
|
+
const zAddSandboxSnapshotData = z.object({
|
|
1225
|
+
body: z.optional(zAddSnapshotRequest),
|
|
1226
|
+
path: z.object({
|
|
1227
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1228
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1229
|
+
}),
|
|
1230
|
+
query: z.optional(z.never())
|
|
1231
|
+
});
|
|
1232
|
+
const zDeleteSandboxSnapshotData = z.object({
|
|
1233
|
+
body: z.optional(z.never()),
|
|
1234
|
+
path: z.object({
|
|
1235
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1236
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1237
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })
|
|
1238
|
+
}),
|
|
1239
|
+
query: z.optional(z.never())
|
|
1240
|
+
});
|
|
1241
|
+
/**
|
|
1242
|
+
* Sandbox snapshot deleted successfully
|
|
1243
|
+
*/
|
|
1244
|
+
const zDeleteSandboxSnapshotResponse = z.void().register(z.globalRegistry, { description: "Sandbox snapshot deleted successfully" });
|
|
1245
|
+
const zGetSandboxSnapshotData = z.object({
|
|
1246
|
+
body: z.optional(z.never()),
|
|
1247
|
+
path: z.object({
|
|
1248
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1249
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" }),
|
|
1250
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })
|
|
1251
|
+
}),
|
|
1252
|
+
query: z.optional(z.never())
|
|
1253
|
+
});
|
|
1254
|
+
const zStartSandboxData = z.object({
|
|
1255
|
+
body: z.optional(z.never()),
|
|
1256
|
+
path: z.object({
|
|
1257
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1258
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1259
|
+
}),
|
|
1260
|
+
query: z.optional(z.never())
|
|
1261
|
+
});
|
|
1262
|
+
const zStartSandboxResponse = zSandboxResponse;
|
|
1263
|
+
const zStopSandboxData = z.object({
|
|
1264
|
+
body: z.optional(z.never()),
|
|
1265
|
+
path: z.object({
|
|
1266
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1267
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1268
|
+
}),
|
|
1269
|
+
query: z.optional(z.never())
|
|
1270
|
+
});
|
|
1271
|
+
const zStopSandboxResponse = zSandboxResponse;
|
|
1272
|
+
const zGetSandboxYamlData = z.object({
|
|
1273
|
+
body: z.optional(z.never()),
|
|
1274
|
+
path: z.object({
|
|
1275
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1276
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1277
|
+
}),
|
|
1278
|
+
query: z.optional(z.never())
|
|
1279
|
+
});
|
|
1280
|
+
const zUpdateSandboxByYamlData = z.object({
|
|
1281
|
+
body: z.optional(zSandboxYamlViewWritable),
|
|
1282
|
+
path: z.object({
|
|
1283
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1284
|
+
sandbox_id: z.string().register(z.globalRegistry, { description: "The ID of the sandbox" })
|
|
1285
|
+
}),
|
|
1286
|
+
query: z.optional(z.never())
|
|
1287
|
+
});
|
|
1288
|
+
const zGetProjectSnapshotsData = z.object({
|
|
1289
|
+
body: z.optional(z.never()),
|
|
1290
|
+
path: z.object({ workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }) }),
|
|
1291
|
+
query: z.object({ project_name: z.string().register(z.globalRegistry, { description: "The human-readable ID of the project to filter sandboxes" }) })
|
|
1292
|
+
});
|
|
1293
|
+
const zDeleteSnapshotData = z.object({
|
|
1294
|
+
body: z.optional(z.never()),
|
|
1295
|
+
path: z.object({
|
|
1296
|
+
workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }),
|
|
1297
|
+
id: z.string().register(z.globalRegistry, { description: "The ID of the snapshot" })
|
|
1298
|
+
}),
|
|
1299
|
+
query: z.optional(z.never())
|
|
1300
|
+
});
|
|
1301
|
+
/**
|
|
1302
|
+
* Sandbox snapshot deleted successfully
|
|
1303
|
+
*/
|
|
1304
|
+
const zDeleteSnapshotResponse = z.void().register(z.globalRegistry, { description: "Sandbox snapshot deleted successfully" });
|
|
1305
|
+
const zAddSandboxByYamlData = z.object({
|
|
1306
|
+
body: z.optional(zSandboxYamlViewWritable),
|
|
1307
|
+
path: z.object({ workspace_domain: z.string().register(z.globalRegistry, { description: "The human-readable ID of the workspace" }) }),
|
|
1308
|
+
query: z.object({ project_name: z.string().register(z.globalRegistry, { description: "The human-readable ID of the project to filter sandboxes" }) })
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
//#endregion
|
|
1312
|
+
//#region package.json
|
|
1313
|
+
var name = "@buddy-works/sandbox-sdk";
|
|
1314
|
+
var version = "0.1.0-rc.1";
|
|
1315
|
+
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/utils/environment.ts
|
|
1318
|
+
const environmentConfig = {
|
|
1319
|
+
BUDDY_TOKEN: {
|
|
1320
|
+
type: "string",
|
|
1321
|
+
secret: true
|
|
1322
|
+
},
|
|
1323
|
+
BUDDY_API_URL: { type: "string" },
|
|
1324
|
+
BUDDY_REGION: { type: "string" },
|
|
1325
|
+
BUDDY_WORKSPACE: { type: "string" },
|
|
1326
|
+
BUDDY_PROJECT: { type: "string" },
|
|
1327
|
+
BUDDY_LOGGER_LEVEL: { type: "string" }
|
|
1328
|
+
};
|
|
1329
|
+
function processConfigEntry(key, config) {
|
|
1330
|
+
return config.required === true ? getEnvironment(key, true) : getEnvironment(key, false);
|
|
1331
|
+
}
|
|
1332
|
+
function loadEnvironment() {
|
|
1333
|
+
const variables = {};
|
|
1334
|
+
for (const key of Object.keys(environmentConfig)) try {
|
|
1335
|
+
const config = environmentConfig[key];
|
|
1336
|
+
if (config.type === "string" && config.required) getEnvironment(key, true);
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
return {
|
|
1339
|
+
error,
|
|
1340
|
+
variables: {}
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
for (const key of Object.keys(environmentConfig)) Object.defineProperty(variables, key, {
|
|
1344
|
+
get() {
|
|
1345
|
+
return processConfigEntry(key, environmentConfig[key]);
|
|
1346
|
+
},
|
|
1347
|
+
enumerable: true,
|
|
1348
|
+
configurable: true
|
|
1349
|
+
});
|
|
1350
|
+
return { variables };
|
|
1351
|
+
}
|
|
1352
|
+
function getEnvironment(key, required = false) {
|
|
1353
|
+
const MISSING_REQUIRED_ENVIRONMENT_VARIABLE_ERROR = `Missing required configuration. Please set the ${key} environment variable.`;
|
|
1354
|
+
const value = process.env[key];
|
|
1355
|
+
if (value === void 0) {
|
|
1356
|
+
if (required) throw new Error(MISSING_REQUIRED_ENVIRONMENT_VARIABLE_ERROR);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
const trimmedValue = value.trim();
|
|
1360
|
+
if (trimmedValue === "") {
|
|
1361
|
+
if (required) throw new Error(MISSING_REQUIRED_ENVIRONMENT_VARIABLE_ERROR);
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
return trimmedValue;
|
|
1365
|
+
}
|
|
1366
|
+
const environmentResult = loadEnvironment();
|
|
1367
|
+
var environment_default = environmentResult.variables;
|
|
1368
|
+
|
|
1369
|
+
//#endregion
|
|
1370
|
+
//#region src/utils/logger.ts
|
|
1371
|
+
const LOG_LEVELS = {
|
|
1372
|
+
debug: 5,
|
|
1373
|
+
info: 4,
|
|
1374
|
+
warn: 3,
|
|
1375
|
+
error: 2,
|
|
1376
|
+
silent: 0
|
|
1377
|
+
};
|
|
1378
|
+
var Logger = class {
|
|
1379
|
+
#prefix;
|
|
1380
|
+
#MAX_ERROR_DEPTH = 10;
|
|
1381
|
+
level;
|
|
1382
|
+
constructor() {
|
|
1383
|
+
this.#prefix = `${name}@${version}`;
|
|
1384
|
+
this.level = LOG_LEVELS[environment_default.BUDDY_LOGGER_LEVEL ?? ""] ?? LOG_LEVELS.warn;
|
|
1385
|
+
}
|
|
1386
|
+
get prefix() {
|
|
1387
|
+
return this.#prefix;
|
|
1388
|
+
}
|
|
1389
|
+
safeStringify(object) {
|
|
1390
|
+
if (object === null || object === void 0) return "";
|
|
1391
|
+
const cache = /* @__PURE__ */ new Set();
|
|
1392
|
+
return JSON.stringify(object, (_key, value) => {
|
|
1393
|
+
if (typeof value === "object" && value !== null) {
|
|
1394
|
+
if (cache.has(value)) return "[Circular chain]";
|
|
1395
|
+
cache.add(value);
|
|
1396
|
+
}
|
|
1397
|
+
return value;
|
|
1398
|
+
}, 2);
|
|
1399
|
+
}
|
|
1400
|
+
#safeGetProperties(error) {
|
|
1401
|
+
try {
|
|
1402
|
+
const customProperties = Object.keys(error).filter((k) => k !== "cause");
|
|
1403
|
+
return customProperties.length > 0 ? Object.fromEntries(customProperties.map((k) => [k, Reflect.get(error, k)])) : void 0;
|
|
1404
|
+
} catch {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
#formatCompactError(error) {
|
|
1409
|
+
let output = `${error.name}: ${error.message}`;
|
|
1410
|
+
const properties = this.#safeGetProperties(error);
|
|
1411
|
+
if (properties) try {
|
|
1412
|
+
const propertyPairs = Object.entries(properties).map(([key, value]) => `${key}: ${this.safeStringify(value)}`).join(", ");
|
|
1413
|
+
output += ` (${propertyPairs})`;
|
|
1414
|
+
} catch {
|
|
1415
|
+
output += " (properties unavailable)";
|
|
1416
|
+
}
|
|
1417
|
+
return output;
|
|
1418
|
+
}
|
|
1419
|
+
#formatFullError(error, depth) {
|
|
1420
|
+
let output = error.stack ? `${error.stack}\n` : `${error.name}: ${error.message}\n`;
|
|
1421
|
+
const properties = this.#safeGetProperties(error);
|
|
1422
|
+
if (properties) try {
|
|
1423
|
+
output += `Properties: ${this.safeStringify(properties)}\n`;
|
|
1424
|
+
} catch {
|
|
1425
|
+
output += "Properties: [unable to serialize]\n";
|
|
1426
|
+
}
|
|
1427
|
+
if ("cause" in error && error.cause) {
|
|
1428
|
+
output += ` Caused by: ${this.#formatErrorForDebug(error.cause, true, depth + 1)}`;
|
|
1429
|
+
let currentCause = error.cause;
|
|
1430
|
+
let currentDepth = depth + 1;
|
|
1431
|
+
while (currentDepth < this.#MAX_ERROR_DEPTH && typeof currentCause === "object" && "cause" in currentCause && currentCause.cause) {
|
|
1432
|
+
output += `\n → ${this.#formatErrorForDebug(currentCause.cause, true, currentDepth + 1)}`;
|
|
1433
|
+
currentCause = currentCause.cause;
|
|
1434
|
+
currentDepth++;
|
|
1435
|
+
}
|
|
1436
|
+
output += "\n";
|
|
1437
|
+
}
|
|
1438
|
+
return output;
|
|
1439
|
+
}
|
|
1440
|
+
#formatErrorForDebug(error, compact = false, depth = 0) {
|
|
1441
|
+
try {
|
|
1442
|
+
if (depth >= this.#MAX_ERROR_DEPTH) return "[Max depth reached - possible circular cause chain]";
|
|
1443
|
+
if (!(error instanceof Error)) return this.safeStringify(error);
|
|
1444
|
+
return compact ? this.#formatCompactError(error) : this.#formatFullError(error, depth);
|
|
1445
|
+
} catch {
|
|
1446
|
+
return "[Logger Error: Unable to format error details]";
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
debug(message, data) {
|
|
1450
|
+
if (this.level >= LOG_LEVELS.debug) console.debug(`[${this.#prefix}] DEBUG: ${message}`, data ? this.safeStringify(data) : "");
|
|
1451
|
+
}
|
|
1452
|
+
info(message, data) {
|
|
1453
|
+
if (this.level >= LOG_LEVELS.info) console.log(`[${this.#prefix}] INFO: ${message}`, data ? this.safeStringify(data) : "");
|
|
1454
|
+
}
|
|
1455
|
+
warn(message, data) {
|
|
1456
|
+
if (this.level >= LOG_LEVELS.warn) console.warn(`[${this.#prefix}] WARN: ${message}`, data ? this.safeStringify(data) : "");
|
|
1457
|
+
}
|
|
1458
|
+
error(message, error) {
|
|
1459
|
+
if (this.level >= LOG_LEVELS.error) if (this.level >= LOG_LEVELS.debug) {
|
|
1460
|
+
const fullError = this.#formatErrorForDebug(error);
|
|
1461
|
+
console.error(`[${this.#prefix}] ERROR: ${message}\n${fullError}`);
|
|
1462
|
+
} else {
|
|
1463
|
+
const errorMessage = error instanceof Error ? error.message : this.safeStringify(error);
|
|
1464
|
+
console.error(`[${this.#prefix}] ERROR: ${message}${errorMessage ? ` - ${errorMessage}` : ""}`);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
var logger_default = new Logger();
|
|
1469
|
+
|
|
1470
|
+
//#endregion
|
|
1471
|
+
//#region src/core/http-client.ts
|
|
1472
|
+
/** Custom error class for HTTP request failures with status and response details */
|
|
1473
|
+
var HttpError = class HttpError extends Error {
|
|
1474
|
+
status;
|
|
1475
|
+
response;
|
|
1476
|
+
errors;
|
|
1477
|
+
/** Create an HttpError with message, status code, and optional response */
|
|
1478
|
+
constructor(message, status, response) {
|
|
1479
|
+
const apiErrors = response?.data && typeof response.data === "object" && "errors" in response.data ? response.data.errors : void 0;
|
|
1480
|
+
let fullMessage = message;
|
|
1481
|
+
if (status) fullMessage = `HTTP ${String(status)}: ${message}`;
|
|
1482
|
+
if (apiErrors && Array.isArray(apiErrors) && apiErrors.length > 0) {
|
|
1483
|
+
const errorMessages = apiErrors.map((error) => typeof error === "object" && error && "message" in error ? error.message : String(error)).filter(Boolean);
|
|
1484
|
+
if (errorMessages.length > 0) fullMessage += `\n${errorMessages.join("\n")}`;
|
|
1485
|
+
}
|
|
1486
|
+
super(fullMessage);
|
|
1487
|
+
this.name = "HttpError";
|
|
1488
|
+
this.status = status;
|
|
1489
|
+
Object.defineProperty(this, "response", {
|
|
1490
|
+
value: response,
|
|
1491
|
+
enumerable: false,
|
|
1492
|
+
writable: false,
|
|
1493
|
+
configurable: true
|
|
1494
|
+
});
|
|
1495
|
+
Object.defineProperty(this, "errors", {
|
|
1496
|
+
value: apiErrors,
|
|
1497
|
+
enumerable: false,
|
|
1498
|
+
writable: false,
|
|
1499
|
+
configurable: true
|
|
1500
|
+
});
|
|
1501
|
+
Object.setPrototypeOf(this, HttpError.prototype);
|
|
1502
|
+
}
|
|
1503
|
+
/** Custom inspect output for Node.js util.inspect */
|
|
1504
|
+
[inspect.custom]() {
|
|
1505
|
+
return this.stack ?? `${this.name}: ${this.message}`;
|
|
1506
|
+
}
|
|
1507
|
+
};
|
|
1508
|
+
/** Base HTTP client with retry logic, timeout handling, and authentication support */
|
|
1509
|
+
var HttpClient = class {
|
|
1510
|
+
#baseURL;
|
|
1511
|
+
#timeout;
|
|
1512
|
+
#defaultHeaders;
|
|
1513
|
+
debugMode;
|
|
1514
|
+
#authToken;
|
|
1515
|
+
/** Create a new HTTP client with optional base URL, timeout, and headers */
|
|
1516
|
+
constructor(config = {}) {
|
|
1517
|
+
this.debugMode = config.debugMode ?? logger_default.level >= 5;
|
|
1518
|
+
this.#baseURL = config.baseURL ?? "";
|
|
1519
|
+
this.#timeout = config.timeout ?? 3e4;
|
|
1520
|
+
this.#defaultHeaders = {
|
|
1521
|
+
"Content-Type": "application/json",
|
|
1522
|
+
...config.headers
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
/** Build a full URL from path and optional query parameters */
|
|
1526
|
+
#buildUrl(path, queryParameters) {
|
|
1527
|
+
const url = new URL(path, this.#baseURL);
|
|
1528
|
+
if (queryParameters) {
|
|
1529
|
+
for (const [key, value] of Object.entries(queryParameters)) if (value !== void 0) url.searchParams.set(key, String(value));
|
|
1530
|
+
}
|
|
1531
|
+
return url.toString();
|
|
1532
|
+
}
|
|
1533
|
+
/** Merge default headers with additional headers and auth token */
|
|
1534
|
+
#getHeaders(additionalHeaders) {
|
|
1535
|
+
const headers = {
|
|
1536
|
+
...this.#defaultHeaders,
|
|
1537
|
+
...additionalHeaders
|
|
1538
|
+
};
|
|
1539
|
+
if (this.#authToken) headers["Authorization"] = `Bearer ${this.#authToken}`;
|
|
1540
|
+
return headers;
|
|
1541
|
+
}
|
|
1542
|
+
/** Execute a request function with automatic retry on transient failures */
|
|
1543
|
+
async #executeWithRetry(requestFunction, skipRetry = false) {
|
|
1544
|
+
if (skipRetry) return requestFunction();
|
|
1545
|
+
return pRetry(requestFunction, {
|
|
1546
|
+
retries: 3,
|
|
1547
|
+
minTimeout: 1e3,
|
|
1548
|
+
maxTimeout: 1e4,
|
|
1549
|
+
onFailedAttempt: ({ error }) => {
|
|
1550
|
+
if (error instanceof HttpError) {
|
|
1551
|
+
const status = error.status;
|
|
1552
|
+
if (status && status >= 400 && status < 500 && status !== 429) throw error;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
/** Execute an HTTP request with timeout, retry, and error handling */
|
|
1558
|
+
async #request(method, url, data, config) {
|
|
1559
|
+
const { skipRetry, queryParams, headers: additionalHeaders, responseType = "json" } = config ?? {};
|
|
1560
|
+
const fullUrl = this.#buildUrl(url, queryParams);
|
|
1561
|
+
const headers = this.#getHeaders(additionalHeaders);
|
|
1562
|
+
const makeRequest = async () => {
|
|
1563
|
+
const controller = new AbortController();
|
|
1564
|
+
const timeoutId = setTimeout(() => {
|
|
1565
|
+
controller.abort();
|
|
1566
|
+
}, this.#timeout);
|
|
1567
|
+
try {
|
|
1568
|
+
if (this.debugMode) logger_default.debug("[HTTP REQUEST]", {
|
|
1569
|
+
method,
|
|
1570
|
+
url: fullUrl,
|
|
1571
|
+
headers: {
|
|
1572
|
+
...headers,
|
|
1573
|
+
Authorization: headers["Authorization"] ? "***" : void 0
|
|
1574
|
+
},
|
|
1575
|
+
body: data
|
|
1576
|
+
});
|
|
1577
|
+
const fetchOptions = {
|
|
1578
|
+
method,
|
|
1579
|
+
headers,
|
|
1580
|
+
signal: controller.signal
|
|
1581
|
+
};
|
|
1582
|
+
if (data !== void 0) fetchOptions.body = JSON.stringify(data);
|
|
1583
|
+
const response = await fetch(fullUrl, fetchOptions);
|
|
1584
|
+
let responseData;
|
|
1585
|
+
if (responseType === "text") responseData = await response.text();
|
|
1586
|
+
else {
|
|
1587
|
+
const text = await response.text();
|
|
1588
|
+
responseData = text ? JSON.parse(text) : void 0;
|
|
1589
|
+
}
|
|
1590
|
+
const httpResponse = {
|
|
1591
|
+
status: response.status,
|
|
1592
|
+
statusText: response.statusText,
|
|
1593
|
+
data: responseData,
|
|
1594
|
+
headers: response.headers
|
|
1595
|
+
};
|
|
1596
|
+
if (this.debugMode) logger_default.debug("[HTTP RESPONSE]", {
|
|
1597
|
+
status: response.status,
|
|
1598
|
+
body: responseData
|
|
1599
|
+
});
|
|
1600
|
+
clearTimeout(timeoutId);
|
|
1601
|
+
if (!response.ok) throw new HttpError(response.statusText || "Request failed", response.status, httpResponse);
|
|
1602
|
+
return httpResponse;
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
clearTimeout(timeoutId);
|
|
1605
|
+
if (error instanceof HttpError) throw error;
|
|
1606
|
+
if (error instanceof Error && error.name === "AbortError") throw new HttpError("Request timeout", 0);
|
|
1607
|
+
throw new HttpError(error instanceof Error ? error.message : "Request failed", 0);
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
return this.#executeWithRetry(makeRequest, skipRetry);
|
|
1611
|
+
}
|
|
1612
|
+
/** Perform a GET request */
|
|
1613
|
+
async get(url, config) {
|
|
1614
|
+
return this.#request("GET", url, void 0, config);
|
|
1615
|
+
}
|
|
1616
|
+
/** Perform a POST request with optional body data */
|
|
1617
|
+
async post(url, data, config) {
|
|
1618
|
+
return this.#request("POST", url, data ?? {}, config);
|
|
1619
|
+
}
|
|
1620
|
+
/** Perform a DELETE request */
|
|
1621
|
+
async delete(url, config) {
|
|
1622
|
+
return this.#request("DELETE", url, void 0, config);
|
|
1623
|
+
}
|
|
1624
|
+
/** Set the Bearer token for authenticated requests */
|
|
1625
|
+
setAuthToken(token) {
|
|
1626
|
+
this.#authToken = token;
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
//#endregion
|
|
1631
|
+
//#region src/core/buddy-api-client.ts
|
|
1632
|
+
/** API client for Buddy sandbox operations with request validation and response transformation */
|
|
1633
|
+
var BuddyApiClient = class extends HttpClient {
|
|
1634
|
+
workspace;
|
|
1635
|
+
project_name;
|
|
1636
|
+
#apiUrl;
|
|
1637
|
+
#token;
|
|
1638
|
+
/** Builds a parameterized URL by replacing path placeholders */
|
|
1639
|
+
#buildUrl(params) {
|
|
1640
|
+
const { path = {}, url } = params;
|
|
1641
|
+
return url.replace(/{(\w+)}/g, (_, key) => {
|
|
1642
|
+
const value = path[key];
|
|
1643
|
+
if (value === void 0) throw new Error(`Missing path parameter: ${key}`);
|
|
1644
|
+
return value;
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
/** Parse and validate HTTP response data against a Zod schema */
|
|
1648
|
+
async #parseResponse(schema, response) {
|
|
1649
|
+
const result = await schema.safeParseAsync(response.data);
|
|
1650
|
+
if (!result.success) throw new HttpError(`Response validation failed:\n${prettifyError(result.error)}`, response.status, response);
|
|
1651
|
+
return result.data;
|
|
1652
|
+
}
|
|
1653
|
+
/** Check if a schema expects query parameters (not ZodNever) */
|
|
1654
|
+
#schemaExpectsQuery(schema) {
|
|
1655
|
+
const querySchema = schema.shape.query;
|
|
1656
|
+
if (querySchema instanceof z.ZodOptional) {
|
|
1657
|
+
if (querySchema._def.innerType instanceof z.ZodNever) return false;
|
|
1658
|
+
}
|
|
1659
|
+
return true;
|
|
1660
|
+
}
|
|
1661
|
+
/** Execute an HTTP request with input/output validation */
|
|
1662
|
+
async #requestWithValidation({ method, url, data, dataSchema, responseSchema, skipRetry }) {
|
|
1663
|
+
const expectsQuery = this.#schemaExpectsQuery(dataSchema);
|
|
1664
|
+
const fullData = {
|
|
1665
|
+
body: data.body,
|
|
1666
|
+
path: {
|
|
1667
|
+
workspace_domain: this.workspace,
|
|
1668
|
+
...data.path ?? {}
|
|
1669
|
+
},
|
|
1670
|
+
query: expectsQuery ? {
|
|
1671
|
+
project_name: this.project_name,
|
|
1672
|
+
...data.query ?? {}
|
|
1673
|
+
} : void 0
|
|
1674
|
+
};
|
|
1675
|
+
const result = await dataSchema.safeParseAsync(fullData);
|
|
1676
|
+
if (!result.success) throw result.error;
|
|
1677
|
+
const validatedData = result.data;
|
|
1678
|
+
const parameterizedUrl = this.#buildUrl({
|
|
1679
|
+
url,
|
|
1680
|
+
path: validatedData.path
|
|
1681
|
+
});
|
|
1682
|
+
const requestConfig = {
|
|
1683
|
+
queryParams: validatedData.query,
|
|
1684
|
+
skipRetry
|
|
1685
|
+
};
|
|
1686
|
+
let request;
|
|
1687
|
+
switch (method) {
|
|
1688
|
+
case "POST":
|
|
1689
|
+
request = this.post(parameterizedUrl, validatedData.body ?? {}, requestConfig);
|
|
1690
|
+
break;
|
|
1691
|
+
case "GET":
|
|
1692
|
+
request = this.get(parameterizedUrl, requestConfig);
|
|
1693
|
+
break;
|
|
1694
|
+
case "DELETE":
|
|
1695
|
+
request = this.delete(parameterizedUrl, requestConfig);
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
1698
|
+
const response = await request;
|
|
1699
|
+
return await this.#parseResponse(responseSchema, response);
|
|
1700
|
+
}
|
|
1701
|
+
/** Create a new sandbox */
|
|
1702
|
+
async addSandbox(data) {
|
|
1703
|
+
return this.#requestWithValidation({
|
|
1704
|
+
method: "POST",
|
|
1705
|
+
data,
|
|
1706
|
+
url: "/workspaces/{workspace_domain}/sandboxes",
|
|
1707
|
+
dataSchema: zAddSandboxData,
|
|
1708
|
+
responseSchema: zAddSandboxResponse.transform(addSandboxResponseTransformer)
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
/** Get a specific sandbox by its ID */
|
|
1712
|
+
async getSandboxById(data) {
|
|
1713
|
+
return this.#requestWithValidation({
|
|
1714
|
+
method: "GET",
|
|
1715
|
+
data,
|
|
1716
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{id}",
|
|
1717
|
+
dataSchema: zGetSandboxData,
|
|
1718
|
+
responseSchema: zGetSandboxResponse.transform(getSandboxResponseTransformer)
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
/** Execute a command in a sandbox */
|
|
1722
|
+
async executeCommand(data) {
|
|
1723
|
+
return this.#requestWithValidation({
|
|
1724
|
+
method: "POST",
|
|
1725
|
+
data,
|
|
1726
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/commands",
|
|
1727
|
+
dataSchema: zExecuteSandboxCommandData,
|
|
1728
|
+
responseSchema: zExecuteSandboxCommandResponse
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
/** Get a specific command execution details */
|
|
1732
|
+
async getCommandDetails(data) {
|
|
1733
|
+
return this.#requestWithValidation({
|
|
1734
|
+
method: "GET",
|
|
1735
|
+
data,
|
|
1736
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/commands/{id}",
|
|
1737
|
+
dataSchema: zGetSandboxCommandData,
|
|
1738
|
+
responseSchema: zGetSandboxCommandResponse
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
/** Terminate a running command in a sandbox */
|
|
1742
|
+
async terminateCommand(data) {
|
|
1743
|
+
return this.#requestWithValidation({
|
|
1744
|
+
method: "POST",
|
|
1745
|
+
data,
|
|
1746
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/commands/{command_id}/terminate",
|
|
1747
|
+
dataSchema: zTerminateSandboxCommandData,
|
|
1748
|
+
responseSchema: zTerminateSandboxCommandResponse
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
/** Delete a sandbox by its ID */
|
|
1752
|
+
async deleteSandboxById(data) {
|
|
1753
|
+
try {
|
|
1754
|
+
return await this.#requestWithValidation({
|
|
1755
|
+
method: "DELETE",
|
|
1756
|
+
data,
|
|
1757
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{id}",
|
|
1758
|
+
dataSchema: zDeleteSandboxData,
|
|
1759
|
+
responseSchema: zDeleteSandboxResponse,
|
|
1760
|
+
skipRetry: true
|
|
1761
|
+
});
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
if (error instanceof HttpError && error.status === 404) return;
|
|
1764
|
+
throw error;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
/** Get all sandboxes in the workspace for a specific project */
|
|
1768
|
+
async getSandboxes(data) {
|
|
1769
|
+
return this.#requestWithValidation({
|
|
1770
|
+
method: "GET",
|
|
1771
|
+
data,
|
|
1772
|
+
url: "/workspaces/{workspace_domain}/sandboxes",
|
|
1773
|
+
dataSchema: zGetSandboxesData,
|
|
1774
|
+
responseSchema: zGetSandboxesResponse
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
/** Start a sandbox */
|
|
1778
|
+
async startSandbox(data) {
|
|
1779
|
+
return this.#requestWithValidation({
|
|
1780
|
+
method: "POST",
|
|
1781
|
+
data,
|
|
1782
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/start",
|
|
1783
|
+
dataSchema: zStartSandboxData,
|
|
1784
|
+
responseSchema: zStartSandboxResponse.transform(startSandboxResponseTransformer)
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
/** Stop a sandbox */
|
|
1788
|
+
async stopSandbox(data) {
|
|
1789
|
+
return this.#requestWithValidation({
|
|
1790
|
+
method: "POST",
|
|
1791
|
+
data,
|
|
1792
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/stop",
|
|
1793
|
+
dataSchema: zStopSandboxData,
|
|
1794
|
+
responseSchema: zStopSandboxResponse.transform(stopSandboxResponseTransformer)
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
/** Restart a sandbox */
|
|
1798
|
+
async restartSandbox(data) {
|
|
1799
|
+
return this.#requestWithValidation({
|
|
1800
|
+
method: "POST",
|
|
1801
|
+
data,
|
|
1802
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/restart",
|
|
1803
|
+
dataSchema: zRestartSandboxData,
|
|
1804
|
+
responseSchema: zRestartSandboxResponse.transform(restartSandboxResponseTransformer)
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
/** Get sandbox content (list files/directories at a path) */
|
|
1808
|
+
async getSandboxContent(data) {
|
|
1809
|
+
return this.#requestWithValidation({
|
|
1810
|
+
method: "GET",
|
|
1811
|
+
data,
|
|
1812
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/content/{path}",
|
|
1813
|
+
dataSchema: zGetSandboxContentData,
|
|
1814
|
+
responseSchema: zGetSandboxContentResponse.transform(getSandboxContentResponseTransformer)
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
/** Delete a file or directory from a sandbox */
|
|
1818
|
+
async deleteSandboxFile(data) {
|
|
1819
|
+
return this.#requestWithValidation({
|
|
1820
|
+
method: "DELETE",
|
|
1821
|
+
data,
|
|
1822
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/content/{path}",
|
|
1823
|
+
dataSchema: zDeleteSandboxFileData,
|
|
1824
|
+
responseSchema: zDeleteSandboxFileResponse
|
|
1825
|
+
});
|
|
1826
|
+
}
|
|
1827
|
+
/** Create a directory in a sandbox */
|
|
1828
|
+
async createSandboxDirectory(data) {
|
|
1829
|
+
return this.#requestWithValidation({
|
|
1830
|
+
method: "POST",
|
|
1831
|
+
data,
|
|
1832
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/content/{path}",
|
|
1833
|
+
dataSchema: zCreateSandboxDirectoryData,
|
|
1834
|
+
responseSchema: zCreateSandboxDirectoryResponse.transform(createSandboxDirectoryResponseTransformer)
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
/** Upload a file to a sandbox */
|
|
1838
|
+
async uploadSandboxFile(data) {
|
|
1839
|
+
const fullData = {
|
|
1840
|
+
body: data.body,
|
|
1841
|
+
path: {
|
|
1842
|
+
workspace_domain: this.workspace,
|
|
1843
|
+
...data.path ?? {}
|
|
1844
|
+
},
|
|
1845
|
+
query: void 0
|
|
1846
|
+
};
|
|
1847
|
+
const validationResult = await zUploadSandboxFileData.safeParseAsync({
|
|
1848
|
+
...fullData,
|
|
1849
|
+
body: void 0
|
|
1850
|
+
});
|
|
1851
|
+
if (!validationResult.success) throw validationResult.error;
|
|
1852
|
+
const validatedData = validationResult.data;
|
|
1853
|
+
const parameterizedUrl = this.#buildUrl({
|
|
1854
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/content/upload/{path}",
|
|
1855
|
+
path: validatedData.path
|
|
1856
|
+
});
|
|
1857
|
+
const url = new URL(parameterizedUrl, this.#apiUrl);
|
|
1858
|
+
url.searchParams.set("project_name", this.project_name);
|
|
1859
|
+
const filename = data.path.path.split("/").pop() ?? "file";
|
|
1860
|
+
const formData = new FormData();
|
|
1861
|
+
formData.append("file", data.body, filename);
|
|
1862
|
+
const headers = { Authorization: `Bearer ${this.#token}` };
|
|
1863
|
+
if (this.debugMode) logger_default.debug("[HTTP REQUEST - Upload]", {
|
|
1864
|
+
method: "POST",
|
|
1865
|
+
url: url.toString(),
|
|
1866
|
+
headers: {
|
|
1867
|
+
...headers,
|
|
1868
|
+
Authorization: "***"
|
|
1869
|
+
},
|
|
1870
|
+
formData
|
|
1871
|
+
});
|
|
1872
|
+
const response = await fetch(url.toString(), {
|
|
1873
|
+
method: "POST",
|
|
1874
|
+
headers,
|
|
1875
|
+
body: formData
|
|
1876
|
+
});
|
|
1877
|
+
if (!response.ok) throw new HttpError(`Failed to upload file: ${response.statusText}`, response.status);
|
|
1878
|
+
const responseData = await response.json();
|
|
1879
|
+
const result = await zUploadSandboxFileResponse.transform(uploadSandboxFileResponseTransformer).safeParseAsync(responseData);
|
|
1880
|
+
if (!result.success) throw new HttpError(`Response validation failed:\n${prettifyError(result.error)}`, response.status);
|
|
1881
|
+
return result.data;
|
|
1882
|
+
}
|
|
1883
|
+
/** Download content from a sandbox (file or directory as tar.gz) */
|
|
1884
|
+
async downloadSandboxContent(data) {
|
|
1885
|
+
const fullData = {
|
|
1886
|
+
body: void 0,
|
|
1887
|
+
path: {
|
|
1888
|
+
workspace_domain: this.workspace,
|
|
1889
|
+
...data.path
|
|
1890
|
+
},
|
|
1891
|
+
query: void 0
|
|
1892
|
+
};
|
|
1893
|
+
const validationResult = await zDownloadSandboxContentData.safeParseAsync(fullData);
|
|
1894
|
+
if (!validationResult.success) throw validationResult.error;
|
|
1895
|
+
const validatedData = validationResult.data;
|
|
1896
|
+
const parameterizedUrl = this.#buildUrl({
|
|
1897
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/download/{path}",
|
|
1898
|
+
path: validatedData.path
|
|
1899
|
+
});
|
|
1900
|
+
const url = new URL(parameterizedUrl, this.#apiUrl);
|
|
1901
|
+
const headers = {
|
|
1902
|
+
Accept: "application/octet-stream",
|
|
1903
|
+
Authorization: `Bearer ${this.#token}`
|
|
1904
|
+
};
|
|
1905
|
+
if (this.debugMode) logger_default.debug("[HTTP REQUEST - Download]", {
|
|
1906
|
+
method: "GET",
|
|
1907
|
+
url: url.toString(),
|
|
1908
|
+
headers: {
|
|
1909
|
+
...headers,
|
|
1910
|
+
Authorization: "***"
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
const response = await fetch(url.toString(), {
|
|
1914
|
+
method: "GET",
|
|
1915
|
+
headers
|
|
1916
|
+
});
|
|
1917
|
+
if (!response.ok) throw new HttpError(`Failed to download content: ${response.statusText}`, response.status);
|
|
1918
|
+
const contentDisposition = response.headers.get("Content-Disposition");
|
|
1919
|
+
let filename = "download";
|
|
1920
|
+
if (contentDisposition) {
|
|
1921
|
+
const match = contentDisposition.match(/filename="?([^";\n]+)"?/);
|
|
1922
|
+
if (match?.[1]) filename = match[1];
|
|
1923
|
+
}
|
|
1924
|
+
return {
|
|
1925
|
+
data: await response.arrayBuffer(),
|
|
1926
|
+
filename
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
/** Stream logs from a specific command execution */
|
|
1930
|
+
async *streamCommandLogs(data) {
|
|
1931
|
+
const fullData = {
|
|
1932
|
+
body: data.body,
|
|
1933
|
+
path: {
|
|
1934
|
+
workspace_domain: this.workspace,
|
|
1935
|
+
...data.path ?? {}
|
|
1936
|
+
},
|
|
1937
|
+
query: data.query
|
|
1938
|
+
};
|
|
1939
|
+
const validationResult = await zGetSandboxCommandLogsData.safeParseAsync(fullData);
|
|
1940
|
+
if (!validationResult.success) throw validationResult.error;
|
|
1941
|
+
const validatedData = validationResult.data;
|
|
1942
|
+
const parameterizedUrl = this.#buildUrl({
|
|
1943
|
+
url: "/workspaces/{workspace_domain}/sandboxes/{sandbox_id}/commands/{command_id}/logs",
|
|
1944
|
+
path: validatedData.path
|
|
1945
|
+
});
|
|
1946
|
+
const url = new URL(parameterizedUrl, this.#apiUrl);
|
|
1947
|
+
if (validatedData.query?.follow !== void 0) url.searchParams.set("follow", String(validatedData.query.follow));
|
|
1948
|
+
const headers = {
|
|
1949
|
+
Accept: "application/jsonl",
|
|
1950
|
+
"Content-Type": "application/json",
|
|
1951
|
+
Authorization: `Bearer ${this.#token}`
|
|
1952
|
+
};
|
|
1953
|
+
const response = await fetch(url.toString(), {
|
|
1954
|
+
method: "GET",
|
|
1955
|
+
headers
|
|
1956
|
+
});
|
|
1957
|
+
if (this.debugMode) logger_default.debug("[HTTP REQUEST - Streaming]", {
|
|
1958
|
+
method: "GET",
|
|
1959
|
+
url: url.toString(),
|
|
1960
|
+
headers: {
|
|
1961
|
+
...headers,
|
|
1962
|
+
Authorization: "***"
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
if (!response.ok) throw new HttpError(`Failed to stream logs: ${response.statusText}`, response.status);
|
|
1966
|
+
const contentType = response.headers.get("content-type");
|
|
1967
|
+
if (!contentType?.includes("application/jsonl")) throw new Error(`Expected application/jsonl content type, got: ${contentType ?? "none"}`);
|
|
1968
|
+
if (!response.body) throw new Error("No response body available for streaming");
|
|
1969
|
+
const reader = response.body.getReader();
|
|
1970
|
+
const decoder = new TextDecoder();
|
|
1971
|
+
let buffer = "";
|
|
1972
|
+
try {
|
|
1973
|
+
while (true) {
|
|
1974
|
+
const readResult = await reader.read();
|
|
1975
|
+
if (readResult.done) break;
|
|
1976
|
+
const chunk = readResult.value;
|
|
1977
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
1978
|
+
const lines = buffer.split("\n");
|
|
1979
|
+
buffer = lines.pop() || "";
|
|
1980
|
+
for (const line of lines) {
|
|
1981
|
+
if (!line.trim()) continue;
|
|
1982
|
+
const logEntry = await this.#parseAndValidateLogEntry(line);
|
|
1983
|
+
if (this.debugMode) logger_default.debug(`[STREAM] ${logEntry.type}`, { content: logEntry.data });
|
|
1984
|
+
yield logEntry;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
if (buffer.trim()) yield this.#parseAndValidateLogEntry(buffer);
|
|
1988
|
+
} finally {
|
|
1989
|
+
reader.releaseLock();
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
/** Parse a JSON line and validate it as a SandboxCommandLog */
|
|
1993
|
+
async #parseAndValidateLogEntry(line) {
|
|
1994
|
+
let parsed;
|
|
1995
|
+
try {
|
|
1996
|
+
parsed = JSON.parse(line);
|
|
1997
|
+
} catch (error) {
|
|
1998
|
+
throw new Error(`Failed to parse log entry as JSON: ${error instanceof Error ? error.message : String(error)}. Line: ${line}`);
|
|
1999
|
+
}
|
|
2000
|
+
const result = await zSandboxCommandLog.safeParseAsync(parsed);
|
|
2001
|
+
if (!result.success) throw result.error;
|
|
2002
|
+
return result.data;
|
|
2003
|
+
}
|
|
2004
|
+
/** Create a new Buddy API client instance */
|
|
2005
|
+
constructor(config) {
|
|
2006
|
+
const token = config.token ?? environment_default.BUDDY_TOKEN;
|
|
2007
|
+
if (!token) throw new Error("Buddy API token is required. Set BUDDY_TOKEN environment variable or pass token in config.");
|
|
2008
|
+
super({
|
|
2009
|
+
...config,
|
|
2010
|
+
baseURL: config.apiUrl,
|
|
2011
|
+
headers: {
|
|
2012
|
+
Accept: "application/json",
|
|
2013
|
+
"Content-Type": "application/json",
|
|
2014
|
+
...config.headers
|
|
2015
|
+
}
|
|
2016
|
+
});
|
|
2017
|
+
this.workspace = config.workspace;
|
|
2018
|
+
this.project_name = config.project_name;
|
|
2019
|
+
this.#apiUrl = config.apiUrl;
|
|
2020
|
+
this.#token = token;
|
|
2021
|
+
this.setAuthToken(token);
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
|
|
2025
|
+
//#endregion
|
|
2026
|
+
//#region src/entity/command.ts
|
|
2027
|
+
/** Represents a running or completed command execution in a sandbox */
|
|
2028
|
+
var Command = class Command {
|
|
2029
|
+
commandResponse;
|
|
2030
|
+
client;
|
|
2031
|
+
sandboxId;
|
|
2032
|
+
commandId;
|
|
2033
|
+
/** Create a new Command instance from an API response */
|
|
2034
|
+
constructor({ commandResponse, client, sandboxId }) {
|
|
2035
|
+
if (!commandResponse.id) throw new Error("Command response must have an id");
|
|
2036
|
+
this.commandResponse = commandResponse;
|
|
2037
|
+
this.client = client;
|
|
2038
|
+
this.sandboxId = sandboxId;
|
|
2039
|
+
this.commandId = commandResponse.id;
|
|
2040
|
+
}
|
|
2041
|
+
/** The raw command response data from the API */
|
|
2042
|
+
get data() {
|
|
2043
|
+
return this.commandResponse;
|
|
2044
|
+
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Stream logs from the command in real-time
|
|
2047
|
+
* @returns AsyncGenerator yielding log entries with type and data
|
|
2048
|
+
*/
|
|
2049
|
+
logs({ follow } = {}) {
|
|
2050
|
+
return this.client.streamCommandLogs({
|
|
2051
|
+
path: {
|
|
2052
|
+
command_id: this.commandId,
|
|
2053
|
+
sandbox_id: this.sandboxId
|
|
2054
|
+
},
|
|
2055
|
+
query: { follow }
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Wait for the command to finish execution
|
|
2060
|
+
* @returns Command instance with final response data
|
|
2061
|
+
*/
|
|
2062
|
+
async wait() {
|
|
2063
|
+
return new Command({
|
|
2064
|
+
commandResponse: await this.pollForCommandCompletion(),
|
|
2065
|
+
client: this.client,
|
|
2066
|
+
sandboxId: this.sandboxId
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Get all output from the command (waits for completion)
|
|
2071
|
+
* @returns Complete output as a string
|
|
2072
|
+
*/
|
|
2073
|
+
async output(stream = "BOTH") {
|
|
2074
|
+
let data = "";
|
|
2075
|
+
for await (const log of this.logs({ follow: true })) if (stream === "BOTH" || log.type === stream) data += `${log.data ?? ""}\n`;
|
|
2076
|
+
return data;
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Get all stdout output from the command (waits for completion)
|
|
2080
|
+
* @returns Stdout as a string
|
|
2081
|
+
*/
|
|
2082
|
+
async stdout() {
|
|
2083
|
+
return this.output("STDOUT");
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Get all stderr output from the command (waits for completion)
|
|
2087
|
+
* @returns Stderr as a string
|
|
2088
|
+
*/
|
|
2089
|
+
async stderr() {
|
|
2090
|
+
return this.output("STDERR");
|
|
2091
|
+
}
|
|
2092
|
+
/** Terminate the running command */
|
|
2093
|
+
async kill() {
|
|
2094
|
+
await this.client.terminateCommand({ path: {
|
|
2095
|
+
sandbox_id: this.sandboxId,
|
|
2096
|
+
command_id: this.commandId
|
|
2097
|
+
} });
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Poll the API until the command reaches a terminal state
|
|
2101
|
+
* @returns Final command response
|
|
2102
|
+
*/
|
|
2103
|
+
async pollForCommandCompletion(pollIntervalMs = 1e3) {
|
|
2104
|
+
while (true) {
|
|
2105
|
+
const commandResponse = await this.client.getCommandDetails({ path: {
|
|
2106
|
+
sandbox_id: this.sandboxId,
|
|
2107
|
+
id: this.commandId
|
|
2108
|
+
} });
|
|
2109
|
+
if (commandResponse.status === "SUCCESSFUL" || commandResponse.status === "FAILED") return commandResponse;
|
|
2110
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
//#endregion
|
|
2116
|
+
//#region src/errors/index.ts
|
|
2117
|
+
const ERROR_CODES = {
|
|
2118
|
+
HTTP_ERROR: "HTTP_ERROR",
|
|
2119
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
2120
|
+
GENERIC_ERROR: "GENERIC_ERROR"
|
|
2121
|
+
};
|
|
2122
|
+
var BuddySDKError = class BuddySDKError extends Error {
|
|
2123
|
+
code;
|
|
2124
|
+
constructor(message, options) {
|
|
2125
|
+
super(message);
|
|
2126
|
+
this.name = "BuddySDKError";
|
|
2127
|
+
this.code = options?.code ?? ERROR_CODES.GENERIC_ERROR;
|
|
2128
|
+
if (options?.statusCode !== void 0) Object.defineProperty(this, "statusCode", {
|
|
2129
|
+
value: options.statusCode,
|
|
2130
|
+
enumerable: false,
|
|
2131
|
+
writable: false,
|
|
2132
|
+
configurable: true
|
|
2133
|
+
});
|
|
2134
|
+
if (options?.details !== void 0) Object.defineProperty(this, "details", {
|
|
2135
|
+
value: options.details,
|
|
2136
|
+
enumerable: false,
|
|
2137
|
+
writable: false,
|
|
2138
|
+
configurable: true
|
|
2139
|
+
});
|
|
2140
|
+
if (options?.cause !== void 0) Object.defineProperty(this, "cause", {
|
|
2141
|
+
value: options.cause,
|
|
2142
|
+
enumerable: false,
|
|
2143
|
+
writable: false,
|
|
2144
|
+
configurable: true
|
|
2145
|
+
});
|
|
2146
|
+
Object.setPrototypeOf(this, BuddySDKError.prototype);
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
function fromHttpError(operation, httpError) {
|
|
2150
|
+
return new BuddySDKError(`${operation}${httpError.status ? ` (HTTP ${httpError.status})` : ""}: ${httpError.errors && httpError.errors.length > 0 ? httpError.errors.map((error) => typeof error === "object" && error && "message" in error ? error.message : String(error)).join(", ") : httpError.message}`, {
|
|
2151
|
+
code: ERROR_CODES.HTTP_ERROR,
|
|
2152
|
+
statusCode: httpError.status,
|
|
2153
|
+
details: httpError.errors
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
function fromZodError(operation, zodError) {
|
|
2157
|
+
return new BuddySDKError(`${operation}:\n${prettifyError(zodError)}`, { code: ERROR_CODES.VALIDATION_ERROR });
|
|
2158
|
+
}
|
|
2159
|
+
async function withErrorHandler(operation, fn) {
|
|
2160
|
+
try {
|
|
2161
|
+
return await fn();
|
|
2162
|
+
} catch (error) {
|
|
2163
|
+
if (error instanceof BuddySDKError) throw error;
|
|
2164
|
+
let sdkError;
|
|
2165
|
+
if (error instanceof HttpError) sdkError = fromHttpError(operation, error);
|
|
2166
|
+
else if (error instanceof ZodError) sdkError = fromZodError(operation, error);
|
|
2167
|
+
else sdkError = new BuddySDKError(error instanceof Error ? error.message : String(error), {
|
|
2168
|
+
code: ERROR_CODES.GENERIC_ERROR,
|
|
2169
|
+
...error instanceof Error && { cause: error }
|
|
2170
|
+
});
|
|
2171
|
+
throw sdkError;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
//#endregion
|
|
2176
|
+
//#region src/utils/regions.ts
|
|
2177
|
+
const REGIONS = {
|
|
2178
|
+
US: "US",
|
|
2179
|
+
EU: "EU",
|
|
2180
|
+
AP: "AP"
|
|
2181
|
+
};
|
|
2182
|
+
const API_URLS = {
|
|
2183
|
+
US: "https://api.buddy.works",
|
|
2184
|
+
EU: "https://api.eu.buddy.works",
|
|
2185
|
+
AP: "https://api.asia.buddy.works"
|
|
2186
|
+
};
|
|
2187
|
+
function getApiUrlFromRegion(region) {
|
|
2188
|
+
return API_URLS[region];
|
|
2189
|
+
}
|
|
2190
|
+
function parseRegion(input) {
|
|
2191
|
+
if (!input) return REGIONS.US;
|
|
2192
|
+
const normalized = input.toUpperCase().trim();
|
|
2193
|
+
if (normalized === "US" || normalized === "EU" || normalized === "AP") return normalized;
|
|
2194
|
+
throw new Error(`Invalid region: "${input}". Valid regions are: US, EU, AP`);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
//#endregion
|
|
2198
|
+
//#region src/utils/client.ts
|
|
2199
|
+
/** Resolve connection config with environment variable fallbacks */
|
|
2200
|
+
function getConfig(connection) {
|
|
2201
|
+
const workspace = connection?.workspace ?? environment_default.BUDDY_WORKSPACE;
|
|
2202
|
+
if (!workspace) throw new Error("Workspace not found. Set workspace in config.connection or BUDDY_WORKSPACE env var.");
|
|
2203
|
+
const project = connection?.project ?? environment_default.BUDDY_PROJECT;
|
|
2204
|
+
if (!project) throw new Error("Project not found. Set project in config.connection or BUDDY_PROJECT env var.");
|
|
2205
|
+
let apiUrl;
|
|
2206
|
+
if (connection?.apiUrl) apiUrl = connection.apiUrl;
|
|
2207
|
+
else if (environment_default.BUDDY_API_URL) apiUrl = environment_default.BUDDY_API_URL;
|
|
2208
|
+
else if (connection?.region) apiUrl = getApiUrlFromRegion(parseRegion(connection.region));
|
|
2209
|
+
else if (environment_default.BUDDY_REGION) apiUrl = getApiUrlFromRegion(parseRegion(environment_default.BUDDY_REGION));
|
|
2210
|
+
else apiUrl = API_URLS.US;
|
|
2211
|
+
return {
|
|
2212
|
+
workspace,
|
|
2213
|
+
projectName: project,
|
|
2214
|
+
token: connection?.token,
|
|
2215
|
+
apiUrl
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
/** Create a BuddyApiClient from connection config */
|
|
2219
|
+
function createClient(connection) {
|
|
2220
|
+
const { workspace, projectName, token, apiUrl } = getConfig(connection);
|
|
2221
|
+
return new BuddyApiClient({
|
|
2222
|
+
workspace,
|
|
2223
|
+
project_name: projectName,
|
|
2224
|
+
apiUrl,
|
|
2225
|
+
...token ? { token } : {}
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
//#endregion
|
|
2230
|
+
//#region src/entity/filesystem.ts
|
|
2231
|
+
/**
|
|
2232
|
+
* Provides file system operations within a Sandbox.
|
|
2233
|
+
*
|
|
2234
|
+
* FileSystem instances can be created either direct via `FileSystem.forSandbox()`
|
|
2235
|
+
* or accessed via the `Sandbox.fs` property.
|
|
2236
|
+
*/
|
|
2237
|
+
var FileSystem = class FileSystem {
|
|
2238
|
+
#client;
|
|
2239
|
+
#sandboxId;
|
|
2240
|
+
/**
|
|
2241
|
+
* Create a FileSystem instance for a specific sandbox.
|
|
2242
|
+
*
|
|
2243
|
+
* @param sandboxId - The ID of the sandbox
|
|
2244
|
+
* @param config - Optional configuration including connection settings
|
|
2245
|
+
* @returns A FileSystem instance for the specified sandbox
|
|
2246
|
+
*/
|
|
2247
|
+
static forSandbox(sandboxId, config) {
|
|
2248
|
+
return new FileSystem(createClient(config?.connection), sandboxId);
|
|
2249
|
+
}
|
|
2250
|
+
constructor(client, sandboxId) {
|
|
2251
|
+
this.#client = client;
|
|
2252
|
+
this.#sandboxId = sandboxId;
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Lists contents of a directory in the Sandbox.
|
|
2256
|
+
*
|
|
2257
|
+
* @param dirPath - Directory path to list. Relative paths are resolved based on the sandbox working directory.
|
|
2258
|
+
* @returns Array of file and directory information
|
|
2259
|
+
*/
|
|
2260
|
+
async listFiles(dirPath) {
|
|
2261
|
+
return withErrorHandler("Failed to list files", async () => {
|
|
2262
|
+
return ((await this.#client.getSandboxContent({ path: {
|
|
2263
|
+
sandbox_id: this.#sandboxId,
|
|
2264
|
+
path: this.#normalizePath(dirPath)
|
|
2265
|
+
} })).contents ?? []).map((item) => this.#mapContentItemToFileInfo(item));
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Create a new directory in the Sandbox.
|
|
2270
|
+
*
|
|
2271
|
+
* @param dirPath - Path where the directory should be created
|
|
2272
|
+
*/
|
|
2273
|
+
async createFolder(dirPath) {
|
|
2274
|
+
return withErrorHandler("Failed to create folder", async () => {
|
|
2275
|
+
await this.#client.createSandboxDirectory({ path: {
|
|
2276
|
+
sandbox_id: this.#sandboxId,
|
|
2277
|
+
path: this.#normalizePath(dirPath)
|
|
2278
|
+
} });
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* Deletes a file or directory from the Sandbox.
|
|
2283
|
+
*
|
|
2284
|
+
* @param filePath - Path to the file or directory to delete
|
|
2285
|
+
*/
|
|
2286
|
+
async deleteFile(filePath) {
|
|
2287
|
+
return withErrorHandler("Failed to delete file", async () => {
|
|
2288
|
+
await this.#client.deleteSandboxFile({ path: {
|
|
2289
|
+
sandbox_id: this.#sandboxId,
|
|
2290
|
+
path: this.#normalizePath(filePath)
|
|
2291
|
+
} });
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
/**
|
|
2295
|
+
* Downloads a file from the Sandbox.
|
|
2296
|
+
*
|
|
2297
|
+
* @param remotePath - Path to the file in the Sandbox
|
|
2298
|
+
* @param localPath - Optional local path to save the file
|
|
2299
|
+
* @returns File contents as a Buffer
|
|
2300
|
+
*/
|
|
2301
|
+
async downloadFile(remotePath, localPath) {
|
|
2302
|
+
return withErrorHandler("Failed to download file", async () => {
|
|
2303
|
+
const { data } = await this.#client.downloadSandboxContent({ path: {
|
|
2304
|
+
sandbox_id: this.#sandboxId,
|
|
2305
|
+
path: this.#normalizePath(remotePath)
|
|
2306
|
+
} });
|
|
2307
|
+
const buffer = Buffer.from(data);
|
|
2308
|
+
if (localPath) await fs.promises.writeFile(localPath, buffer);
|
|
2309
|
+
return buffer;
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Uploads a file to the Sandbox.
|
|
2314
|
+
*
|
|
2315
|
+
* @param source - Buffer with content or path to local file
|
|
2316
|
+
* @param remotePath - Destination path in the Sandbox
|
|
2317
|
+
*/
|
|
2318
|
+
async uploadFile(source, remotePath) {
|
|
2319
|
+
return withErrorHandler("Failed to upload file", async () => {
|
|
2320
|
+
let blob;
|
|
2321
|
+
if (Buffer.isBuffer(source)) blob = new Blob([source]);
|
|
2322
|
+
else {
|
|
2323
|
+
const fileContent = await fs.promises.readFile(source);
|
|
2324
|
+
blob = new Blob([fileContent]);
|
|
2325
|
+
}
|
|
2326
|
+
await this.#client.uploadSandboxFile({
|
|
2327
|
+
body: blob,
|
|
2328
|
+
path: {
|
|
2329
|
+
sandbox_id: this.#sandboxId,
|
|
2330
|
+
path: this.#normalizePath(remotePath)
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
});
|
|
2334
|
+
}
|
|
2335
|
+
#mapContentItemToFileInfo(item) {
|
|
2336
|
+
return {
|
|
2337
|
+
name: item.name ?? "",
|
|
2338
|
+
path: item.path ?? "",
|
|
2339
|
+
type: item.type ?? "FILE",
|
|
2340
|
+
size: item.size,
|
|
2341
|
+
url: item.url,
|
|
2342
|
+
htmlUrl: item.html_url
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* Normalize path for API calls - strip leading slash.
|
|
2347
|
+
* API expects: "buddy/src" not "/buddy/src"
|
|
2348
|
+
*/
|
|
2349
|
+
#normalizePath(filePath) {
|
|
2350
|
+
return filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
2351
|
+
}
|
|
2352
|
+
};
|
|
2353
|
+
|
|
2354
|
+
//#endregion
|
|
2355
|
+
//#region src/entity/sandbox.ts
|
|
2356
|
+
const PRIVATE_CONSTRUCTOR_KEY = Symbol("SandboxConstructor");
|
|
2357
|
+
const INITIALIZE_INSTRUCTIONS = "Use Sandbox.create(), Sandbox.getById(), or Sandbox.getByIdentifier() to obtain an instance.";
|
|
2358
|
+
var Sandbox = class Sandbox {
|
|
2359
|
+
#sandboxData;
|
|
2360
|
+
#client;
|
|
2361
|
+
#fs;
|
|
2362
|
+
/** The raw sandbox response data from the API */
|
|
2363
|
+
get data() {
|
|
2364
|
+
return this.#sandboxData ?? {};
|
|
2365
|
+
}
|
|
2366
|
+
/** The sandbox ID, throws if not initialized */
|
|
2367
|
+
get initializedId() {
|
|
2368
|
+
const id = this.#sandboxData?.id;
|
|
2369
|
+
if (!id) throw new Error(`Sandbox ID is missing. The sandbox may have been deleted or not properly initialized. ${INITIALIZE_INSTRUCTIONS}`);
|
|
2370
|
+
return id;
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* File system operations for this sandbox.
|
|
2374
|
+
* Provides methods for listing, uploading, downloading, and managing files.
|
|
2375
|
+
*/
|
|
2376
|
+
get fs() {
|
|
2377
|
+
const sandboxId = this.initializedId;
|
|
2378
|
+
if (!this.#fs) this.#fs = new FileSystem(this.#client, sandboxId);
|
|
2379
|
+
return this.#fs;
|
|
2380
|
+
}
|
|
2381
|
+
/**
|
|
2382
|
+
* Create a new sandbox
|
|
2383
|
+
* @param config - Sandbox configuration including identifier, name, os, and optional connection settings
|
|
2384
|
+
* @returns A ready-to-use Sandbox instance
|
|
2385
|
+
*/
|
|
2386
|
+
static async create(config) {
|
|
2387
|
+
return withErrorHandler("Failed to create sandbox", async () => {
|
|
2388
|
+
const { connection, ...sandboxConfig } = config ?? {};
|
|
2389
|
+
const client = createClient(connection);
|
|
2390
|
+
const requestBody = {
|
|
2391
|
+
name: `Sandbox ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
2392
|
+
identifier: config?.identifier || `sandbox_${String(Date.now())}`,
|
|
2393
|
+
os: "ubuntu:24.04",
|
|
2394
|
+
...sandboxConfig
|
|
2395
|
+
};
|
|
2396
|
+
const sandbox = new Sandbox(await client.addSandbox({ body: requestBody }), client, PRIVATE_CONSTRUCTOR_KEY);
|
|
2397
|
+
logger_default.debug(`Waiting for sandbox ${sandbox.data.id} to be ready...`);
|
|
2398
|
+
await sandbox.waitUntilReady();
|
|
2399
|
+
logger_default.debug(`Sandbox ${sandbox.data.id} is ready (Setup status: ${sandbox.data.setup_status})`);
|
|
2400
|
+
return sandbox;
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2404
|
+
* Get an existing sandbox by its identifier
|
|
2405
|
+
* @param identifier - Identifier of the sandbox to retrieve
|
|
2406
|
+
* @param config - Optional configuration including connection settings
|
|
2407
|
+
* @returns The Sandbox instance
|
|
2408
|
+
*/
|
|
2409
|
+
static async getByIdentifier(identifier, config) {
|
|
2410
|
+
return withErrorHandler("Failed to get sandbox by identifier", async () => {
|
|
2411
|
+
const { connection } = config ?? {};
|
|
2412
|
+
const client = createClient(connection);
|
|
2413
|
+
const sandboxId = ((await client.getSandboxes({}))?.sandboxes ?? []).find((s) => s.identifier === identifier)?.id;
|
|
2414
|
+
if (!sandboxId) throw new Error(`Sandbox with identifier '${identifier}' not found`);
|
|
2415
|
+
const sandboxResponse = await client.getSandboxById({ path: { id: sandboxId } });
|
|
2416
|
+
if (!sandboxResponse) throw new Error(`Sandbox with ID '${sandboxId}' not found`);
|
|
2417
|
+
return new Sandbox(sandboxResponse, client, PRIVATE_CONSTRUCTOR_KEY);
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Get an existing sandbox by its ID
|
|
2422
|
+
* @param sandboxId - ID of the sandbox to retrieve
|
|
2423
|
+
* @param config - Optional configuration including connection settings
|
|
2424
|
+
* @returns The Sandbox instance
|
|
2425
|
+
*/
|
|
2426
|
+
static async getById(sandboxId, config) {
|
|
2427
|
+
return withErrorHandler("Failed to get sandbox", async () => {
|
|
2428
|
+
const { connection } = config ?? {};
|
|
2429
|
+
const client = createClient(connection);
|
|
2430
|
+
const sandboxResponse = await client.getSandboxById({ path: { id: sandboxId } });
|
|
2431
|
+
if (!sandboxResponse) throw new Error(`Sandbox with ID '${sandboxId}' not found`);
|
|
2432
|
+
return new Sandbox(sandboxResponse, client, PRIVATE_CONSTRUCTOR_KEY);
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* List all sandboxes in the workspace
|
|
2437
|
+
*
|
|
2438
|
+
* Returns a simplified view of each sandbox (id, identifier, name, status, urls)
|
|
2439
|
+
* rather than full Sandbox instances. Use `getById()` or `getByIdentifier()`
|
|
2440
|
+
* to get a full Sandbox instance for a specific sandbox.
|
|
2441
|
+
*
|
|
2442
|
+
* @param config - Optional configuration including connection settings
|
|
2443
|
+
* @returns Array of simplified sandbox objects
|
|
2444
|
+
*/
|
|
2445
|
+
static async list(config) {
|
|
2446
|
+
return withErrorHandler("Failed to list sandboxes", async () => {
|
|
2447
|
+
const { connection } = config ?? {};
|
|
2448
|
+
return (await createClient(connection).getSandboxes({}))?.sandboxes ?? [];
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Execute a command in the sandbox
|
|
2453
|
+
* @returns Command instance (call wait() for blocking execution)
|
|
2454
|
+
*/
|
|
2455
|
+
async runCommand(options) {
|
|
2456
|
+
const sandboxId = this.initializedId;
|
|
2457
|
+
return withErrorHandler("Failed to run command", async () => {
|
|
2458
|
+
const { stdout, stderr, detached, ...commandRequest } = options;
|
|
2459
|
+
const outputStdout = stdout === null ? null : stdout ?? process.stdout;
|
|
2460
|
+
const outputStderr = stderr === null ? null : stderr ?? process.stderr;
|
|
2461
|
+
logger_default.debug(`Executing command: $ ${commandRequest.command}`);
|
|
2462
|
+
const command = new Command({
|
|
2463
|
+
commandResponse: await this.#client.executeCommand({
|
|
2464
|
+
body: commandRequest,
|
|
2465
|
+
path: { sandbox_id: sandboxId }
|
|
2466
|
+
}),
|
|
2467
|
+
client: this.#client,
|
|
2468
|
+
sandboxId
|
|
2469
|
+
});
|
|
2470
|
+
const streamingPromise = outputStdout || outputStderr ? await (async () => {
|
|
2471
|
+
for await (const log of command.logs({ follow: true })) {
|
|
2472
|
+
const output = `${log.data ?? ""}\n`;
|
|
2473
|
+
if (log.type === "STDOUT" && outputStdout) outputStdout.write(output);
|
|
2474
|
+
else if (log.type === "STDERR" && outputStderr) outputStderr.write(output);
|
|
2475
|
+
}
|
|
2476
|
+
})() : Promise.resolve();
|
|
2477
|
+
if (detached) return command;
|
|
2478
|
+
const [finishedCommand] = await Promise.all([command.wait(), streamingPromise]);
|
|
2479
|
+
return finishedCommand;
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Delete the sandbox permanently
|
|
2484
|
+
*/
|
|
2485
|
+
async destroy() {
|
|
2486
|
+
const sandboxId = this.initializedId;
|
|
2487
|
+
return withErrorHandler("Failed to destroy sandbox", async () => {
|
|
2488
|
+
await this.#client.deleteSandboxById({ path: { id: sandboxId } });
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Refresh the sandbox data from the API
|
|
2493
|
+
* Updates the internal state with the latest sandbox information
|
|
2494
|
+
*/
|
|
2495
|
+
async refresh() {
|
|
2496
|
+
const sandboxId = this.initializedId;
|
|
2497
|
+
return withErrorHandler("Failed to refresh sandbox", async () => {
|
|
2498
|
+
this.#sandboxData = await this.#client.getSandboxById({ path: { id: sandboxId } });
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Wait until the sandbox setup is complete
|
|
2503
|
+
* @param pollIntervalMs - How often to check the status (default: 1000ms)
|
|
2504
|
+
*/
|
|
2505
|
+
async waitUntilReady(pollIntervalMs = 1e3) {
|
|
2506
|
+
const sandboxId = this.initializedId;
|
|
2507
|
+
return withErrorHandler("Sandbox not ready", async () => {
|
|
2508
|
+
while (true) {
|
|
2509
|
+
await this.refresh();
|
|
2510
|
+
if (this.data.setup_status === "SUCCESS") return;
|
|
2511
|
+
if (this.data.setup_status === "FAILED") throw new Error(`Sandbox ${sandboxId} setup failed. Status: ${this.data.setup_status}`);
|
|
2512
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2513
|
+
}
|
|
2514
|
+
});
|
|
2515
|
+
}
|
|
2516
|
+
/**
|
|
2517
|
+
* Wait until the sandbox is in RUNNING state
|
|
2518
|
+
* @param pollIntervalMs - How often to check the status (default: 1000ms)
|
|
2519
|
+
* @param maxWaitMs - Maximum time to wait before timing out (default: 60000ms)
|
|
2520
|
+
*/
|
|
2521
|
+
async waitUntilRunning(pollIntervalMs = 1e3, maxWaitMs = 6e4) {
|
|
2522
|
+
const sandboxId = this.initializedId;
|
|
2523
|
+
return withErrorHandler("Sandbox not running", async () => {
|
|
2524
|
+
const startTime = Date.now();
|
|
2525
|
+
while (true) {
|
|
2526
|
+
await this.refresh();
|
|
2527
|
+
if (this.data.status === "RUNNING") return;
|
|
2528
|
+
if (this.data.status === "FAILED") throw new Error(`Sandbox ${sandboxId} failed. Status: ${this.data.status}`);
|
|
2529
|
+
if (Date.now() - startTime > maxWaitMs) throw new Error(`Timeout waiting for sandbox ${sandboxId} to be RUNNING. Current: ${this.data.status}`);
|
|
2530
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2531
|
+
}
|
|
2532
|
+
});
|
|
2533
|
+
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Wait until the sandbox is in STOPPED state
|
|
2536
|
+
* @param pollIntervalMs - How often to check the status (default: 1000ms)
|
|
2537
|
+
* @param maxWaitMs - Maximum time to wait before timing out (default: 60000ms)
|
|
2538
|
+
*/
|
|
2539
|
+
async waitUntilStopped(pollIntervalMs = 1e3, maxWaitMs = 6e4) {
|
|
2540
|
+
const sandboxId = this.initializedId;
|
|
2541
|
+
return withErrorHandler("Sandbox not stopped", async () => {
|
|
2542
|
+
const startTime = Date.now();
|
|
2543
|
+
while (true) {
|
|
2544
|
+
await this.refresh();
|
|
2545
|
+
if (this.data.status === "STOPPED") return;
|
|
2546
|
+
if (this.data.status === "FAILED") throw new Error(`Sandbox ${sandboxId} failed. Status: ${this.data.status}`);
|
|
2547
|
+
if (Date.now() - startTime > maxWaitMs) throw new Error(`Timeout waiting for sandbox ${sandboxId} to be STOPPED. Current: ${this.data.status}`);
|
|
2548
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
2549
|
+
}
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2552
|
+
/**
|
|
2553
|
+
* Start a stopped sandbox
|
|
2554
|
+
* Waits until the sandbox reaches RUNNING state
|
|
2555
|
+
*/
|
|
2556
|
+
async start() {
|
|
2557
|
+
const sandboxId = this.initializedId;
|
|
2558
|
+
return withErrorHandler("Failed to start sandbox", async () => {
|
|
2559
|
+
logger_default.debug(`Starting sandbox ${sandboxId}...`);
|
|
2560
|
+
this.#sandboxData = await this.#client.startSandbox({ path: { sandbox_id: sandboxId } });
|
|
2561
|
+
await this.waitUntilRunning();
|
|
2562
|
+
logger_default.debug(`Sandbox ${sandboxId} is now running. Status: ${this.data.status}`);
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
/**
|
|
2566
|
+
* Stop a running sandbox
|
|
2567
|
+
* Waits until the sandbox reaches STOPPED state
|
|
2568
|
+
*/
|
|
2569
|
+
async stop() {
|
|
2570
|
+
const sandboxId = this.initializedId;
|
|
2571
|
+
return withErrorHandler("Failed to stop sandbox", async () => {
|
|
2572
|
+
logger_default.debug(`Stopping sandbox ${sandboxId}...`);
|
|
2573
|
+
this.#sandboxData = await this.#client.stopSandbox({ path: { sandbox_id: sandboxId } });
|
|
2574
|
+
await this.waitUntilStopped();
|
|
2575
|
+
logger_default.debug(`Sandbox ${sandboxId} is now stopped. Status: ${this.data.status}`);
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
/**
|
|
2579
|
+
* Restart the sandbox
|
|
2580
|
+
* Waits until the sandbox reaches RUNNING state and setup is complete
|
|
2581
|
+
*/
|
|
2582
|
+
async restart() {
|
|
2583
|
+
const sandboxId = this.initializedId;
|
|
2584
|
+
return withErrorHandler("Failed to restart sandbox", async () => {
|
|
2585
|
+
logger_default.debug(`Restarting sandbox ${sandboxId}...`);
|
|
2586
|
+
this.#sandboxData = await this.#client.restartSandbox({ path: { sandbox_id: sandboxId } });
|
|
2587
|
+
await this.waitUntilRunning();
|
|
2588
|
+
await this.waitUntilReady();
|
|
2589
|
+
logger_default.debug(`Sandbox ${sandboxId} has been restarted and is ready. Status: ${this.data.status}, Setup status: ${this.data.setup_status}`);
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
constructor(sandboxData, client, constructorKey) {
|
|
2593
|
+
if (constructorKey !== PRIVATE_CONSTRUCTOR_KEY) throw new Error(`Cannot construct Sandbox directly. ${INITIALIZE_INSTRUCTIONS}`);
|
|
2594
|
+
this.#sandboxData = sandboxData;
|
|
2595
|
+
this.#client = client;
|
|
2596
|
+
}
|
|
2597
|
+
};
|
|
2598
|
+
|
|
2599
|
+
//#endregion
|
|
2600
|
+
export { API_URLS, BuddyApiClient, BuddySDKError, Command, ERROR_CODES, FileSystem, REGIONS, Sandbox };
|