@boatdev/sdk 1.9.7 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.openapi-generator/FILES +4 -0
  2. package/README.md +2 -2
  3. package/dist/apis/BoatApi.d.ts +2 -2
  4. package/dist/apis/BoatApi.js +2 -2
  5. package/dist/boat-helpers.d.ts +23 -0
  6. package/dist/boat-helpers.js +97 -0
  7. package/dist/esm/apis/BoatApi.d.ts +2 -2
  8. package/dist/esm/apis/BoatApi.js +2 -2
  9. package/dist/esm/boat-helpers.d.ts +23 -0
  10. package/dist/esm/boat-helpers.js +95 -0
  11. package/dist/esm/models/CredentialProfile.d.ts +1 -1
  12. package/dist/esm/models/DeletionOperation.d.ts +1 -3
  13. package/dist/esm/models/DeletionOperation.js +0 -2
  14. package/dist/esm/models/LimitsFields.d.ts +7 -0
  15. package/dist/esm/models/LimitsFields.js +3 -0
  16. package/dist/esm/models/LimitsFieldsMachineTypesInner.d.ts +54 -0
  17. package/dist/esm/models/LimitsFieldsMachineTypesInner.js +60 -0
  18. package/dist/esm/models/LimitsResponse.d.ts +7 -0
  19. package/dist/esm/models/LimitsResponse.js +3 -0
  20. package/dist/esm/models/Sandbox.d.ts +15 -2
  21. package/dist/esm/models/Sandbox.js +5 -0
  22. package/dist/esm/models/SandboxHydration.d.ts +50 -0
  23. package/dist/esm/models/SandboxHydration.js +55 -0
  24. package/dist/esm/models/index.d.ts +2 -0
  25. package/dist/esm/models/index.js +2 -0
  26. package/dist/models/CredentialProfile.d.ts +1 -1
  27. package/dist/models/DeletionOperation.d.ts +1 -3
  28. package/dist/models/DeletionOperation.js +0 -2
  29. package/dist/models/LimitsFields.d.ts +7 -0
  30. package/dist/models/LimitsFields.js +3 -0
  31. package/dist/models/LimitsFieldsMachineTypesInner.d.ts +54 -0
  32. package/dist/models/LimitsFieldsMachineTypesInner.js +68 -0
  33. package/dist/models/LimitsResponse.d.ts +7 -0
  34. package/dist/models/LimitsResponse.js +3 -0
  35. package/dist/models/Sandbox.d.ts +15 -2
  36. package/dist/models/Sandbox.js +5 -0
  37. package/dist/models/SandboxHydration.d.ts +50 -0
  38. package/dist/models/SandboxHydration.js +62 -0
  39. package/dist/models/index.d.ts +2 -0
  40. package/dist/models/index.js +2 -0
  41. package/docs/BoatApi.md +1 -1
  42. package/docs/LimitsFields.md +2 -0
  43. package/docs/LimitsFieldsMachineTypesInner.md +36 -0
  44. package/docs/LimitsResponse.md +2 -0
  45. package/docs/Sandbox.md +4 -0
  46. package/docs/SandboxHydration.md +39 -0
  47. package/package.json +2 -2
  48. package/src/apis/BoatApi.ts +2 -2
  49. package/src/boat-helpers.ts +109 -0
  50. package/src/models/CredentialProfile.ts +1 -1
  51. package/src/models/DeletionOperation.ts +1 -3
  52. package/src/models/LimitsFields.ts +15 -0
  53. package/src/models/LimitsFieldsMachineTypesInner.ts +97 -0
  54. package/src/models/LimitsResponse.ts +15 -0
  55. package/src/models/Sandbox.ts +25 -2
  56. package/src/models/SandboxHydration.ts +93 -0
  57. package/src/models/index.ts +2 -0
@@ -77,6 +77,7 @@ docs/HostPortResponse.md
77
77
  docs/LimitsFields.md
78
78
  docs/LimitsFieldsCurrentLimits.md
79
79
  docs/LimitsFieldsGiftLimit.md
80
+ docs/LimitsFieldsMachineTypesInner.md
80
81
  docs/LimitsFieldsSandboxPlanTiersInner.md
81
82
  docs/LimitsFieldsStartLimits.md
82
83
  docs/LimitsFieldsStarts.md
@@ -126,6 +127,7 @@ docs/SandboxEnvironmentListResponse.md
126
127
  docs/SandboxEnvironmentResponse.md
127
128
  docs/SandboxEnvironmentVersionSummary.md
128
129
  docs/SandboxEvent.md
130
+ docs/SandboxHydration.md
129
131
  docs/SandboxInfoResponse.md
130
132
  docs/SandboxListResponse.md
131
133
  docs/SandboxProcess.md
@@ -263,6 +265,7 @@ src/models/HostPortResponse.ts
263
265
  src/models/LimitsFields.ts
264
266
  src/models/LimitsFieldsCurrentLimits.ts
265
267
  src/models/LimitsFieldsGiftLimit.ts
268
+ src/models/LimitsFieldsMachineTypesInner.ts
266
269
  src/models/LimitsFieldsSandboxPlanTiersInner.ts
267
270
  src/models/LimitsFieldsStartLimits.ts
268
271
  src/models/LimitsFieldsStarts.ts
@@ -312,6 +315,7 @@ src/models/SandboxEnvironmentListResponse.ts
312
315
  src/models/SandboxEnvironmentResponse.ts
313
316
  src/models/SandboxEnvironmentVersionSummary.ts
314
317
  src/models/SandboxEvent.ts
318
+ src/models/SandboxHydration.ts
315
319
  src/models/SandboxInfoResponse.ts
316
320
  src/models/SandboxListResponse.ts
317
321
  src/models/SandboxProcess.ts
package/README.md CHANGED
@@ -10,8 +10,8 @@ npm install @boatdev/sdk
10
10
 
11
11
  ## Links
12
12
 
13
- - SDK docs: https://docs.boat.dev/sdks
14
- - API reference: https://docs.boat.dev/api/reference
13
+ - SDK docs: https://docs.boat.dev/sdks/overview
14
+ - API reference: https://docs.boat.dev/api/v1
15
15
  - Dashboard: https://boat.dev/dashboard
16
16
  - API keys: https://boat.dev/dashboard?tab=api-keys
17
17
 
@@ -1281,12 +1281,12 @@ export declare class BoatApi extends runtime.BaseAPI {
1281
1281
  */
1282
1282
  listCredentialAccountsRequestOpts(requestParameters: ListCredentialAccountsRequest): Promise<runtime.RequestOpts>;
1283
1283
  /**
1284
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
1284
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
1285
1285
  * List the accounts of a credential
1286
1286
  */
1287
1287
  listCredentialAccountsRaw(requestParameters: ListCredentialAccountsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<CredentialAccountsResponse>>;
1288
1288
  /**
1289
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
1289
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
1290
1290
  * List the accounts of a credential
1291
1291
  */
1292
1292
  listCredentialAccounts(requestParameters: ListCredentialAccountsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<CredentialAccountsResponse>;
@@ -2716,7 +2716,7 @@ class BoatApi extends runtime.BaseAPI {
2716
2716
  };
2717
2717
  }
2718
2718
  /**
2719
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
2719
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
2720
2720
  * List the accounts of a credential
2721
2721
  */
2722
2722
  async listCredentialAccountsRaw(requestParameters, initOverrides) {
@@ -2725,7 +2725,7 @@ class BoatApi extends runtime.BaseAPI {
2725
2725
  return new runtime.JSONApiResponse(response, (jsonValue) => (0, CredentialAccountsResponse_1.CredentialAccountsResponseFromJSON)(jsonValue));
2726
2726
  }
2727
2727
  /**
2728
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
2728
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
2729
2729
  * List the accounts of a credential
2730
2730
  */
2731
2731
  async listCredentialAccounts(requestParameters, initOverrides) {
@@ -76,3 +76,26 @@ export type StreamCommandOptions = {
76
76
  * sent to a starting sandbox for up to 60 s instead of refusing it.
77
77
  */
78
78
  export declare function streamCommand(api: BoatApi, sandboxId: string, command: string, options?: StreamCommandOptions): AsyncGenerator<CommandFrame>;
79
+ export type FollowCommandOptions = {
80
+ signal?: AbortSignal;
81
+ };
82
+ /**
83
+ * Yield a detached command's output from its start until it ends: `stdout`/`stderr`
84
+ * chunks (`frame.data`), then exactly one `exit` (`exitCode`, ...) or `error`
85
+ * (`message`). The server ends each connection after 10 minutes; this reconnects
86
+ * from the same offsets, with no gap and no repeat. A network cut is reconnected
87
+ * the same way for up to 60 s.
88
+ */
89
+ export declare function followCommand(api: BoatApi, sandboxId: string, processId: number, options?: FollowCommandOptions): AsyncGenerator<CommandFrame>;
90
+ export type RunCommandOptions = FollowCommandOptions & {
91
+ cwd?: string;
92
+ };
93
+ /**
94
+ * Run a command with no time limit and yield its output until it ends.
95
+ *
96
+ * The command runs detached, so it has no 600 s cap and survives a dropped
97
+ * connection. Frames: `{ type: 'started', processId }`, then the frames of
98
+ * `followCommand`. Stopping early leaves the command running: call
99
+ * `stopCommand({ sandboxId, processId })` to stop it.
100
+ */
101
+ export declare function runCommand(api: BoatApi, sandboxId: string, command: string, options?: RunCommandOptions): AsyncGenerator<CommandFrame>;
@@ -12,6 +12,8 @@ exports.readText = readText;
12
12
  exports.writeText = writeText;
13
13
  exports.execCommand = execCommand;
14
14
  exports.streamCommand = streamCommand;
15
+ exports.followCommand = followCommand;
16
+ exports.runCommand = runCommand;
15
17
  const terminalPromptStatuses = new Set(['finished', 'failed']);
16
18
  function delay(ms) {
17
19
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -259,3 +261,98 @@ async function* streamCommand(api, sandboxId, command, options) {
259
261
  await delay(1000);
260
262
  }
261
263
  }
264
+ // The server sends a heartbeat every 15 s, so 60 s of silence is a dead connection.
265
+ const ATTACH_IDLE_MS = 60000;
266
+ // After the first connection, a failed reconnect is tried again for this long.
267
+ const ATTACH_RETRY_MS = 60000;
268
+ function isNetworkError(e, signal) {
269
+ if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || e instanceof SyntaxError)
270
+ return false;
271
+ return !(e === null || e === void 0 ? void 0 : e.response);
272
+ }
273
+ /**
274
+ * Yield a detached command's output from its start until it ends: `stdout`/`stderr`
275
+ * chunks (`frame.data`), then exactly one `exit` (`exitCode`, ...) or `error`
276
+ * (`message`). The server ends each connection after 10 minutes; this reconnects
277
+ * from the same offsets, with no gap and no repeat. A network cut is reconnected
278
+ * the same way for up to 60 s.
279
+ */
280
+ async function* followCommand(api, sandboxId, processId, options) {
281
+ var _a, _b, _c;
282
+ var _d, _e, _f, _g;
283
+ const offsets = { stdout: 0, stderr: 0 };
284
+ let connected = false;
285
+ // Set at the first failure after a good connection; any good connection clears it.
286
+ let failingSince;
287
+ for (;;) {
288
+ if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted)
289
+ throw (_d = options.signal.reason) !== null && _d !== void 0 ? _d : new Error('followCommand aborted');
290
+ // One controller per connection: the caller's signal, or 60 s with no line.
291
+ const connection = new AbortController();
292
+ const abort = () => connection.abort();
293
+ (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', abort);
294
+ let idle;
295
+ const touch = () => {
296
+ clearTimeout(idle);
297
+ idle = setTimeout(abort, ATTACH_IDLE_MS);
298
+ };
299
+ try {
300
+ touch();
301
+ const response = await api.attachCommandRaw({ sandboxId, processId, stdoutOffset: offsets.stdout, stderrOffset: offsets.stderr }, { signal: connection.signal });
302
+ connected = true;
303
+ failingSince = undefined;
304
+ for await (const frame of ndjsonFrames(response.raw)) {
305
+ touch();
306
+ if (frame.type === 'stdout' || frame.type === 'stderr') {
307
+ offsets[frame.type] = (_e = frame.nextOffset) !== null && _e !== void 0 ? _e : offsets[frame.type];
308
+ yield frame;
309
+ }
310
+ else if (frame.type === 'exit' || frame.type === 'error') {
311
+ yield frame;
312
+ return;
313
+ }
314
+ else {
315
+ // attached, heartbeat, reconnect: ours to handle, never the caller's.
316
+ offsets.stdout = (_f = frame.stdoutOffset) !== null && _f !== void 0 ? _f : offsets.stdout;
317
+ offsets.stderr = (_g = frame.stderrOffset) !== null && _g !== void 0 ? _g : offsets.stderr;
318
+ }
319
+ }
320
+ }
321
+ catch (e) {
322
+ failingSince !== null && failingSince !== void 0 ? failingSince : (failingSince = Date.now());
323
+ if (!isNetworkError(e, options === null || options === void 0 ? void 0 : options.signal) || !connected || Date.now() - failingSince >= ATTACH_RETRY_MS)
324
+ throw e;
325
+ await delay(1000);
326
+ }
327
+ finally {
328
+ clearTimeout(idle);
329
+ (_c = options === null || options === void 0 ? void 0 : options.signal) === null || _c === void 0 ? void 0 : _c.removeEventListener('abort', abort);
330
+ }
331
+ }
332
+ }
333
+ /**
334
+ * Run a command with no time limit and yield its output until it ends.
335
+ *
336
+ * The command runs detached, so it has no 600 s cap and survives a dropped
337
+ * connection. Frames: `{ type: 'started', processId }`, then the frames of
338
+ * `followCommand`. Stopping early leaves the command running: call
339
+ * `stopCommand({ sandboxId, processId })` to stop it.
340
+ */
341
+ async function* runCommand(api, sandboxId, command, options) {
342
+ const deadline = Date.now() + STREAM_RETRY_MS;
343
+ let processId;
344
+ for (;;) {
345
+ try {
346
+ const started = await api.command({ sandboxId, commandRequest: { command, cwd: options === null || options === void 0 ? void 0 : options.cwd, detached: true } });
347
+ processId = started.processId;
348
+ break;
349
+ }
350
+ catch (e) {
351
+ if (Date.now() + 1000 >= deadline || !(await isRetryable(e)))
352
+ throw e;
353
+ }
354
+ await delay(1000);
355
+ }
356
+ yield { type: 'started', processId };
357
+ yield* followCommand(api, sandboxId, processId, options);
358
+ }
@@ -1281,12 +1281,12 @@ export declare class BoatApi extends runtime.BaseAPI {
1281
1281
  */
1282
1282
  listCredentialAccountsRequestOpts(requestParameters: ListCredentialAccountsRequest): Promise<runtime.RequestOpts>;
1283
1283
  /**
1284
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
1284
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
1285
1285
  * List the accounts of a credential
1286
1286
  */
1287
1287
  listCredentialAccountsRaw(requestParameters: ListCredentialAccountsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<CredentialAccountsResponse>>;
1288
1288
  /**
1289
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
1289
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
1290
1290
  * List the accounts of a credential
1291
1291
  */
1292
1292
  listCredentialAccounts(requestParameters: ListCredentialAccountsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<CredentialAccountsResponse>;
@@ -2680,7 +2680,7 @@ export class BoatApi extends runtime.BaseAPI {
2680
2680
  };
2681
2681
  }
2682
2682
  /**
2683
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
2683
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
2684
2684
  * List the accounts of a credential
2685
2685
  */
2686
2686
  async listCredentialAccountsRaw(requestParameters, initOverrides) {
@@ -2689,7 +2689,7 @@ export class BoatApi extends runtime.BaseAPI {
2689
2689
  return new runtime.JSONApiResponse(response, (jsonValue) => CredentialAccountsResponseFromJSON(jsonValue));
2690
2690
  }
2691
2691
  /**
2692
- * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`.
2692
+ * Every account of one credential (several ChatGPT sign-ins, several OpenAI keys), in the order they were added, the one in use marked. Labels only, never a secret. Needs an API key with `account.admin`, on a profile you manage: an org member who only uses an org profile gets `403`.
2693
2693
  * List the accounts of a credential
2694
2694
  */
2695
2695
  async listCredentialAccounts(requestParameters, initOverrides) {
@@ -76,3 +76,26 @@ export type StreamCommandOptions = {
76
76
  * sent to a starting sandbox for up to 60 s instead of refusing it.
77
77
  */
78
78
  export declare function streamCommand(api: BoatApi, sandboxId: string, command: string, options?: StreamCommandOptions): AsyncGenerator<CommandFrame>;
79
+ export type FollowCommandOptions = {
80
+ signal?: AbortSignal;
81
+ };
82
+ /**
83
+ * Yield a detached command's output from its start until it ends: `stdout`/`stderr`
84
+ * chunks (`frame.data`), then exactly one `exit` (`exitCode`, ...) or `error`
85
+ * (`message`). The server ends each connection after 10 minutes; this reconnects
86
+ * from the same offsets, with no gap and no repeat. A network cut is reconnected
87
+ * the same way for up to 60 s.
88
+ */
89
+ export declare function followCommand(api: BoatApi, sandboxId: string, processId: number, options?: FollowCommandOptions): AsyncGenerator<CommandFrame>;
90
+ export type RunCommandOptions = FollowCommandOptions & {
91
+ cwd?: string;
92
+ };
93
+ /**
94
+ * Run a command with no time limit and yield its output until it ends.
95
+ *
96
+ * The command runs detached, so it has no 600 s cap and survives a dropped
97
+ * connection. Frames: `{ type: 'started', processId }`, then the frames of
98
+ * `followCommand`. Stopping early leaves the command running: call
99
+ * `stopCommand({ sandboxId, processId })` to stop it.
100
+ */
101
+ export declare function runCommand(api: BoatApi, sandboxId: string, command: string, options?: RunCommandOptions): AsyncGenerator<CommandFrame>;
@@ -245,3 +245,98 @@ export async function* streamCommand(api, sandboxId, command, options) {
245
245
  await delay(1000);
246
246
  }
247
247
  }
248
+ // The server sends a heartbeat every 15 s, so 60 s of silence is a dead connection.
249
+ const ATTACH_IDLE_MS = 60000;
250
+ // After the first connection, a failed reconnect is tried again for this long.
251
+ const ATTACH_RETRY_MS = 60000;
252
+ function isNetworkError(e, signal) {
253
+ if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || e instanceof SyntaxError)
254
+ return false;
255
+ return !(e === null || e === void 0 ? void 0 : e.response);
256
+ }
257
+ /**
258
+ * Yield a detached command's output from its start until it ends: `stdout`/`stderr`
259
+ * chunks (`frame.data`), then exactly one `exit` (`exitCode`, ...) or `error`
260
+ * (`message`). The server ends each connection after 10 minutes; this reconnects
261
+ * from the same offsets, with no gap and no repeat. A network cut is reconnected
262
+ * the same way for up to 60 s.
263
+ */
264
+ export async function* followCommand(api, sandboxId, processId, options) {
265
+ var _a, _b, _c;
266
+ var _d, _e, _f, _g;
267
+ const offsets = { stdout: 0, stderr: 0 };
268
+ let connected = false;
269
+ // Set at the first failure after a good connection; any good connection clears it.
270
+ let failingSince;
271
+ for (;;) {
272
+ if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted)
273
+ throw (_d = options.signal.reason) !== null && _d !== void 0 ? _d : new Error('followCommand aborted');
274
+ // One controller per connection: the caller's signal, or 60 s with no line.
275
+ const connection = new AbortController();
276
+ const abort = () => connection.abort();
277
+ (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', abort);
278
+ let idle;
279
+ const touch = () => {
280
+ clearTimeout(idle);
281
+ idle = setTimeout(abort, ATTACH_IDLE_MS);
282
+ };
283
+ try {
284
+ touch();
285
+ const response = await api.attachCommandRaw({ sandboxId, processId, stdoutOffset: offsets.stdout, stderrOffset: offsets.stderr }, { signal: connection.signal });
286
+ connected = true;
287
+ failingSince = undefined;
288
+ for await (const frame of ndjsonFrames(response.raw)) {
289
+ touch();
290
+ if (frame.type === 'stdout' || frame.type === 'stderr') {
291
+ offsets[frame.type] = (_e = frame.nextOffset) !== null && _e !== void 0 ? _e : offsets[frame.type];
292
+ yield frame;
293
+ }
294
+ else if (frame.type === 'exit' || frame.type === 'error') {
295
+ yield frame;
296
+ return;
297
+ }
298
+ else {
299
+ // attached, heartbeat, reconnect: ours to handle, never the caller's.
300
+ offsets.stdout = (_f = frame.stdoutOffset) !== null && _f !== void 0 ? _f : offsets.stdout;
301
+ offsets.stderr = (_g = frame.stderrOffset) !== null && _g !== void 0 ? _g : offsets.stderr;
302
+ }
303
+ }
304
+ }
305
+ catch (e) {
306
+ failingSince !== null && failingSince !== void 0 ? failingSince : (failingSince = Date.now());
307
+ if (!isNetworkError(e, options === null || options === void 0 ? void 0 : options.signal) || !connected || Date.now() - failingSince >= ATTACH_RETRY_MS)
308
+ throw e;
309
+ await delay(1000);
310
+ }
311
+ finally {
312
+ clearTimeout(idle);
313
+ (_c = options === null || options === void 0 ? void 0 : options.signal) === null || _c === void 0 ? void 0 : _c.removeEventListener('abort', abort);
314
+ }
315
+ }
316
+ }
317
+ /**
318
+ * Run a command with no time limit and yield its output until it ends.
319
+ *
320
+ * The command runs detached, so it has no 600 s cap and survives a dropped
321
+ * connection. Frames: `{ type: 'started', processId }`, then the frames of
322
+ * `followCommand`. Stopping early leaves the command running: call
323
+ * `stopCommand({ sandboxId, processId })` to stop it.
324
+ */
325
+ export async function* runCommand(api, sandboxId, command, options) {
326
+ const deadline = Date.now() + STREAM_RETRY_MS;
327
+ let processId;
328
+ for (;;) {
329
+ try {
330
+ const started = await api.command({ sandboxId, commandRequest: { command, cwd: options === null || options === void 0 ? void 0 : options.cwd, detached: true } });
331
+ processId = started.processId;
332
+ break;
333
+ }
334
+ catch (e) {
335
+ if (Date.now() + 1000 >= deadline || !(await isRetryable(e)))
336
+ throw e;
337
+ }
338
+ await delay(1000);
339
+ }
340
+ yield { type: 'started', processId };
341
+ yield* followCommand(api, sandboxId, processId, options);
342
+ }
@@ -55,7 +55,7 @@ export interface CredentialProfile {
55
55
  */
56
56
  connected: Array<CredentialId>;
57
57
  /**
58
- * Credentials with several accounts, keyed by credential id. Each lists every account (labels only), the one in use marked `active`.
58
+ * Credentials with several accounts, keyed by credential id. Each lists every account (labels only), the one in use marked `active`. Empty when you cannot manage the profile.
59
59
  * @type {{ [key: string]: Array<CredentialAccount>; }}
60
60
  * @memberof CredentialProfile
61
61
  */
@@ -46,7 +46,7 @@ export interface DeletionOperation {
46
46
  */
47
47
  status: DeletionOperationStatusEnum;
48
48
  /**
49
- * What the background purge is doing. The target is already gone from every list, restore and fork once the operation exists. `waiting_for_uploads`: stored data is erased once the last upload URL issued for it expires (`expectedBy`). `kept_for_newer_snapshots`: a newer snapshot, or a sandbox forked or deployed from it, still builds on this data; it goes when they go. `waiting_for_restore`: a sandbox is still restoring from it. `retrying`: a transient fault, retried automatically.
49
+ * What the background purge is doing. The target is already gone from every list, restore and fork once the operation exists. `waiting_for_uploads`: stored data is erased once the last upload URL issued for it expires (`expectedBy`). `retrying`: a transient fault, retried automatically. `completed`: a newer snapshot, a fork or a named snapshot made from it keeps the data it reads, until that is deleted too.
50
50
  * @type {DeletionOperationStageEnum}
51
51
  * @memberof DeletionOperation
52
52
  */
@@ -109,8 +109,6 @@ export type DeletionOperationStatusEnum = typeof DeletionOperationStatusEnum[key
109
109
  export declare const DeletionOperationStageEnum: {
110
110
  readonly Removing: 'removing';
111
111
  readonly WaitingForUploads: 'waiting_for_uploads';
112
- readonly KeptForNewerSnapshots: 'kept_for_newer_snapshots';
113
- readonly WaitingForRestore: 'waiting_for_restore';
114
112
  readonly Retrying: 'retrying';
115
113
  readonly Completed: 'completed';
116
114
  };
@@ -41,8 +41,6 @@ export const DeletionOperationStatusEnum = {
41
41
  export const DeletionOperationStageEnum = {
42
42
  Removing: 'removing',
43
43
  WaitingForUploads: 'waiting_for_uploads',
44
- KeptForNewerSnapshots: 'kept_for_newer_snapshots',
45
- WaitingForRestore: 'waiting_for_restore',
46
44
  Retrying: 'retrying',
47
45
  Completed: 'completed'
48
46
  };
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import type { LimitsFieldsGiftLimit } from './LimitsFieldsGiftLimit';
13
13
  import type { LimitsFieldsCurrentLimits } from './LimitsFieldsCurrentLimits';
14
+ import type { LimitsFieldsMachineTypesInner } from './LimitsFieldsMachineTypesInner';
14
15
  import type { LimitsFieldsStartLimits } from './LimitsFieldsStartLimits';
15
16
  import type { LimitsFieldsStarts } from './LimitsFieldsStarts';
16
17
  import type { LimitsFieldsSandboxPlanTiersInner } from './LimitsFieldsSandboxPlanTiersInner';
@@ -271,6 +272,12 @@ export interface LimitsFields {
271
272
  * @memberof LimitsFields
272
273
  */
273
274
  trialLine?: string | null;
275
+ /**
276
+ * Each sandbox type, and whether this account can create it now. A blocked type carries the reason.
277
+ * @type {Array<LimitsFieldsMachineTypesInner>}
278
+ * @memberof LimitsFields
279
+ */
280
+ machineTypes?: Array<LimitsFieldsMachineTypesInner>;
274
281
  /**
275
282
  *
276
283
  * @type {LimitsFieldsGiftLimit}
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import { LimitsFieldsGiftLimitFromJSON, LimitsFieldsGiftLimitToJSON, } from './LimitsFieldsGiftLimit';
15
15
  import { LimitsFieldsCurrentLimitsFromJSON, LimitsFieldsCurrentLimitsToJSON, } from './LimitsFieldsCurrentLimits';
16
+ import { LimitsFieldsMachineTypesInnerFromJSON, LimitsFieldsMachineTypesInnerToJSON, } from './LimitsFieldsMachineTypesInner';
16
17
  import { LimitsFieldsStartLimitsFromJSON, LimitsFieldsStartLimitsToJSON, } from './LimitsFieldsStartLimits';
17
18
  import { LimitsFieldsStartsFromJSON, LimitsFieldsStartsToJSON, } from './LimitsFieldsStarts';
18
19
  import { LimitsFieldsSandboxPlanTiersInnerFromJSON, LimitsFieldsSandboxPlanTiersInnerToJSON, } from './LimitsFieldsSandboxPlanTiersInner';
@@ -80,6 +81,7 @@ export function LimitsFieldsFromJSONTyped(json, ignoreDiscriminator) {
80
81
  'last24hUsageSeconds': json['last24hUsageSeconds'] == null ? undefined : json['last24hUsageSeconds'],
81
82
  'trialComputeCapSeconds': json['trialComputeCapSeconds'] == null ? undefined : json['trialComputeCapSeconds'],
82
83
  'trialLine': json['trialLine'] == null ? undefined : json['trialLine'],
84
+ 'machineTypes': json['machineTypes'] == null ? undefined : (json['machineTypes'].map(LimitsFieldsMachineTypesInnerFromJSON)),
83
85
  'giftLimit': json['giftLimit'] == null ? undefined : LimitsFieldsGiftLimitFromJSON(json['giftLimit']),
84
86
  'billingStatus': json['billingStatus'],
85
87
  'subscriptionStatus': json['subscriptionStatus'] == null ? undefined : json['subscriptionStatus'],
@@ -142,6 +144,7 @@ export function LimitsFieldsToJSONTyped(value, ignoreDiscriminator = false) {
142
144
  'last24hUsageSeconds': value['last24hUsageSeconds'],
143
145
  'trialComputeCapSeconds': value['trialComputeCapSeconds'],
144
146
  'trialLine': value['trialLine'],
147
+ 'machineTypes': value['machineTypes'] == null ? undefined : (value['machineTypes'].map(LimitsFieldsMachineTypesInnerToJSON)),
145
148
  'giftLimit': LimitsFieldsGiftLimitToJSON(value['giftLimit']),
146
149
  'billingStatus': value['billingStatus'],
147
150
  'subscriptionStatus': value['subscriptionStatus'],
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Boat Public API v1
3
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
4
+ *
5
+ * The version of the OpenAPI document: 1.0.0
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ /**
13
+ *
14
+ * @export
15
+ * @interface LimitsFieldsMachineTypesInner
16
+ */
17
+ export interface LimitsFieldsMachineTypesInner {
18
+ /**
19
+ *
20
+ * @type {LimitsFieldsMachineTypesInnerTypeEnum}
21
+ * @memberof LimitsFieldsMachineTypesInner
22
+ */
23
+ type: LimitsFieldsMachineTypesInnerTypeEnum;
24
+ /**
25
+ *
26
+ * @type {boolean}
27
+ * @memberof LimitsFieldsMachineTypesInner
28
+ */
29
+ available: boolean;
30
+ /**
31
+ * Why the type is blocked, for example `not during the free trial; the first payment unlocks it`. Null when available.
32
+ * @type {string}
33
+ * @memberof LimitsFieldsMachineTypesInner
34
+ */
35
+ reason: string | null;
36
+ }
37
+ /**
38
+ * @export
39
+ */
40
+ export declare const LimitsFieldsMachineTypesInnerTypeEnum: {
41
+ readonly Small: 'small';
42
+ readonly Default: 'default';
43
+ readonly Large: 'large';
44
+ readonly Xlarge: 'xlarge';
45
+ };
46
+ export type LimitsFieldsMachineTypesInnerTypeEnum = typeof LimitsFieldsMachineTypesInnerTypeEnum[keyof typeof LimitsFieldsMachineTypesInnerTypeEnum];
47
+ /**
48
+ * Check if a given object implements the LimitsFieldsMachineTypesInner interface.
49
+ */
50
+ export declare function instanceOfLimitsFieldsMachineTypesInner(value: object): value is LimitsFieldsMachineTypesInner;
51
+ export declare function LimitsFieldsMachineTypesInnerFromJSON(json: any): LimitsFieldsMachineTypesInner;
52
+ export declare function LimitsFieldsMachineTypesInnerFromJSONTyped(json: any, ignoreDiscriminator: boolean): LimitsFieldsMachineTypesInner;
53
+ export declare function LimitsFieldsMachineTypesInnerToJSON(json: any): LimitsFieldsMachineTypesInner;
54
+ export declare function LimitsFieldsMachineTypesInnerToJSONTyped(value?: LimitsFieldsMachineTypesInner | null, ignoreDiscriminator?: boolean): any;
@@ -0,0 +1,60 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Boat Public API v1
5
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
6
+ *
7
+ * The version of the OpenAPI document: 1.0.0
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+ /**
15
+ * @export
16
+ */
17
+ export const LimitsFieldsMachineTypesInnerTypeEnum = {
18
+ Small: 'small',
19
+ Default: 'default',
20
+ Large: 'large',
21
+ Xlarge: 'xlarge'
22
+ };
23
+ /**
24
+ * Check if a given object implements the LimitsFieldsMachineTypesInner interface.
25
+ */
26
+ export function instanceOfLimitsFieldsMachineTypesInner(value) {
27
+ if (!('type' in value) || value['type'] === undefined)
28
+ return false;
29
+ if (!('available' in value) || value['available'] === undefined)
30
+ return false;
31
+ if (!('reason' in value) || value['reason'] === undefined)
32
+ return false;
33
+ return true;
34
+ }
35
+ export function LimitsFieldsMachineTypesInnerFromJSON(json) {
36
+ return LimitsFieldsMachineTypesInnerFromJSONTyped(json, false);
37
+ }
38
+ export function LimitsFieldsMachineTypesInnerFromJSONTyped(json, ignoreDiscriminator) {
39
+ if (json == null) {
40
+ return json;
41
+ }
42
+ return {
43
+ 'type': json['type'],
44
+ 'available': json['available'],
45
+ 'reason': json['reason'],
46
+ };
47
+ }
48
+ export function LimitsFieldsMachineTypesInnerToJSON(json) {
49
+ return LimitsFieldsMachineTypesInnerToJSONTyped(json, false);
50
+ }
51
+ export function LimitsFieldsMachineTypesInnerToJSONTyped(value, ignoreDiscriminator = false) {
52
+ if (value == null) {
53
+ return value;
54
+ }
55
+ return {
56
+ 'type': value['type'],
57
+ 'available': value['available'],
58
+ 'reason': value['reason'],
59
+ };
60
+ }
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import type { LimitsFieldsGiftLimit } from './LimitsFieldsGiftLimit';
13
13
  import type { LimitsFieldsCurrentLimits } from './LimitsFieldsCurrentLimits';
14
+ import type { LimitsFieldsMachineTypesInner } from './LimitsFieldsMachineTypesInner';
14
15
  import type { LimitsFieldsStartLimits } from './LimitsFieldsStartLimits';
15
16
  import type { LimitsFieldsStarts } from './LimitsFieldsStarts';
16
17
  import type { LimitsFieldsSandboxPlanTiersInner } from './LimitsFieldsSandboxPlanTiersInner';
@@ -282,6 +283,12 @@ export interface LimitsResponse {
282
283
  * @memberof LimitsResponse
283
284
  */
284
285
  trialLine?: string;
286
+ /**
287
+ * Each sandbox type, and whether this account can create it now. A blocked type carries the reason.
288
+ * @type {Array<LimitsFieldsMachineTypesInner>}
289
+ * @memberof LimitsResponse
290
+ */
291
+ machineTypes?: Array<LimitsFieldsMachineTypesInner>;
285
292
  /**
286
293
  *
287
294
  * @type {LimitsFieldsGiftLimit}
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import { LimitsFieldsGiftLimitFromJSON, LimitsFieldsGiftLimitToJSON, } from './LimitsFieldsGiftLimit';
15
15
  import { LimitsFieldsCurrentLimitsFromJSON, LimitsFieldsCurrentLimitsToJSON, } from './LimitsFieldsCurrentLimits';
16
+ import { LimitsFieldsMachineTypesInnerFromJSON, LimitsFieldsMachineTypesInnerToJSON, } from './LimitsFieldsMachineTypesInner';
16
17
  import { LimitsFieldsStartLimitsFromJSON, LimitsFieldsStartLimitsToJSON, } from './LimitsFieldsStartLimits';
17
18
  import { LimitsFieldsStartsFromJSON, LimitsFieldsStartsToJSON, } from './LimitsFieldsStarts';
18
19
  import { LimitsFieldsSandboxPlanTiersInnerFromJSON, LimitsFieldsSandboxPlanTiersInnerToJSON, } from './LimitsFieldsSandboxPlanTiersInner';
@@ -85,6 +86,7 @@ export function LimitsResponseFromJSONTyped(json, ignoreDiscriminator) {
85
86
  'last24hUsageSeconds': json['last24hUsageSeconds'] == null ? undefined : json['last24hUsageSeconds'],
86
87
  'trialComputeCapSeconds': json['trialComputeCapSeconds'] == null ? undefined : json['trialComputeCapSeconds'],
87
88
  'trialLine': json['trialLine'] == null ? undefined : json['trialLine'],
89
+ 'machineTypes': json['machineTypes'] == null ? undefined : (json['machineTypes'].map(LimitsFieldsMachineTypesInnerFromJSON)),
88
90
  'giftLimit': json['giftLimit'] == null ? undefined : LimitsFieldsGiftLimitFromJSON(json['giftLimit']),
89
91
  'billingStatus': json['billingStatus'],
90
92
  'subscriptionStatus': json['subscriptionStatus'] == null ? undefined : json['subscriptionStatus'],
@@ -148,6 +150,7 @@ export function LimitsResponseToJSONTyped(value, ignoreDiscriminator = false) {
148
150
  'last24hUsageSeconds': value['last24hUsageSeconds'],
149
151
  'trialComputeCapSeconds': value['trialComputeCapSeconds'],
150
152
  'trialLine': value['trialLine'],
153
+ 'machineTypes': value['machineTypes'] == null ? undefined : (value['machineTypes'].map(LimitsFieldsMachineTypesInnerToJSON)),
151
154
  'giftLimit': LimitsFieldsGiftLimitToJSON(value['giftLimit']),
152
155
  'billingStatus': value['billingStatus'],
153
156
  'subscriptionStatus': value['subscriptionStatus'],