@miosa/sdk 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ import { performAction, pngSize, toBase64 } from './chunk-H245ZDMW.js';
2
+ export { ACTION_NAMES, InvalidActionInputError, performAction, pngSize } from './chunk-H245ZDMW.js';
3
+ import { __require, NotFoundError, MiosaError, TimeoutError, NetworkError, InvalidSetupFileError } from './chunk-BMWUKYWU.js';
4
+ export { AmbiguousOrgError, AuthError, BillToForbiddenError, BillToLockedError, BillToSuspendedError, ChatBusyError, ComputerStartingError, CreditRequiredError, EgressHostNotAllowedError, EnvironmentIsDefaultError, EnvironmentMemoryWithheldError, EnvironmentNameTakenError, EnvironmentNotFoundError, EnvironmentScrubFailedError, InstallationRequiredError, InsufficientCreditsError, InvalidIdError, InvalidSetupFileError, MachineKeyScopeError, MachineStartingError, ManagedProviderBindingOnlyError, MemberLimitReachedError, MiosaError, NetworkError, NoAgentRunError, NoReadyMachineError, NotFoundError, OrgNotFoundError, OwnCredentialsRequiredError, ProjectNotLinkedError, RateLimitError, RunSessionNotResumableError, SandboxStartingError, ScopeNotAllowedError, SnapshotInUseError, SubjectNotAllowedError, TeamMemberCapReachedError, TimeoutError, TokenRefreshFailedError, UnknownEnvironmentError, UserAuthorizationRequiredError, ValidationError } from './chunk-BMWUKYWU.js';
1
5
  import EventEmitter from 'events';
2
6
  import { createHmac, timingSafeEqual, randomUUID } from 'crypto';
3
7
  import { isIP } from 'net';
@@ -5,457 +9,8 @@ import { lookup } from 'dns/promises';
5
9
  import * as http2 from 'http2';
6
10
  import { createRequire } from 'module';
7
11
 
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined") return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
-
15
- // src/errors.ts
16
- function defaultRetryable(status) {
17
- return status === 408 || status === 429 || status >= 500;
18
- }
19
- var MiosaError = class _MiosaError extends Error {
20
- status;
21
- code;
22
- details;
23
- requestId;
24
- retryable;
25
- /**
26
- * Server-supplied retry hint in milliseconds, taken from the canonical
27
- * error shape's `retry_after_ms` (nested under `error` or top-level) or,
28
- * failing that, the HTTP `Retry-After` header. `undefined` when the
29
- * response carried neither, in which case a caller should fall back to
30
- * its own backoff policy.
31
- */
32
- retryAfterMs;
33
- constructor(message, status, code, details, requestId, retryable = defaultRetryable(status), retryAfterMs2) {
34
- super(message);
35
- this.name = "MiosaError";
36
- this.status = status;
37
- this.code = code;
38
- this.details = details;
39
- this.requestId = requestId;
40
- this.retryable = retryable;
41
- this.retryAfterMs = retryAfterMs2;
42
- }
43
- /**
44
- * @param retryAfterHeaderMs The `Retry-After` header value, already
45
- * converted to milliseconds by the caller. Used only when the body does
46
- * not carry the more precise `retry_after_ms`.
47
- */
48
- static fromResponse(status, body5, requestId, retryAfterHeaderMs2) {
49
- const nested = typeof body5.error === "object" ? body5.error : void 0;
50
- const flatError = typeof body5.error === "string" ? body5.error : void 0;
51
- const flatErrorIsCode = !!flatError && (/^[A-Z][A-Z0-9_]+$/.test(flatError) || /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(flatError));
52
- const message = nested?.message ?? body5.message ?? body5.detail ?? body5.reason ?? flatError ?? `HTTP ${status}`;
53
- const code = nested?.code ?? body5.code ?? (flatErrorIsCode ? flatError : "UNKNOWN_ERROR");
54
- const details = nested?.details ?? body5.details ?? (body5.detail || body5.reason ? { detail: body5.detail, reason: body5.reason } : void 0) ?? extraFields(body5, nested);
55
- requestId ??= nested?.request_id ?? body5.request_id;
56
- const retryable = nested?.retryable ?? body5.retryable ?? RETRYABLE_BY_CODE[code] ?? defaultRetryable(status);
57
- const retryAfterMs2 = nested?.retry_after_ms ?? body5.retry_after_ms ?? retryAfterHeaderMs2;
58
- const connectError = connectErrorFromCode(code, message, status, details, requestId, retryable) ?? typedErrorFromCode(code, message, status, details, requestId, retryable, retryAfterMs2);
59
- const built = connectError ?? (status === 401 || status === 403 ? new AuthError(message, status, code, details, requestId, retryable) : status === 404 ? new NotFoundError(message, code, details, requestId, retryable) : status === 429 ? new RateLimitError(
60
- message,
61
- details,
62
- requestId,
63
- retryAfterMs2 === void 0 ? void 0 : retryAfterMs2 / 1e3,
64
- retryable,
65
- // Keep the server's own code (SERVICE_ACCOUNT_LIMIT, ...) when it sent one.
66
- code === "UNKNOWN_ERROR" ? "RATE_LIMITED" : code
67
- ) : status === 402 ? new InsufficientCreditsError(
68
- message,
69
- details,
70
- requestId,
71
- retryable,
72
- code === "UNKNOWN_ERROR" ? "INSUFFICIENT_CREDITS" : code
73
- ) : status >= 400 && status < 500 ? new ValidationError(message, status, code, details, requestId, retryable) : new _MiosaError(message, status, code, details, requestId, retryable));
74
- built.retryAfterMs = retryAfterMs2;
75
- return built;
76
- }
77
- };
78
- var ENVELOPE_KEYS = /* @__PURE__ */ new Set([
79
- "error",
80
- "message",
81
- "code",
82
- "detail",
83
- "details",
84
- "reason",
85
- "request_id",
86
- "retryable",
87
- "retry_after_ms",
88
- "ok",
89
- "success",
90
- "status"
91
- ]);
92
- var NESTED_KEYS = /* @__PURE__ */ new Set(["code", "message", "details", "retryable", "request_id", "retry_after_ms"]);
93
- function extraFields(body5, nested) {
94
- const extras = {};
95
- for (const [key, value] of Object.entries(body5)) {
96
- if (!ENVELOPE_KEYS.has(key)) extras[key] = value;
97
- }
98
- if (nested) {
99
- for (const [key, value] of Object.entries(nested)) {
100
- if (!NESTED_KEYS.has(key)) extras[key] = value;
101
- }
102
- }
103
- return Object.keys(extras).length > 0 ? extras : void 0;
104
- }
105
- function connectErrorFromCode(code, message, status, details, requestId, retryable) {
106
- switch (code) {
107
- case "PROJECT_NOT_LINKED":
108
- return new ProjectNotLinkedError(message, status, details, requestId, retryable);
109
- case "SUBJECT_NOT_ALLOWED":
110
- return new SubjectNotAllowedError(message, status, details, requestId, retryable);
111
- case "SCOPE_NOT_ALLOWED":
112
- return new ScopeNotAllowedError(message, status, details, requestId, retryable);
113
- case "MANAGED_PROVIDER_BINDING_ONLY":
114
- return new ManagedProviderBindingOnlyError(message, status, details, requestId, retryable);
115
- case "INSTALLATION_REQUIRED":
116
- return new InstallationRequiredError(message, status, details, requestId, retryable);
117
- case "USER_AUTHORIZATION_REQUIRED":
118
- return new UserAuthorizationRequiredError(message, status, details, requestId, retryable);
119
- case "EGRESS_HOST_NOT_ALLOWED":
120
- return new EgressHostNotAllowedError(message, status, details, requestId, retryable);
121
- case "TOKEN_REFRESH_FAILED":
122
- return new TokenRefreshFailedError(message, status, details, requestId, retryable);
123
- default:
124
- return void 0;
125
- }
126
- }
127
- var AuthError = class extends MiosaError {
128
- constructor(message, status = 401, code = "UNAUTHORIZED", details, requestId, retryable) {
129
- super(message, status, code, details, requestId, retryable);
130
- this.name = "AuthError";
131
- }
132
- };
133
- var NotFoundError = class extends MiosaError {
134
- constructor(message, code = "NOT_FOUND", details, requestId, retryable) {
135
- super(message, 404, code, details, requestId, retryable);
136
- this.name = "NotFoundError";
137
- }
138
- };
139
- var RateLimitError = class extends MiosaError {
140
- retryAfter;
141
- constructor(message, details, requestId, retryAfter, retryable, code = "RATE_LIMITED") {
142
- super(message, 429, code, details, requestId, retryable);
143
- this.name = "RateLimitError";
144
- this.retryAfter = retryAfter;
145
- }
146
- };
147
- var InsufficientCreditsError = class extends MiosaError {
148
- constructor(message, details, requestId, retryable, code = "INSUFFICIENT_CREDITS") {
149
- super(message, 402, code, details, requestId, retryable);
150
- this.name = "InsufficientCreditsError";
151
- }
152
- };
153
- var ValidationError = class extends MiosaError {
154
- constructor(message, status, code = "VALIDATION_ERROR", details, requestId, retryable) {
155
- super(message, status, code, details, requestId, retryable);
156
- this.name = "ValidationError";
157
- }
158
- };
159
- var TimeoutError = class extends MiosaError {
160
- constructor(message = "Request timed out") {
161
- super(message, 408, "TIMEOUT", void 0, void 0, true);
162
- this.name = "TimeoutError";
163
- }
164
- };
165
- var NetworkError = class extends MiosaError {
166
- cause;
167
- constructor(message, cause) {
168
- super(message, 0, "NETWORK_ERROR", void 0, void 0, true);
169
- this.name = "NetworkError";
170
- this.cause = cause;
171
- }
172
- };
173
- var ProjectNotLinkedError = class extends MiosaError {
174
- constructor(message, status = 403, details, requestId, retryable) {
175
- super(message, status, "PROJECT_NOT_LINKED", details, requestId, retryable);
176
- this.name = "ProjectNotLinkedError";
177
- }
178
- };
179
- var SubjectNotAllowedError = class extends MiosaError {
180
- constructor(message, status = 403, details, requestId, retryable) {
181
- super(message, status, "SUBJECT_NOT_ALLOWED", details, requestId, retryable);
182
- this.name = "SubjectNotAllowedError";
183
- }
184
- };
185
- var ScopeNotAllowedError = class extends MiosaError {
186
- constructor(message, status = 403, details, requestId, retryable) {
187
- super(message, status, "SCOPE_NOT_ALLOWED", details, requestId, retryable);
188
- this.name = "ScopeNotAllowedError";
189
- }
190
- };
191
- var ManagedProviderBindingOnlyError = class extends MiosaError {
192
- constructor(message, status = 403, details, requestId, retryable) {
193
- super(message, status, "MANAGED_PROVIDER_BINDING_ONLY", details, requestId, retryable);
194
- this.name = "ManagedProviderBindingOnlyError";
195
- }
196
- };
197
- var InstallationRequiredError = class extends MiosaError {
198
- constructor(message, status = 409, details, requestId, retryable) {
199
- super(message, status, "INSTALLATION_REQUIRED", details, requestId, retryable);
200
- this.name = "InstallationRequiredError";
201
- }
202
- };
203
- var UserAuthorizationRequiredError = class extends MiosaError {
204
- constructor(message, status = 403, details, requestId, retryable) {
205
- super(message, status, "USER_AUTHORIZATION_REQUIRED", details, requestId, retryable);
206
- this.name = "UserAuthorizationRequiredError";
207
- }
208
- };
209
- var EgressHostNotAllowedError = class extends MiosaError {
210
- constructor(message, status = 403, details, requestId, retryable) {
211
- super(message, status, "EGRESS_HOST_NOT_ALLOWED", details, requestId, retryable);
212
- this.name = "EgressHostNotAllowedError";
213
- }
214
- };
215
- var TokenRefreshFailedError = class extends MiosaError {
216
- constructor(message, status = 502, details, requestId, retryable) {
217
- super(message, status, "TOKEN_REFRESH_FAILED", details, requestId, retryable);
218
- this.name = "TokenRefreshFailedError";
219
- }
220
- };
221
- var RETRYABLE_BY_CODE = {
222
- SANDBOX_STARTING: true,
223
- COMPUTER_STARTING: true,
224
- ENVIRONMENT_SCRUB_FAILED: true,
225
- CHAT_BUSY: true,
226
- ENVIRONMENT_MEMORY_WITHHELD: false,
227
- NO_AGENT_RUN: false,
228
- MEMBER_LIMIT_REACHED: false
229
- };
230
- var InvalidIdError = class extends ValidationError {
231
- constructor(message, status = 400, details, requestId, retryable) {
232
- super(message, status, "INVALID_ID", details, requestId, retryable);
233
- this.name = "InvalidIdError";
234
- }
235
- };
236
- var OwnCredentialsRequiredError = class extends ValidationError {
237
- constructor(message, status = 422, details, requestId, retryable) {
238
- super(message, status, "OWN_CREDENTIALS_REQUIRED", details, requestId, retryable);
239
- this.name = "OwnCredentialsRequiredError";
240
- }
241
- };
242
- var EnvironmentNotFoundError = class extends NotFoundError {
243
- constructor(message, details, requestId, retryable) {
244
- super(message, "ENVIRONMENT_NOT_FOUND", details, requestId, retryable);
245
- this.name = "EnvironmentNotFoundError";
246
- }
247
- };
248
- var UnknownEnvironmentError = class extends ValidationError {
249
- constructor(message, status = 422, details, requestId, retryable) {
250
- super(message, status, "ENVIRONMENT_NOT_FOUND", details, requestId, retryable);
251
- this.name = "UnknownEnvironmentError";
252
- }
253
- };
254
- var EnvironmentNameTakenError = class extends ValidationError {
255
- constructor(message, status = 409, details, requestId, retryable) {
256
- super(message, status, "ENVIRONMENT_NAME_TAKEN", details, requestId, retryable);
257
- this.name = "EnvironmentNameTakenError";
258
- }
259
- };
260
- var EnvironmentIsDefaultError = class extends ValidationError {
261
- constructor(message, status = 409, details, requestId, retryable) {
262
- super(message, status, "ENVIRONMENT_IS_DEFAULT", details, requestId, retryable);
263
- this.name = "EnvironmentIsDefaultError";
264
- }
265
- };
266
- var EnvironmentScrubFailedError = class extends ValidationError {
267
- constructor(message, status = 409, details, requestId, retryable = true) {
268
- super(message, status, "ENVIRONMENT_SCRUB_FAILED", details, requestId, retryable);
269
- this.name = "EnvironmentScrubFailedError";
270
- }
271
- };
272
- var EnvironmentMemoryWithheldError = class extends ValidationError {
273
- constructor(message, status = 409, details, requestId, retryable = false) {
274
- super(message, status, "ENVIRONMENT_MEMORY_WITHHELD", details, requestId, retryable);
275
- this.name = "EnvironmentMemoryWithheldError";
276
- }
277
- /** `details.reasons`: why the memory was withheld. Empty when absent. */
278
- get reasons() {
279
- const reasons = this.details?.reasons;
280
- return Array.isArray(reasons) ? reasons.filter((r) => typeof r === "string") : [];
281
- }
282
- };
283
- var MachineKeyScopeError = class extends AuthError {
284
- constructor(message, status = 403, details, requestId, retryable) {
285
- super(message, status, "MACHINE_KEY_SCOPE", details, requestId, retryable);
286
- this.name = "MachineKeyScopeError";
287
- }
288
- };
289
- var MachineStartingError = class extends ValidationError {
290
- constructor(message, status = 409, code = "SANDBOX_STARTING", details, requestId, retryable = true) {
291
- super(message, status, code, details, requestId, retryable);
292
- this.name = "MachineStartingError";
293
- }
294
- };
295
- var SandboxStartingError = class extends MachineStartingError {
296
- constructor(message, status = 409, details, requestId, retryable = true) {
297
- super(message, status, "SANDBOX_STARTING", details, requestId, retryable);
298
- this.name = "SandboxStartingError";
299
- }
300
- };
301
- var ComputerStartingError = class extends MachineStartingError {
302
- constructor(message, status = 409, details, requestId, retryable = true) {
303
- super(message, status, "COMPUTER_STARTING", details, requestId, retryable);
304
- this.name = "ComputerStartingError";
305
- }
306
- };
307
- var CreditRequiredError = class extends InsufficientCreditsError {
308
- constructor(message, details, requestId, retryable) {
309
- super(message, details, requestId, retryable, "CREDIT_REQUIRED");
310
- this.name = "CreditRequiredError";
311
- }
312
- };
313
- var TeamMemberCapReachedError = class extends InsufficientCreditsError {
314
- constructor(message, details, requestId, retryable) {
315
- super(message, details, requestId, retryable, "TEAM_MEMBER_CAP_REACHED");
316
- this.name = "TeamMemberCapReachedError";
317
- }
318
- };
319
- var MemberLimitReachedError = class extends RateLimitError {
320
- constructor(message, details, requestId, retryAfter, retryable = false) {
321
- super(message, details, requestId, retryAfter, retryable, "MEMBER_LIMIT_REACHED");
322
- this.name = "MemberLimitReachedError";
323
- }
324
- };
325
- var BillToLockedError = class extends AuthError {
326
- constructor(message, status = 403, details, requestId, retryable) {
327
- super(message, status, "BILL_TO_LOCKED", details, requestId, retryable);
328
- this.name = "BillToLockedError";
329
- }
330
- };
331
- var BillToForbiddenError = class extends AuthError {
332
- constructor(message, status = 403, details, requestId, retryable) {
333
- super(message, status, "BILL_TO_FORBIDDEN", details, requestId, retryable);
334
- this.name = "BillToForbiddenError";
335
- }
336
- };
337
- var BillToSuspendedError = class extends AuthError {
338
- constructor(message, status = 403, details, requestId, retryable) {
339
- super(message, status, "BILL_TO_SUSPENDED", details, requestId, retryable);
340
- this.name = "BillToSuspendedError";
341
- }
342
- };
343
- var OrgNotFoundError = class extends NotFoundError {
344
- constructor(message, details, requestId, retryable) {
345
- super(message, "ORG_NOT_FOUND", details, requestId, retryable);
346
- this.name = "OrgNotFoundError";
347
- }
348
- };
349
- var AmbiguousOrgError = class extends ValidationError {
350
- constructor(message, status = 409, details, requestId, retryable) {
351
- super(message, status, "AMBIGUOUS_ORG", details, requestId, retryable);
352
- this.name = "AmbiguousOrgError";
353
- }
354
- };
355
- var SnapshotInUseError = class extends ValidationError {
356
- constructor(message, status = 409, details, requestId, retryable) {
357
- super(message, status, "SNAPSHOT_IN_USE", details, requestId, retryable);
358
- this.name = "SnapshotInUseError";
359
- }
360
- /** `details.dependents`: every thing that still needs the snapshot's bytes. */
361
- get dependents() {
362
- const dependents = this.details?.dependents;
363
- return Array.isArray(dependents) ? dependents : [];
364
- }
365
- };
366
- var RunSessionNotResumableError = class extends ValidationError {
367
- constructor(message, status = 409, details, requestId, retryable) {
368
- super(message, status, "RUN_SESSION_NOT_RESUMABLE", details, requestId, retryable);
369
- this.name = "RunSessionNotResumableError";
370
- }
371
- get reason() {
372
- const reason = this.details?.reason;
373
- return typeof reason === "string" ? reason : void 0;
374
- }
375
- };
376
- var ChatBusyError = class extends ValidationError {
377
- constructor(message, status = 409, details, requestId, retryable = true) {
378
- super(message, status, "CHAT_BUSY", details, requestId, retryable);
379
- this.name = "ChatBusyError";
380
- }
381
- };
382
- var NoAgentRunError = class extends ValidationError {
383
- constructor(message, status = 409, details, requestId, retryable = false) {
384
- super(message, status, "NO_AGENT_RUN", details, requestId, retryable);
385
- this.name = "NoAgentRunError";
386
- }
387
- };
388
- var InvalidSetupFileError = class extends ValidationError {
389
- constructor(message, status = 422, details, requestId, retryable) {
390
- super(message, status, "INVALID_SETUP_FILE", details, requestId, retryable);
391
- this.name = "InvalidSetupFileError";
392
- }
393
- get reason() {
394
- const reason = this.details?.reason;
395
- return typeof reason === "string" ? reason : void 0;
396
- }
397
- };
398
- function typedErrorFromCode(code, message, status, details, requestId, retryable, retryAfterMs2) {
399
- switch (code) {
400
- case "INVALID_ID":
401
- return new InvalidIdError(message, status, details, requestId, retryable);
402
- case "OWN_CREDENTIALS_REQUIRED":
403
- return new OwnCredentialsRequiredError(message, status, details, requestId, retryable);
404
- case "ENVIRONMENT_NOT_FOUND":
405
- return status === 404 ? new EnvironmentNotFoundError(message, details, requestId, retryable) : new UnknownEnvironmentError(message, status, details, requestId, retryable);
406
- case "ENVIRONMENT_NAME_TAKEN":
407
- return new EnvironmentNameTakenError(message, status, details, requestId, retryable);
408
- case "ENVIRONMENT_IS_DEFAULT":
409
- return new EnvironmentIsDefaultError(message, status, details, requestId, retryable);
410
- case "ENVIRONMENT_SCRUB_FAILED":
411
- return new EnvironmentScrubFailedError(message, status, details, requestId, retryable);
412
- case "ENVIRONMENT_MEMORY_WITHHELD":
413
- return new EnvironmentMemoryWithheldError(message, status, details, requestId, retryable);
414
- case "MACHINE_KEY_SCOPE":
415
- return new MachineKeyScopeError(message, status, details, requestId, retryable);
416
- case "SANDBOX_STARTING":
417
- return new SandboxStartingError(message, status, details, requestId, retryable);
418
- case "COMPUTER_STARTING":
419
- return new ComputerStartingError(message, status, details, requestId, retryable);
420
- case "CREDIT_REQUIRED":
421
- return new CreditRequiredError(message, details, requestId, retryable);
422
- case "TEAM_MEMBER_CAP_REACHED":
423
- return new TeamMemberCapReachedError(message, details, requestId, retryable);
424
- case "MEMBER_LIMIT_REACHED":
425
- return new MemberLimitReachedError(
426
- message,
427
- details,
428
- requestId,
429
- retryAfterMs2 === void 0 ? void 0 : retryAfterMs2 / 1e3,
430
- retryable
431
- );
432
- case "BILL_TO_LOCKED":
433
- return new BillToLockedError(message, status, details, requestId, retryable);
434
- case "BILL_TO_FORBIDDEN":
435
- return new BillToForbiddenError(message, status, details, requestId, retryable);
436
- case "BILL_TO_SUSPENDED":
437
- return new BillToSuspendedError(message, status, details, requestId, retryable);
438
- case "ORG_NOT_FOUND":
439
- return new OrgNotFoundError(message, details, requestId, retryable);
440
- case "AMBIGUOUS_ORG":
441
- return new AmbiguousOrgError(message, status, details, requestId, retryable);
442
- case "SNAPSHOT_IN_USE":
443
- return new SnapshotInUseError(message, status, details, requestId, retryable);
444
- case "RUN_SESSION_NOT_RESUMABLE":
445
- return new RunSessionNotResumableError(message, status, details, requestId, retryable);
446
- case "CHAT_BUSY":
447
- return new ChatBusyError(message, status, details, requestId, retryable);
448
- case "NO_AGENT_RUN":
449
- return new NoAgentRunError(message, status, details, requestId, retryable);
450
- case "INVALID_SETUP_FILE":
451
- return new InvalidSetupFileError(message, status, details, requestId, retryable);
452
- default:
453
- return void 0;
454
- }
455
- }
456
-
457
12
  // src/version.ts
458
- var SDK_VERSION = "3.5.0";
13
+ var SDK_VERSION = "3.6.0";
459
14
  var SDK_USER_AGENT = `@miosa/sdk/${SDK_VERSION}`;
460
15
 
461
16
  // src/http.ts
@@ -561,7 +116,8 @@ var HttpClient = class {
561
116
  fetchBody = JSON.stringify(body5);
562
117
  }
563
118
  let lastError;
564
- const maxRetries = options.maxRetries ?? this.maxRetries;
119
+ const failFast = body5 !== null && typeof body5 === "object" && body5.fail_fast === true;
120
+ const maxRetries = options.maxRetries ?? (failFast ? 0 : this.maxRetries);
565
121
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
566
122
  options.signal?.throwIfAborted();
567
123
  const controller = new AbortController();
@@ -1348,6 +904,13 @@ var Tokens = class {
1348
904
  constructor(http) {
1349
905
  this.scoped = new ScopedTokens(http);
1350
906
  }
907
+ /**
908
+ * The platform-builder path: mint a short-lived token for one end user and
909
+ * hand it to their browser. Same as `tokens.scoped.create()`.
910
+ */
911
+ createScoped(params) {
912
+ return this.scoped.create(params);
913
+ }
1351
914
  };
1352
915
 
1353
916
  // src/resources/governance.ts
@@ -1629,6 +1192,10 @@ var BulkResource = class {
1629
1192
  }
1630
1193
  };
1631
1194
 
1195
+ // src/dispose.ts
1196
+ var symbols = Symbol;
1197
+ symbols.asyncDispose ??= /* @__PURE__ */ Symbol.for("Symbol.asyncDispose");
1198
+
1632
1199
  // src/resources/checkpoints.ts
1633
1200
  var Checkpoints = class {
1634
1201
  http;
@@ -2683,8 +2250,241 @@ var Desktop = class {
2683
2250
  const params = { app_name: appName };
2684
2251
  return this.http.post(`${this.base()}/launch`, params);
2685
2252
  }
2253
+ // ─── Keyboard ──────────────────────────────────────────────────────────────
2254
+ /** Press several keys at once, for example `hotkey("ctrl", "c")`. `POST /desktop/hotkey`. */
2255
+ async hotkey(...keys) {
2256
+ if (keys.length === 0) throw new RangeError("hotkey needs at least one key");
2257
+ return this.http.post(`${this.base()}/hotkey`, { keys });
2258
+ }
2259
+ /** Press a key and keep it down until {@link keyUp}. `POST /desktop/key-down`. */
2260
+ async keyDown(key) {
2261
+ return this.http.post(`${this.base()}/key-down`, { key });
2262
+ }
2263
+ /** Release a key held by {@link keyDown}. `POST /desktop/key-up`. */
2264
+ async keyUp(key) {
2265
+ return this.http.post(`${this.base()}/key-up`, { key });
2266
+ }
2267
+ // ─── Pointer ───────────────────────────────────────────────────────────────
2268
+ /** Press a mouse button without releasing it. `POST /desktop/mouse-down`. */
2269
+ async mouseDown(x, y, button = "left") {
2270
+ return this.http.post(`${this.base()}/mouse-down`, { x, y, button });
2271
+ }
2272
+ /** Release a mouse button. `POST /desktop/mouse-up`. */
2273
+ async mouseUp(x, y, button = "left") {
2274
+ return this.http.post(`${this.base()}/mouse-up`, { x, y, button });
2275
+ }
2276
+ // ─── Screen ────────────────────────────────────────────────────────────────
2277
+ /** Screen dimensions in pixels. `GET /desktop/screen-size`. */
2278
+ async screenSize() {
2279
+ return unwrapData(await this.http.get(`${this.base()}/screen-size`));
2280
+ }
2281
+ /** PNG bytes of one rectangle of the screen. `POST /desktop/screenshot/region`. */
2282
+ async screenshotRegion(x, y, width, height) {
2283
+ return this.http.request(`${this.base()}/screenshot/region`, {
2284
+ method: "POST",
2285
+ body: { x, y, width, height },
2286
+ binary: true
2287
+ });
2288
+ }
2289
+ /** The accessibility tree of the focused application. Cheaper to read than a screenshot. */
2290
+ async accessibilityTree() {
2291
+ return unwrapData(
2292
+ await this.http.get(`${this.base()}/accessibility-tree`)
2293
+ );
2294
+ }
2295
+ /** The desktop environment (name and details). `GET /desktop/environment`. */
2296
+ async environment() {
2297
+ return unwrapData(await this.http.get(`${this.base()}/environment`));
2298
+ }
2299
+ /** Set the wallpaper from an image path inside the computer. `POST /desktop/wallpaper`. */
2300
+ async setWallpaper(path) {
2301
+ return this.http.post(`${this.base()}/wallpaper`, { path });
2302
+ }
2303
+ // ─── Clipboard ─────────────────────────────────────────────────────────────
2304
+ /** Read the clipboard text. `GET /desktop/clipboard`. */
2305
+ async getClipboard() {
2306
+ const body5 = unwrapData(await this.http.get(`${this.base()}/clipboard`));
2307
+ return body5.text ?? "";
2308
+ }
2309
+ /** Replace the clipboard text. `POST /desktop/clipboard`. */
2310
+ async setClipboard(text) {
2311
+ return this.http.post(`${this.base()}/clipboard`, { text });
2312
+ }
2313
+ // ─── Windows ───────────────────────────────────────────────────────────────
2314
+ windowPath(windowId, action) {
2315
+ return `${this.base()}/window/${encodeURIComponent(windowId)}/${action}`;
2316
+ }
2317
+ async windowSize(windowId) {
2318
+ return unwrapData(await this.http.get(this.windowPath(windowId, "size")));
2319
+ }
2320
+ async windowPosition(windowId) {
2321
+ return unwrapData(await this.http.get(this.windowPath(windowId, "position")));
2322
+ }
2323
+ async resizeWindow(windowId, width, height) {
2324
+ return this.http.post(this.windowPath(windowId, "resize"), { width, height });
2325
+ }
2326
+ async moveWindow(windowId, x, y) {
2327
+ return this.http.post(this.windowPath(windowId, "move"), { x, y });
2328
+ }
2329
+ async maximizeWindow(windowId) {
2330
+ return this.http.post(this.windowPath(windowId, "maximize"), {});
2331
+ }
2332
+ async minimizeWindow(windowId) {
2333
+ return this.http.post(this.windowPath(windowId, "minimize"), {});
2334
+ }
2335
+ async closeWindow(windowId) {
2336
+ return this.http.post(this.windowPath(windowId, "close"), {});
2337
+ }
2686
2338
  };
2687
2339
 
2340
+ // src/resources/computer-agent.ts
2341
+ var READY_STATES = /* @__PURE__ */ new Set(["active", "running"]);
2342
+ var FAILED_STATES = /* @__PURE__ */ new Set(["error", "destroyed"]);
2343
+ var sleep2 = (ms, signal) => new Promise((resolve, reject) => {
2344
+ if (signal?.aborted) {
2345
+ reject(signal.reason);
2346
+ return;
2347
+ }
2348
+ const timer = setTimeout(resolve, ms);
2349
+ signal?.addEventListener(
2350
+ "abort",
2351
+ () => {
2352
+ clearTimeout(timer);
2353
+ reject(signal.reason);
2354
+ },
2355
+ { once: true }
2356
+ );
2357
+ });
2358
+ async function waitUntilReady(computer, options = {}) {
2359
+ const timeoutMs = options.timeoutMs ?? 12e4;
2360
+ const pollMs = options.pollMs ?? 500;
2361
+ const deadline = Date.now() + timeoutMs;
2362
+ for (; ; ) {
2363
+ if (READY_STATES.has(computer.status)) return computer;
2364
+ if (FAILED_STATES.has(computer.status)) {
2365
+ throw new MiosaError(
2366
+ `computer ${computer.id} is ${computer.status}`,
2367
+ 0,
2368
+ "COMPUTER_NOT_READY",
2369
+ { status: computer.status },
2370
+ void 0,
2371
+ false
2372
+ );
2373
+ }
2374
+ if (Date.now() >= deadline) {
2375
+ throw new MiosaError(
2376
+ `computer ${computer.id} was not ready after ${timeoutMs} ms (status ${computer.status})`,
2377
+ 0,
2378
+ "COMPUTER_READY_TIMEOUT",
2379
+ { status: computer.status, timeoutMs },
2380
+ void 0,
2381
+ true
2382
+ );
2383
+ }
2384
+ await sleep2(pollMs, options.signal);
2385
+ await computer.reload();
2386
+ }
2387
+ }
2388
+ async function waitForDesktop(computer, options = {}) {
2389
+ const timeoutMs = options.timeoutMs ?? 9e4;
2390
+ const pollMs = options.pollMs ?? 500;
2391
+ const deadline = Date.now() + timeoutMs;
2392
+ await waitUntilReady(computer, { ...options, timeoutMs });
2393
+ let last;
2394
+ while (Date.now() < deadline) {
2395
+ try {
2396
+ await computer.desktop.screenSize();
2397
+ return computer;
2398
+ } catch (error) {
2399
+ last = error;
2400
+ await sleep2(pollMs, options.signal);
2401
+ }
2402
+ }
2403
+ throw new MiosaError(
2404
+ `the desktop of computer ${computer.id} did not answer within ${timeoutMs} ms`,
2405
+ 0,
2406
+ "DESKTOP_READY_TIMEOUT",
2407
+ { cause: last instanceof Error ? last.message : void 0 },
2408
+ void 0,
2409
+ true
2410
+ );
2411
+ }
2412
+ function fingerprint(bytes2) {
2413
+ let hash = 2166136261;
2414
+ for (let i = 0; i < bytes2.length; i += 1) {
2415
+ hash ^= bytes2[i];
2416
+ hash = Math.imul(hash, 16777619);
2417
+ }
2418
+ return `${bytes2.length}:${hash >>> 0}`;
2419
+ }
2420
+ async function waitUntilIdle(computer, options = {}) {
2421
+ const timeoutMs = options.timeoutMs ?? 3e4;
2422
+ const pollMs = options.pollMs ?? 500;
2423
+ const quietMs = options.quietMs ?? 1e3;
2424
+ const deadline = Date.now() + timeoutMs;
2425
+ let previous = fingerprint(await computer.desktop.screenshot());
2426
+ let stableSince = Date.now();
2427
+ while (Date.now() < deadline) {
2428
+ await sleep2(pollMs, options.signal);
2429
+ const current = fingerprint(await computer.desktop.screenshot());
2430
+ if (current !== previous) {
2431
+ previous = current;
2432
+ stableSince = Date.now();
2433
+ } else if (Date.now() - stableSince >= quietMs) {
2434
+ return;
2435
+ }
2436
+ }
2437
+ throw new MiosaError(
2438
+ `the screen of computer ${computer.id} kept changing for ${timeoutMs} ms`,
2439
+ 0,
2440
+ "DESKTOP_IDLE_TIMEOUT",
2441
+ { timeoutMs, quietMs },
2442
+ void 0,
2443
+ true
2444
+ );
2445
+ }
2446
+ async function look(computer, options = {}) {
2447
+ const wantImage = options.includeImage ?? true;
2448
+ const wantTree = options.includeTree ?? true;
2449
+ const [image, tree] = await Promise.all([
2450
+ wantImage ? computer.desktop.screenshot() : Promise.resolve(void 0),
2451
+ wantTree ? computer.desktop.accessibilityTree().then(
2452
+ (value) => ({ value }),
2453
+ (error) => ({ error: error instanceof Error ? error.message : String(error) })
2454
+ ) : Promise.resolve(void 0)
2455
+ ]);
2456
+ const result = { takenAt: (/* @__PURE__ */ new Date()).toISOString() };
2457
+ if (image) {
2458
+ const [width, height] = pngSize(image);
2459
+ result.imageBase64 = toBase64(image);
2460
+ result.mediaType = "image/png";
2461
+ result.width = width;
2462
+ result.height = height;
2463
+ }
2464
+ if (tree) {
2465
+ if ("value" in tree) result.tree = tree.value;
2466
+ else result.treeError = tree.error;
2467
+ }
2468
+ return result;
2469
+ }
2470
+ function str(value) {
2471
+ return typeof value === "string" ? value : "";
2472
+ }
2473
+ async function viewerUrl(computer, options = {}) {
2474
+ const raw = options.ttlSeconds === void 0 ? await computer.embed() : await computer.embed({ ttlSeconds: options.ttlSeconds });
2475
+ const expiresAtUnix = typeof raw["expires_at"] === "number" ? raw["expires_at"] : 0;
2476
+ return {
2477
+ url: str(raw["embed_url"]),
2478
+ desktopUrl: str(raw["desktop_url"] ?? raw["raw_desktop_url"]),
2479
+ wsUrl: str(raw["ws_url"]),
2480
+ token: str(raw["token"]),
2481
+ expiresAtUnix,
2482
+ expiresAt: expiresAtUnix ? new Date(expiresAtUnix * 1e3).toISOString() : "",
2483
+ ttlSeconds: typeof raw["ttl_seconds"] === "number" ? raw["ttl_seconds"] : 0,
2484
+ mode: "vnc"
2485
+ };
2486
+ }
2487
+
2688
2488
  // src/resources/egressAudit.ts
2689
2489
  function unwrap9(payload) {
2690
2490
  if (payload && typeof payload === "object") {
@@ -2731,7 +2531,7 @@ function listQuery(params) {
2731
2531
  )
2732
2532
  });
2733
2533
  }
2734
- function sleep2(ms) {
2534
+ function sleep3(ms) {
2735
2535
  return new Promise((resolve) => setTimeout(resolve, ms));
2736
2536
  }
2737
2537
  var EgressAudit = class {
@@ -2780,7 +2580,7 @@ var EgressAudit = class {
2780
2580
  const ts = event.inserted_at ?? event.timestamp;
2781
2581
  if (typeof ts === "string") since = ts;
2782
2582
  }
2783
- await sleep2(pollMs);
2583
+ await sleep3(pollMs);
2784
2584
  }
2785
2585
  }
2786
2586
  };
@@ -3168,7 +2968,7 @@ function oauthBody(params) {
3168
2968
  redirect_uri: pickFirst4(params.redirectUri, params.redirect_uri)
3169
2969
  });
3170
2970
  }
3171
- function sleep3(ms) {
2971
+ function sleep4(ms) {
3172
2972
  return new Promise((resolve) => setTimeout(resolve, ms));
3173
2973
  }
3174
2974
  var OAuthFlow = class {
@@ -3211,7 +3011,7 @@ var OAuthFlow = class {
3211
3011
  return providerMatches && when !== void 0 && Date.parse(when) >= startedAt;
3212
3012
  });
3213
3013
  if (created) return { status: "completed", state: this.state, secret_id: created.id };
3214
- await sleep3(pollMs);
3014
+ await sleep4(pollMs);
3215
3015
  }
3216
3016
  throw new Error(
3217
3017
  `OAuth flow ${this.state} did not complete within ${timeoutSec}s`
@@ -3646,7 +3446,7 @@ function createWebSocket2(url, apiKey, protocol) {
3646
3446
  }
3647
3447
 
3648
3448
  // src/resources/files.ts
3649
- function toBase64(bytes2) {
3449
+ function toBase642(bytes2) {
3650
3450
  const maybeBuffer = globalThis.Buffer;
3651
3451
  if (maybeBuffer) return maybeBuffer.from(bytes2).toString("base64");
3652
3452
  let bin = "";
@@ -3683,7 +3483,7 @@ var Files = class {
3683
3483
  const buf = await content.arrayBuffer();
3684
3484
  bytes2 = new Uint8Array(buf);
3685
3485
  }
3686
- const contentBase64 = toBase64(bytes2);
3486
+ const contentBase64 = toBase642(bytes2);
3687
3487
  return this.http.post(`${this.base()}/write`, {
3688
3488
  path: remotePath,
3689
3489
  content_base64: contentBase64
@@ -3868,7 +3668,8 @@ function environmentSelectionBody(p) {
3868
3668
  return compact({
3869
3669
  environment: p.environment,
3870
3670
  environment_id: p.environmentId ?? p.environment_id,
3871
- no_env: p.noEnv ?? p.no_env
3671
+ no_env: p.noEnv ?? p.no_env,
3672
+ fail_fast: p.failFast ?? p.fail_fast
3872
3673
  });
3873
3674
  }
3874
3675
  function billToHeaders(p) {
@@ -3918,7 +3719,7 @@ var MachineAgent = class {
3918
3719
  return unwrapData(await this.http.post(`${this.base}/agent/stop`));
3919
3720
  }
3920
3721
  };
3921
- var sleep4 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3722
+ var sleep5 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3922
3723
  async function waitForSetupStatus(refresh, options = {}) {
3923
3724
  const deadline = Date.now() + (options.timeoutMs ?? 30 * 6e4);
3924
3725
  for (; ; ) {
@@ -3928,7 +3729,7 @@ async function waitForSetupStatus(refresh, options = {}) {
3928
3729
  if (Date.now() >= deadline) {
3929
3730
  throw new TimeoutError(`setup did not finish before the ${options.timeoutMs ?? 30 * 6e4}ms wait budget`);
3930
3731
  }
3931
- await sleep4(options.pollMs ?? 2e3);
3732
+ await sleep5(options.pollMs ?? 2e3);
3932
3733
  }
3933
3734
  }
3934
3735
 
@@ -3947,7 +3748,7 @@ function stripUndefined5(input) {
3947
3748
  function isTerminalStatus(status, terminalStatuses) {
3948
3749
  return typeof status === "string" && terminalStatuses.includes(status.toLowerCase());
3949
3750
  }
3950
- function sleep5(ms) {
3751
+ function sleep6(ms) {
3951
3752
  if (ms <= 0) return Promise.resolve();
3952
3753
  return new Promise((resolve) => setTimeout(resolve, ms));
3953
3754
  }
@@ -4027,7 +3828,7 @@ var AgentRuns = class {
4027
3828
  if (Date.now() >= deadline) {
4028
3829
  throw new Error(`Timed out waiting for agent run ${id}`);
4029
3830
  }
4030
- await sleep5(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
3831
+ await sleep6(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
4031
3832
  }
4032
3833
  }
4033
3834
  async run(params) {
@@ -4092,7 +3893,7 @@ function stripUndefined6(input) {
4092
3893
  function isTerminalStatus2(status, terminalStatuses) {
4093
3894
  return typeof status === "string" && terminalStatuses.includes(status.toLowerCase());
4094
3895
  }
4095
- function sleep6(ms) {
3896
+ function sleep7(ms) {
4096
3897
  if (ms <= 0) return Promise.resolve();
4097
3898
  return new Promise((resolve) => setTimeout(resolve, ms));
4098
3899
  }
@@ -4230,7 +4031,7 @@ var Runs = class {
4230
4031
  if (Date.now() >= deadline) {
4231
4032
  throw new Error(`Timed out waiting for run ${id}`);
4232
4033
  }
4233
- await sleep6(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
4034
+ await sleep7(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
4234
4035
  }
4235
4036
  }
4236
4037
  async run(params) {
@@ -4714,11 +4515,58 @@ var Computer = class _Computer {
4714
4515
  * Use this inside MIOSA or tenant apps. Raw shared desktop URLs can still use
4715
4516
  * the viewer password flow when opened outside an authenticated platform.
4716
4517
  */
4717
- async embed() {
4518
+ async embed(options = {}) {
4718
4519
  return unwrapData2(
4719
- await this.http.get(`/computers/${this.id}/embed`)
4520
+ await this.http.get(
4521
+ withQuery(`/computers/${this.id}/embed`, { ttl_seconds: options.ttlSeconds })
4522
+ )
4720
4523
  );
4721
4524
  }
4525
+ /** A typed, expiring viewer link. See {@link ComputerViewer}. */
4526
+ viewerUrl(options = {}) {
4527
+ return viewerUrl(this, options);
4528
+ }
4529
+ // ─── Agent helpers ─────────────────────────────────────────────────────────
4530
+ /**
4531
+ * Run one desktop action by name and get a typed result. The names are the
4532
+ * members of Anthropic's `computer_toolset_20260801`:
4533
+ *
4534
+ * ```ts
4535
+ * const shot = await computer.act("screenshot"); // imageBase64, width, height
4536
+ * const at = await computer.act("cursor_position"); // x, y
4537
+ * await computer.act("left_click", { coordinate: [512, 384] });
4538
+ * ```
4539
+ */
4540
+ act(action, ...args) {
4541
+ return performAction(this.desktop, action, ...args);
4542
+ }
4543
+ /** A screenshot and the accessibility tree in one call. */
4544
+ look(options = {}) {
4545
+ return look(this, options);
4546
+ }
4547
+ /** Wait until the computer is `active` or `running`. */
4548
+ waitUntilReady(options = {}) {
4549
+ return waitUntilReady(this, options);
4550
+ }
4551
+ /** Wait until the computer is ready and its desktop answers. */
4552
+ waitForDesktop(options = {}) {
4553
+ return waitForDesktop(this, options);
4554
+ }
4555
+ /** Wait until the screen stops changing. */
4556
+ waitUntilIdle(options = {}) {
4557
+ return waitUntilIdle(this, options);
4558
+ }
4559
+ /**
4560
+ * `await using computer = await miosa.computers.create(...)` destroys the
4561
+ * computer when the scope ends. A computer that is already gone is ignored.
4562
+ */
4563
+ async [Symbol.asyncDispose]() {
4564
+ try {
4565
+ await this.destroy();
4566
+ } catch (error) {
4567
+ if (!(error instanceof NotFoundError)) throw error;
4568
+ }
4569
+ }
4722
4570
  /**
4723
4571
  * `DELETE /computers/:id/stream-tokens`: revoke every viewer stream token
4724
4572
  * minted for this computer (see {@link streamToken}).
@@ -5619,7 +5467,7 @@ function forkBody(p) {
5619
5467
  env: p.env
5620
5468
  });
5621
5469
  }
5622
- var sleep7 = (ms, signal) => new Promise((resolve, reject) => {
5470
+ var sleep8 = (ms, signal) => new Promise((resolve, reject) => {
5623
5471
  const timer = setTimeout(resolve, ms);
5624
5472
  signal?.addEventListener(
5625
5473
  "abort",
@@ -5729,7 +5577,7 @@ var Snapshots = class {
5729
5577
  if (!isWarming(res)) return res.data;
5730
5578
  if (!wait) throw new SnapshotWarmingError(res.retry_after_ms);
5731
5579
  if (Date.now() + res.retry_after_ms > deadline) throw new SnapshotWarmingError(res.retry_after_ms);
5732
- await sleep7(res.retry_after_ms, options.signal);
5580
+ await sleep8(res.retry_after_ms, options.signal);
5733
5581
  }
5734
5582
  }
5735
5583
  /**
@@ -5753,7 +5601,7 @@ var Snapshots = class {
5753
5601
  if (!wait || Date.now() + warming.retry_after_ms > deadline) {
5754
5602
  throw new SnapshotWarmingError(warming.retry_after_ms);
5755
5603
  }
5756
- await sleep7(warming.retry_after_ms, options.signal);
5604
+ await sleep8(warming.retry_after_ms, options.signal);
5757
5605
  continue;
5758
5606
  }
5759
5607
  return new Uint8Array(await response.arrayBuffer());
@@ -5869,7 +5717,7 @@ function runBody(entry) {
5869
5717
  function isTerminalStatus3(status, terminalStatuses) {
5870
5718
  return typeof status === "string" && terminalStatuses.includes(status.toLowerCase());
5871
5719
  }
5872
- function sleep8(ms) {
5720
+ function sleep9(ms) {
5873
5721
  if (ms <= 0) return Promise.resolve();
5874
5722
  return new Promise((resolve) => setTimeout(resolve, ms));
5875
5723
  }
@@ -5972,7 +5820,7 @@ var AgentRunGroups = class {
5972
5820
  if (Date.now() >= deadline) {
5973
5821
  throw new Error(`Timed out waiting for agent run group ${id}`);
5974
5822
  }
5975
- await sleep8(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
5823
+ await sleep9(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
5976
5824
  }
5977
5825
  }
5978
5826
  };
@@ -6036,7 +5884,7 @@ function runBody2(entry) {
6036
5884
  function isTerminalStatus4(status, terminalStatuses) {
6037
5885
  return typeof status === "string" && terminalStatuses.includes(status.toLowerCase());
6038
5886
  }
6039
- function sleep9(ms) {
5887
+ function sleep10(ms) {
6040
5888
  if (ms <= 0) return Promise.resolve();
6041
5889
  return new Promise((resolve) => setTimeout(resolve, ms));
6042
5890
  }
@@ -6139,7 +5987,7 @@ var RunGroups = class {
6139
5987
  if (Date.now() >= deadline) {
6140
5988
  throw new Error(`Timed out waiting for run group ${id}`);
6141
5989
  }
6142
- await sleep9(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
5990
+ await sleep10(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
6143
5991
  }
6144
5992
  }
6145
5993
  };
@@ -7250,6 +7098,8 @@ var Computers = class {
7250
7098
  environment_id,
7251
7099
  noEnv,
7252
7100
  no_env,
7101
+ failFast,
7102
+ fail_fast,
7253
7103
  setupFile,
7254
7104
  setup_file,
7255
7105
  billTo,
@@ -7260,7 +7110,7 @@ var Computers = class {
7260
7110
  const requestBody2 = {
7261
7111
  template_type: "miosa-desktop",
7262
7112
  ...body5,
7263
- ...environmentSelectionBody({ environmentId, environment_id, noEnv, no_env }),
7113
+ ...environmentSelectionBody({ environmentId, environment_id, noEnv, no_env, failFast, fail_fast }),
7264
7114
  ...setupFile ?? setup_file ? { setup_file: setupFile ?? setup_file } : {},
7265
7115
  size: normalizeComputerSize(body5.size ?? "small"),
7266
7116
  agent_runtime_profile_id: agentRuntimeProfileId ?? params.agent_runtime_profile_id ?? agentProfileId ?? params.agent_profile_id,
@@ -7497,7 +7347,7 @@ var Dashboard = class {
7497
7347
  };
7498
7348
 
7499
7349
  // src/resources/fs-api.ts
7500
- function toBase642(bytes2) {
7350
+ function toBase643(bytes2) {
7501
7351
  const maybeBuffer = globalThis.Buffer;
7502
7352
  if (maybeBuffer) return maybeBuffer.from(bytes2).toString("base64");
7503
7353
  let bin = "";
@@ -7559,7 +7409,7 @@ var FsApi = class {
7559
7409
  write(path, content) {
7560
7410
  return this.http.post(`${this.base}/write`, {
7561
7411
  path,
7562
- content_base64: toBase642(bytesOf(content))
7412
+ content_base64: toBase643(bytesOf(content))
7563
7413
  });
7564
7414
  }
7565
7415
  /**
@@ -7569,7 +7419,7 @@ var FsApi = class {
7569
7419
  async writeMany(files) {
7570
7420
  return unwrapData(
7571
7421
  await this.http.post(`${this.base}/write-many`, {
7572
- files: files.map((f) => ({ path: f.path, content_base64: toBase642(bytesOf(f.content)) }))
7422
+ files: files.map((f) => ({ path: f.path, content_base64: toBase643(bytesOf(f.content)) }))
7573
7423
  })
7574
7424
  );
7575
7425
  }
@@ -12227,7 +12077,7 @@ var Sandbox = class _Sandbox {
12227
12077
  const bytes2 = typeof content === "string" ? new TextEncoder().encode(content) : content;
12228
12078
  await this.http.post(`/sandboxes/${this.id}/fs/write`, {
12229
12079
  path,
12230
- content_base64: toBase643(bytes2)
12080
+ content_base64: toBase644(bytes2)
12231
12081
  });
12232
12082
  }
12233
12083
  async download(path) {
@@ -12813,6 +12663,17 @@ var Sandbox = class _Sandbox {
12813
12663
  }
12814
12664
  }
12815
12665
  }
12666
+ /**
12667
+ * `await using sandbox = await miosa.sandboxes.create(...)` destroys the
12668
+ * sandbox when the scope ends. A sandbox that is already gone is ignored.
12669
+ */
12670
+ async [Symbol.asyncDispose]() {
12671
+ try {
12672
+ await this.destroy();
12673
+ } catch (error) {
12674
+ if (!(error instanceof NotFoundError)) throw error;
12675
+ }
12676
+ }
12816
12677
  async destroy() {
12817
12678
  if (this.data.state === "destroyed" || this.data.state === "destroying") {
12818
12679
  return;
@@ -12854,7 +12715,7 @@ var Sandbox = class _Sandbox {
12854
12715
  }
12855
12716
  }
12856
12717
  };
12857
- function sleep10(ms) {
12718
+ function sleep11(ms) {
12858
12719
  return new Promise((resolve) => setTimeout(resolve, ms));
12859
12720
  }
12860
12721
  function isResumableState(state) {
@@ -12867,7 +12728,7 @@ var RESUME_RETRY_FALLBACK_DELAY_MS = 500;
12867
12728
  async function waitOutPausingState(sandbox, timeoutSec) {
12868
12729
  const deadline = Date.now() + timeoutSec * 1e3;
12869
12730
  while (sandbox.state === "pausing" && Date.now() < deadline) {
12870
- await sleep10(PAUSING_POLL_INTERVAL_MS);
12731
+ await sleep11(PAUSING_POLL_INTERVAL_MS);
12871
12732
  try {
12872
12733
  await sandbox.refresh();
12873
12734
  } catch {
@@ -12882,7 +12743,7 @@ async function resumeWithRetryHint(sandbox) {
12882
12743
  } catch (error) {
12883
12744
  const canRetry = error instanceof MiosaError && error.status === 409 && error.retryable === true && attempt < RESUME_RETRY_MAX_ATTEMPTS;
12884
12745
  if (!canRetry) throw error;
12885
- await sleep10(error.retryAfterMs ?? RESUME_RETRY_FALLBACK_DELAY_MS);
12746
+ await sleep11(error.retryAfterMs ?? RESUME_RETRY_FALLBACK_DELAY_MS);
12886
12747
  }
12887
12748
  }
12888
12749
  }
@@ -13143,7 +13004,7 @@ var Sandboxes = class {
13143
13004
  return unwrap49(response);
13144
13005
  }
13145
13006
  };
13146
- function toBase643(bytes2) {
13007
+ function toBase644(bytes2) {
13147
13008
  const maybeBuffer = globalThis.Buffer;
13148
13009
  if (maybeBuffer) return maybeBuffer.from(bytes2).toString("base64");
13149
13010
  let binary = "";
@@ -15264,7 +15125,7 @@ function retryAfterMs(headers, capMs = RATE_LIMIT_RETRY_CAP_MS) {
15264
15125
  const at = Date.parse(raw);
15265
15126
  return Number.isNaN(at) ? 0 : Math.min(Math.max(0, at - Date.now()), capMs);
15266
15127
  }
15267
- function sleep11(ms) {
15128
+ function sleep12(ms) {
15268
15129
  return new Promise((resolve) => setTimeout(resolve, ms));
15269
15130
  }
15270
15131
  var RunnerClient = class {
@@ -15363,7 +15224,7 @@ var RunnerClient = class {
15363
15224
  rateLimitRetries += 1;
15364
15225
  lastError = error;
15365
15226
  const waitMs = retryAfterMs(res.headers);
15366
- if (waitMs > 0) await sleep11(waitMs);
15227
+ if (waitMs > 0) await sleep12(waitMs);
15367
15228
  continue;
15368
15229
  }
15369
15230
  throw error;
@@ -15881,7 +15742,7 @@ var Miosa = class _Miosa {
15881
15742
  whoami() {
15882
15743
  return this.identity.whoami();
15883
15744
  }
15884
- constructor(config) {
15745
+ constructor(config = {}) {
15885
15746
  const env = (name) => typeof process !== "undefined" && typeof process.env !== "undefined" ? process.env[name] || void 0 : void 0;
15886
15747
  const resolved = {
15887
15748
  ...config,
@@ -16501,6 +16362,6 @@ var AppAuth = class {
16501
16362
  }
16502
16363
  };
16503
16364
 
16504
- export { AGENT_BUILD_KIND_SPECS, Admin, AgentChats, AgentDefinitions, AgentRuntimeProfiles, AgentSettingsResource, AgentSignins, AiGateway, AmbiguousOrgError, Analytics, ApiKeys, AppAuth, AppDocuments, AuditLog, AuthError, Benchmarks, BillTo, BillToForbiddenError, BillToLockedError, BillToSuspendedError, BuilderSessions, BulkResource, Channels, ChatBusyError, Checkpoints, Cloud, CommandCenter, Community, Completions, Computer, ComputerAudit, ComputerAutoStop, ComputerConnectors, ComputerEnv, ComputerInbox, ComputerLogs, ComputerNetwork, ComputerOsa, ComputerPorts, ComputerSecrets, ComputerShares, ComputerStartingError, ComputerTerminal, ComputerVolumes, Computers, Connections, Connectors, CreditRequiredError, Credits, CronJobs, DEFAULT_AGENT_BUILD_OUTPUT_ROOT, DEFAULT_AGENT_BUILD_PACKET_VERSION, Dashboard, Databases, DeploymentConnectors, DeploymentDomains, DeploymentReleases, DeploymentRuntimeInstances, DeploymentVersions, Deployments, Desktop, Devices, DnsAddressResolver, DockerDeploy, Domains, EgressAudit, EgressHostNotAllowedError, EgressNetwork, EgressSecrets, Email, EmailCampaigns, EmailInbox, EmailTemplates, Embeddings, EnvironmentIsDefaultError, EnvironmentMemoryWithheldError, EnvironmentNameTakenError, EnvironmentNotFoundError, EnvironmentScrubFailedError, Environments, EventSubscriptions, Exec, ExternalKeys, ExternalQuotas, ExternalUsers, Files, FlatCustomDomains, Forge, ForgeContractError, ForgePolicyViolationError, ForgeRepositories, ForgeStorageError, ForgeUnavailableError, FsApi, Functions, HealthChecks, Http2Transport, Http3Transport, InstallationRequiredError, InsufficientCreditsError, Integrations, InvalidIdError, InvalidSetupFileError, MachineAgent, MachineKeyScopeError, MachineStartingError, ManagedProviderBindingOnlyError, Mcp, MemberLimitReachedError, Miosa, MiosaError, Models, NamedSnapshots, NetworkError, NetworkPolicy, NoAgentRunError, NotFoundError, OAuthFlow, OpenComputers, OrgInvites, OrgNotFoundError, OrganizationMembers, Organizations, OwnCredentialsRequiredError, PortTunnel, ProjectAuth, ProjectIntegrations, ProjectNotLinkedError, ProviderDefaults, Quotas, RacingTransport, RateLimitError, Regions, RunGroups, RunSessionNotResumableError, RunnerClient, RunnerConnectError, RunnerError, RunnerTimeoutError, Runs, RuntimeCapabilitiesResource, RuntimeEnv, SANDBOX_TEMPLATE, Sandbox, SandboxAudit, SandboxBatches, SandboxCommands, SandboxConnectors, SandboxEnv, SandboxEvents, SandboxFiles, SandboxNetwork, SandboxPreview, SandboxPreviews, SandboxSecrets, SandboxSsh, SandboxStartingError, SandboxTags, SandboxTemplates, SandboxTerminal, SandboxTunnel, Sandboxes, ScopeNotAllowedError, ScopedFs, ScopedTokens, ServiceAccounts, Settings, SharedLinks, SnapshotInUseError, SnapshotWarmingError, Snapshots, SnapshotsStandalone, StaticAddressResolver, Storage, SubjectNotAllowedError, TUNNEL_CLOSE_REASONS, TUNNEL_SUBPROTOCOL, TeamMemberCapReachedError, Templates, Tenant, TenantEventStreamResource, TenantMembersResource, TenantPolicy, TimeoutError, TokenRefreshFailedError, Tokens, TunnelClosedError, UnknownEnvironmentError, Usage, UserAuthorizationRequiredError, ValidationError, Volumes, WEBHOOK_DELIVERY_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_SIGNATURE_HEADER, WebhookSignatureError, Webhooks, WorkspaceInvites, WorkspaceMembers, WorkspaceMembersResource, WorkspacePolicyResource, WorkspaceProxy, Workspaces, buildSshCommand, buildSshConfig, constructWebhookEvent, createAgentBuildExecutionPacket, createAgentBuildExpectedOutputs, createAgentBuildPrompt, createBestTransport, createBuildRunParams, daysUntil, decodeSomaBytes, detectHttp3Support, encodeSomaBytes, generateSshKeyPair, getAgentBuildKindSpec, hyphenateInstanceId, isConnectFailure, regionFromApiKey, regionHostname, resetHttp3DetectionCache, resolveAgentBuildKind, sandboxTag, signWebhookBody, tagHostname, unwrapSomaEnvelope, verifySignature, verifyWebhookSignature, verifyWebhookSignatureAsync };
16365
+ export { AGENT_BUILD_KIND_SPECS, Admin, AgentChats, AgentDefinitions, AgentRuntimeProfiles, AgentSettingsResource, AgentSignins, AiGateway, Analytics, ApiKeys, AppAuth, AppDocuments, AuditLog, Benchmarks, BillTo, BuilderSessions, BulkResource, Channels, Checkpoints, Cloud, CommandCenter, Community, Completions, Computer, ComputerAudit, ComputerAutoStop, ComputerConnectors, ComputerEnv, ComputerInbox, ComputerLogs, ComputerNetwork, ComputerOsa, ComputerPorts, ComputerSecrets, ComputerShares, ComputerTerminal, ComputerVolumes, Computers, Connections, Connectors, Credits, CronJobs, DEFAULT_AGENT_BUILD_OUTPUT_ROOT, DEFAULT_AGENT_BUILD_PACKET_VERSION, Dashboard, Databases, DeploymentConnectors, DeploymentDomains, DeploymentReleases, DeploymentRuntimeInstances, DeploymentVersions, Deployments, Desktop, Devices, DnsAddressResolver, DockerDeploy, Domains, EgressAudit, EgressNetwork, EgressSecrets, Email, EmailCampaigns, EmailInbox, EmailTemplates, Embeddings, Environments, EventSubscriptions, Exec, ExternalKeys, ExternalQuotas, ExternalUsers, Files, FlatCustomDomains, Forge, ForgeContractError, ForgePolicyViolationError, ForgeRepositories, ForgeStorageError, ForgeUnavailableError, FsApi, Functions, HealthChecks, Http2Transport, Http3Transport, Integrations, MachineAgent, Mcp, Miosa, Models, NamedSnapshots, NetworkPolicy, OAuthFlow, OpenComputers, OrgInvites, OrganizationMembers, Organizations, PortTunnel, ProjectAuth, ProjectIntegrations, ProviderDefaults, Quotas, RacingTransport, Regions, RunGroups, RunnerClient, RunnerConnectError, RunnerError, RunnerTimeoutError, Runs, RuntimeCapabilitiesResource, RuntimeEnv, SANDBOX_TEMPLATE, Sandbox, SandboxAudit, SandboxBatches, SandboxCommands, SandboxConnectors, SandboxEnv, SandboxEvents, SandboxFiles, SandboxNetwork, SandboxPreview, SandboxPreviews, SandboxSecrets, SandboxSsh, SandboxTags, SandboxTemplates, SandboxTerminal, SandboxTunnel, Sandboxes, ScopedFs, ScopedTokens, ServiceAccounts, Settings, SharedLinks, SnapshotWarmingError, Snapshots, SnapshotsStandalone, StaticAddressResolver, Storage, TUNNEL_CLOSE_REASONS, TUNNEL_SUBPROTOCOL, Templates, Tenant, TenantEventStreamResource, TenantMembersResource, TenantPolicy, Tokens, TunnelClosedError, Usage, Volumes, WEBHOOK_DELIVERY_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_SIGNATURE_HEADER, WebhookSignatureError, Webhooks, WorkspaceInvites, WorkspaceMembers, WorkspaceMembersResource, WorkspacePolicyResource, WorkspaceProxy, Workspaces, buildSshCommand, buildSshConfig, constructWebhookEvent, createAgentBuildExecutionPacket, createAgentBuildExpectedOutputs, createAgentBuildPrompt, createBestTransport, createBuildRunParams, daysUntil, decodeSomaBytes, detectHttp3Support, encodeSomaBytes, generateSshKeyPair, getAgentBuildKindSpec, hyphenateInstanceId, isConnectFailure, regionFromApiKey, regionHostname, resetHttp3DetectionCache, resolveAgentBuildKind, sandboxTag, signWebhookBody, tagHostname, unwrapSomaEnvelope, verifySignature, verifyWebhookSignature, verifyWebhookSignatureAsync };
16505
16366
  //# sourceMappingURL=index.js.map
16506
16367
  //# sourceMappingURL=index.js.map