@daytonaio/sdk 0.18.0-alpha.1 → 0.18.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Process.js CHANGED
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Process = exports.CodeRunParams = void 0;
4
4
  const ArtifactParser_1 = require("./utils/ArtifactParser");
5
- const Stream_1 = require("./utils/Stream");
6
5
  /**
7
6
  * Parameters for code execution.
8
7
  */
@@ -234,9 +233,20 @@ class Process {
234
233
  const response = await this.toolboxApi.getSessionCommandLogs(this.instance.id, sessionId, commandId);
235
234
  return response.data;
236
235
  }
237
- await (0, Stream_1.processStreamingResponse)(() => this.toolboxApi.getSessionCommandLogs(this.instance.id, sessionId, commandId, undefined, true, {
238
- responseType: 'stream',
239
- }), onLogs, () => this.getSessionCommand(sessionId, commandId).then((res) => res.exitCode !== null && res.exitCode !== undefined));
236
+ await new Promise((resolve, reject) => {
237
+ this.toolboxApi
238
+ .getSessionCommandLogs(this.instance.id, sessionId, commandId, undefined, true, { responseType: 'stream' })
239
+ .then((res) => {
240
+ const stream = res.data;
241
+ this.streamWithStatusPoll(stream, (chunk) => onLogs(chunk), async () => {
242
+ const statusRes = await this.getSessionCommand(sessionId, commandId);
243
+ return statusRes.exitCode;
244
+ })
245
+ .then(() => resolve())
246
+ .catch((err) => reject(err));
247
+ })
248
+ .catch((err) => reject(err));
249
+ });
240
250
  }
241
251
  /**
242
252
  * Lists all active sessions in the Sandbox.
@@ -269,5 +279,60 @@ class Process {
269
279
  async deleteSession(sessionId) {
270
280
  await this.toolboxApi.deleteSession(this.instance.id, sessionId);
271
281
  }
282
+ async streamWithStatusPoll(stream, onLogs, getExitCode) {
283
+ let nextChunkPromise = null;
284
+ let exitCodeSeenCount = 0;
285
+ const readNext = () => {
286
+ return new Promise((resolve) => {
287
+ const onData = (data) => {
288
+ cleanup();
289
+ resolve(data);
290
+ };
291
+ const onClose = () => {
292
+ cleanup();
293
+ resolve(null);
294
+ };
295
+ const onError = () => {
296
+ cleanup();
297
+ resolve(null);
298
+ };
299
+ function cleanup() {
300
+ stream.off('data', onData);
301
+ stream.off('close', onClose);
302
+ stream.off('error', onError);
303
+ }
304
+ stream.once('data', onData);
305
+ stream.once('close', onClose);
306
+ stream.once('error', onError);
307
+ });
308
+ };
309
+ while (true) {
310
+ // kick off reading and polling race
311
+ if (!nextChunkPromise) {
312
+ nextChunkPromise = readNext();
313
+ }
314
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(null), 2000));
315
+ const result = await Promise.race([nextChunkPromise, timeoutPromise]);
316
+ if (result instanceof Buffer) {
317
+ // got data
318
+ const chunk = result.toString('utf8');
319
+ onLogs(chunk);
320
+ nextChunkPromise = null; // reset for next loop
321
+ exitCodeSeenCount = 0; // reset exit-code counter
322
+ } /* result === null from timeout */
323
+ else {
324
+ const exit_code = await getExitCode();
325
+ if (exit_code != undefined && exit_code != null) {
326
+ exitCodeSeenCount += 1;
327
+ // after seeing finished status twice in a row, break
328
+ if (exitCodeSeenCount > 1) {
329
+ stream.destroy();
330
+ break;
331
+ }
332
+ }
333
+ // else loop again: nextChunkPromise still pending
334
+ }
335
+ }
336
+ }
272
337
  }
273
338
  exports.Process = Process;
package/dist/Sandbox.d.ts CHANGED
@@ -43,7 +43,7 @@ export interface SandboxResources {
43
43
  *
44
44
  * @interface
45
45
  * @property {string} id - Unique identifier for the Sandbox
46
- * @property {string} [image] - Docker image used for the Sandbox.
46
+ * @property {string} image - Docker image used for the Sandbox
47
47
  * @property {string} user - OS user running in the Sandbox
48
48
  * @property {Record<string, string>} env - Environment variables set in the Sandbox
49
49
  * @property {Record<string, string>} labels - Custom labels attached to the Sandbox
package/dist/Sandbox.js CHANGED
@@ -169,18 +169,18 @@ class Sandbox {
169
169
  }
170
170
  const checkInterval = 100; // Wait 100 ms between checks
171
171
  const startTime = Date.now();
172
- let state = (await this.info()).state;
173
- while (state !== 'started') {
172
+ while (timeout === 0 || Date.now() - startTime < timeout * 1000) {
174
173
  const response = await this.sandboxApi.getWorkspace(this.id);
175
- state = response.data.state;
174
+ const state = response.data.state;
175
+ if (state === 'started') {
176
+ return;
177
+ }
176
178
  if (state === 'error') {
177
179
  throw new DaytonaError_1.DaytonaError(`Sandbox ${this.id} failed to start with status: ${state}, error reason: ${response.data.errorReason}`);
178
180
  }
179
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
180
- throw new DaytonaError_1.DaytonaError('Sandbox failed to become ready within the timeout period');
181
- }
182
181
  await new Promise((resolve) => setTimeout(resolve, checkInterval));
183
182
  }
183
+ throw new DaytonaError_1.DaytonaError('Sandbox failed to become ready within the timeout period');
184
184
  }
185
185
  /**
186
186
  * Wait for Sandbox to reach 'stopped' state.
@@ -199,18 +199,18 @@ class Sandbox {
199
199
  }
200
200
  const checkInterval = 100; // Wait 100 ms between checks
201
201
  const startTime = Date.now();
202
- let state = (await this.info()).state;
203
- while (state !== 'stopped') {
202
+ while (timeout === 0 || Date.now() - startTime < timeout * 1000) {
204
203
  const response = await this.sandboxApi.getWorkspace(this.id);
205
- state = response.data.state;
204
+ const state = response.data.state;
205
+ if (state === 'stopped') {
206
+ return;
207
+ }
206
208
  if (state === 'error') {
207
209
  throw new DaytonaError_1.DaytonaError(`Sandbox failed to stop with status: ${state}, error reason: ${response.data.errorReason}`);
208
210
  }
209
- if (timeout !== 0 && Date.now() - startTime > timeout * 1000) {
210
- throw new DaytonaError_1.DaytonaError('Sandbox failed to become stopped within the timeout period');
211
- }
212
211
  await new Promise((resolve) => setTimeout(resolve, checkInterval));
213
212
  }
213
+ throw new DaytonaError_1.DaytonaError('Sandbox failed to become stopped within the timeout period');
214
214
  }
215
215
  /**
216
216
  * Gets structured information about the Sandbox.
package/dist/index.d.ts CHANGED
@@ -5,7 +5,6 @@ export { Git } from './Git';
5
5
  export { LspLanguageId } from './LspServer';
6
6
  export { Process } from './Process';
7
7
  export { DaytonaError } from './errors/DaytonaError';
8
- export { Image } from './Image';
9
8
  export { Sandbox } from './Sandbox';
10
9
  export type { SandboxCodeToolbox } from './Sandbox';
11
10
  export { ChartType } from './types/Charts';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WorkspaceTargetRegion = exports.WorkspaceState = exports.Workspace = exports.SandboxTargetRegion = exports.SandboxState = exports.ChartType = exports.Sandbox = exports.Image = exports.DaytonaError = exports.Process = exports.LspLanguageId = exports.Git = exports.FileSystem = exports.Daytona = exports.CodeLanguage = void 0;
3
+ exports.WorkspaceTargetRegion = exports.WorkspaceState = exports.Workspace = exports.SandboxTargetRegion = exports.SandboxState = exports.ChartType = exports.Sandbox = exports.DaytonaError = exports.Process = exports.LspLanguageId = exports.Git = exports.FileSystem = exports.Daytona = exports.CodeLanguage = void 0;
4
4
  var Daytona_1 = require("./Daytona");
5
5
  Object.defineProperty(exports, "CodeLanguage", { enumerable: true, get: function () { return Daytona_1.CodeLanguage; } });
6
6
  Object.defineProperty(exports, "Daytona", { enumerable: true, get: function () { return Daytona_1.Daytona; } });
@@ -16,8 +16,6 @@ Object.defineProperty(exports, "Process", { enumerable: true, get: function () {
16
16
  // export type { LspLanguageId, Position } from './LspServer'
17
17
  var DaytonaError_1 = require("./errors/DaytonaError");
18
18
  Object.defineProperty(exports, "DaytonaError", { enumerable: true, get: function () { return DaytonaError_1.DaytonaError; } });
19
- var Image_1 = require("./Image");
20
- Object.defineProperty(exports, "Image", { enumerable: true, get: function () { return Image_1.Image; } });
21
19
  var Sandbox_1 = require("./Sandbox");
22
20
  Object.defineProperty(exports, "Sandbox", { enumerable: true, get: function () { return Sandbox_1.Sandbox; } });
23
21
  // Chart and artifact types
@@ -36,15 +36,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.prefixRelativePath = prefixRelativePath;
37
37
  const _path = __importStar(require("path"));
38
38
  function prefixRelativePath(prefix, path) {
39
- let result = path;
40
- if (!result || result === '~') {
41
- result = prefix;
42
- }
43
- else if (path && path.startsWith(prefix.replace(/^\/+/, ''))) {
44
- result = path;
45
- }
46
- else if (path && !_path.isAbsolute(path)) {
47
- result = _path.join(prefix, path);
39
+ let result = prefix;
40
+ if (path) {
41
+ path = path.trim();
42
+ if (path === '~') {
43
+ result = prefix;
44
+ }
45
+ else if (path.startsWith('~/')) {
46
+ result = _path.join(prefix, path.slice(2));
47
+ }
48
+ else if (_path.isAbsolute(path)) {
49
+ result = path;
50
+ }
51
+ else {
52
+ result = _path.join(prefix, path);
53
+ }
48
54
  }
49
55
  return result;
50
56
  }
@@ -1,2 +1,18 @@
1
- export declare function processStreamingResponse(getStream: () => Promise<any>, // can return AxiosResponse with .data being the stream
2
- onChunk: (chunk: string) => void, shouldTerminate: () => Promise<boolean>, chunkTimeout?: number, requireConsecutiveTermination?: boolean): Promise<void>;
1
+ /**
2
+ * Process a streaming response from a URL. Stream will terminate if the server-side stream
3
+ * ends or if the shouldTerminate function returns True.
4
+ *
5
+ * @param getStream - A function that returns a promise of an AxiosResponse with .data being the stream
6
+ * @param onChunk - A function to process each chunk of the response
7
+ * @param shouldTerminate - A function to check if the response should be terminated
8
+ * @param chunkTimeout - The timeout for each chunk
9
+ * @param requireConsecutiveTermination - Whether to require two consecutive termination signals
10
+ * to terminate the stream.
11
+ */
12
+ export declare function processStreamingResponse(
13
+ getStream: () => Promise<any>, // can return AxiosResponse with .data being the stream
14
+ onChunk: (chunk: string) => void,
15
+ shouldTerminate: () => Promise<boolean>,
16
+ chunkTimeout?: number,
17
+ requireConsecutiveTermination?: boolean
18
+ ): Promise<void>
@@ -1,6 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.processStreamingResponse = processStreamingResponse;
4
+ /**
5
+ * Process a streaming response from a URL. Stream will terminate if the server-side stream
6
+ * ends or if the shouldTerminate function returns True.
7
+ *
8
+ * @param getStream - A function that returns a promise of an AxiosResponse with .data being the stream
9
+ * @param onChunk - A function to process each chunk of the response
10
+ * @param shouldTerminate - A function to check if the response should be terminated
11
+ * @param chunkTimeout - The timeout for each chunk
12
+ * @param requireConsecutiveTermination - Whether to require two consecutive termination signals
13
+ * to terminate the stream.
14
+ */
4
15
  async function processStreamingResponse(getStream, // can return AxiosResponse with .data being the stream
5
16
  onChunk, shouldTerminate, chunkTimeout = 2000, requireConsecutiveTermination = true) {
6
17
  const response = await getStream();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daytonaio/sdk",
3
- "version": "0.18.0-alpha.1",
3
+ "version": "0.18.0-alpha.3",
4
4
  "description": "Daytona client library for AI Agents",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,23 +29,15 @@
29
29
  "@babel/preset-typescript": "^7.22.0",
30
30
  "@types/jest": "^29.5.0",
31
31
  "@types/node": "^22.10.0",
32
- "@types/shell-quote": "^1.7.5",
33
- "@types/tar": "^6.1.13",
34
32
  "jest": "^29.5.0",
35
33
  "ts-jest": "^29.1.0",
36
34
  "typescript": "^5.0.0"
37
35
  },
38
36
  "dependencies": {
39
- "@aws-sdk/client-s3": "^3.445.0",
40
- "@aws-sdk/lib-storage": "^3.798.0",
41
- "@daytonaio/api-client": "^0.19.0-alpha.3",
37
+ "@daytonaio/api-client": "0.19.0-alpha.4",
38
+ "uuid": "^11.0.3",
42
39
  "@dotenvx/dotenvx": "^1.25.1",
43
- "@iarna/toml": "^2.2.5",
44
40
  "axios": "^1.6.0",
45
- "fast-glob": "^3.3.0",
46
- "shell-quote": "^1.8.2",
47
- "tar": "^6.2.0",
48
- "untildify": "^5.0.0",
49
- "uuid": "^11.0.3"
41
+ "form-data": "^4.0.0"
50
42
  }
51
43
  }