@daytonaio/sdk 0.175.0 → 0.178.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/cjs/CodeInterpreter.d.ts +3 -2
  2. package/cjs/CodeInterpreter.js.map +1 -1
  3. package/cjs/ComputerUse.d.ts +104 -2
  4. package/cjs/ComputerUse.js +851 -763
  5. package/cjs/ComputerUse.js.map +1 -1
  6. package/cjs/Daytona.d.ts +4 -3
  7. package/cjs/Daytona.js +429 -443
  8. package/cjs/Daytona.js.map +1 -1
  9. package/cjs/FileSystem.d.ts +2 -2
  10. package/cjs/FileSystem.js +491 -521
  11. package/cjs/FileSystem.js.map +1 -1
  12. package/cjs/Git.d.ts +2 -1
  13. package/cjs/Git.js +287 -310
  14. package/cjs/Git.js.map +1 -1
  15. package/cjs/LspServer.d.ts +2 -1
  16. package/cjs/LspServer.js +209 -226
  17. package/cjs/LspServer.js.map +1 -1
  18. package/cjs/ObjectStorage.js +170 -166
  19. package/cjs/ObjectStorage.js.map +1 -1
  20. package/cjs/Process.d.ts +4 -3
  21. package/cjs/Process.js +562 -600
  22. package/cjs/Process.js.map +1 -1
  23. package/cjs/PtyHandle.d.ts +2 -2
  24. package/cjs/PtyHandle.js +327 -338
  25. package/cjs/PtyHandle.js.map +1 -1
  26. package/cjs/Sandbox.d.ts +4 -3
  27. package/cjs/Sandbox.js +756 -821
  28. package/cjs/Sandbox.js.map +1 -1
  29. package/cjs/Snapshot.d.ts +3 -2
  30. package/cjs/Snapshot.js +203 -213
  31. package/cjs/Snapshot.js.map +1 -1
  32. package/cjs/Volume.d.ts +2 -1
  33. package/cjs/Volume.js +90 -92
  34. package/cjs/Volume.js.map +1 -1
  35. package/cjs/errors/DaytonaError.d.ts +2 -1
  36. package/cjs/errors/DaytonaError.js.map +1 -1
  37. package/cjs/index.d.ts +2 -2
  38. package/cjs/index.js +2 -1
  39. package/cjs/index.js.map +1 -1
  40. package/cjs/types/CodeInterpreter.d.ts +1 -1
  41. package/cjs/utils/Binary.js +14 -2
  42. package/cjs/utils/Binary.js.map +1 -1
  43. package/cjs/utils/otel.decorator.d.ts +7 -8
  44. package/cjs/utils/otel.decorator.js +24 -30
  45. package/cjs/utils/otel.decorator.js.map +1 -1
  46. package/esm/CodeInterpreter.d.ts +3 -2
  47. package/esm/CodeInterpreter.js.map +1 -1
  48. package/esm/ComputerUse.d.ts +104 -2
  49. package/esm/ComputerUse.js +857 -763
  50. package/esm/ComputerUse.js.map +1 -1
  51. package/esm/Daytona.d.ts +4 -3
  52. package/esm/Daytona.js +431 -444
  53. package/esm/Daytona.js.map +1 -1
  54. package/esm/FileSystem.d.ts +2 -2
  55. package/esm/FileSystem.js +493 -522
  56. package/esm/FileSystem.js.map +1 -1
  57. package/esm/Git.d.ts +2 -1
  58. package/esm/Git.js +289 -311
  59. package/esm/Git.js.map +1 -1
  60. package/esm/LspServer.d.ts +2 -1
  61. package/esm/LspServer.js +211 -227
  62. package/esm/LspServer.js.map +1 -1
  63. package/esm/ObjectStorage.js +172 -167
  64. package/esm/ObjectStorage.js.map +1 -1
  65. package/esm/Process.d.ts +4 -3
  66. package/esm/Process.js +564 -601
  67. package/esm/Process.js.map +1 -1
  68. package/esm/PtyHandle.d.ts +2 -2
  69. package/esm/PtyHandle.js +329 -339
  70. package/esm/PtyHandle.js.map +1 -1
  71. package/esm/Sandbox.d.ts +4 -3
  72. package/esm/Sandbox.js +759 -823
  73. package/esm/Sandbox.js.map +1 -1
  74. package/esm/Snapshot.d.ts +3 -2
  75. package/esm/Snapshot.js +206 -215
  76. package/esm/Snapshot.js.map +1 -1
  77. package/esm/Volume.d.ts +2 -1
  78. package/esm/Volume.js +92 -93
  79. package/esm/Volume.js.map +1 -1
  80. package/esm/errors/DaytonaError.d.ts +2 -1
  81. package/esm/errors/DaytonaError.js.map +1 -1
  82. package/esm/index.d.ts +2 -2
  83. package/esm/index.js +1 -1
  84. package/esm/index.js.map +1 -1
  85. package/esm/types/CodeInterpreter.d.ts +1 -1
  86. package/esm/utils/Binary.js +14 -2
  87. package/esm/utils/Binary.js.map +1 -1
  88. package/esm/utils/otel.decorator.d.ts +7 -8
  89. package/esm/utils/otel.decorator.js +26 -32
  90. package/esm/utils/otel.decorator.js.map +1 -1
  91. package/package.json +3 -3
package/esm/Sandbox.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * Copyright 2025 Daytona Platforms Inc.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- import { __decorate, __metadata } from "tslib";
6
- import { SandboxState, } from '@daytona/api-client';
5
+ import { __esDecorate, __runInitializers } from "tslib";
6
+ import { SandboxState } from '@daytona/api-client';
7
7
  import { Daytona } from './Daytona.js';
8
8
  import { FileSystemApi, GitApi, ProcessApi, LspApi, InfoApi, ComputerUseApi, InterpreterApi, } from '@daytona/toolbox-api-client';
9
9
  import { FileSystem } from './FileSystem.js';
@@ -54,848 +54,784 @@ import { WithInstrumentation } from './utils/otel.decorator.js';
54
54
  *
55
55
  * @class
56
56
  */
57
- export class Sandbox {
58
- clientConfig;
59
- axiosInstance;
60
- sandboxApi;
61
- fs;
62
- git;
63
- process;
64
- computerUse;
65
- codeInterpreter;
66
- id;
67
- name;
68
- organizationId;
69
- snapshot;
70
- user;
71
- env;
72
- labels;
73
- public;
74
- target;
75
- cpu;
76
- gpu;
77
- memory;
78
- disk;
79
- state;
80
- errorReason;
81
- recoverable;
82
- backupState;
83
- backupCreatedAt;
84
- autoStopInterval;
85
- autoArchiveInterval;
86
- autoDeleteInterval;
87
- volumes;
88
- buildInfo;
89
- createdAt;
90
- updatedAt;
91
- lastActivityAt;
92
- networkBlockAll;
93
- networkAllowList;
94
- toolboxProxyUrl;
95
- infoApi;
96
- /**
97
- * Creates a new Sandbox instance
98
- *
99
- * @param {SandboxDto} sandboxDto - The API Sandbox instance
100
- */
101
- constructor(sandboxDto, clientConfig, axiosInstance, sandboxApi) {
102
- this.clientConfig = clientConfig;
103
- this.axiosInstance = axiosInstance;
104
- this.sandboxApi = sandboxApi;
105
- this.processSandboxDto(sandboxDto);
106
- // Set the toolbox base URL
107
- let baseUrl = this.toolboxProxyUrl;
108
- if (!baseUrl.endsWith('/')) {
109
- baseUrl += '/';
110
- }
111
- this.axiosInstance.defaults.baseURL = baseUrl + this.id;
112
- this.clientConfig.basePath = this.axiosInstance.defaults.baseURL;
113
- // Initialize Services
114
- const getPreviewToken = async () => (await this.getPreviewLink(1)).token;
115
- this.fs = new FileSystem(this.clientConfig, new FileSystemApi(this.clientConfig, '', this.axiosInstance));
116
- this.git = new Git(new GitApi(this.clientConfig, '', this.axiosInstance));
117
- const language = sandboxDto.labels?.[CODE_TOOLBOX_LANGUAGE_LABEL];
118
- this.process = new Process(this.clientConfig, new ProcessApi(this.clientConfig, '', this.axiosInstance), getPreviewToken, language);
119
- this.codeInterpreter = new CodeInterpreter(this.clientConfig, new InterpreterApi(this.clientConfig, '', this.axiosInstance), getPreviewToken);
120
- this.computerUse = new ComputerUse(new ComputerUseApi(this.clientConfig, '', this.axiosInstance));
121
- this.infoApi = new InfoApi(this.clientConfig, '', this.axiosInstance);
122
- }
123
- /**
124
- * Gets the user's home directory path for the logged in user inside the Sandbox.
125
- *
126
- * @returns {Promise<string | undefined>} The absolute path to the Sandbox user's home directory for the logged in user
127
- *
128
- * @example
129
- * const userHomeDir = await sandbox.getUserHomeDir();
130
- * console.log(`Sandbox user home: ${userHomeDir}`);
131
- */
132
- async getUserHomeDir() {
133
- const response = await this.infoApi.getUserHomeDir();
134
- return response.data.dir;
135
- }
136
- /**
137
- * @deprecated Use `getUserHomeDir` instead. This method will be removed in a future version.
138
- */
139
- async getUserRootDir() {
140
- return this.getUserHomeDir();
141
- }
142
- /**
143
- * Gets the working directory path inside the Sandbox.
144
- *
145
- * @returns {Promise<string | undefined>} The absolute path to the Sandbox working directory. Uses the WORKDIR specified
146
- * in the Dockerfile if present, or falling back to the user's home directory if not.
147
- *
148
- * @example
149
- * const workDir = await sandbox.getWorkDir();
150
- * console.log(`Sandbox working directory: ${workDir}`);
151
- */
152
- async getWorkDir() {
153
- const response = await this.infoApi.getWorkDir();
154
- return response.data.dir;
155
- }
156
- /**
157
- * Creates a new Language Server Protocol (LSP) server instance.
158
- *
159
- * The LSP server provides language-specific features like code completion,
160
- * diagnostics, and more.
161
- *
162
- * @param {LspLanguageId} languageId - The language server type (e.g., "typescript")
163
- * @param {string} pathToProject - Path to the project root directory. Relative paths are resolved based on the sandbox working directory.
164
- * @returns {LspServer} A new LSP server instance configured for the specified language
165
- *
166
- * @example
167
- * const lsp = await sandbox.createLspServer('typescript', 'workspace/project');
168
- */
169
- async createLspServer(languageId, pathToProject) {
170
- return new LspServer(languageId, pathToProject, new LspApi(this.clientConfig, '', this.axiosInstance));
171
- }
172
- /**
173
- * Sets labels for the Sandbox.
174
- *
175
- * Labels are key-value pairs that can be used to organize and identify Sandboxes.
176
- *
177
- * @param {Record<string, string>} labels - Dictionary of key-value pairs representing Sandbox labels
178
- * @returns {Promise<void>}
179
- *
180
- * @example
181
- * // Set sandbox labels
182
- * await sandbox.setLabels({
183
- * project: 'my-project',
184
- * environment: 'development',
185
- * team: 'backend'
186
- * });
187
- */
188
- async setLabels(labels) {
189
- this.labels = (await this.sandboxApi.replaceLabels(this.id, { labels })).data.labels;
190
- return this.labels;
191
- }
192
- /**
193
- * Start the Sandbox.
194
- *
195
- * This method starts the Sandbox and waits for it to be ready.
196
- *
197
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
198
- * Defaults to 60-second timeout.
199
- * @returns {Promise<void>}
200
- * @throws {DaytonaError} - `DaytonaError` - If Sandbox fails to start or times out
201
- *
202
- * @example
203
- * const sandbox = await daytona.getCurrentSandbox('my-sandbox');
204
- * await sandbox.start(40); // Wait up to 40 seconds
205
- * console.log('Sandbox started successfully');
206
- */
207
- async start(timeout = 60) {
208
- if (timeout < 0) {
209
- throw new DaytonaValidationError('Timeout must be a non-negative number');
210
- }
211
- const startTime = Date.now();
212
- const response = await this.sandboxApi.startSandbox(this.id, undefined, { timeout: timeout * 1000 });
213
- this.processSandboxDto(response.data);
214
- const timeElapsed = Date.now() - startTime;
215
- await this.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
216
- }
217
- /**
218
- * Recover the Sandbox from a recoverable error and wait for it to be ready.
219
- *
220
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
221
- * Defaults to 60-second timeout.
222
- * @returns {Promise<void>}
223
- * @throws {DaytonaError} - `DaytonaError` - If Sandbox fails to recover or times out
224
- *
225
- * @example
226
- * const sandbox = await daytona.get('my-sandbox-id');
227
- * await sandbox.recover();
228
- * console.log('Sandbox recovered successfully');
229
- */
230
- async recover(timeout = 60) {
231
- if (timeout < 0) {
232
- throw new DaytonaValidationError('Timeout must be a non-negative number');
233
- }
234
- const startTime = Date.now();
235
- const response = await this.sandboxApi.recoverSandbox(this.id, undefined, undefined, { timeout: timeout * 1000 });
236
- this.processSandboxDto(response.data);
237
- const timeElapsed = Date.now() - startTime;
238
- await this.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
239
- }
240
- /**
241
- * Stops the Sandbox.
242
- *
243
- * This method stops the Sandbox and waits for it to be fully stopped.
244
- *
245
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
246
- * Defaults to 60-second timeout.
247
- * @param {boolean} [force] - If true, uses SIGKILL instead of SIGTERM. Defaults to false.
248
- * @returns {Promise<void>}
249
- *
250
- * @example
251
- * const sandbox = await daytona.get('my-sandbox-id');
252
- * await sandbox.stop();
253
- * console.log('Sandbox stopped successfully');
254
- */
255
- async stop(timeout = 60, force = false) {
256
- if (timeout < 0) {
257
- throw new DaytonaValidationError('Timeout must be a non-negative number');
258
- }
259
- const startTime = Date.now();
260
- await this.sandboxApi.stopSandbox(this.id, undefined, force, { timeout: timeout * 1000 });
261
- await this.refreshDataSafe();
262
- const timeElapsed = Date.now() - startTime;
263
- await this.waitUntilStopped(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
264
- }
265
- /**
266
- * Forks the Sandbox, creating a new Sandbox with an identical filesystem.
267
- *
268
- * The forked Sandbox is a copy-on-write clone of the original. It starts
269
- * with the same disk contents but operates independently from that point on.
270
- *
271
- * @param {object} [params] - Fork parameters
272
- * @param {string} [params.name] - Optional name for the forked Sandbox. If not provided, a unique name will be generated.
273
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
274
- * Defaults to 60-second timeout.
275
- * @returns {Promise<Sandbox>} The forked Sandbox.
276
- * @throws {DaytonaValidationError} - If timeout is a negative number
277
- * @throws {DaytonaError} - If the fork operation fails or times out
278
- *
279
- * @example
280
- * const sandbox = await daytona.get('my-sandbox');
281
- * const forked = await sandbox._experimental_fork({ name: 'my-fork' });
282
- * console.log(`Forked sandbox: ${forked.id}`);
283
- */
284
- async _experimental_fork(params, timeout = 60) {
285
- if (timeout < 0) {
286
- throw new DaytonaValidationError('Timeout must be a non-negative number');
287
- }
288
- const startTime = Date.now();
289
- const response = await this.sandboxApi.forkSandbox(this.id, { name: params?.name }, undefined, {
290
- timeout: timeout * 1000,
291
- });
292
- const sandboxDto = response.data;
293
- const forkedSandbox = new Sandbox(sandboxDto, structuredClone(this.clientConfig), Daytona.createAxiosInstance(), this.sandboxApi);
294
- const timeElapsed = Date.now() - startTime;
295
- await forkedSandbox.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
296
- return forkedSandbox;
297
- }
298
- /**
299
- * Creates a snapshot from the current state of the Sandbox.
300
- *
301
- * This captures the Sandbox's filesystem into a reusable snapshot that can be
302
- * used to create new Sandboxes. The Sandbox will temporarily enter a
303
- * 'snapshotting' state and return to its previous state when complete.
304
- *
305
- * @param {string} name - Name for the new snapshot
306
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
307
- * Defaults to 60-second timeout.
308
- * @returns {Promise<void>}
309
- * @throws {DaytonaValidationError} - If timeout is a negative number
310
- * @throws {DaytonaError} - If the snapshot operation fails or times out
311
- *
312
- * @example
313
- * const sandbox = await daytona.get('my-sandbox');
314
- * await sandbox._experimental_createSnapshot('my-snapshot');
315
- * console.log('Snapshot created successfully');
316
- */
317
- async _experimental_createSnapshot(name, timeout = 60) {
318
- if (timeout < 0) {
319
- throw new DaytonaValidationError('Timeout must be a non-negative number');
320
- }
321
- const startTime = Date.now();
322
- const req = { name };
323
- await this.sandboxApi.createSandboxSnapshot(this.id, req, undefined, {
324
- timeout: timeout * 1000,
325
- });
326
- await this.refreshData();
327
- const timeElapsed = Date.now() - startTime;
328
- const remainingTimeout = timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout;
329
- await this.waitForSnapshotComplete(remainingTimeout);
330
- }
331
- async waitForSnapshotComplete(timeout) {
332
- let checkInterval = 100;
333
- const startTime = Date.now();
334
- while (this.state === SandboxState.SNAPSHOTTING) {
335
- await this.refreshData();
336
- // @ts-expect-error this.refreshData() can modify this.state so this check is fine
337
- if (this.state === SandboxState.ERROR || this.state === SandboxState.BUILD_FAILED) {
338
- throw new DaytonaError(`Sandbox ${this.id} snapshot failed with state: ${this.state}, error reason: ${this.errorReason}`);
339
- }
340
- if (this.state !== SandboxState.SNAPSHOTTING) {
341
- return;
57
+ let Sandbox = (() => {
58
+ let _instanceExtraInitializers = [];
59
+ let _getUserHomeDir_decorators;
60
+ let _getUserRootDir_decorators;
61
+ let _getWorkDir_decorators;
62
+ let _createLspServer_decorators;
63
+ let _setLabels_decorators;
64
+ let _start_decorators;
65
+ let _stop_decorators;
66
+ let __experimental_fork_decorators;
67
+ let __experimental_createSnapshot_decorators;
68
+ let _delete_decorators;
69
+ let _waitUntilStarted_decorators;
70
+ let _waitUntilStopped_decorators;
71
+ let _refreshData_decorators;
72
+ let _setAutostopInterval_decorators;
73
+ let _setAutoArchiveInterval_decorators;
74
+ let _setAutoDeleteInterval_decorators;
75
+ let _updateNetworkSettings_decorators;
76
+ let _getPreviewLink_decorators;
77
+ let _archive_decorators;
78
+ let _resize_decorators;
79
+ let _waitForResizeComplete_decorators;
80
+ let _createSshAccess_decorators;
81
+ let _revokeSshAccess_decorators;
82
+ let _validateSshAccess_decorators;
83
+ return class Sandbox {
84
+ static {
85
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
86
+ _getUserHomeDir_decorators = [WithInstrumentation()];
87
+ _getUserRootDir_decorators = [WithInstrumentation()];
88
+ _getWorkDir_decorators = [WithInstrumentation()];
89
+ _createLspServer_decorators = [WithInstrumentation()];
90
+ _setLabels_decorators = [WithInstrumentation()];
91
+ _start_decorators = [WithInstrumentation()];
92
+ _stop_decorators = [WithInstrumentation()];
93
+ __experimental_fork_decorators = [WithInstrumentation()];
94
+ __experimental_createSnapshot_decorators = [WithInstrumentation()];
95
+ _delete_decorators = [WithInstrumentation()];
96
+ _waitUntilStarted_decorators = [WithInstrumentation()];
97
+ _waitUntilStopped_decorators = [WithInstrumentation()];
98
+ _refreshData_decorators = [WithInstrumentation()];
99
+ _setAutostopInterval_decorators = [WithInstrumentation()];
100
+ _setAutoArchiveInterval_decorators = [WithInstrumentation()];
101
+ _setAutoDeleteInterval_decorators = [WithInstrumentation()];
102
+ _updateNetworkSettings_decorators = [WithInstrumentation()];
103
+ _getPreviewLink_decorators = [WithInstrumentation()];
104
+ _archive_decorators = [WithInstrumentation()];
105
+ _resize_decorators = [WithInstrumentation()];
106
+ _waitForResizeComplete_decorators = [WithInstrumentation()];
107
+ _createSshAccess_decorators = [WithInstrumentation()];
108
+ _revokeSshAccess_decorators = [WithInstrumentation()];
109
+ _validateSshAccess_decorators = [WithInstrumentation()];
110
+ __esDecorate(this, null, _getUserHomeDir_decorators, { kind: "method", name: "getUserHomeDir", static: false, private: false, access: { has: obj => "getUserHomeDir" in obj, get: obj => obj.getUserHomeDir }, metadata: _metadata }, null, _instanceExtraInitializers);
111
+ __esDecorate(this, null, _getUserRootDir_decorators, { kind: "method", name: "getUserRootDir", static: false, private: false, access: { has: obj => "getUserRootDir" in obj, get: obj => obj.getUserRootDir }, metadata: _metadata }, null, _instanceExtraInitializers);
112
+ __esDecorate(this, null, _getWorkDir_decorators, { kind: "method", name: "getWorkDir", static: false, private: false, access: { has: obj => "getWorkDir" in obj, get: obj => obj.getWorkDir }, metadata: _metadata }, null, _instanceExtraInitializers);
113
+ __esDecorate(this, null, _createLspServer_decorators, { kind: "method", name: "createLspServer", static: false, private: false, access: { has: obj => "createLspServer" in obj, get: obj => obj.createLspServer }, metadata: _metadata }, null, _instanceExtraInitializers);
114
+ __esDecorate(this, null, _setLabels_decorators, { kind: "method", name: "setLabels", static: false, private: false, access: { has: obj => "setLabels" in obj, get: obj => obj.setLabels }, metadata: _metadata }, null, _instanceExtraInitializers);
115
+ __esDecorate(this, null, _start_decorators, { kind: "method", name: "start", static: false, private: false, access: { has: obj => "start" in obj, get: obj => obj.start }, metadata: _metadata }, null, _instanceExtraInitializers);
116
+ __esDecorate(this, null, _stop_decorators, { kind: "method", name: "stop", static: false, private: false, access: { has: obj => "stop" in obj, get: obj => obj.stop }, metadata: _metadata }, null, _instanceExtraInitializers);
117
+ __esDecorate(this, null, __experimental_fork_decorators, { kind: "method", name: "_experimental_fork", static: false, private: false, access: { has: obj => "_experimental_fork" in obj, get: obj => obj._experimental_fork }, metadata: _metadata }, null, _instanceExtraInitializers);
118
+ __esDecorate(this, null, __experimental_createSnapshot_decorators, { kind: "method", name: "_experimental_createSnapshot", static: false, private: false, access: { has: obj => "_experimental_createSnapshot" in obj, get: obj => obj._experimental_createSnapshot }, metadata: _metadata }, null, _instanceExtraInitializers);
119
+ __esDecorate(this, null, _delete_decorators, { kind: "method", name: "delete", static: false, private: false, access: { has: obj => "delete" in obj, get: obj => obj.delete }, metadata: _metadata }, null, _instanceExtraInitializers);
120
+ __esDecorate(this, null, _waitUntilStarted_decorators, { kind: "method", name: "waitUntilStarted", static: false, private: false, access: { has: obj => "waitUntilStarted" in obj, get: obj => obj.waitUntilStarted }, metadata: _metadata }, null, _instanceExtraInitializers);
121
+ __esDecorate(this, null, _waitUntilStopped_decorators, { kind: "method", name: "waitUntilStopped", static: false, private: false, access: { has: obj => "waitUntilStopped" in obj, get: obj => obj.waitUntilStopped }, metadata: _metadata }, null, _instanceExtraInitializers);
122
+ __esDecorate(this, null, _refreshData_decorators, { kind: "method", name: "refreshData", static: false, private: false, access: { has: obj => "refreshData" in obj, get: obj => obj.refreshData }, metadata: _metadata }, null, _instanceExtraInitializers);
123
+ __esDecorate(this, null, _setAutostopInterval_decorators, { kind: "method", name: "setAutostopInterval", static: false, private: false, access: { has: obj => "setAutostopInterval" in obj, get: obj => obj.setAutostopInterval }, metadata: _metadata }, null, _instanceExtraInitializers);
124
+ __esDecorate(this, null, _setAutoArchiveInterval_decorators, { kind: "method", name: "setAutoArchiveInterval", static: false, private: false, access: { has: obj => "setAutoArchiveInterval" in obj, get: obj => obj.setAutoArchiveInterval }, metadata: _metadata }, null, _instanceExtraInitializers);
125
+ __esDecorate(this, null, _setAutoDeleteInterval_decorators, { kind: "method", name: "setAutoDeleteInterval", static: false, private: false, access: { has: obj => "setAutoDeleteInterval" in obj, get: obj => obj.setAutoDeleteInterval }, metadata: _metadata }, null, _instanceExtraInitializers);
126
+ __esDecorate(this, null, _updateNetworkSettings_decorators, { kind: "method", name: "updateNetworkSettings", static: false, private: false, access: { has: obj => "updateNetworkSettings" in obj, get: obj => obj.updateNetworkSettings }, metadata: _metadata }, null, _instanceExtraInitializers);
127
+ __esDecorate(this, null, _getPreviewLink_decorators, { kind: "method", name: "getPreviewLink", static: false, private: false, access: { has: obj => "getPreviewLink" in obj, get: obj => obj.getPreviewLink }, metadata: _metadata }, null, _instanceExtraInitializers);
128
+ __esDecorate(this, null, _archive_decorators, { kind: "method", name: "archive", static: false, private: false, access: { has: obj => "archive" in obj, get: obj => obj.archive }, metadata: _metadata }, null, _instanceExtraInitializers);
129
+ __esDecorate(this, null, _resize_decorators, { kind: "method", name: "resize", static: false, private: false, access: { has: obj => "resize" in obj, get: obj => obj.resize }, metadata: _metadata }, null, _instanceExtraInitializers);
130
+ __esDecorate(this, null, _waitForResizeComplete_decorators, { kind: "method", name: "waitForResizeComplete", static: false, private: false, access: { has: obj => "waitForResizeComplete" in obj, get: obj => obj.waitForResizeComplete }, metadata: _metadata }, null, _instanceExtraInitializers);
131
+ __esDecorate(this, null, _createSshAccess_decorators, { kind: "method", name: "createSshAccess", static: false, private: false, access: { has: obj => "createSshAccess" in obj, get: obj => obj.createSshAccess }, metadata: _metadata }, null, _instanceExtraInitializers);
132
+ __esDecorate(this, null, _revokeSshAccess_decorators, { kind: "method", name: "revokeSshAccess", static: false, private: false, access: { has: obj => "revokeSshAccess" in obj, get: obj => obj.revokeSshAccess }, metadata: _metadata }, null, _instanceExtraInitializers);
133
+ __esDecorate(this, null, _validateSshAccess_decorators, { kind: "method", name: "validateSshAccess", static: false, private: false, access: { has: obj => "validateSshAccess" in obj, get: obj => obj.validateSshAccess }, metadata: _metadata }, null, _instanceExtraInitializers);
134
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
135
+ }
136
+ clientConfig = __runInitializers(this, _instanceExtraInitializers);
137
+ axiosInstance;
138
+ sandboxApi;
139
+ fs;
140
+ git;
141
+ process;
142
+ computerUse;
143
+ codeInterpreter;
144
+ id;
145
+ name;
146
+ organizationId;
147
+ snapshot;
148
+ user;
149
+ env;
150
+ labels;
151
+ public;
152
+ target;
153
+ cpu;
154
+ gpu;
155
+ memory;
156
+ disk;
157
+ state;
158
+ errorReason;
159
+ recoverable;
160
+ backupState;
161
+ backupCreatedAt;
162
+ autoStopInterval;
163
+ autoArchiveInterval;
164
+ autoDeleteInterval;
165
+ volumes;
166
+ buildInfo;
167
+ createdAt;
168
+ updatedAt;
169
+ lastActivityAt;
170
+ networkBlockAll;
171
+ networkAllowList;
172
+ toolboxProxyUrl;
173
+ infoApi;
174
+ /**
175
+ * Creates a new Sandbox instance
176
+ *
177
+ * @param {SandboxDto} sandboxDto - The API Sandbox instance
178
+ */
179
+ constructor(sandboxDto, clientConfig, axiosInstance, sandboxApi) {
180
+ this.clientConfig = clientConfig;
181
+ this.axiosInstance = axiosInstance;
182
+ this.sandboxApi = sandboxApi;
183
+ this.processSandboxDto(sandboxDto);
184
+ // Set the toolbox base URL
185
+ let baseUrl = this.toolboxProxyUrl;
186
+ if (!baseUrl.endsWith('/')) {
187
+ baseUrl += '/';
342
188
  }
343
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
344
- throw new DaytonaTimeoutError('Sandbox snapshot did not complete within the timeout period');
189
+ this.axiosInstance.defaults.baseURL = baseUrl + this.id;
190
+ this.clientConfig.basePath = this.axiosInstance.defaults.baseURL;
191
+ // Initialize Services
192
+ const getPreviewToken = async () => (await this.getPreviewLink(1)).token;
193
+ this.fs = new FileSystem(this.clientConfig, new FileSystemApi(this.clientConfig, '', this.axiosInstance));
194
+ this.git = new Git(new GitApi(this.clientConfig, '', this.axiosInstance));
195
+ const language = sandboxDto.labels?.[CODE_TOOLBOX_LANGUAGE_LABEL];
196
+ this.process = new Process(this.clientConfig, new ProcessApi(this.clientConfig, '', this.axiosInstance), getPreviewToken, language);
197
+ this.codeInterpreter = new CodeInterpreter(this.clientConfig, new InterpreterApi(this.clientConfig, '', this.axiosInstance), getPreviewToken);
198
+ this.computerUse = new ComputerUse(new ComputerUseApi(this.clientConfig, '', this.axiosInstance));
199
+ this.infoApi = new InfoApi(this.clientConfig, '', this.axiosInstance);
200
+ }
201
+ /**
202
+ * Gets the user's home directory path for the logged in user inside the Sandbox.
203
+ *
204
+ * @returns {Promise<string | undefined>} The absolute path to the Sandbox user's home directory for the logged in user
205
+ *
206
+ * @example
207
+ * const userHomeDir = await sandbox.getUserHomeDir();
208
+ * console.log(`Sandbox user home: ${userHomeDir}`);
209
+ */
210
+ async getUserHomeDir() {
211
+ const response = await this.infoApi.getUserHomeDir();
212
+ return response.data.dir;
213
+ }
214
+ /**
215
+ * @deprecated Use `getUserHomeDir` instead. This method will be removed in a future version.
216
+ */
217
+ async getUserRootDir() {
218
+ return this.getUserHomeDir();
219
+ }
220
+ /**
221
+ * Gets the working directory path inside the Sandbox.
222
+ *
223
+ * @returns {Promise<string | undefined>} The absolute path to the Sandbox working directory. Uses the WORKDIR specified
224
+ * in the Dockerfile if present, or falling back to the user's home directory if not.
225
+ *
226
+ * @example
227
+ * const workDir = await sandbox.getWorkDir();
228
+ * console.log(`Sandbox working directory: ${workDir}`);
229
+ */
230
+ async getWorkDir() {
231
+ const response = await this.infoApi.getWorkDir();
232
+ return response.data.dir;
233
+ }
234
+ /**
235
+ * Creates a new Language Server Protocol (LSP) server instance.
236
+ *
237
+ * The LSP server provides language-specific features like code completion,
238
+ * diagnostics, and more.
239
+ *
240
+ * @param {LspLanguageId} languageId - The language server type (e.g., "typescript")
241
+ * @param {string} pathToProject - Path to the project root directory. Relative paths are resolved based on the sandbox working directory.
242
+ * @returns {LspServer} A new LSP server instance configured for the specified language
243
+ *
244
+ * @example
245
+ * const lsp = await sandbox.createLspServer('typescript', 'workspace/project');
246
+ */
247
+ async createLspServer(languageId, pathToProject) {
248
+ return new LspServer(languageId, pathToProject, new LspApi(this.clientConfig, '', this.axiosInstance));
249
+ }
250
+ /**
251
+ * Sets labels for the Sandbox.
252
+ *
253
+ * Labels are key-value pairs that can be used to organize and identify Sandboxes.
254
+ *
255
+ * @param {Record<string, string>} labels - Dictionary of key-value pairs representing Sandbox labels
256
+ * @returns {Promise<void>}
257
+ *
258
+ * @example
259
+ * // Set sandbox labels
260
+ * await sandbox.setLabels({
261
+ * project: 'my-project',
262
+ * environment: 'development',
263
+ * team: 'backend'
264
+ * });
265
+ */
266
+ async setLabels(labels) {
267
+ this.labels = (await this.sandboxApi.replaceLabels(this.id, { labels })).data.labels;
268
+ return this.labels;
269
+ }
270
+ /**
271
+ * Start the Sandbox.
272
+ *
273
+ * This method starts the Sandbox and waits for it to be ready.
274
+ *
275
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
276
+ * Defaults to 60-second timeout.
277
+ * @returns {Promise<void>}
278
+ * @throws {DaytonaError} - `DaytonaError` - If Sandbox fails to start or times out
279
+ *
280
+ * @example
281
+ * const sandbox = await daytona.getCurrentSandbox('my-sandbox');
282
+ * await sandbox.start(40); // Wait up to 40 seconds
283
+ * console.log('Sandbox started successfully');
284
+ */
285
+ async start(timeout = 60) {
286
+ if (timeout < 0) {
287
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
345
288
  }
346
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
347
- if (Date.now() - startTime > 5000) {
348
- checkInterval = Math.min(checkInterval * 1.1, 1000);
289
+ const startTime = Date.now();
290
+ const response = await this.sandboxApi.startSandbox(this.id, undefined, { timeout: timeout * 1000 });
291
+ this.processSandboxDto(response.data);
292
+ const timeElapsed = Date.now() - startTime;
293
+ await this.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
294
+ }
295
+ /**
296
+ * Recover the Sandbox from a recoverable error and wait for it to be ready.
297
+ *
298
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
299
+ * Defaults to 60-second timeout.
300
+ * @returns {Promise<void>}
301
+ * @throws {DaytonaError} - `DaytonaError` - If Sandbox fails to recover or times out
302
+ *
303
+ * @example
304
+ * const sandbox = await daytona.get('my-sandbox-id');
305
+ * await sandbox.recover();
306
+ * console.log('Sandbox recovered successfully');
307
+ */
308
+ async recover(timeout = 60) {
309
+ if (timeout < 0) {
310
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
349
311
  }
312
+ const startTime = Date.now();
313
+ const response = await this.sandboxApi.recoverSandbox(this.id, undefined, undefined, { timeout: timeout * 1000 });
314
+ this.processSandboxDto(response.data);
315
+ const timeElapsed = Date.now() - startTime;
316
+ await this.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
350
317
  }
351
- }
352
- /**
353
- * Deletes the Sandbox.
354
- * @returns {Promise<void>}
355
- */
356
- async delete(timeout = 60) {
357
- await this.sandboxApi.deleteSandbox(this.id, undefined, { timeout: timeout * 1000 });
358
- this.refreshDataSafe();
359
- }
360
- /**
361
- * Waits for the Sandbox to reach the 'started' state.
362
- *
363
- * This method polls the Sandbox status until it reaches the 'started' state
364
- * or encounters an error.
365
- *
366
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
367
- * Defaults to 60 seconds.
368
- * @returns {Promise<void>}
369
- * @throws {DaytonaError} - `DaytonaError` - If the sandbox ends up in an error state or fails to start within the timeout period.
370
- */
371
- async waitUntilStarted(timeout = 60) {
372
- if (timeout < 0) {
373
- throw new DaytonaValidationError('Timeout must be a non-negative number');
374
- }
375
- let checkInterval = 100;
376
- const startTime = Date.now();
377
- while (this.state !== 'started') {
378
- await this.refreshData();
379
- // @ts-expect-error this.refreshData() can modify this.state so this check is fine
380
- if (this.state === 'started') {
381
- return;
318
+ /**
319
+ * Stops the Sandbox.
320
+ *
321
+ * This method stops the Sandbox and waits for it to be fully stopped.
322
+ *
323
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
324
+ * Defaults to 60-second timeout.
325
+ * @param {boolean} [force] - If true, uses SIGKILL instead of SIGTERM. Defaults to false.
326
+ * @returns {Promise<void>}
327
+ *
328
+ * @example
329
+ * const sandbox = await daytona.get('my-sandbox-id');
330
+ * await sandbox.stop();
331
+ * console.log('Sandbox stopped successfully');
332
+ */
333
+ async stop(timeout = 60, force = false) {
334
+ if (timeout < 0) {
335
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
382
336
  }
383
- if (this.state === 'error') {
384
- const errMsg = `Sandbox ${this.id} failed to start with status: ${this.state}, error reason: ${this.errorReason}`;
385
- throw new DaytonaError(errMsg);
337
+ const startTime = Date.now();
338
+ await this.sandboxApi.stopSandbox(this.id, undefined, force, { timeout: timeout * 1000 });
339
+ await this.refreshDataSafe();
340
+ const timeElapsed = Date.now() - startTime;
341
+ await this.waitUntilStopped(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
342
+ }
343
+ /**
344
+ * Forks the Sandbox, creating a new Sandbox with an identical filesystem.
345
+ *
346
+ * The forked Sandbox is a copy-on-write clone of the original. It starts
347
+ * with the same disk contents but operates independently from that point on.
348
+ *
349
+ * @param {object} [params] - Fork parameters
350
+ * @param {string} [params.name] - Optional name for the forked Sandbox. If not provided, a unique name will be generated.
351
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
352
+ * Defaults to 60-second timeout.
353
+ * @returns {Promise<Sandbox>} The forked Sandbox.
354
+ * @throws {DaytonaValidationError} - If timeout is a negative number
355
+ * @throws {DaytonaError} - If the fork operation fails or times out
356
+ *
357
+ * @example
358
+ * const sandbox = await daytona.get('my-sandbox');
359
+ * const forked = await sandbox._experimental_fork({ name: 'my-fork' });
360
+ * console.log(`Forked sandbox: ${forked.id}`);
361
+ */
362
+ async _experimental_fork(params, timeout = 60) {
363
+ if (timeout < 0) {
364
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
386
365
  }
387
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
388
- throw new DaytonaTimeoutError('Sandbox failed to become ready within the timeout period');
366
+ const startTime = Date.now();
367
+ const response = await this.sandboxApi.forkSandbox(this.id, { name: params?.name }, undefined, {
368
+ timeout: timeout * 1000,
369
+ });
370
+ const sandboxDto = response.data;
371
+ const forkedSandbox = new Sandbox(sandboxDto, structuredClone(this.clientConfig), Daytona.createAxiosInstance(), this.sandboxApi);
372
+ const timeElapsed = Date.now() - startTime;
373
+ await forkedSandbox.waitUntilStarted(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
374
+ return forkedSandbox;
375
+ }
376
+ /**
377
+ * Creates a snapshot from the current state of the Sandbox.
378
+ *
379
+ * This captures the Sandbox's filesystem into a reusable snapshot that can be
380
+ * used to create new Sandboxes. The Sandbox will temporarily enter a
381
+ * 'snapshotting' state and return to its previous state when complete.
382
+ *
383
+ * @param {string} name - Name for the new snapshot
384
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
385
+ * Defaults to 60-second timeout.
386
+ * @returns {Promise<void>}
387
+ * @throws {DaytonaValidationError} - If timeout is a negative number
388
+ * @throws {DaytonaError} - If the snapshot operation fails or times out
389
+ *
390
+ * @example
391
+ * const sandbox = await daytona.get('my-sandbox');
392
+ * await sandbox._experimental_createSnapshot('my-snapshot');
393
+ * console.log('Snapshot created successfully');
394
+ */
395
+ async _experimental_createSnapshot(name, timeout = 60) {
396
+ if (timeout < 0) {
397
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
389
398
  }
390
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
391
- if (Date.now() - startTime > 5000) {
392
- checkInterval = Math.min(checkInterval * 1.1, 1000);
399
+ const startTime = Date.now();
400
+ const req = { name };
401
+ await this.sandboxApi.createSandboxSnapshot(this.id, req, undefined, {
402
+ timeout: timeout * 1000,
403
+ });
404
+ await this.refreshData();
405
+ const timeElapsed = Date.now() - startTime;
406
+ const remainingTimeout = timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout;
407
+ await this.waitForSnapshotComplete(remainingTimeout);
408
+ }
409
+ async waitForSnapshotComplete(timeout) {
410
+ let checkInterval = 100;
411
+ const startTime = Date.now();
412
+ while (this.state === SandboxState.SNAPSHOTTING) {
413
+ await this.refreshData();
414
+ // @ts-expect-error this.refreshData() can modify this.state so this check is fine
415
+ if (this.state === SandboxState.ERROR || this.state === SandboxState.BUILD_FAILED) {
416
+ throw new DaytonaError(`Sandbox ${this.id} snapshot failed with state: ${this.state}, error reason: ${this.errorReason}`);
417
+ }
418
+ if (this.state !== SandboxState.SNAPSHOTTING) {
419
+ return;
420
+ }
421
+ if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
422
+ throw new DaytonaTimeoutError('Sandbox snapshot did not complete within the timeout period');
423
+ }
424
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
425
+ if (Date.now() - startTime > 5000) {
426
+ checkInterval = Math.min(checkInterval * 1.1, 1000);
427
+ }
393
428
  }
394
429
  }
395
- }
396
- /**
397
- * Wait for Sandbox to reach 'stopped' state.
398
- *
399
- * This method polls the Sandbox status until it reaches the 'stopped' state
400
- * or encounters an error.
401
- *
402
- * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
403
- * Defaults to 60 seconds.
404
- * @returns {Promise<void>}
405
- * @throws {DaytonaError} - `DaytonaError` - If the sandbox fails to stop within the timeout period.
406
- */
407
- async waitUntilStopped(timeout = 60) {
408
- if (timeout < 0) {
409
- throw new DaytonaValidationError('Timeout must be a non-negative number');
410
- }
411
- let checkInterval = 100;
412
- const startTime = Date.now();
413
- // Treat destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping
414
- while (this.state !== 'stopped' && this.state !== 'destroyed') {
430
+ /**
431
+ * Deletes the Sandbox.
432
+ * @returns {Promise<void>}
433
+ */
434
+ async delete(timeout = 60) {
435
+ await this.sandboxApi.deleteSandbox(this.id, undefined, { timeout: timeout * 1000 });
415
436
  this.refreshDataSafe();
416
- // @ts-expect-error this.refreshData() can modify this.state so this check is fine
417
- if (this.state === 'stopped' || this.state === 'destroyed') {
418
- return;
437
+ }
438
+ /**
439
+ * Waits for the Sandbox to reach the 'started' state.
440
+ *
441
+ * This method polls the Sandbox status until it reaches the 'started' state
442
+ * or encounters an error.
443
+ *
444
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
445
+ * Defaults to 60 seconds.
446
+ * @returns {Promise<void>}
447
+ * @throws {DaytonaError} - `DaytonaError` - If the sandbox ends up in an error state or fails to start within the timeout period.
448
+ */
449
+ async waitUntilStarted(timeout = 60) {
450
+ if (timeout < 0) {
451
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
419
452
  }
420
- if (this.state === 'error') {
421
- const errMsg = `Sandbox failed to stop with status: ${this.state}, error reason: ${this.errorReason}`;
422
- throw new DaytonaError(errMsg);
453
+ let checkInterval = 100;
454
+ const startTime = Date.now();
455
+ while (this.state !== 'started') {
456
+ await this.refreshData();
457
+ // @ts-expect-error this.refreshData() can modify this.state so this check is fine
458
+ if (this.state === 'started') {
459
+ return;
460
+ }
461
+ if (this.state === 'error') {
462
+ const errMsg = `Sandbox ${this.id} failed to start with status: ${this.state}, error reason: ${this.errorReason}`;
463
+ throw new DaytonaError(errMsg);
464
+ }
465
+ if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
466
+ throw new DaytonaTimeoutError('Sandbox failed to become ready within the timeout period');
467
+ }
468
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
469
+ if (Date.now() - startTime > 5000) {
470
+ checkInterval = Math.min(checkInterval * 1.1, 1000);
471
+ }
423
472
  }
424
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
425
- throw new DaytonaTimeoutError('Sandbox failed to become stopped within the timeout period');
473
+ }
474
+ /**
475
+ * Wait for Sandbox to reach 'stopped' state.
476
+ *
477
+ * This method polls the Sandbox status until it reaches the 'stopped' state
478
+ * or encounters an error.
479
+ *
480
+ * @param {number} [timeout] - Maximum time to wait in seconds. 0 means no timeout.
481
+ * Defaults to 60 seconds.
482
+ * @returns {Promise<void>}
483
+ * @throws {DaytonaError} - `DaytonaError` - If the sandbox fails to stop within the timeout period.
484
+ */
485
+ async waitUntilStopped(timeout = 60) {
486
+ if (timeout < 0) {
487
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
426
488
  }
427
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
428
- if (Date.now() - startTime > 5000) {
429
- checkInterval = Math.min(checkInterval * 1.1, 1000);
489
+ let checkInterval = 100;
490
+ const startTime = Date.now();
491
+ // Treat destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping
492
+ while (this.state !== 'stopped' && this.state !== 'destroyed') {
493
+ this.refreshDataSafe();
494
+ // @ts-expect-error this.refreshData() can modify this.state so this check is fine
495
+ if (this.state === 'stopped' || this.state === 'destroyed') {
496
+ return;
497
+ }
498
+ if (this.state === 'error') {
499
+ const errMsg = `Sandbox failed to stop with status: ${this.state}, error reason: ${this.errorReason}`;
500
+ throw new DaytonaError(errMsg);
501
+ }
502
+ if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
503
+ throw new DaytonaTimeoutError('Sandbox failed to become stopped within the timeout period');
504
+ }
505
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
506
+ if (Date.now() - startTime > 5000) {
507
+ checkInterval = Math.min(checkInterval * 1.1, 1000);
508
+ }
430
509
  }
431
510
  }
432
- }
433
- /**
434
- * Refreshes the Sandbox data from the API.
435
- *
436
- * @returns {Promise<void>}
437
- *
438
- * @example
439
- * await sandbox.refreshData();
440
- * console.log(`Sandbox ${sandbox.id}:`);
441
- * console.log(`State: ${sandbox.state}`);
442
- * console.log(`Resources: ${sandbox.cpu} CPU, ${sandbox.memory} GiB RAM`);
443
- */
444
- async refreshData() {
445
- const response = await this.sandboxApi.getSandbox(this.id);
446
- this.processSandboxDto(response.data);
447
- }
448
- /**
449
- * Refreshes the sandbox activity to reset the timer for automated lifecycle management actions.
450
- *
451
- * This method updates the sandbox's last activity timestamp without changing its state.
452
- * It is useful for keeping long-running sessions alive while there is still user activity.
453
- *
454
- * @returns {Promise<void>}
455
- *
456
- * @example
457
- * // Keep sandbox activity alive
458
- * await sandbox.refreshActivity();
459
- */
460
- async refreshActivity() {
461
- await this.sandboxApi.updateLastActivity(this.id);
462
- }
463
- /**
464
- * Set the auto-stop interval for the Sandbox.
465
- *
466
- * The Sandbox will automatically stop after being idle (no new events) for the specified interval.
467
- * Events include any state changes or interactions with the Sandbox through the sdk.
468
- * Interactions using Sandbox Previews are not included.
469
- *
470
- * @param {number} interval - Number of minutes of inactivity before auto-stopping.
471
- * Set to 0 to disable auto-stop. Default is 15 minutes.
472
- * @returns {Promise<void>}
473
- * @throws {DaytonaError} - `DaytonaError` - If interval is not a non-negative integer
474
- *
475
- * @example
476
- * // Auto-stop after 1 hour
477
- * await sandbox.setAutostopInterval(60);
478
- * // Or disable auto-stop
479
- * await sandbox.setAutostopInterval(0);
480
- */
481
- async setAutostopInterval(interval) {
482
- if (!Number.isInteger(interval) || interval < 0) {
483
- throw new DaytonaValidationError('autoStopInterval must be a non-negative integer');
484
- }
485
- await this.sandboxApi.setAutostopInterval(this.id, interval);
486
- this.autoStopInterval = interval;
487
- }
488
- /**
489
- * Set the auto-archive interval for the Sandbox.
490
- *
491
- * The Sandbox will automatically archive after being continuously stopped for the specified interval.
492
- *
493
- * @param {number} interval - Number of minutes after which a continuously stopped Sandbox will be auto-archived.
494
- * Set to 0 for the maximum interval. Default is 7 days.
495
- * @returns {Promise<void>}
496
- * @throws {DaytonaError} - `DaytonaError` - If interval is not a non-negative integer
497
- *
498
- * @example
499
- * // Auto-archive after 1 hour
500
- * await sandbox.setAutoArchiveInterval(60);
501
- * // Or use the maximum interval
502
- * await sandbox.setAutoArchiveInterval(0);
503
- */
504
- async setAutoArchiveInterval(interval) {
505
- if (!Number.isInteger(interval) || interval < 0) {
506
- throw new DaytonaValidationError('autoArchiveInterval must be a non-negative integer');
507
- }
508
- await this.sandboxApi.setAutoArchiveInterval(this.id, interval);
509
- this.autoArchiveInterval = interval;
510
- }
511
- /**
512
- * Set the auto-delete interval for the Sandbox.
513
- *
514
- * The Sandbox will automatically delete after being continuously stopped for the specified interval.
515
- *
516
- * @param {number} interval - Number of minutes after which a continuously stopped Sandbox will be auto-deleted.
517
- * Set to negative value to disable auto-delete. Set to 0 to delete immediately upon stopping.
518
- * By default, auto-delete is disabled.
519
- * @returns {Promise<void>}
520
- *
521
- * @example
522
- * // Auto-delete after 1 hour
523
- * await sandbox.setAutoDeleteInterval(60);
524
- * // Or delete immediately upon stopping
525
- * await sandbox.setAutoDeleteInterval(0);
526
- * // Or disable auto-delete
527
- * await sandbox.setAutoDeleteInterval(-1);
528
- */
529
- async setAutoDeleteInterval(interval) {
530
- await this.sandboxApi.setAutoDeleteInterval(this.id, interval);
531
- this.autoDeleteInterval = interval;
532
- }
533
- /**
534
- * Updates outbound network policy for this sandbox on the runner (for example block all traffic,
535
- * restore general internet access, or apply a CIDR allow list) without stopping the sandbox.
536
- *
537
- * This maps to the same mechanism as creating a sandbox with `networkBlockAll` / `networkAllowList`:
538
- * the runner applies iptables rules to the sandbox container.
539
- *
540
- * @param {UpdateSandboxNetworkSettings} settings - At least one of `networkBlockAll` or `networkAllowList` must be set.
541
- * Set `networkBlockAll` to `false` to restore outbound access after a block (and clear a stored allow list).
542
- *
543
- * @example
544
- * // Pause internet (outbound blocked)
545
- * await sandbox.updateNetworkSettings({ networkBlockAll: true });
546
- * // Resume internet
547
- * await sandbox.updateNetworkSettings({ networkBlockAll: false });
548
- */
549
- async updateNetworkSettings(settings) {
550
- if (settings.networkBlockAll === undefined && settings.networkAllowList === undefined) {
551
- throw new DaytonaValidationError('At least one of networkBlockAll or networkAllowList must be set');
552
- }
553
- const response = await this.sandboxApi.updateNetworkSettings(this.id, settings);
554
- this.processSandboxDto(response.data);
555
- }
556
- /**
557
- * Retrieves the preview link for the sandbox at the specified port. If the port is closed,
558
- * it will be opened automatically. For private sandboxes, a token is included to grant access
559
- * to the URL.
560
- *
561
- * @param {number} port - The port to open the preview link on.
562
- * @returns {PortPreviewUrl} The response object for the preview link, which includes the `url`
563
- * and the `token` (to access private sandboxes).
564
- *
565
- * @example
566
- * const previewLink = await sandbox.getPreviewLink(3000);
567
- * console.log(`Preview URL: ${previewLink.url}`);
568
- * console.log(`Token: ${previewLink.token}`);
569
- */
570
- async getPreviewLink(port) {
571
- return (await this.sandboxApi.getPortPreviewUrl(this.id, port)).data;
572
- }
573
- /**
574
- * Retrieves a signed preview url for the sandbox at the specified port.
575
- *
576
- * @param {number} port - The port to open the preview link on.
577
- * @param {number} [expiresInSeconds] - The number of seconds the signed preview url will be valid for. Defaults to 60 seconds.
578
- * @returns {Promise<SignedPortPreviewUrl>} The response object for the signed preview url.
579
- */
580
- async getSignedPreviewUrl(port, expiresInSeconds) {
581
- return (await this.sandboxApi.getSignedPortPreviewUrl(this.id, port, undefined, expiresInSeconds)).data;
582
- }
583
- /**
584
- * Expires a signed preview url for the sandbox at the specified port.
585
- *
586
- * @param {number} port - The port to expire the signed preview url on.
587
- * @param {string} token - The token to expire the signed preview url on.
588
- * @returns {Promise<void>}
589
- */
590
- async expireSignedPreviewUrl(port, token) {
591
- await this.sandboxApi.expireSignedPortPreviewUrl(this.id, port, token);
592
- }
593
- /**
594
- * Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem
595
- * state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period.
596
- * The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size.
597
- * Sandbox must be stopped before archiving.
598
- */
599
- async archive() {
600
- await this.sandboxApi.archiveSandbox(this.id);
601
- await this.refreshData();
602
- }
603
- /**
604
- * Resizes the Sandbox resources.
605
- *
606
- * Changes the CPU, memory, or disk allocation for the Sandbox. Hot resize (on running
607
- * sandbox) only allows CPU/memory increases. Disk resize requires a stopped sandbox.
608
- *
609
- * @param {Resources} resources - New resource configuration. Only specified fields will be updated.
610
- * - cpu: Number of CPU cores (minimum: 1). For hot resize, can only be increased.
611
- * - memory: Memory in GiB (minimum: 1). For hot resize, can only be increased.
612
- * - disk: Disk space in GiB (can only be increased, requires stopped sandbox).
613
- * @param {number} [timeout=60] - Timeout in seconds for the resize operation. 0 means no timeout.
614
- * @returns {Promise<void>}
615
- * @throws {DaytonaError} - If hot resize constraints are violated, disk resize attempted on running sandbox,
616
- * disk size decrease is attempted, no resource changes are specified, or resize operation times out.
617
- *
618
- * @example
619
- * // Increase CPU/memory on running sandbox (hot resize)
620
- * await sandbox.resize({ cpu: 4, memory: 8 });
621
- *
622
- * // Change disk (sandbox must be stopped)
623
- * await sandbox.stop();
624
- * await sandbox.resize({ cpu: 2, memory: 4, disk: 30 });
625
- */
626
- async resize(resources, timeout = 60) {
627
- if (timeout < 0) {
628
- throw new DaytonaValidationError('Timeout must be a non-negative number');
629
- }
630
- const startTime = Date.now();
631
- const resizeRequest = {
632
- cpu: resources.cpu,
633
- memory: resources.memory,
634
- disk: resources.disk,
635
- };
636
- const response = await this.sandboxApi.resizeSandbox(this.id, resizeRequest, this.organizationId, {
637
- timeout: timeout * 1000,
638
- });
639
- this.processSandboxDto(response.data);
640
- const timeElapsed = Date.now() - startTime;
641
- await this.waitForResizeComplete(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
642
- }
643
- /**
644
- * Waits for the Sandbox resize operation to complete.
645
- *
646
- * This method polls the Sandbox status until the state is no longer 'resizing'.
647
- *
648
- * @param {number} [timeout=60] - Maximum time to wait in seconds. 0 means no timeout.
649
- * @returns {Promise<void>}
650
- * @throws {DaytonaError} - If the sandbox ends up in an error state or resize times out.
651
- */
652
- async waitForResizeComplete(timeout = 60) {
653
- if (timeout < 0) {
654
- throw new DaytonaValidationError('Timeout must be a non-negative number');
655
- }
656
- let checkInterval = 100;
657
- const startTime = Date.now();
658
- while (this.state === SandboxState.RESIZING) {
659
- await this.refreshData();
660
- // @ts-expect-error this.refreshData() can modify this.state so this check is fine
661
- if (this.state === SandboxState.ERROR || this.state === SandboxState.BUILD_FAILED) {
662
- throw new DaytonaError(`Sandbox ${this.id} resize failed with state: ${this.state}, error reason: ${this.errorReason}`);
663
- }
664
- if (this.state !== SandboxState.RESIZING) {
665
- return;
511
+ /**
512
+ * Refreshes the Sandbox data from the API.
513
+ *
514
+ * @returns {Promise<void>}
515
+ *
516
+ * @example
517
+ * await sandbox.refreshData();
518
+ * console.log(`Sandbox ${sandbox.id}:`);
519
+ * console.log(`State: ${sandbox.state}`);
520
+ * console.log(`Resources: ${sandbox.cpu} CPU, ${sandbox.memory} GiB RAM`);
521
+ */
522
+ async refreshData() {
523
+ const response = await this.sandboxApi.getSandbox(this.id);
524
+ this.processSandboxDto(response.data);
525
+ }
526
+ /**
527
+ * Refreshes the sandbox activity to reset the timer for automated lifecycle management actions.
528
+ *
529
+ * This method updates the sandbox's last activity timestamp without changing its state.
530
+ * It is useful for keeping long-running sessions alive while there is still user activity.
531
+ *
532
+ * @returns {Promise<void>}
533
+ *
534
+ * @example
535
+ * // Keep sandbox activity alive
536
+ * await sandbox.refreshActivity();
537
+ */
538
+ async refreshActivity() {
539
+ await this.sandboxApi.updateLastActivity(this.id);
540
+ }
541
+ /**
542
+ * Set the auto-stop interval for the Sandbox.
543
+ *
544
+ * The Sandbox will automatically stop after being idle (no new events) for the specified interval.
545
+ * Events include any state changes or interactions with the Sandbox through the sdk.
546
+ * Interactions using Sandbox Previews are not included.
547
+ *
548
+ * @param {number} interval - Number of minutes of inactivity before auto-stopping.
549
+ * Set to 0 to disable auto-stop. Default is 15 minutes.
550
+ * @returns {Promise<void>}
551
+ * @throws {DaytonaError} - `DaytonaError` - If interval is not a non-negative integer
552
+ *
553
+ * @example
554
+ * // Auto-stop after 1 hour
555
+ * await sandbox.setAutostopInterval(60);
556
+ * // Or disable auto-stop
557
+ * await sandbox.setAutostopInterval(0);
558
+ */
559
+ async setAutostopInterval(interval) {
560
+ if (!Number.isInteger(interval) || interval < 0) {
561
+ throw new DaytonaValidationError('autoStopInterval must be a non-negative integer');
666
562
  }
667
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
668
- throw new DaytonaTimeoutError('Sandbox resize did not complete within the timeout period');
563
+ await this.sandboxApi.setAutostopInterval(this.id, interval);
564
+ this.autoStopInterval = interval;
565
+ }
566
+ /**
567
+ * Set the auto-archive interval for the Sandbox.
568
+ *
569
+ * The Sandbox will automatically archive after being continuously stopped for the specified interval.
570
+ *
571
+ * @param {number} interval - Number of minutes after which a continuously stopped Sandbox will be auto-archived.
572
+ * Set to 0 for the maximum interval. Default is 7 days.
573
+ * @returns {Promise<void>}
574
+ * @throws {DaytonaError} - `DaytonaError` - If interval is not a non-negative integer
575
+ *
576
+ * @example
577
+ * // Auto-archive after 1 hour
578
+ * await sandbox.setAutoArchiveInterval(60);
579
+ * // Or use the maximum interval
580
+ * await sandbox.setAutoArchiveInterval(0);
581
+ */
582
+ async setAutoArchiveInterval(interval) {
583
+ if (!Number.isInteger(interval) || interval < 0) {
584
+ throw new DaytonaValidationError('autoArchiveInterval must be a non-negative integer');
669
585
  }
670
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
671
- if (Date.now() - startTime > 5000) {
672
- checkInterval = Math.min(checkInterval * 1.1, 1000);
586
+ await this.sandboxApi.setAutoArchiveInterval(this.id, interval);
587
+ this.autoArchiveInterval = interval;
588
+ }
589
+ /**
590
+ * Set the auto-delete interval for the Sandbox.
591
+ *
592
+ * The Sandbox will automatically delete after being continuously stopped for the specified interval.
593
+ *
594
+ * @param {number} interval - Number of minutes after which a continuously stopped Sandbox will be auto-deleted.
595
+ * Set to negative value to disable auto-delete. Set to 0 to delete immediately upon stopping.
596
+ * By default, auto-delete is disabled.
597
+ * @returns {Promise<void>}
598
+ *
599
+ * @example
600
+ * // Auto-delete after 1 hour
601
+ * await sandbox.setAutoDeleteInterval(60);
602
+ * // Or delete immediately upon stopping
603
+ * await sandbox.setAutoDeleteInterval(0);
604
+ * // Or disable auto-delete
605
+ * await sandbox.setAutoDeleteInterval(-1);
606
+ */
607
+ async setAutoDeleteInterval(interval) {
608
+ await this.sandboxApi.setAutoDeleteInterval(this.id, interval);
609
+ this.autoDeleteInterval = interval;
610
+ }
611
+ /**
612
+ * Updates outbound network policy for this sandbox on the runner (for example block all traffic,
613
+ * restore general internet access, or apply a CIDR allow list) without stopping the sandbox.
614
+ *
615
+ * This maps to the same mechanism as creating a sandbox with `networkBlockAll` / `networkAllowList`:
616
+ * the runner applies iptables rules to the sandbox container.
617
+ *
618
+ * @param {UpdateSandboxNetworkSettings} settings - At least one of `networkBlockAll` or `networkAllowList` must be set.
619
+ * Set `networkBlockAll` to `false` to restore outbound access after a block (and clear a stored allow list).
620
+ *
621
+ * @example
622
+ * // Pause internet (outbound blocked)
623
+ * await sandbox.updateNetworkSettings({ networkBlockAll: true });
624
+ * // Resume internet
625
+ * await sandbox.updateNetworkSettings({ networkBlockAll: false });
626
+ */
627
+ async updateNetworkSettings(settings) {
628
+ if (settings.networkBlockAll === undefined && settings.networkAllowList === undefined) {
629
+ throw new DaytonaValidationError('At least one of networkBlockAll or networkAllowList must be set');
673
630
  }
631
+ const response = await this.sandboxApi.updateNetworkSettings(this.id, settings);
632
+ this.processSandboxDto(response.data);
674
633
  }
675
- }
676
- /**
677
- * Creates an SSH access token for the sandbox.
678
- *
679
- * @param {number} expiresInMinutes - The number of minutes the SSH access token will be valid for.
680
- * @returns {Promise<SshAccessDto>} The SSH access token.
681
- */
682
- async createSshAccess(expiresInMinutes) {
683
- return (await this.sandboxApi.createSshAccess(this.id, undefined, expiresInMinutes)).data;
684
- }
685
- /**
686
- * Revokes an SSH access token for the sandbox.
687
- *
688
- * @param {string} token - The token to revoke.
689
- * @returns {Promise<void>}
690
- */
691
- async revokeSshAccess(token) {
692
- await this.sandboxApi.revokeSshAccess(this.id, undefined, token);
693
- }
694
- /**
695
- * Validates an SSH access token for the sandbox.
696
- *
697
- * @param {string} token - The token to validate.
698
- * @returns {Promise<SshAccessValidationDto>} The SSH access validation result.
699
- */
700
- async validateSshAccess(token) {
701
- return (await this.sandboxApi.validateSshAccess(token)).data;
702
- }
703
- /**
704
- * Assigns the API sandbox data to the Sandbox object.
705
- *
706
- * @param {SandboxDto} sandboxDto - The API sandbox instance to assign data from
707
- * @returns {void}
708
- */
709
- processSandboxDto(sandboxDto) {
710
- this.id = sandboxDto.id;
711
- this.name = sandboxDto.name;
712
- this.organizationId = sandboxDto.organizationId;
713
- this.snapshot = sandboxDto.snapshot;
714
- this.user = sandboxDto.user;
715
- this.env = sandboxDto.env;
716
- this.labels = sandboxDto.labels;
717
- this.public = sandboxDto.public;
718
- this.target = sandboxDto.target;
719
- this.cpu = sandboxDto.cpu;
720
- this.gpu = sandboxDto.gpu;
721
- this.memory = sandboxDto.memory;
722
- this.disk = sandboxDto.disk;
723
- this.state = sandboxDto.state;
724
- this.errorReason = sandboxDto.errorReason;
725
- this.recoverable = sandboxDto.recoverable;
726
- this.backupState = sandboxDto.backupState;
727
- this.backupCreatedAt = sandboxDto.backupCreatedAt;
728
- this.autoStopInterval = sandboxDto.autoStopInterval;
729
- this.autoArchiveInterval = sandboxDto.autoArchiveInterval;
730
- this.autoDeleteInterval = sandboxDto.autoDeleteInterval;
731
- this.volumes = sandboxDto.volumes;
732
- this.buildInfo = sandboxDto.buildInfo;
733
- this.createdAt = sandboxDto.createdAt;
734
- this.updatedAt = sandboxDto.updatedAt;
735
- this.lastActivityAt = sandboxDto.lastActivityAt;
736
- this.networkBlockAll = sandboxDto.networkBlockAll;
737
- this.networkAllowList = sandboxDto.networkAllowList;
738
- this.toolboxProxyUrl = sandboxDto.toolboxProxyUrl;
739
- }
740
- /**
741
- * Refreshes the Sandbox data from the API, but does not throw an error if the sandbox has been deleted.
742
- * Instead, it sets the state to destroyed.
743
- *
744
- * @returns {Promise<void>}
745
- */
746
- async refreshDataSafe() {
747
- try {
634
+ /**
635
+ * Retrieves the preview link for the sandbox at the specified port. If the port is closed,
636
+ * it will be opened automatically. For private sandboxes, a token is included to grant access
637
+ * to the URL.
638
+ *
639
+ * @param {number} port - The port to open the preview link on.
640
+ * @returns {PortPreviewUrl} The response object for the preview link, which includes the `url`
641
+ * and the `token` (to access private sandboxes).
642
+ *
643
+ * @example
644
+ * const previewLink = await sandbox.getPreviewLink(3000);
645
+ * console.log(`Preview URL: ${previewLink.url}`);
646
+ * console.log(`Token: ${previewLink.token}`);
647
+ */
648
+ async getPreviewLink(port) {
649
+ return (await this.sandboxApi.getPortPreviewUrl(this.id, port)).data;
650
+ }
651
+ /**
652
+ * Retrieves a signed preview url for the sandbox at the specified port.
653
+ *
654
+ * @param {number} port - The port to open the preview link on.
655
+ * @param {number} [expiresInSeconds] - The number of seconds the signed preview url will be valid for. Defaults to 60 seconds.
656
+ * @returns {Promise<SignedPortPreviewUrl>} The response object for the signed preview url.
657
+ */
658
+ async getSignedPreviewUrl(port, expiresInSeconds) {
659
+ return (await this.sandboxApi.getSignedPortPreviewUrl(this.id, port, undefined, expiresInSeconds)).data;
660
+ }
661
+ /**
662
+ * Expires a signed preview url for the sandbox at the specified port.
663
+ *
664
+ * @param {number} port - The port to expire the signed preview url on.
665
+ * @param {string} token - The token to expire the signed preview url on.
666
+ * @returns {Promise<void>}
667
+ */
668
+ async expireSignedPreviewUrl(port, token) {
669
+ await this.sandboxApi.expireSignedPortPreviewUrl(this.id, port, token);
670
+ }
671
+ /**
672
+ * Archives the sandbox, making it inactive and preserving its state. When sandboxes are archived, the entire filesystem
673
+ * state is moved to cost-effective object storage, making it possible to keep sandboxes available for an extended period.
674
+ * The tradeoff between archived and stopped states is that starting an archived sandbox takes more time, depending on its size.
675
+ * Sandbox must be stopped before archiving.
676
+ */
677
+ async archive() {
678
+ await this.sandboxApi.archiveSandbox(this.id);
748
679
  await this.refreshData();
749
680
  }
750
- catch (error) {
751
- if (error instanceof DaytonaNotFoundError) {
752
- this.state = SandboxState.DESTROYED;
681
+ /**
682
+ * Resizes the Sandbox resources.
683
+ *
684
+ * Changes the CPU, memory, or disk allocation for the Sandbox. Hot resize (on running
685
+ * sandbox) only allows CPU/memory increases. Disk resize requires a stopped sandbox.
686
+ *
687
+ * @param {Resources} resources - New resource configuration. Only specified fields will be updated.
688
+ * - cpu: Number of CPU cores (minimum: 1). For hot resize, can only be increased.
689
+ * - memory: Memory in GiB (minimum: 1). For hot resize, can only be increased.
690
+ * - disk: Disk space in GiB (can only be increased, requires stopped sandbox).
691
+ * @param {number} [timeout=60] - Timeout in seconds for the resize operation. 0 means no timeout.
692
+ * @returns {Promise<void>}
693
+ * @throws {DaytonaError} - If hot resize constraints are violated, disk resize attempted on running sandbox,
694
+ * disk size decrease is attempted, no resource changes are specified, or resize operation times out.
695
+ *
696
+ * @example
697
+ * // Increase CPU/memory on running sandbox (hot resize)
698
+ * await sandbox.resize({ cpu: 4, memory: 8 });
699
+ *
700
+ * // Change disk (sandbox must be stopped)
701
+ * await sandbox.stop();
702
+ * await sandbox.resize({ cpu: 2, memory: 4, disk: 30 });
703
+ */
704
+ async resize(resources, timeout = 60) {
705
+ if (timeout < 0) {
706
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
707
+ }
708
+ const startTime = Date.now();
709
+ const resizeRequest = {
710
+ cpu: resources.cpu,
711
+ memory: resources.memory,
712
+ disk: resources.disk,
713
+ };
714
+ const response = await this.sandboxApi.resizeSandbox(this.id, resizeRequest, this.organizationId, {
715
+ timeout: timeout * 1000,
716
+ });
717
+ this.processSandboxDto(response.data);
718
+ const timeElapsed = Date.now() - startTime;
719
+ await this.waitForResizeComplete(timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout);
720
+ }
721
+ /**
722
+ * Waits for the Sandbox resize operation to complete.
723
+ *
724
+ * This method polls the Sandbox status until the state is no longer 'resizing'.
725
+ *
726
+ * @param {number} [timeout=60] - Maximum time to wait in seconds. 0 means no timeout.
727
+ * @returns {Promise<void>}
728
+ * @throws {DaytonaError} - If the sandbox ends up in an error state or resize times out.
729
+ */
730
+ async waitForResizeComplete(timeout = 60) {
731
+ if (timeout < 0) {
732
+ throw new DaytonaValidationError('Timeout must be a non-negative number');
733
+ }
734
+ let checkInterval = 100;
735
+ const startTime = Date.now();
736
+ while (this.state === SandboxState.RESIZING) {
737
+ await this.refreshData();
738
+ // @ts-expect-error this.refreshData() can modify this.state so this check is fine
739
+ if (this.state === SandboxState.ERROR || this.state === SandboxState.BUILD_FAILED) {
740
+ throw new DaytonaError(`Sandbox ${this.id} resize failed with state: ${this.state}, error reason: ${this.errorReason}`);
741
+ }
742
+ if (this.state !== SandboxState.RESIZING) {
743
+ return;
744
+ }
745
+ if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
746
+ throw new DaytonaTimeoutError('Sandbox resize did not complete within the timeout period');
747
+ }
748
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
749
+ if (Date.now() - startTime > 5000) {
750
+ checkInterval = Math.min(checkInterval * 1.1, 1000);
751
+ }
752
+ }
753
+ }
754
+ /**
755
+ * Creates an SSH access token for the sandbox.
756
+ *
757
+ * @param {number} expiresInMinutes - The number of minutes the SSH access token will be valid for.
758
+ * @returns {Promise<SshAccessDto>} The SSH access token.
759
+ */
760
+ async createSshAccess(expiresInMinutes) {
761
+ return (await this.sandboxApi.createSshAccess(this.id, undefined, expiresInMinutes)).data;
762
+ }
763
+ /**
764
+ * Revokes an SSH access token for the sandbox.
765
+ *
766
+ * @param {string} token - The token to revoke.
767
+ * @returns {Promise<void>}
768
+ */
769
+ async revokeSshAccess(token) {
770
+ await this.sandboxApi.revokeSshAccess(this.id, undefined, token);
771
+ }
772
+ /**
773
+ * Validates an SSH access token for the sandbox.
774
+ *
775
+ * @param {string} token - The token to validate.
776
+ * @returns {Promise<SshAccessValidationDto>} The SSH access validation result.
777
+ */
778
+ async validateSshAccess(token) {
779
+ return (await this.sandboxApi.validateSshAccess(token)).data;
780
+ }
781
+ /**
782
+ * Assigns the API sandbox data to the Sandbox object.
783
+ *
784
+ * @param {SandboxDto} sandboxDto - The API sandbox instance to assign data from
785
+ * @returns {void}
786
+ */
787
+ processSandboxDto(sandboxDto) {
788
+ this.id = sandboxDto.id;
789
+ this.name = sandboxDto.name;
790
+ this.organizationId = sandboxDto.organizationId;
791
+ this.snapshot = sandboxDto.snapshot;
792
+ this.user = sandboxDto.user;
793
+ this.env = sandboxDto.env;
794
+ this.labels = sandboxDto.labels;
795
+ this.public = sandboxDto.public;
796
+ this.target = sandboxDto.target;
797
+ this.cpu = sandboxDto.cpu;
798
+ this.gpu = sandboxDto.gpu;
799
+ this.memory = sandboxDto.memory;
800
+ this.disk = sandboxDto.disk;
801
+ this.state = sandboxDto.state;
802
+ this.errorReason = sandboxDto.errorReason;
803
+ this.recoverable = sandboxDto.recoverable;
804
+ this.backupState = sandboxDto.backupState;
805
+ this.backupCreatedAt = sandboxDto.backupCreatedAt;
806
+ this.autoStopInterval = sandboxDto.autoStopInterval;
807
+ this.autoArchiveInterval = sandboxDto.autoArchiveInterval;
808
+ this.autoDeleteInterval = sandboxDto.autoDeleteInterval;
809
+ this.volumes = sandboxDto.volumes;
810
+ this.buildInfo = sandboxDto.buildInfo;
811
+ this.createdAt = sandboxDto.createdAt;
812
+ this.updatedAt = sandboxDto.updatedAt;
813
+ this.lastActivityAt = sandboxDto.lastActivityAt;
814
+ this.networkBlockAll = sandboxDto.networkBlockAll;
815
+ this.networkAllowList = sandboxDto.networkAllowList;
816
+ this.toolboxProxyUrl = sandboxDto.toolboxProxyUrl;
817
+ }
818
+ /**
819
+ * Refreshes the Sandbox data from the API, but does not throw an error if the sandbox has been deleted.
820
+ * Instead, it sets the state to destroyed.
821
+ *
822
+ * @returns {Promise<void>}
823
+ */
824
+ async refreshDataSafe() {
825
+ try {
826
+ await this.refreshData();
827
+ }
828
+ catch (error) {
829
+ if (error instanceof DaytonaNotFoundError) {
830
+ this.state = SandboxState.DESTROYED;
831
+ }
753
832
  }
754
833
  }
755
- }
756
- }
757
- __decorate([
758
- WithInstrumentation(),
759
- __metadata("design:type", Function),
760
- __metadata("design:paramtypes", []),
761
- __metadata("design:returntype", Promise)
762
- ], Sandbox.prototype, "getUserHomeDir", null);
763
- __decorate([
764
- WithInstrumentation(),
765
- __metadata("design:type", Function),
766
- __metadata("design:paramtypes", []),
767
- __metadata("design:returntype", Promise)
768
- ], Sandbox.prototype, "getUserRootDir", null);
769
- __decorate([
770
- WithInstrumentation(),
771
- __metadata("design:type", Function),
772
- __metadata("design:paramtypes", []),
773
- __metadata("design:returntype", Promise)
774
- ], Sandbox.prototype, "getWorkDir", null);
775
- __decorate([
776
- WithInstrumentation(),
777
- __metadata("design:type", Function),
778
- __metadata("design:paramtypes", [String, String]),
779
- __metadata("design:returntype", Promise)
780
- ], Sandbox.prototype, "createLspServer", null);
781
- __decorate([
782
- WithInstrumentation(),
783
- __metadata("design:type", Function),
784
- __metadata("design:paramtypes", [Object]),
785
- __metadata("design:returntype", Promise)
786
- ], Sandbox.prototype, "setLabels", null);
787
- __decorate([
788
- WithInstrumentation(),
789
- __metadata("design:type", Function),
790
- __metadata("design:paramtypes", [Object]),
791
- __metadata("design:returntype", Promise)
792
- ], Sandbox.prototype, "start", null);
793
- __decorate([
794
- WithInstrumentation(),
795
- __metadata("design:type", Function),
796
- __metadata("design:paramtypes", [Object, Object]),
797
- __metadata("design:returntype", Promise)
798
- ], Sandbox.prototype, "stop", null);
799
- __decorate([
800
- WithInstrumentation(),
801
- __metadata("design:type", Function),
802
- __metadata("design:paramtypes", [Object, Object]),
803
- __metadata("design:returntype", Promise)
804
- ], Sandbox.prototype, "_experimental_fork", null);
805
- __decorate([
806
- WithInstrumentation(),
807
- __metadata("design:type", Function),
808
- __metadata("design:paramtypes", [String, Object]),
809
- __metadata("design:returntype", Promise)
810
- ], Sandbox.prototype, "_experimental_createSnapshot", null);
811
- __decorate([
812
- WithInstrumentation(),
813
- __metadata("design:type", Function),
814
- __metadata("design:paramtypes", [Object]),
815
- __metadata("design:returntype", Promise)
816
- ], Sandbox.prototype, "delete", null);
817
- __decorate([
818
- WithInstrumentation(),
819
- __metadata("design:type", Function),
820
- __metadata("design:paramtypes", [Object]),
821
- __metadata("design:returntype", Promise)
822
- ], Sandbox.prototype, "waitUntilStarted", null);
823
- __decorate([
824
- WithInstrumentation(),
825
- __metadata("design:type", Function),
826
- __metadata("design:paramtypes", [Object]),
827
- __metadata("design:returntype", Promise)
828
- ], Sandbox.prototype, "waitUntilStopped", null);
829
- __decorate([
830
- WithInstrumentation(),
831
- __metadata("design:type", Function),
832
- __metadata("design:paramtypes", []),
833
- __metadata("design:returntype", Promise)
834
- ], Sandbox.prototype, "refreshData", null);
835
- __decorate([
836
- WithInstrumentation(),
837
- __metadata("design:type", Function),
838
- __metadata("design:paramtypes", [Number]),
839
- __metadata("design:returntype", Promise)
840
- ], Sandbox.prototype, "setAutostopInterval", null);
841
- __decorate([
842
- WithInstrumentation(),
843
- __metadata("design:type", Function),
844
- __metadata("design:paramtypes", [Number]),
845
- __metadata("design:returntype", Promise)
846
- ], Sandbox.prototype, "setAutoArchiveInterval", null);
847
- __decorate([
848
- WithInstrumentation(),
849
- __metadata("design:type", Function),
850
- __metadata("design:paramtypes", [Number]),
851
- __metadata("design:returntype", Promise)
852
- ], Sandbox.prototype, "setAutoDeleteInterval", null);
853
- __decorate([
854
- WithInstrumentation(),
855
- __metadata("design:type", Function),
856
- __metadata("design:paramtypes", [Object]),
857
- __metadata("design:returntype", Promise)
858
- ], Sandbox.prototype, "updateNetworkSettings", null);
859
- __decorate([
860
- WithInstrumentation(),
861
- __metadata("design:type", Function),
862
- __metadata("design:paramtypes", [Number]),
863
- __metadata("design:returntype", Promise)
864
- ], Sandbox.prototype, "getPreviewLink", null);
865
- __decorate([
866
- WithInstrumentation(),
867
- __metadata("design:type", Function),
868
- __metadata("design:paramtypes", []),
869
- __metadata("design:returntype", Promise)
870
- ], Sandbox.prototype, "archive", null);
871
- __decorate([
872
- WithInstrumentation(),
873
- __metadata("design:type", Function),
874
- __metadata("design:paramtypes", [Object, Object]),
875
- __metadata("design:returntype", Promise)
876
- ], Sandbox.prototype, "resize", null);
877
- __decorate([
878
- WithInstrumentation(),
879
- __metadata("design:type", Function),
880
- __metadata("design:paramtypes", [Object]),
881
- __metadata("design:returntype", Promise)
882
- ], Sandbox.prototype, "waitForResizeComplete", null);
883
- __decorate([
884
- WithInstrumentation(),
885
- __metadata("design:type", Function),
886
- __metadata("design:paramtypes", [Number]),
887
- __metadata("design:returntype", Promise)
888
- ], Sandbox.prototype, "createSshAccess", null);
889
- __decorate([
890
- WithInstrumentation(),
891
- __metadata("design:type", Function),
892
- __metadata("design:paramtypes", [String]),
893
- __metadata("design:returntype", Promise)
894
- ], Sandbox.prototype, "revokeSshAccess", null);
895
- __decorate([
896
- WithInstrumentation(),
897
- __metadata("design:type", Function),
898
- __metadata("design:paramtypes", [String]),
899
- __metadata("design:returntype", Promise)
900
- ], Sandbox.prototype, "validateSshAccess", null);
834
+ };
835
+ })();
836
+ export { Sandbox };
901
837
  //# sourceMappingURL=Sandbox.js.map