@daytona/sdk 0.196.0 → 0.198.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/Daytona.d.ts +25 -2
- package/cjs/Daytona.js +60 -7
- package/cjs/Daytona.js.map +1 -1
- package/cjs/Process.js +52 -12
- package/cjs/Process.js.map +1 -1
- package/cjs/PtyHandle.d.ts +14 -0
- package/cjs/PtyHandle.js +100 -34
- package/cjs/PtyHandle.js.map +1 -1
- package/cjs/Sandbox.d.ts +128 -4
- package/cjs/Sandbox.js +493 -136
- package/cjs/Sandbox.js.map +1 -1
- package/cjs/index.d.ts +1 -1
- package/cjs/utils/EventDispatcher.d.ts +85 -0
- package/cjs/utils/EventDispatcher.js +398 -0
- package/cjs/utils/EventDispatcher.js.map +1 -0
- package/cjs/utils/EventSubscriptionManager.d.ts +14 -0
- package/cjs/utils/EventSubscriptionManager.js +98 -0
- package/cjs/utils/EventSubscriptionManager.js.map +1 -0
- package/cjs/utils/WebSocket.d.ts +2 -1
- package/cjs/utils/WebSocket.js +10 -3
- package/cjs/utils/WebSocket.js.map +1 -1
- package/esm/Daytona.d.ts +25 -2
- package/esm/Daytona.js +60 -7
- package/esm/Daytona.js.map +1 -1
- package/esm/Process.js +52 -12
- package/esm/Process.js.map +1 -1
- package/esm/PtyHandle.d.ts +14 -0
- package/esm/PtyHandle.js +100 -34
- package/esm/PtyHandle.js.map +1 -1
- package/esm/Sandbox.d.ts +128 -4
- package/esm/Sandbox.js +494 -137
- package/esm/Sandbox.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/utils/EventDispatcher.d.ts +85 -0
- package/esm/utils/EventDispatcher.js +394 -0
- package/esm/utils/EventDispatcher.js.map +1 -0
- package/esm/utils/EventSubscriptionManager.d.ts +14 -0
- package/esm/utils/EventSubscriptionManager.js +94 -0
- package/esm/utils/EventSubscriptionManager.js.map +1 -0
- package/esm/utils/Import.js +1 -1
- package/esm/utils/WebSocket.d.ts +2 -1
- package/esm/utils/WebSocket.js +10 -3
- package/esm/utils/WebSocket.js.map +1 -1
- package/package.json +5 -3
package/cjs/Sandbox.js
CHANGED
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.Sandbox = void 0;
|
|
8
8
|
const tslib_1 = require("tslib");
|
|
9
9
|
const api_client_1 = require("@daytona/api-client");
|
|
10
|
+
const analytics_api_client_1 = require("@daytona/analytics-api-client");
|
|
10
11
|
const Daytona_1 = require("./Daytona");
|
|
11
12
|
const toolbox_api_client_1 = require("@daytona/toolbox-api-client");
|
|
12
13
|
const FileSystem_1 = require("./FileSystem");
|
|
@@ -18,6 +19,13 @@ const Daytona_2 = require("./Daytona");
|
|
|
18
19
|
const ComputerUse_1 = require("./ComputerUse");
|
|
19
20
|
const CodeInterpreter_1 = require("./CodeInterpreter");
|
|
20
21
|
const otel_decorator_1 = require("./utils/otel.decorator");
|
|
22
|
+
function withEvents(target, _context) {
|
|
23
|
+
return function (...args) {
|
|
24
|
+
;
|
|
25
|
+
this.ensureSubscribed();
|
|
26
|
+
return target.apply(this, args);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
21
29
|
/**
|
|
22
30
|
* Represents a Daytona Sandbox.
|
|
23
31
|
*
|
|
@@ -47,6 +55,7 @@ const otel_decorator_1 = require("./utils/otel.decorator");
|
|
|
47
55
|
* @property {string} [backupCreatedAt] - When the backup was created (not returned by list results;
|
|
48
56
|
* call `refreshData()` on each item to populate)
|
|
49
57
|
* @property {number} [autoStopInterval] - Auto-stop interval in minutes
|
|
58
|
+
* @property {number} [autoPauseInterval] - Auto-pause interval in minutes
|
|
50
59
|
* @property {number} [autoArchiveInterval] - Auto-archive interval in minutes
|
|
51
60
|
* @property {number} [autoDeleteInterval] - Auto-delete interval in minutes
|
|
52
61
|
* @property {Array<SandboxVolume>} [volumes] - Volumes attached to the Sandbox (not returned by
|
|
@@ -70,11 +79,14 @@ const otel_decorator_1 = require("./utils/otel.decorator");
|
|
|
70
79
|
let Sandbox = (() => {
|
|
71
80
|
let _instanceExtraInitializers = [];
|
|
72
81
|
let _getUserHomeDir_decorators;
|
|
82
|
+
let _getMetricsLatest_decorators;
|
|
83
|
+
let _getMetrics_decorators;
|
|
73
84
|
let _getUserRootDir_decorators;
|
|
74
85
|
let _getWorkDir_decorators;
|
|
75
86
|
let _createLspServer_decorators;
|
|
76
87
|
let _setLabels_decorators;
|
|
77
88
|
let _start_decorators;
|
|
89
|
+
let _recover_decorators;
|
|
78
90
|
let _stop_decorators;
|
|
79
91
|
let __experimental_fork_decorators;
|
|
80
92
|
let __experimental_createSnapshot_decorators;
|
|
@@ -83,13 +95,17 @@ let Sandbox = (() => {
|
|
|
83
95
|
let _waitUntilStarted_decorators;
|
|
84
96
|
let _waitUntilStopped_decorators;
|
|
85
97
|
let _refreshData_decorators;
|
|
98
|
+
let _refreshActivity_decorators;
|
|
86
99
|
let _setAutostopInterval_decorators;
|
|
100
|
+
let _setAutoPauseInterval_decorators;
|
|
87
101
|
let _setAutoArchiveInterval_decorators;
|
|
88
102
|
let _setAutoDeleteInterval_decorators;
|
|
89
103
|
let _updateNetworkSettings_decorators;
|
|
90
104
|
let _updateSecrets_decorators;
|
|
91
105
|
let _updateEnv_decorators;
|
|
92
106
|
let _getPreviewLink_decorators;
|
|
107
|
+
let _getSignedPreviewUrl_decorators;
|
|
108
|
+
let _expireSignedPreviewUrl_decorators;
|
|
93
109
|
let _archive_decorators;
|
|
94
110
|
let _resize_decorators;
|
|
95
111
|
let _waitForResizeComplete_decorators;
|
|
@@ -99,39 +115,49 @@ let Sandbox = (() => {
|
|
|
99
115
|
return class Sandbox {
|
|
100
116
|
static {
|
|
101
117
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
102
|
-
_getUserHomeDir_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
_getUserHomeDir_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
119
|
+
_getMetricsLatest_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
120
|
+
_getMetrics_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
121
|
+
_getUserRootDir_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
122
|
+
_getWorkDir_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
123
|
+
_createLspServer_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
124
|
+
_setLabels_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
125
|
+
_start_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
126
|
+
_recover_decorators = [withEvents];
|
|
127
|
+
_stop_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
128
|
+
__experimental_fork_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
129
|
+
__experimental_createSnapshot_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
130
|
+
_pause_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
131
|
+
_delete_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
132
|
+
_waitUntilStarted_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
133
|
+
_waitUntilStopped_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
134
|
+
_refreshData_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
135
|
+
_refreshActivity_decorators = [withEvents];
|
|
136
|
+
_setAutostopInterval_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
137
|
+
_setAutoPauseInterval_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
138
|
+
_setAutoArchiveInterval_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
139
|
+
_setAutoDeleteInterval_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
119
140
|
_updateNetworkSettings_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
120
141
|
_updateSecrets_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
121
142
|
_updateEnv_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
122
|
-
_getPreviewLink_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
143
|
+
_getPreviewLink_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
144
|
+
_getSignedPreviewUrl_decorators = [withEvents];
|
|
145
|
+
_expireSignedPreviewUrl_decorators = [withEvents];
|
|
146
|
+
_archive_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
147
|
+
_resize_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
148
|
+
_waitForResizeComplete_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
149
|
+
_createSshAccess_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
150
|
+
_revokeSshAccess_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
151
|
+
_validateSshAccess_decorators = [(0, otel_decorator_1.WithInstrumentation)(), withEvents];
|
|
129
152
|
tslib_1.__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);
|
|
153
|
+
tslib_1.__esDecorate(this, null, _getMetricsLatest_decorators, { kind: "method", name: "getMetricsLatest", static: false, private: false, access: { has: obj => "getMetricsLatest" in obj, get: obj => obj.getMetricsLatest }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
154
|
+
tslib_1.__esDecorate(this, null, _getMetrics_decorators, { kind: "method", name: "getMetrics", static: false, private: false, access: { has: obj => "getMetrics" in obj, get: obj => obj.getMetrics }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
130
155
|
tslib_1.__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);
|
|
131
156
|
tslib_1.__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);
|
|
132
157
|
tslib_1.__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);
|
|
133
158
|
tslib_1.__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);
|
|
134
159
|
tslib_1.__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);
|
|
160
|
+
tslib_1.__esDecorate(this, null, _recover_decorators, { kind: "method", name: "recover", static: false, private: false, access: { has: obj => "recover" in obj, get: obj => obj.recover }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
135
161
|
tslib_1.__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);
|
|
136
162
|
tslib_1.__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);
|
|
137
163
|
tslib_1.__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);
|
|
@@ -140,13 +166,17 @@ let Sandbox = (() => {
|
|
|
140
166
|
tslib_1.__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);
|
|
141
167
|
tslib_1.__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);
|
|
142
168
|
tslib_1.__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);
|
|
169
|
+
tslib_1.__esDecorate(this, null, _refreshActivity_decorators, { kind: "method", name: "refreshActivity", static: false, private: false, access: { has: obj => "refreshActivity" in obj, get: obj => obj.refreshActivity }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
143
170
|
tslib_1.__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);
|
|
171
|
+
tslib_1.__esDecorate(this, null, _setAutoPauseInterval_decorators, { kind: "method", name: "setAutoPauseInterval", static: false, private: false, access: { has: obj => "setAutoPauseInterval" in obj, get: obj => obj.setAutoPauseInterval }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
144
172
|
tslib_1.__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);
|
|
145
173
|
tslib_1.__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);
|
|
146
174
|
tslib_1.__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);
|
|
147
175
|
tslib_1.__esDecorate(this, null, _updateSecrets_decorators, { kind: "method", name: "updateSecrets", static: false, private: false, access: { has: obj => "updateSecrets" in obj, get: obj => obj.updateSecrets }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
148
176
|
tslib_1.__esDecorate(this, null, _updateEnv_decorators, { kind: "method", name: "updateEnv", static: false, private: false, access: { has: obj => "updateEnv" in obj, get: obj => obj.updateEnv }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
149
177
|
tslib_1.__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);
|
|
178
|
+
tslib_1.__esDecorate(this, null, _getSignedPreviewUrl_decorators, { kind: "method", name: "getSignedPreviewUrl", static: false, private: false, access: { has: obj => "getSignedPreviewUrl" in obj, get: obj => obj.getSignedPreviewUrl }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
179
|
+
tslib_1.__esDecorate(this, null, _expireSignedPreviewUrl_decorators, { kind: "method", name: "expireSignedPreviewUrl", static: false, private: false, access: { has: obj => "expireSignedPreviewUrl" in obj, get: obj => obj.expireSignedPreviewUrl }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
150
180
|
tslib_1.__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);
|
|
151
181
|
tslib_1.__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);
|
|
152
182
|
tslib_1.__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);
|
|
@@ -158,6 +188,8 @@ let Sandbox = (() => {
|
|
|
158
188
|
clientConfig = tslib_1.__runInitializers(this, _instanceExtraInitializers);
|
|
159
189
|
axiosInstance;
|
|
160
190
|
sandboxApi;
|
|
191
|
+
getAnalyticsApiUrl;
|
|
192
|
+
subscriptionManager;
|
|
161
193
|
fs;
|
|
162
194
|
git;
|
|
163
195
|
process;
|
|
@@ -182,6 +214,7 @@ let Sandbox = (() => {
|
|
|
182
214
|
backupState;
|
|
183
215
|
backupCreatedAt;
|
|
184
216
|
autoStopInterval;
|
|
217
|
+
autoPauseInterval;
|
|
185
218
|
autoArchiveInterval;
|
|
186
219
|
autoDeleteInterval;
|
|
187
220
|
volumes;
|
|
@@ -196,24 +229,28 @@ let Sandbox = (() => {
|
|
|
196
229
|
toolboxProxyUrl;
|
|
197
230
|
infoApi;
|
|
198
231
|
serverApi;
|
|
232
|
+
systemApi;
|
|
233
|
+
stateWaiters = [];
|
|
234
|
+
stateWaiterErrorMessageFns = new WeakMap();
|
|
235
|
+
subId;
|
|
199
236
|
/**
|
|
200
|
-
* Creates a new Sandbox instance
|
|
237
|
+
* Creates a new Sandbox instance.
|
|
238
|
+
*
|
|
239
|
+
* Internal: obtain sandboxes via {@link Daytona.create}, {@link Daytona.get}, or
|
|
240
|
+
* {@link Daytona.list} rather than constructing directly.
|
|
201
241
|
*
|
|
202
242
|
* @param {SandboxDto} sandboxDto - The API Sandbox instance
|
|
243
|
+
* @param {SandboxApi} sandboxApi - API client for Sandbox operations
|
|
244
|
+
* @param {InfoApi} infoApi - API client for info operations
|
|
245
|
+
* @param {EventSubscriptionManager} subscriptionManager - Event subscription manager for real-time updates
|
|
203
246
|
*/
|
|
204
|
-
constructor(sandboxDto, clientConfig, axiosInstance, sandboxApi) {
|
|
247
|
+
constructor(sandboxDto, clientConfig, axiosInstance, sandboxApi, getAnalyticsApiUrl, subscriptionManager) {
|
|
205
248
|
this.clientConfig = clientConfig;
|
|
206
249
|
this.axiosInstance = axiosInstance;
|
|
207
250
|
this.sandboxApi = sandboxApi;
|
|
251
|
+
this.getAnalyticsApiUrl = getAnalyticsApiUrl;
|
|
252
|
+
this.subscriptionManager = subscriptionManager;
|
|
208
253
|
this.processSandboxDto(sandboxDto);
|
|
209
|
-
// Set the toolbox base URL
|
|
210
|
-
let baseUrl = this.toolboxProxyUrl;
|
|
211
|
-
if (!baseUrl.endsWith('/')) {
|
|
212
|
-
baseUrl += '/';
|
|
213
|
-
}
|
|
214
|
-
this.axiosInstance.defaults.baseURL = baseUrl + this.id;
|
|
215
|
-
this.clientConfig.basePath = this.axiosInstance.defaults.baseURL;
|
|
216
|
-
// Initialize Services
|
|
217
254
|
const getPreviewToken = async () => (await this.getPreviewLink(1)).token;
|
|
218
255
|
this.fs = new FileSystem_1.FileSystem(this.clientConfig, new toolbox_api_client_1.FileSystemApi(this.clientConfig, '', this.axiosInstance));
|
|
219
256
|
this.git = new Git_1.Git(new toolbox_api_client_1.GitApi(this.clientConfig, '', this.axiosInstance));
|
|
@@ -223,6 +260,8 @@ let Sandbox = (() => {
|
|
|
223
260
|
this.computerUse = new ComputerUse_1.ComputerUse(new toolbox_api_client_1.ComputerUseApi(this.clientConfig, '', this.axiosInstance));
|
|
224
261
|
this.infoApi = new toolbox_api_client_1.InfoApi(this.clientConfig, '', this.axiosInstance);
|
|
225
262
|
this.serverApi = new toolbox_api_client_1.ServerApi(this.clientConfig, '', this.axiosInstance);
|
|
263
|
+
this.systemApi = new toolbox_api_client_1.SystemApi(this.clientConfig, '', this.axiosInstance);
|
|
264
|
+
this.subscribeToEvents();
|
|
226
265
|
}
|
|
227
266
|
/**
|
|
228
267
|
* Gets the user's home directory path for the logged in user inside the Sandbox.
|
|
@@ -237,6 +276,53 @@ let Sandbox = (() => {
|
|
|
237
276
|
const response = await this.infoApi.getUserHomeDir();
|
|
238
277
|
return response.data.dir;
|
|
239
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Gets the most recent resource usage sample directly from the sandbox daemon.
|
|
281
|
+
*
|
|
282
|
+
* Unlike {@link getMetrics}, which returns aggregated historical samples, this returns the
|
|
283
|
+
* single current reading without going through the telemetry backend.
|
|
284
|
+
*
|
|
285
|
+
* @returns The current resource usage sample for the sandbox.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* const m = await sandbox.getMetricsLatest()
|
|
289
|
+
* console.log(`CPU: ${m.cpuUsedPct}%, mem: ${m.memUsed}/${m.memTotal}`)
|
|
290
|
+
*/
|
|
291
|
+
async getMetricsLatest() {
|
|
292
|
+
const response = await this.systemApi.getSystemMetrics();
|
|
293
|
+
return sandboxMetricsFromSystemMetrics(response.data);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Gets historical time-series resource usage metrics for the Sandbox.
|
|
297
|
+
*
|
|
298
|
+
* @param {Date} [start] - Start of the time range. Defaults to the Sandbox creation time.
|
|
299
|
+
* @param {Date} [end] - End of the time range. Defaults to the current time.
|
|
300
|
+
* @returns Time-ordered usage samples over the requested range.
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* const samples = await sandbox.getMetrics()
|
|
304
|
+
* for (const s of samples) {
|
|
305
|
+
* console.log(`${s.timestamp.toISOString()} CPU: ${s.cpuUsedPct}% mem: ${s.memUsed}/${s.memTotal}`)
|
|
306
|
+
* }
|
|
307
|
+
*/
|
|
308
|
+
async getMetrics(start, end) {
|
|
309
|
+
const to = end ?? new Date();
|
|
310
|
+
const from = start ?? (this.createdAt ? new Date(this.createdAt) : to);
|
|
311
|
+
const analyticsApiUrl = await this.getAnalyticsApiUrl();
|
|
312
|
+
if (analyticsApiUrl) {
|
|
313
|
+
const response = await this.buildAnalyticsTelemetryApi(analyticsApiUrl).organizationOrganizationIdSandboxSandboxIdTelemetryMetricsGet(this.organizationId, this.id, from.toISOString(), to.toISOString(), SANDBOX_METRIC_NAMES.join(','));
|
|
314
|
+
return pivotSandboxMetricPoints(response.data);
|
|
315
|
+
}
|
|
316
|
+
const response = await this.sandboxApi.getSandboxMetrics(this.id, from, to, undefined, SANDBOX_METRIC_NAMES);
|
|
317
|
+
return pivotSandboxMetrics(response.data.series);
|
|
318
|
+
}
|
|
319
|
+
buildAnalyticsTelemetryApi(analyticsApiUrl) {
|
|
320
|
+
const analyticsConfig = new analytics_api_client_1.Configuration({
|
|
321
|
+
basePath: analyticsApiUrl,
|
|
322
|
+
apiKey: this.clientConfig.baseOptions?.headers?.Authorization,
|
|
323
|
+
});
|
|
324
|
+
return new analytics_api_client_1.TelemetryApi(analyticsConfig, undefined, Daytona_1.Daytona.createAxiosInstance());
|
|
325
|
+
}
|
|
240
326
|
/**
|
|
241
327
|
* @deprecated Use `getUserHomeDir` instead. This method will be removed in a future version.
|
|
242
328
|
*/
|
|
@@ -394,9 +480,16 @@ let Sandbox = (() => {
|
|
|
394
480
|
timeout: timeout * 1000,
|
|
395
481
|
});
|
|
396
482
|
const sandboxDto = response.data;
|
|
397
|
-
const
|
|
483
|
+
const sandboxWithProxyUrl = sandboxDto.toolboxProxyUrl
|
|
484
|
+
? sandboxDto
|
|
485
|
+
: {
|
|
486
|
+
...sandboxDto,
|
|
487
|
+
toolboxProxyUrl: (await this.sandboxApi.getToolboxProxyUrl(sandboxDto.id)).data.url,
|
|
488
|
+
};
|
|
489
|
+
const forkedSandbox = new Sandbox(sandboxWithProxyUrl, structuredClone(this.clientConfig), Daytona_1.Daytona.createAxiosInstance(), this.sandboxApi, this.getAnalyticsApiUrl, this.subscriptionManager);
|
|
398
490
|
const timeElapsed = Date.now() - startTime;
|
|
399
|
-
|
|
491
|
+
const remainingTimeout = timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout;
|
|
492
|
+
await forkedSandbox.waitUntilStarted(remainingTimeout);
|
|
400
493
|
return forkedSandbox;
|
|
401
494
|
}
|
|
402
495
|
/**
|
|
@@ -424,34 +517,19 @@ let Sandbox = (() => {
|
|
|
424
517
|
}
|
|
425
518
|
const startTime = Date.now();
|
|
426
519
|
const req = { name };
|
|
427
|
-
await this.sandboxApi.createSandboxSnapshot(this.id, req, undefined, {
|
|
520
|
+
const response = await this.sandboxApi.createSandboxSnapshot(this.id, req, undefined, {
|
|
428
521
|
timeout: timeout * 1000,
|
|
429
522
|
});
|
|
430
|
-
|
|
523
|
+
this.processSandboxDto(response.data);
|
|
431
524
|
const timeElapsed = Date.now() - startTime;
|
|
432
525
|
const remainingTimeout = timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout;
|
|
433
526
|
await this.waitForSnapshotComplete(remainingTimeout);
|
|
434
527
|
}
|
|
435
528
|
async waitForSnapshotComplete(timeout) {
|
|
436
|
-
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
// @ts-expect-error this.refreshData() can modify this.state so this check is fine
|
|
441
|
-
if (this.state === api_client_1.SandboxState.ERROR || this.state === api_client_1.SandboxState.BUILD_FAILED) {
|
|
442
|
-
throw new DaytonaError_1.DaytonaError(`Sandbox ${this.id} snapshot failed with state: ${this.state}, error reason: ${this.errorReason}`);
|
|
443
|
-
}
|
|
444
|
-
if (this.state !== api_client_1.SandboxState.SNAPSHOTTING) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
|
|
448
|
-
throw new DaytonaError_1.DaytonaTimeoutError('Sandbox snapshot did not complete within the timeout period');
|
|
449
|
-
}
|
|
450
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
451
|
-
if (Date.now() - startTime > 5000) {
|
|
452
|
-
checkInterval = Math.min(checkInterval * 1.1, 1000);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
529
|
+
const errorStates = [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED];
|
|
530
|
+
const excludeStates = new Set([api_client_1.SandboxState.SNAPSHOTTING, ...errorStates]);
|
|
531
|
+
const targetStates = Object.values(api_client_1.SandboxState).filter((s) => !excludeStates.has(s));
|
|
532
|
+
return this.waitForState(targetStates, errorStates, timeout, 'Sandbox snapshot did not complete within the timeout period', (state) => `Sandbox ${this.id} snapshot failed with state: ${state}, error reason: ${this.errorReason}`);
|
|
455
533
|
}
|
|
456
534
|
/**
|
|
457
535
|
* Pauses the Sandbox, freezing all running processes.
|
|
@@ -482,31 +560,47 @@ let Sandbox = (() => {
|
|
|
482
560
|
await this.refreshData();
|
|
483
561
|
const timeElapsed = Date.now() - startTime;
|
|
484
562
|
const remainingTimeout = timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout;
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
await this.refreshData();
|
|
492
|
-
// @ts-expect-error this.refreshData() can modify this.state so this check is fine
|
|
493
|
-
if (this.state === api_client_1.SandboxState.ERROR) {
|
|
494
|
-
throw new DaytonaError_1.DaytonaError(`Sandbox ${this.id} pause failed with state: ${this.state}, error reason: ${this.errorReason}`);
|
|
495
|
-
}
|
|
496
|
-
if (timeout > 0 && (Date.now() - startTime) / 1000 >= timeout) {
|
|
497
|
-
throw new DaytonaError_1.DaytonaError(`Sandbox ${this.id} failed to pause within ${timeout} seconds`);
|
|
498
|
-
}
|
|
499
|
-
await new Promise((resolve) => globalThis.setTimeout(resolve, checkInterval));
|
|
500
|
-
checkInterval = Math.min(checkInterval * 1.5, 1000);
|
|
501
|
-
}
|
|
563
|
+
// Main's contract: pause completes when the sandbox has *left* PAUSING
|
|
564
|
+
// (paused, stopped, archived, ...), not only on exactly PAUSED.
|
|
565
|
+
const errorStates = [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED];
|
|
566
|
+
const excludeStates = new Set([api_client_1.SandboxState.PAUSING, ...errorStates]);
|
|
567
|
+
const targetStates = Object.values(api_client_1.SandboxState).filter((s) => !excludeStates.has(s));
|
|
568
|
+
await this.waitForState(targetStates, errorStates, remainingTimeout, 'Sandbox failed to become paused within the timeout period', (state) => `Sandbox ${this.id} pause failed with state: ${state}, error reason: ${this.errorReason}`);
|
|
502
569
|
}
|
|
503
570
|
/**
|
|
504
571
|
* Deletes the Sandbox.
|
|
572
|
+
*
|
|
573
|
+
* By default this returns as soon as the deletion request is accepted (matching
|
|
574
|
+
* historical behavior). Pass `wait = true` to block until the Sandbox reaches
|
|
575
|
+
* the 'destroyed' state.
|
|
576
|
+
*
|
|
577
|
+
* @param {number} [timeout] - Timeout in seconds for the request — and, when
|
|
578
|
+
* `wait` is true, for reaching 'destroyed'. 0 means no timeout.
|
|
579
|
+
* Defaults to 60-second timeout.
|
|
580
|
+
* @param {boolean} [wait] - If true, wait until the Sandbox is destroyed. Defaults to false.
|
|
505
581
|
* @returns {Promise<void>}
|
|
506
582
|
*/
|
|
507
|
-
async delete(timeout = 60) {
|
|
508
|
-
|
|
509
|
-
|
|
583
|
+
async delete(timeout = 60, wait = false) {
|
|
584
|
+
if (timeout < 0) {
|
|
585
|
+
throw new DaytonaError_1.DaytonaValidationError('Timeout must be a non-negative number');
|
|
586
|
+
}
|
|
587
|
+
const startTime = Date.now();
|
|
588
|
+
const response = await this.sandboxApi.deleteSandbox(this.id, undefined, { timeout: timeout * 1000 });
|
|
589
|
+
if (response.data) {
|
|
590
|
+
this.processSandboxDto(response.data);
|
|
591
|
+
}
|
|
592
|
+
try {
|
|
593
|
+
if (wait && this.state !== api_client_1.SandboxState.DESTROYED) {
|
|
594
|
+
const timeElapsed = Date.now() - startTime;
|
|
595
|
+
await this.waitForState([api_client_1.SandboxState.DESTROYED], [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED], timeout ? Math.max(0.001, timeout - timeElapsed / 1000) : timeout, 'Sandbox failed to be destroyed within the timeout period', (state) => `Sandbox ${this.id} failed to delete with state: ${state}, error reason: ${this.errorReason}`, true);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
finally {
|
|
599
|
+
if (this.subId) {
|
|
600
|
+
this.subscriptionManager.unsubscribe(this.subId);
|
|
601
|
+
this.subId = undefined;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
510
604
|
}
|
|
511
605
|
/**
|
|
512
606
|
* Waits for the Sandbox to reach the 'started' state.
|
|
@@ -523,26 +617,10 @@ let Sandbox = (() => {
|
|
|
523
617
|
if (timeout < 0) {
|
|
524
618
|
throw new DaytonaError_1.DaytonaValidationError('Timeout must be a non-negative number');
|
|
525
619
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
while (this.state !== 'started') {
|
|
529
|
-
await this.refreshData();
|
|
530
|
-
// @ts-expect-error this.refreshData() can modify this.state so this check is fine
|
|
531
|
-
if (this.state === 'started') {
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
if (this.state === 'error') {
|
|
535
|
-
const errMsg = `Sandbox ${this.id} failed to start with status: ${this.state}, error reason: ${this.errorReason}`;
|
|
536
|
-
throw new DaytonaError_1.DaytonaError(errMsg);
|
|
537
|
-
}
|
|
538
|
-
if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
|
|
539
|
-
throw new DaytonaError_1.DaytonaTimeoutError('Sandbox failed to become ready within the timeout period');
|
|
540
|
-
}
|
|
541
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
542
|
-
if (Date.now() - startTime > 5000) {
|
|
543
|
-
checkInterval = Math.min(checkInterval * 1.1, 1000);
|
|
544
|
-
}
|
|
620
|
+
if (this.state === api_client_1.SandboxState.STARTED) {
|
|
621
|
+
return;
|
|
545
622
|
}
|
|
623
|
+
return this.waitForState([api_client_1.SandboxState.STARTED], [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED], timeout, 'Sandbox failed to become ready within the timeout period', (state) => `Sandbox ${this.id} failed to start with status: ${state}, error reason: ${this.errorReason}`);
|
|
546
624
|
}
|
|
547
625
|
/**
|
|
548
626
|
* Wait for Sandbox to reach 'stopped' state.
|
|
@@ -559,27 +637,11 @@ let Sandbox = (() => {
|
|
|
559
637
|
if (timeout < 0) {
|
|
560
638
|
throw new DaytonaError_1.DaytonaValidationError('Timeout must be a non-negative number');
|
|
561
639
|
}
|
|
562
|
-
let checkInterval = 100;
|
|
563
|
-
const startTime = Date.now();
|
|
564
640
|
// Treat destroyed as stopped to cover ephemeral sandboxes that are automatically deleted after stopping
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
// @ts-expect-error this.refreshData() can modify this.state so this check is fine
|
|
568
|
-
if (this.state === 'stopped' || this.state === 'destroyed') {
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
if (this.state === 'error') {
|
|
572
|
-
const errMsg = `Sandbox failed to stop with status: ${this.state}, error reason: ${this.errorReason}`;
|
|
573
|
-
throw new DaytonaError_1.DaytonaError(errMsg);
|
|
574
|
-
}
|
|
575
|
-
if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
|
|
576
|
-
throw new DaytonaError_1.DaytonaTimeoutError('Sandbox failed to become stopped within the timeout period');
|
|
577
|
-
}
|
|
578
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
579
|
-
if (Date.now() - startTime > 5000) {
|
|
580
|
-
checkInterval = Math.min(checkInterval * 1.1, 1000);
|
|
581
|
-
}
|
|
641
|
+
if (this.state === api_client_1.SandboxState.STOPPED || this.state === api_client_1.SandboxState.DESTROYED) {
|
|
642
|
+
return;
|
|
582
643
|
}
|
|
644
|
+
return this.waitForState([api_client_1.SandboxState.STOPPED, api_client_1.SandboxState.DESTROYED], [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED], timeout, 'Sandbox failed to become stopped within the timeout period', (state) => `Sandbox failed to stop with status: ${state}, error reason: ${this.errorReason}`, true);
|
|
583
645
|
}
|
|
584
646
|
/**
|
|
585
647
|
* Refreshes the Sandbox data from the API.
|
|
@@ -636,6 +698,36 @@ let Sandbox = (() => {
|
|
|
636
698
|
await this.sandboxApi.setAutostopInterval(this.id, interval);
|
|
637
699
|
this.autoStopInterval = interval;
|
|
638
700
|
}
|
|
701
|
+
/**
|
|
702
|
+
* Set the auto-pause interval for the Sandbox.
|
|
703
|
+
*
|
|
704
|
+
* The Sandbox will automatically pause after being idle (no new events) for the specified interval.
|
|
705
|
+
* Events include any state changes or interactions with the Sandbox through the sdk.
|
|
706
|
+
* Interactions using Sandbox Previews are not included.
|
|
707
|
+
*
|
|
708
|
+
* Only supported for sandbox classes that support pausing. At most one of the auto-stop
|
|
709
|
+
* and auto-pause intervals may be non-zero, so disable auto-stop first by setting its
|
|
710
|
+
* interval to 0.
|
|
711
|
+
*
|
|
712
|
+
* @param {number} interval - Number of minutes of inactivity before auto-pausing.
|
|
713
|
+
* Set to 0 to disable auto-pause. For pause-supporting sandbox
|
|
714
|
+
* classes, creation defaults to 60 minutes when neither interval is provided.
|
|
715
|
+
* @returns {Promise<void>}
|
|
716
|
+
* @throws {DaytonaError} - `DaytonaError` - If interval is not a non-negative integer
|
|
717
|
+
*
|
|
718
|
+
* @example
|
|
719
|
+
* // Auto-pause after 1 hour
|
|
720
|
+
* await sandbox.setAutoPauseInterval(60);
|
|
721
|
+
* // Or disable auto-pause
|
|
722
|
+
* await sandbox.setAutoPauseInterval(0);
|
|
723
|
+
*/
|
|
724
|
+
async setAutoPauseInterval(interval) {
|
|
725
|
+
if (!Number.isInteger(interval) || interval < 0) {
|
|
726
|
+
throw new DaytonaError_1.DaytonaValidationError('autoPauseInterval must be a non-negative integer');
|
|
727
|
+
}
|
|
728
|
+
await this.sandboxApi.setAutoPauseInterval(this.id, interval);
|
|
729
|
+
this.autoPauseInterval = interval;
|
|
730
|
+
}
|
|
639
731
|
/**
|
|
640
732
|
* Set the auto-archive interval for the Sandbox.
|
|
641
733
|
*
|
|
@@ -858,25 +950,13 @@ let Sandbox = (() => {
|
|
|
858
950
|
if (timeout < 0) {
|
|
859
951
|
throw new DaytonaError_1.DaytonaValidationError('Timeout must be a non-negative number');
|
|
860
952
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
while (this.state === api_client_1.SandboxState.RESIZING) {
|
|
864
|
-
await this.refreshData();
|
|
865
|
-
// @ts-expect-error this.refreshData() can modify this.state so this check is fine
|
|
866
|
-
if (this.state === api_client_1.SandboxState.ERROR || this.state === api_client_1.SandboxState.BUILD_FAILED) {
|
|
867
|
-
throw new DaytonaError_1.DaytonaError(`Sandbox ${this.id} resize failed with state: ${this.state}, error reason: ${this.errorReason}`);
|
|
868
|
-
}
|
|
869
|
-
if (this.state !== api_client_1.SandboxState.RESIZING) {
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
|
|
873
|
-
throw new DaytonaError_1.DaytonaTimeoutError('Sandbox resize did not complete within the timeout period');
|
|
874
|
-
}
|
|
875
|
-
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
876
|
-
if (Date.now() - startTime > 5000) {
|
|
877
|
-
checkInterval = Math.min(checkInterval * 1.1, 1000);
|
|
878
|
-
}
|
|
953
|
+
if (this.state !== api_client_1.SandboxState.RESIZING) {
|
|
954
|
+
return;
|
|
879
955
|
}
|
|
956
|
+
const errorStates = [api_client_1.SandboxState.ERROR, api_client_1.SandboxState.BUILD_FAILED];
|
|
957
|
+
const excludeStates = new Set([api_client_1.SandboxState.RESIZING, ...errorStates]);
|
|
958
|
+
const targetStates = Object.values(api_client_1.SandboxState).filter((s) => !excludeStates.has(s));
|
|
959
|
+
return this.waitForState(targetStates, errorStates, timeout, 'Sandbox resize did not complete within the timeout period', (state) => `Sandbox ${this.id} resize failed with state: ${state}, error reason: ${this.errorReason}`);
|
|
880
960
|
}
|
|
881
961
|
/**
|
|
882
962
|
* Creates an SSH access token for the sandbox.
|
|
@@ -905,6 +985,172 @@ let Sandbox = (() => {
|
|
|
905
985
|
async validateSshAccess(token) {
|
|
906
986
|
return (await this.sandboxApi.validateSshAccess(token)).data;
|
|
907
987
|
}
|
|
988
|
+
/**
|
|
989
|
+
* Subscribes to real-time events for this sandbox.
|
|
990
|
+
* Auto-updates sandbox metadata on every event.
|
|
991
|
+
*/
|
|
992
|
+
subscribeToEvents() {
|
|
993
|
+
if (this.subId) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
this.subId = this.subscriptionManager.subscribe(this.id, this.handleEvent.bind(this), [
|
|
997
|
+
'sandbox.state.updated',
|
|
998
|
+
'sandbox.created',
|
|
999
|
+
]);
|
|
1000
|
+
}
|
|
1001
|
+
ensureSubscribed() {
|
|
1002
|
+
if (this.subId) {
|
|
1003
|
+
if (this.subscriptionManager.refresh(this.subId)) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
this.subId = undefined;
|
|
1007
|
+
}
|
|
1008
|
+
this.subscribeToEvents();
|
|
1009
|
+
}
|
|
1010
|
+
handleEvent(eventName, data) {
|
|
1011
|
+
if (!data || typeof data !== 'object')
|
|
1012
|
+
return;
|
|
1013
|
+
const raw = data.sandbox ?? data;
|
|
1014
|
+
if (!raw || typeof raw !== 'object')
|
|
1015
|
+
return;
|
|
1016
|
+
if (eventName === 'sandbox.created') {
|
|
1017
|
+
this.processSandboxDto(raw);
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const newState = raw.state ?? data.newState;
|
|
1021
|
+
if (newState) {
|
|
1022
|
+
this.applyState(newState);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Waits for the sandbox to reach one of the target states.
|
|
1027
|
+
* Throws on error states or timeout.
|
|
1028
|
+
*
|
|
1029
|
+
* @param targetStates - States that indicate success.
|
|
1030
|
+
* @param errorStates - States that indicate failure.
|
|
1031
|
+
* @param timeout - Maximum time to wait in seconds. 0 means no timeout.
|
|
1032
|
+
* @param timeoutMessage - Error message when timeout is reached.
|
|
1033
|
+
* @param errorMessageFn - Function that produces an error message from the current state.
|
|
1034
|
+
* @param safeRefresh - If true, use refreshDataSafe() for polling (for delete operations where 404 is expected).
|
|
1035
|
+
*/
|
|
1036
|
+
waitForState(targetStates, errorStates, timeout, timeoutMessage, errorMessageFn, safeRefresh = false) {
|
|
1037
|
+
this.ensureSubscribed();
|
|
1038
|
+
return new Promise((resolve, reject) => {
|
|
1039
|
+
let timeoutTimer = null;
|
|
1040
|
+
let pollTimer = null;
|
|
1041
|
+
let settled = false;
|
|
1042
|
+
const waiter = {
|
|
1043
|
+
targetStates: new Set(targetStates),
|
|
1044
|
+
errorStates: new Set(errorStates),
|
|
1045
|
+
resolve: (_) => {
|
|
1046
|
+
if (settled)
|
|
1047
|
+
return;
|
|
1048
|
+
cleanup();
|
|
1049
|
+
resolve();
|
|
1050
|
+
},
|
|
1051
|
+
reject: (err) => {
|
|
1052
|
+
if (settled)
|
|
1053
|
+
return;
|
|
1054
|
+
cleanup();
|
|
1055
|
+
reject(err);
|
|
1056
|
+
},
|
|
1057
|
+
};
|
|
1058
|
+
this.stateWaiters.push(waiter);
|
|
1059
|
+
this.stateWaiterErrorMessageFns.set(waiter, errorMessageFn);
|
|
1060
|
+
const cleanup = () => {
|
|
1061
|
+
if (settled)
|
|
1062
|
+
return;
|
|
1063
|
+
settled = true;
|
|
1064
|
+
if (timeoutTimer)
|
|
1065
|
+
clearTimeout(timeoutTimer);
|
|
1066
|
+
if (pollTimer)
|
|
1067
|
+
clearTimeout(pollTimer);
|
|
1068
|
+
this.removeStateWaiter(waiter);
|
|
1069
|
+
};
|
|
1070
|
+
// Fast-path only on cached *target* states (parity with main's pre-check).
|
|
1071
|
+
// Cached error states are deliberately NOT evaluated here — main always
|
|
1072
|
+
// refreshed before failing, so a stale ERROR must survive one refresh.
|
|
1073
|
+
if (this.state && waiter.targetStates.has(this.state)) {
|
|
1074
|
+
waiter.resolve(this.state);
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
if (timeout !== 0) {
|
|
1078
|
+
timeoutTimer = setTimeout(() => {
|
|
1079
|
+
void (async () => {
|
|
1080
|
+
if (settled)
|
|
1081
|
+
return;
|
|
1082
|
+
// Parity with main: complete one final refresh-then-evaluate before
|
|
1083
|
+
// rejecting, so a clamped/short timeout still observes the latest state.
|
|
1084
|
+
let refreshed = false;
|
|
1085
|
+
try {
|
|
1086
|
+
if (safeRefresh) {
|
|
1087
|
+
refreshed = await this.refreshDataSafe();
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
await this.refreshData();
|
|
1091
|
+
refreshed = true;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
catch {
|
|
1095
|
+
// fall through to the timeout rejection below
|
|
1096
|
+
}
|
|
1097
|
+
if (!settled) {
|
|
1098
|
+
// Explicit evaluation: applyState() no-ops on unchanged state, so a
|
|
1099
|
+
// persistent error state would otherwise time out generically here.
|
|
1100
|
+
// Only evaluate when the refresh succeeded — a failed refresh leaves
|
|
1101
|
+
// the cached state stale and must not be treated as authoritative.
|
|
1102
|
+
if (refreshed && this.checkStateWaiter(waiter, this.state)) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
cleanup();
|
|
1106
|
+
reject(new DaytonaError_1.DaytonaTimeoutError(timeoutMessage));
|
|
1107
|
+
}
|
|
1108
|
+
})();
|
|
1109
|
+
}, timeout * 1000);
|
|
1110
|
+
}
|
|
1111
|
+
// Poll as a safety net for missed state changes. With an active event subscription
|
|
1112
|
+
// a sparse 1s cadence suffices; without events (polling mode) replicate main's
|
|
1113
|
+
// cadence exactly: 100ms steady for the first 5s, then exponential backoff capped at 1s.
|
|
1114
|
+
const streaming = !!this.subId;
|
|
1115
|
+
const pollStart = Date.now();
|
|
1116
|
+
let pollInterval = streaming ? 1000 : 100;
|
|
1117
|
+
const doPoll = async () => {
|
|
1118
|
+
if (settled)
|
|
1119
|
+
return;
|
|
1120
|
+
let refreshed = false;
|
|
1121
|
+
try {
|
|
1122
|
+
if (safeRefresh) {
|
|
1123
|
+
refreshed = await this.refreshDataSafe();
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
await this.refreshData();
|
|
1127
|
+
refreshed = true;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
catch (error) {
|
|
1131
|
+
waiter.reject(error instanceof Error ? error : new DaytonaError_1.DaytonaError(String(error)));
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
if (!settled) {
|
|
1135
|
+
// Evaluate the refreshed state explicitly: applyState() no-ops when the
|
|
1136
|
+
// state is unchanged, so a persistent error state would otherwise never
|
|
1137
|
+
// reject the waiter. Only evaluate when the refresh succeeded — a failed
|
|
1138
|
+
// safe refresh leaves the cached state stale, so keep polling instead.
|
|
1139
|
+
if (refreshed && this.checkStateWaiter(waiter, this.state)) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
if (!streaming && Date.now() - pollStart > 5000) {
|
|
1143
|
+
pollInterval = Math.min(pollInterval * 1.1, 1000);
|
|
1144
|
+
}
|
|
1145
|
+
pollTimer = setTimeout(() => {
|
|
1146
|
+
void doPoll();
|
|
1147
|
+
}, pollInterval);
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
// First poll runs immediately (main refreshed before any state evaluation).
|
|
1151
|
+
void doPoll();
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
908
1154
|
/**
|
|
909
1155
|
* Assigns the API sandbox data to the Sandbox object.
|
|
910
1156
|
*
|
|
@@ -912,6 +1158,7 @@ let Sandbox = (() => {
|
|
|
912
1158
|
* @returns {void}
|
|
913
1159
|
*/
|
|
914
1160
|
processSandboxDto(sandboxDto) {
|
|
1161
|
+
const newState = sandboxDto.state;
|
|
915
1162
|
this.id = sandboxDto.id;
|
|
916
1163
|
this.name = sandboxDto.name;
|
|
917
1164
|
this.organizationId = sandboxDto.organizationId;
|
|
@@ -924,17 +1171,16 @@ let Sandbox = (() => {
|
|
|
924
1171
|
this.gpu = sandboxDto.gpu;
|
|
925
1172
|
this.memory = sandboxDto.memory;
|
|
926
1173
|
this.disk = sandboxDto.disk;
|
|
927
|
-
this.state = sandboxDto.state;
|
|
928
1174
|
this.errorReason = sandboxDto.errorReason;
|
|
929
1175
|
this.recoverable = sandboxDto.recoverable;
|
|
930
1176
|
this.backupState = sandboxDto.backupState;
|
|
931
1177
|
this.autoStopInterval = sandboxDto.autoStopInterval;
|
|
1178
|
+
this.autoPauseInterval = sandboxDto.autoPauseInterval;
|
|
932
1179
|
this.autoArchiveInterval = sandboxDto.autoArchiveInterval;
|
|
933
1180
|
this.autoDeleteInterval = sandboxDto.autoDeleteInterval;
|
|
934
1181
|
this.createdAt = sandboxDto.createdAt;
|
|
935
1182
|
this.updatedAt = sandboxDto.updatedAt;
|
|
936
1183
|
this.lastActivityAt = sandboxDto.lastActivityAt;
|
|
937
|
-
this.toolboxProxyUrl = sandboxDto.toolboxProxyUrl;
|
|
938
1184
|
// Fields only present in the full SandboxDto (not returned by list endpoint)
|
|
939
1185
|
if ('env' in sandboxDto) {
|
|
940
1186
|
this.env = sandboxDto.env;
|
|
@@ -946,6 +1192,21 @@ let Sandbox = (() => {
|
|
|
946
1192
|
this.buildInfo = sandboxDto.buildInfo;
|
|
947
1193
|
this.backupCreatedAt = sandboxDto.backupCreatedAt;
|
|
948
1194
|
}
|
|
1195
|
+
const newProxyUrl = sandboxDto.toolboxProxyUrl;
|
|
1196
|
+
if (newProxyUrl && newProxyUrl !== this.toolboxProxyUrl && this.axiosInstance) {
|
|
1197
|
+
let baseUrl = newProxyUrl;
|
|
1198
|
+
if (!baseUrl.endsWith('/')) {
|
|
1199
|
+
baseUrl += '/';
|
|
1200
|
+
}
|
|
1201
|
+
this.axiosInstance.defaults.baseURL = baseUrl + this.id;
|
|
1202
|
+
this.clientConfig.basePath = this.axiosInstance.defaults.baseURL;
|
|
1203
|
+
}
|
|
1204
|
+
if (newProxyUrl) {
|
|
1205
|
+
this.toolboxProxyUrl = newProxyUrl;
|
|
1206
|
+
}
|
|
1207
|
+
if (newState) {
|
|
1208
|
+
this.applyState(newState);
|
|
1209
|
+
}
|
|
949
1210
|
}
|
|
950
1211
|
/**
|
|
951
1212
|
* Refreshes the Sandbox data from the API, but does not throw an error if the sandbox has been deleted.
|
|
@@ -953,17 +1214,113 @@ let Sandbox = (() => {
|
|
|
953
1214
|
*
|
|
954
1215
|
* @returns {Promise<void>}
|
|
955
1216
|
*/
|
|
1217
|
+
/**
|
|
1218
|
+
* @returns true when the refresh produced authoritative state (success, or 404
|
|
1219
|
+
* mapped to DESTROYED); false when a transient error was swallowed and
|
|
1220
|
+
* the cached state is stale.
|
|
1221
|
+
*/
|
|
956
1222
|
async refreshDataSafe() {
|
|
957
1223
|
try {
|
|
958
1224
|
await this.refreshData();
|
|
1225
|
+
return true;
|
|
959
1226
|
}
|
|
960
1227
|
catch (error) {
|
|
961
1228
|
if (error instanceof DaytonaError_1.DaytonaNotFoundError) {
|
|
962
|
-
this.
|
|
1229
|
+
this.applyState(api_client_1.SandboxState.DESTROYED);
|
|
1230
|
+
return true;
|
|
963
1231
|
}
|
|
1232
|
+
// Other errors are deliberately swallowed (parity with main): transient
|
|
1233
|
+
// failures (e.g. 502) mid-poll must not abort stop()/delete() waits.
|
|
1234
|
+
return false;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
applyState(newState) {
|
|
1238
|
+
if (newState === this.state) {
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
this.state = newState;
|
|
1242
|
+
for (const waiter of [...this.stateWaiters]) {
|
|
1243
|
+
this.checkStateWaiter(waiter, this.state);
|
|
964
1244
|
}
|
|
965
1245
|
}
|
|
1246
|
+
checkStateWaiter(waiter, state) {
|
|
1247
|
+
if (!state) {
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
if (waiter.targetStates.has(state)) {
|
|
1251
|
+
waiter.resolve(state);
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
if (waiter.errorStates.has(state)) {
|
|
1255
|
+
const errorMessageFn = this.stateWaiterErrorMessageFns.get(waiter);
|
|
1256
|
+
waiter.reject(new DaytonaError_1.DaytonaError(errorMessageFn ? errorMessageFn(state) : `Sandbox ${this.id} failed with state: ${state}`));
|
|
1257
|
+
return true;
|
|
1258
|
+
}
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
removeStateWaiter(waiter) {
|
|
1262
|
+
const index = this.stateWaiters.indexOf(waiter);
|
|
1263
|
+
if (index !== -1) {
|
|
1264
|
+
this.stateWaiters.splice(index, 1);
|
|
1265
|
+
}
|
|
1266
|
+
this.stateWaiterErrorMessageFns.delete(waiter);
|
|
1267
|
+
}
|
|
966
1268
|
};
|
|
967
1269
|
})();
|
|
968
1270
|
exports.Sandbox = Sandbox;
|
|
1271
|
+
const SANDBOX_METRIC_FIELD_BY_NAME = {
|
|
1272
|
+
'daytona.sandbox.cpu.utilization': 'cpuUsedPct',
|
|
1273
|
+
'daytona.sandbox.cpu.limit': 'cpuCount',
|
|
1274
|
+
'daytona.sandbox.memory.usage': 'memUsed',
|
|
1275
|
+
'daytona.sandbox.memory.limit': 'memTotal',
|
|
1276
|
+
'daytona.sandbox.memory.cache': 'memCache',
|
|
1277
|
+
'daytona.sandbox.filesystem.usage': 'diskUsed',
|
|
1278
|
+
'daytona.sandbox.filesystem.total': 'diskTotal',
|
|
1279
|
+
};
|
|
1280
|
+
const SANDBOX_METRIC_NAMES = Object.keys(SANDBOX_METRIC_FIELD_BY_NAME);
|
|
1281
|
+
function sandboxMetricsFromSystemMetrics(m) {
|
|
1282
|
+
return {
|
|
1283
|
+
cpuCount: m.cpuCount ?? 0,
|
|
1284
|
+
cpuUsedPct: m.cpuUsedPct ?? 0,
|
|
1285
|
+
diskTotal: m.diskTotal ?? 0,
|
|
1286
|
+
diskUsed: m.diskUsed ?? 0,
|
|
1287
|
+
memTotal: m.memTotal ?? 0,
|
|
1288
|
+
memUsed: m.memUsed ?? 0,
|
|
1289
|
+
memCache: m.memCache ?? 0,
|
|
1290
|
+
timestamp: m.timestamp ? new Date(m.timestamp) : new Date(),
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
function buildSandboxMetrics(buckets) {
|
|
1294
|
+
return [...buckets.keys()].sort().map((ts) => {
|
|
1295
|
+
const v = buckets.get(ts);
|
|
1296
|
+
return {
|
|
1297
|
+
cpuCount: v.cpuCount ?? 0,
|
|
1298
|
+
cpuUsedPct: v.cpuUsedPct ?? 0,
|
|
1299
|
+
diskTotal: v.diskTotal ?? 0,
|
|
1300
|
+
diskUsed: v.diskUsed ?? 0,
|
|
1301
|
+
memTotal: v.memTotal ?? 0,
|
|
1302
|
+
memUsed: v.memUsed ?? 0,
|
|
1303
|
+
memCache: v.memCache ?? 0,
|
|
1304
|
+
timestamp: new Date(ts),
|
|
1305
|
+
};
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
function pivotMetricTriples(triples) {
|
|
1309
|
+
const buckets = new Map();
|
|
1310
|
+
for (const [name, timestamp, value] of triples) {
|
|
1311
|
+
const field = name ? SANDBOX_METRIC_FIELD_BY_NAME[name] : undefined;
|
|
1312
|
+
if (!field || timestamp === undefined || value === undefined)
|
|
1313
|
+
continue;
|
|
1314
|
+
const bucket = buckets.get(timestamp) ?? {};
|
|
1315
|
+
bucket[field] = value;
|
|
1316
|
+
buckets.set(timestamp, bucket);
|
|
1317
|
+
}
|
|
1318
|
+
return buildSandboxMetrics(buckets);
|
|
1319
|
+
}
|
|
1320
|
+
function pivotSandboxMetrics(series) {
|
|
1321
|
+
return pivotMetricTriples((series ?? []).flatMap((s) => (s.dataPoints ?? []).map((p) => [s.metricName, p.timestamp, p.value])));
|
|
1322
|
+
}
|
|
1323
|
+
function pivotSandboxMetricPoints(points) {
|
|
1324
|
+
return pivotMetricTriples((points ?? []).map((p) => [p.metricName, p.timestamp, p.value]));
|
|
1325
|
+
}
|
|
969
1326
|
//# sourceMappingURL=Sandbox.js.map
|