@daytonaio/sdk 0.193.0-alpha.1 → 0.193.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 (126) hide show
  1. package/LICENSE +1 -1
  2. package/cjs/CodeInterpreter.js +1 -1
  3. package/cjs/CodeInterpreter.js.map +1 -1
  4. package/cjs/ComputerUse.js.map +1 -1
  5. package/cjs/Daytona.d.ts +5 -11
  6. package/cjs/Daytona.js +16 -48
  7. package/cjs/Daytona.js.map +1 -1
  8. package/cjs/FileSystem.js +1 -1
  9. package/cjs/FileSystem.js.map +1 -1
  10. package/cjs/Git.js +1 -1
  11. package/cjs/Git.js.map +1 -1
  12. package/cjs/Image.js +1 -1
  13. package/cjs/Image.js.map +1 -1
  14. package/cjs/LspServer.js +1 -1
  15. package/cjs/LspServer.js.map +1 -1
  16. package/cjs/ObjectStorage.js +1 -1
  17. package/cjs/ObjectStorage.js.map +1 -1
  18. package/cjs/Process.js +1 -1
  19. package/cjs/Process.js.map +1 -1
  20. package/cjs/PtyHandle.js +1 -1
  21. package/cjs/PtyHandle.js.map +1 -1
  22. package/cjs/Sandbox.d.ts +1 -5
  23. package/cjs/Sandbox.js +3 -7
  24. package/cjs/Sandbox.js.map +1 -1
  25. package/cjs/Secret.d.ts +139 -0
  26. package/cjs/Secret.js +143 -0
  27. package/cjs/Secret.js.map +1 -0
  28. package/cjs/Snapshot.js +1 -1
  29. package/cjs/Snapshot.js.map +1 -1
  30. package/cjs/Volume.js +1 -1
  31. package/cjs/Volume.js.map +1 -1
  32. package/cjs/errors/DaytonaError.d.ts +2 -4
  33. package/cjs/errors/DaytonaError.js +7 -11
  34. package/cjs/errors/DaytonaError.js.map +1 -1
  35. package/cjs/index.d.ts +1 -2
  36. package/cjs/index.js +2 -6
  37. package/cjs/index.js.map +1 -1
  38. package/cjs/types/Charts.js +1 -1
  39. package/cjs/types/Charts.js.map +1 -1
  40. package/cjs/types/CodeInterpreter.js +1 -1
  41. package/cjs/types/CodeInterpreter.js.map +1 -1
  42. package/cjs/types/ExecuteResponse.js +1 -1
  43. package/cjs/types/ExecuteResponse.js.map +1 -1
  44. package/cjs/types/Pty.js +1 -1
  45. package/cjs/types/Pty.js.map +1 -1
  46. package/cjs/utils/Binary.js +1 -1
  47. package/cjs/utils/Binary.js.map +1 -1
  48. package/cjs/utils/FileTransfer.js +1 -1
  49. package/cjs/utils/FileTransfer.js.map +1 -1
  50. package/cjs/utils/Import.js +1 -1
  51. package/cjs/utils/Import.js.map +1 -1
  52. package/cjs/utils/Multipart.js +1 -1
  53. package/cjs/utils/Multipart.js.map +1 -1
  54. package/cjs/utils/Runtime.js +1 -1
  55. package/cjs/utils/Runtime.js.map +1 -1
  56. package/cjs/utils/Stream.js.map +1 -1
  57. package/cjs/utils/WebSocket.js +1 -1
  58. package/cjs/utils/WebSocket.js.map +1 -1
  59. package/cjs/utils/otel.decorator.js +1 -1
  60. package/cjs/utils/otel.decorator.js.map +1 -1
  61. package/esm/CodeInterpreter.js +1 -1
  62. package/esm/CodeInterpreter.js.map +1 -1
  63. package/esm/ComputerUse.js.map +1 -1
  64. package/esm/Daytona.d.ts +5 -11
  65. package/esm/Daytona.js +17 -49
  66. package/esm/Daytona.js.map +1 -1
  67. package/esm/FileSystem.js +1 -1
  68. package/esm/FileSystem.js.map +1 -1
  69. package/esm/Git.js +1 -1
  70. package/esm/Git.js.map +1 -1
  71. package/esm/Image.js +1 -1
  72. package/esm/Image.js.map +1 -1
  73. package/esm/LspServer.js +1 -1
  74. package/esm/LspServer.js.map +1 -1
  75. package/esm/ObjectStorage.js +1 -1
  76. package/esm/ObjectStorage.js.map +1 -1
  77. package/esm/Process.js +1 -1
  78. package/esm/Process.js.map +1 -1
  79. package/esm/PtyHandle.js +1 -1
  80. package/esm/PtyHandle.js.map +1 -1
  81. package/esm/Sandbox.d.ts +1 -5
  82. package/esm/Sandbox.js +3 -7
  83. package/esm/Sandbox.js.map +1 -1
  84. package/esm/Secret.d.ts +139 -0
  85. package/esm/Secret.js +140 -0
  86. package/esm/Secret.js.map +1 -0
  87. package/esm/Snapshot.js +1 -1
  88. package/esm/Snapshot.js.map +1 -1
  89. package/esm/Volume.js +1 -1
  90. package/esm/Volume.js.map +1 -1
  91. package/esm/errors/DaytonaError.d.ts +2 -4
  92. package/esm/errors/DaytonaError.js +7 -11
  93. package/esm/errors/DaytonaError.js.map +1 -1
  94. package/esm/index.d.ts +1 -2
  95. package/esm/index.js +1 -2
  96. package/esm/index.js.map +1 -1
  97. package/esm/types/Charts.js +1 -1
  98. package/esm/types/Charts.js.map +1 -1
  99. package/esm/types/CodeInterpreter.js +1 -1
  100. package/esm/types/CodeInterpreter.js.map +1 -1
  101. package/esm/types/ExecuteResponse.js +1 -1
  102. package/esm/types/ExecuteResponse.js.map +1 -1
  103. package/esm/types/Pty.js +1 -1
  104. package/esm/types/Pty.js.map +1 -1
  105. package/esm/utils/Binary.js +1 -1
  106. package/esm/utils/Binary.js.map +1 -1
  107. package/esm/utils/FileTransfer.js +1 -1
  108. package/esm/utils/FileTransfer.js.map +1 -1
  109. package/esm/utils/Import.js +2 -2
  110. package/esm/utils/Import.js.map +1 -1
  111. package/esm/utils/Multipart.js +1 -1
  112. package/esm/utils/Multipart.js.map +1 -1
  113. package/esm/utils/Runtime.js +1 -1
  114. package/esm/utils/Runtime.js.map +1 -1
  115. package/esm/utils/Stream.js.map +1 -1
  116. package/esm/utils/WebSocket.js +1 -1
  117. package/esm/utils/WebSocket.js.map +1 -1
  118. package/esm/utils/otel.decorator.js +1 -1
  119. package/esm/utils/otel.decorator.js.map +1 -1
  120. package/package.json +6 -7
  121. package/cjs/Session.d.ts +0 -152
  122. package/cjs/Session.js +0 -523
  123. package/cjs/Session.js.map +0 -1
  124. package/esm/Session.d.ts +0 -152
  125. package/esm/Session.js +0 -516
  126. package/esm/Session.js.map +0 -1
package/esm/Session.d.ts DELETED
@@ -1,152 +0,0 @@
1
- import type { AxiosInstance } from 'axios';
2
- import { DaytonaError } from './errors/DaytonaError.js';
3
- /**
4
- * One frame on the streaming WS protocol. Mirrors the daemon-side frame format 1:1.
5
- */
6
- export type SessionFrameType = 'stdout' | 'stderr' | 'error' | 'display' | 'control';
7
- export interface SessionDisplay {
8
- formats: string[];
9
- /** Mime → payload (base64 for binary). */
10
- data: Record<string, string>;
11
- }
12
- export interface SessionExecutionError {
13
- name: string;
14
- value?: string;
15
- traceback?: string;
16
- }
17
- export interface SessionRunResult {
18
- stdout: string;
19
- stderr: string;
20
- /** The execution error, or `null` when the code ran successfully. */
21
- error: SessionExecutionError | null;
22
- displays: SessionDisplay[];
23
- durationMs: number;
24
- }
25
- /**
26
- * Signed access bundle for a session, returned by the API.
27
- *
28
- * `token` is exposed for revocation / observability; the SDK does not send it
29
- * as an `Authorization` header.
30
- */
31
- export interface SessionAccess {
32
- httpUrl: string;
33
- wsUrl: string;
34
- token: string;
35
- /** ISO timestamp; the access is refreshed shortly before this. */
36
- tokenExpiresAt: string;
37
- /**
38
- * Per-session WS capability. Sent on the first execute frame so the daemon
39
- * can authorize the run. Absent on older servers; the SDK sends `''` then.
40
- */
41
- wsAuth?: string;
42
- }
43
- export interface SessionRef {
44
- id: string;
45
- language: string;
46
- cwd?: string;
47
- createdAt: string;
48
- lastUsedAt?: string;
49
- expiresAt: string;
50
- /** Present on createSession / refresh responses; omitted on listSessions. */
51
- access?: SessionAccess;
52
- }
53
- /**
54
- * Reference to an existing session to run code against, optionally carrying a
55
- * primed access bundle to skip an extra access lookup.
56
- */
57
- export interface SessionContext {
58
- id: string;
59
- access?: SessionAccess;
60
- }
61
- /** Options for {@link SessionService.createSession}. */
62
- export interface CreateSessionOptions {
63
- template?: string;
64
- language?: string;
65
- cwd?: string;
66
- }
67
- /** A runtime template available for sessions. */
68
- export interface SessionTemplate {
69
- name: string;
70
- description?: string;
71
- languages: string[];
72
- packages?: string[];
73
- }
74
- /** A package available within a session template. */
75
- export interface SessionPackage {
76
- name: string;
77
- version: string;
78
- hasNativeBindings?: boolean;
79
- }
80
- export interface SessionRunOptions {
81
- language?: 'python' | 'typescript' | 'javascript';
82
- template?: string;
83
- context?: SessionContext;
84
- env?: Record<string, string>;
85
- timeout?: number;
86
- }
87
- export interface SessionRunStreamOptions extends SessionRunOptions {
88
- onStdout?: (chunk: string) => void;
89
- onStderr?: (chunk: string) => void;
90
- onError?: (err: SessionExecutionError) => void;
91
- onDisplay?: (display: SessionDisplay) => void;
92
- onControl?: (text: string) => void;
93
- signal?: AbortSignal;
94
- }
95
- /**
96
- * SessionInvalidatedError is the SDK projection of HTTP 410
97
- * `error.name=SessionInvalidated`. Surfaces when the underlying sandbox
98
- * has been rolled (death / snapshot drift / autostop).
99
- */
100
- export declare class SessionInvalidatedError extends DaytonaError {
101
- sessionId: string;
102
- invalidatedAt: string;
103
- constructor(sessionId: string, invalidatedAt: string);
104
- }
105
- /**
106
- * SessionExpiredError is the SDK projection of HTTP 410
107
- * `error.name=SessionExpired`. `reason` distinguishes idle vs absolute TTL.
108
- */
109
- export declare class SessionExpiredError extends DaytonaError {
110
- sessionId: string;
111
- expiredAt: string;
112
- reason: 'idle' | 'absolute';
113
- constructor(sessionId: string, expiredAt: string, reason: 'idle' | 'absolute');
114
- }
115
- /**
116
- * SessionService is the user-facing SDK surface for the sessions product.
117
- *
118
- * Use `createSession` to start a persistent session and `run` / `runStream`
119
- * to execute code against it. Calls to `run` / `runStream` can also be made
120
- * without an explicit session — passing only a `template` / `language` — to
121
- * execute one-shot code transparently. `listTemplates` and `listPackages`
122
- * describe the runtimes available for sessions.
123
- */
124
- export declare class SessionService {
125
- private readonly http;
126
- private readonly ctxAccess;
127
- private readonly transientAccess;
128
- private transientSupported;
129
- constructor(http: AxiosInstance);
130
- run(code: string, options?: SessionRunOptions): Promise<SessionRunResult>;
131
- runStream(code: string, options?: SessionRunStreamOptions): Promise<SessionRunResult>;
132
- createSession(options: CreateSessionOptions): Promise<SessionRef>;
133
- listSessions(template?: string): Promise<SessionRef[]>;
134
- deleteSession(id: string): Promise<void>;
135
- listTemplates(): Promise<SessionTemplate[]>;
136
- listPackages(templateName: string, language: string): Promise<SessionPackage[]>;
137
- private runInternal;
138
- private ensureAccess;
139
- private runWsDirect;
140
- private fetchSessionAccess;
141
- private fetchTransient;
142
- private runLegacy;
143
- private runCodeRunLegacy;
144
- private runStreamLegacy;
145
- private isExpired;
146
- private evictAccess;
147
- private isRouteMissing404;
148
- private applyFrame;
149
- private resolveWebSocketImpl;
150
- private translateError;
151
- }
152
- //# sourceMappingURL=Session.d.ts.map
package/esm/Session.js DELETED
@@ -1,516 +0,0 @@
1
- /*
2
- * Copyright Daytona Platforms Inc.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
- import axios from 'axios';
6
- import { DaytonaError } from './errors/DaytonaError.js';
7
- /**
8
- * HTTP status of an error, whether it's a raw AxiosError or a DaytonaError
9
- * already normalized by the shared axios interceptors.
10
- */
11
- function errorStatus(err) {
12
- if (axios.isAxiosError(err)) {
13
- return err.response?.status;
14
- }
15
- if (err instanceof DaytonaError) {
16
- return err.statusCode;
17
- }
18
- return undefined;
19
- }
20
- /**
21
- * Raw response body of an error, from a raw AxiosError or a normalized
22
- * DaytonaError (which preserves the body on `.data`).
23
- */
24
- function errorBody(err) {
25
- if (axios.isAxiosError(err)) {
26
- return err.response?.data;
27
- }
28
- if (err instanceof DaytonaError) {
29
- return err.data;
30
- }
31
- return undefined;
32
- }
33
- /**
34
- * SessionInvalidatedError is the SDK projection of HTTP 410
35
- * `error.name=SessionInvalidated`. Surfaces when the underlying sandbox
36
- * has been rolled (death / snapshot drift / autostop).
37
- */
38
- export class SessionInvalidatedError extends DaytonaError {
39
- sessionId;
40
- invalidatedAt;
41
- constructor(sessionId, invalidatedAt) {
42
- super(`Session ${sessionId} has been invalidated at ${invalidatedAt}`);
43
- this.name = 'SessionInvalidatedError';
44
- this.sessionId = sessionId;
45
- this.invalidatedAt = invalidatedAt;
46
- }
47
- }
48
- /**
49
- * SessionExpiredError is the SDK projection of HTTP 410
50
- * `error.name=SessionExpired`. `reason` distinguishes idle vs absolute TTL.
51
- */
52
- export class SessionExpiredError extends DaytonaError {
53
- sessionId;
54
- expiredAt;
55
- reason;
56
- constructor(sessionId, expiredAt, reason) {
57
- super(`Session ${sessionId} expired (${reason}) at ${expiredAt}`);
58
- this.name = 'SessionExpiredError';
59
- this.sessionId = sessionId;
60
- this.expiredAt = expiredAt;
61
- this.reason = reason;
62
- }
63
- }
64
- const REFRESH_SKEW_SECONDS = 60;
65
- class LegacyFallback extends Error {
66
- }
67
- class WsAuthError extends Error {
68
- }
69
- /**
70
- * SessionService is the user-facing SDK surface for the sessions product.
71
- *
72
- * Use `createSession` to start a persistent session and `run` / `runStream`
73
- * to execute code against it. Calls to `run` / `runStream` can also be made
74
- * without an explicit session — passing only a `template` / `language` — to
75
- * execute one-shot code transparently. `listTemplates` and `listPackages`
76
- * describe the runtimes available for sessions.
77
- */
78
- export class SessionService {
79
- http;
80
- // SDK-side caches keyed by context id and `${template}:${language}` for
81
- // one-shot transients. Survive across calls; eviction happens on auth
82
- // failure, expiry, or explicit deleteSession.
83
- ctxAccess = new Map();
84
- transientAccess = new Map();
85
- // Latches once the API confirms /transients is missing (older server).
86
- transientSupported = null;
87
- constructor(http) {
88
- this.http = http;
89
- }
90
- async run(code, options = {}) {
91
- return this.runInternal(code, options, undefined);
92
- }
93
- async runStream(code, options = {}) {
94
- const { onStdout, onStderr, onError, onDisplay, onControl, signal, ...runOpts } = options;
95
- return this.runInternal(code, runOpts, { onStdout, onStderr, onError, onDisplay, onControl, signal });
96
- }
97
- async createSession(options) {
98
- try {
99
- const { data } = await this.http.post('/sessions', options);
100
- if (data.access) {
101
- this.ctxAccess.set(data.id, data.access);
102
- }
103
- return data;
104
- }
105
- catch (err) {
106
- throw this.translateError(err);
107
- }
108
- }
109
- async listSessions(template) {
110
- try {
111
- const { data } = await this.http.get('/sessions', {
112
- params: template ? { template } : undefined,
113
- });
114
- return data;
115
- }
116
- catch (err) {
117
- throw this.translateError(err);
118
- }
119
- }
120
- async deleteSession(id) {
121
- try {
122
- await this.http.delete(`/sessions/${encodeURIComponent(id)}`);
123
- this.ctxAccess.delete(id);
124
- }
125
- catch (err) {
126
- throw this.translateError(err);
127
- }
128
- }
129
- async listTemplates() {
130
- try {
131
- const { data } = await this.http.get('/sessions/templates');
132
- return data;
133
- }
134
- catch (err) {
135
- throw this.translateError(err);
136
- }
137
- }
138
- async listPackages(templateName, language) {
139
- try {
140
- const { data } = await this.http.get(`/sessions/templates/${encodeURIComponent(templateName)}/packages`, {
141
- params: { language },
142
- });
143
- return data;
144
- }
145
- catch (err) {
146
- throw this.translateError(err);
147
- }
148
- }
149
- // -- direct-to-sandbox hot path ----------------------------------------
150
- async runInternal(code, options, handlers) {
151
- if (!options.context && this.transientSupported === false) {
152
- return this.runLegacy(code, options, handlers);
153
- }
154
- let sessionId;
155
- let access;
156
- let reset;
157
- try {
158
- ;
159
- ({ sessionId, access, reset } = await this.ensureAccess(options));
160
- }
161
- catch (err) {
162
- if (err instanceof LegacyFallback) {
163
- if (!options.context) {
164
- this.transientSupported = false;
165
- }
166
- return this.runLegacy(code, options, handlers);
167
- }
168
- throw err;
169
- }
170
- try {
171
- return await this.runWsDirect(sessionId, access, code, options, reset, handlers);
172
- }
173
- catch (err) {
174
- // Recover once from a stale cached session, then retry on a fresh one:
175
- // - WsAuthError: the signed WS token was rejected (expired/rotated key).
176
- // - SessionInvalidatedError on a *transient* run: the cached transient
177
- // context was GC'd or its instance rolled away. Re-minting yields a
178
- // fresh context. For an explicit context the caller owns the
179
- // lifecycle, so an invalidation is terminal and must propagate.
180
- const recoverable = err instanceof WsAuthError || (err instanceof SessionInvalidatedError && !options.context);
181
- if (recoverable) {
182
- this.evictAccess(options, sessionId);
183
- try {
184
- ;
185
- ({ sessionId, access, reset } = await this.ensureAccess(options));
186
- }
187
- catch (refreshErr) {
188
- if (refreshErr instanceof LegacyFallback) {
189
- if (!options.context) {
190
- this.transientSupported = false;
191
- }
192
- return this.runLegacy(code, options, handlers);
193
- }
194
- throw refreshErr;
195
- }
196
- return this.runWsDirect(sessionId, access, code, options, reset, handlers);
197
- }
198
- throw err;
199
- }
200
- }
201
- async ensureAccess(options) {
202
- if (options.context) {
203
- const sessionId = options.context.id;
204
- // Inline access from a freshly-created context primes the cache —
205
- // avoids an immediate GET /access right after createSession().
206
- if (options.context.access && !this.ctxAccess.has(sessionId)) {
207
- this.ctxAccess.set(sessionId, options.context.access);
208
- }
209
- let access = this.ctxAccess.get(sessionId);
210
- if (!access || this.isExpired(access)) {
211
- access = await this.fetchSessionAccess(sessionId);
212
- this.ctxAccess.set(sessionId, access);
213
- }
214
- return { sessionId, access, reset: false };
215
- }
216
- const key = `${options.template ?? ''}:${options.language ?? ''}`;
217
- const cached = this.transientAccess.get(key);
218
- if (cached && !this.isExpired(cached.access)) {
219
- return { sessionId: cached.sessionId, access: cached.access, reset: true };
220
- }
221
- const fresh = await this.fetchTransient(options.template, options.language);
222
- this.transientAccess.set(key, fresh);
223
- this.transientSupported = true;
224
- return { sessionId: fresh.sessionId, access: fresh.access, reset: true };
225
- }
226
- async runWsDirect(sessionId, access, code, options, reset, handlers) {
227
- const WebSocketImpl = await this.resolveWebSocketImpl();
228
- return new Promise((resolve, reject) => {
229
- const ws = new WebSocketImpl(access.wsUrl);
230
- const aggregated = {
231
- stdout: '',
232
- stderr: '',
233
- error: null,
234
- displays: [],
235
- durationMs: 0,
236
- };
237
- const startedAt = Date.now();
238
- let resolved = false;
239
- let opened = false;
240
- const finish = (resolvedOrErr) => {
241
- if (resolved)
242
- return;
243
- resolved = true;
244
- void options;
245
- handlers?.signal?.removeEventListener('abort', onAbort);
246
- try {
247
- ws.close();
248
- }
249
- catch {
250
- /* close errors are non-fatal here */
251
- }
252
- if (resolvedOrErr instanceof Error) {
253
- reject(resolvedOrErr);
254
- }
255
- else {
256
- resolvedOrErr.durationMs = Date.now() - startedAt;
257
- resolve(resolvedOrErr);
258
- }
259
- };
260
- const onAbort = () => finish(new DaytonaError('runStream aborted by caller'));
261
- if (handlers?.signal?.aborted) {
262
- finish(new DaytonaError('runStream aborted by caller'));
263
- return;
264
- }
265
- handlers?.signal?.addEventListener('abort', onAbort, { once: true });
266
- ws.onopen = () => {
267
- opened = true;
268
- ws.send(JSON.stringify({
269
- code,
270
- envs: options.env ?? {},
271
- timeout: options.timeout ?? 0,
272
- reset,
273
- wsAuth: access.wsAuth ?? '',
274
- }));
275
- };
276
- ws.onmessage = (ev) => {
277
- try {
278
- const frame = JSON.parse(typeof ev.data === 'string' ? ev.data : Buffer.from(ev.data).toString());
279
- this.applyFrame(frame, aggregated, handlers);
280
- }
281
- catch {
282
- // malformed frame — ignore, daemon never emits non-JSON frames in normal operation
283
- }
284
- };
285
- // Node's `ws` exposes the HTTP status code on the unexpected-response
286
- // event before `error` fires. Hook it if available; the browser
287
- // WebSocket gives us no such hook.
288
- const wsAny = ws;
289
- if (typeof wsAny.on === 'function') {
290
- wsAny.on('unexpected-response', (_req, res) => {
291
- const status = res?.statusCode;
292
- if (status === 401 || status === 403) {
293
- finish(new WsAuthError());
294
- }
295
- else {
296
- // 404 (context gone), 400 (proxy: "Is the Sandbox started?"),
297
- // 5xx — all map to invalidation. The caller's recovery action
298
- // is the same: drop the context and create a fresh one.
299
- finish(new SessionInvalidatedError(sessionId, new Date().toISOString()));
300
- }
301
- });
302
- }
303
- ws.onerror = () => {
304
- if (!opened) {
305
- // Pre-open error with no status — treat as sandbox-gone.
306
- finish(new SessionInvalidatedError(sessionId, new Date().toISOString()));
307
- }
308
- else {
309
- finish(new DaytonaError('session websocket error'));
310
- }
311
- };
312
- ws.onclose = () => finish(aggregated);
313
- });
314
- }
315
- async fetchSessionAccess(sessionId) {
316
- try {
317
- const { data } = await this.http.get(`/sessions/${encodeURIComponent(sessionId)}/access`);
318
- return data;
319
- }
320
- catch (err) {
321
- const status = errorStatus(err);
322
- if (status === 404) {
323
- if (this.isRouteMissing404(errorBody(err))) {
324
- throw new LegacyFallback();
325
- }
326
- throw new SessionInvalidatedError(sessionId, new Date().toISOString());
327
- }
328
- if (status === 410) {
329
- throw this.translateError(err);
330
- }
331
- throw err;
332
- }
333
- }
334
- async fetchTransient(template, language) {
335
- try {
336
- const body = {};
337
- if (template !== undefined)
338
- body.template = template;
339
- if (language !== undefined)
340
- body.language = language;
341
- const { data } = await this.http.post('/sessions/transients', body);
342
- if (!data.access) {
343
- throw new LegacyFallback();
344
- }
345
- return { sessionId: data.id, access: data.access };
346
- }
347
- catch (err) {
348
- if (err instanceof LegacyFallback) {
349
- throw err;
350
- }
351
- if (errorStatus(err) === 404 && this.isRouteMissing404(errorBody(err))) {
352
- throw new LegacyFallback();
353
- }
354
- throw err;
355
- }
356
- }
357
- async runLegacy(code, options, handlers) {
358
- if (handlers) {
359
- return this.runStreamLegacy(code, options, handlers);
360
- }
361
- return this.runCodeRunLegacy(code, options);
362
- }
363
- async runCodeRunLegacy(code, options) {
364
- try {
365
- const { data } = await this.http.post('/sessions/code-run', { code, ...options });
366
- return {
367
- ...data,
368
- error: data.error ?? null,
369
- displays: data.displays ?? [],
370
- };
371
- }
372
- catch (err) {
373
- throw this.translateError(err);
374
- }
375
- }
376
- async runStreamLegacy(code, options, handlers) {
377
- let data;
378
- try {
379
- ;
380
- ({ data } = await this.http.post('/sessions/connect', options));
381
- }
382
- catch (err) {
383
- throw this.translateError(err);
384
- }
385
- const WebSocketImpl = await this.resolveWebSocketImpl();
386
- return new Promise((resolve, reject) => {
387
- const ws = new WebSocketImpl(data.wsUrl);
388
- const aggregated = {
389
- stdout: '',
390
- stderr: '',
391
- error: null,
392
- displays: [],
393
- durationMs: 0,
394
- };
395
- const startedAt = Date.now();
396
- let resolved = false;
397
- const finish = (resolvedOrErr) => {
398
- if (resolved)
399
- return;
400
- resolved = true;
401
- handlers.signal?.removeEventListener('abort', onAbort);
402
- try {
403
- ws.close();
404
- }
405
- catch {
406
- /* close errors are non-fatal here */
407
- }
408
- if (resolvedOrErr instanceof Error) {
409
- reject(resolvedOrErr);
410
- }
411
- else {
412
- resolvedOrErr.durationMs = Date.now() - startedAt;
413
- resolve(resolvedOrErr);
414
- }
415
- };
416
- const onAbort = () => finish(new DaytonaError('runStream aborted by caller'));
417
- if (handlers.signal?.aborted) {
418
- finish(new DaytonaError('runStream aborted by caller'));
419
- return;
420
- }
421
- handlers.signal?.addEventListener('abort', onAbort, { once: true });
422
- ws.onopen = () => {
423
- ws.send(JSON.stringify({ code, envs: options.env, timeout: options.timeout, wsAuth: data.wsAuth ?? '' }));
424
- };
425
- ws.onmessage = (ev) => {
426
- try {
427
- const frame = JSON.parse(typeof ev.data === 'string' ? ev.data : Buffer.from(ev.data).toString());
428
- this.applyFrame(frame, aggregated, handlers);
429
- }
430
- catch {
431
- /* ignore malformed frames */
432
- }
433
- };
434
- ws.onerror = () => finish(new DaytonaError('session websocket error'));
435
- ws.onclose = () => finish(aggregated);
436
- });
437
- }
438
- // -- helpers -----------------------------------------------------------
439
- isExpired(access) {
440
- const expiry = new Date(access.tokenExpiresAt).getTime();
441
- return Number.isFinite(expiry) ? Date.now() + REFRESH_SKEW_SECONDS * 1000 >= expiry : true;
442
- }
443
- evictAccess(options, sessionId) {
444
- if (options.context) {
445
- this.ctxAccess.delete(sessionId);
446
- return;
447
- }
448
- this.transientAccess.delete(`${options.template ?? ''}:${options.language ?? ''}`);
449
- }
450
- isRouteMissing404(body) {
451
- // A non-JSON / empty body means we never reached the route layer — treat as route-missing.
452
- if (!body || typeof body !== 'object')
453
- return true;
454
- const b = body;
455
- // Nest's unknown-route 404 carries `message:"Cannot GET /..."`. A genuine
456
- // missing-session NotFoundException carries the SAME `error:"Not Found"` but
457
- // a descriptive message (e.g. "Session <id> not found."), so we must NOT
458
- // key off `error` — only the message (or its absence) is a reliable signal.
459
- if (typeof b.message === 'string') {
460
- return b.message.startsWith('Cannot ') || b.message.trim() === '';
461
- }
462
- // No message field at all → not a recognizable missing-session envelope; assume route-missing.
463
- return b.message === undefined || b.message === null;
464
- }
465
- applyFrame(frame, aggregated, handlers) {
466
- switch (frame.type) {
467
- case 'stdout':
468
- aggregated.stdout += frame.text ?? '';
469
- handlers?.onStdout?.(frame.text ?? '');
470
- break;
471
- case 'stderr':
472
- aggregated.stderr += frame.text ?? '';
473
- handlers?.onStderr?.(frame.text ?? '');
474
- break;
475
- case 'error': {
476
- const e = { name: frame.name ?? 'Error', value: frame.value, traceback: frame.traceback };
477
- aggregated.error = e;
478
- handlers?.onError?.(e);
479
- break;
480
- }
481
- case 'display': {
482
- const d = { formats: frame.formats ?? [], data: frame.data ?? {} };
483
- aggregated.displays.push(d);
484
- handlers?.onDisplay?.(d);
485
- break;
486
- }
487
- case 'control':
488
- handlers?.onControl?.(frame.text ?? '');
489
- break;
490
- }
491
- }
492
- async resolveWebSocketImpl() {
493
- if (typeof WebSocket !== 'undefined') {
494
- return WebSocket;
495
- }
496
- const wsModule = (await import('ws').catch(() => null));
497
- if (!wsModule?.default) {
498
- throw new DaytonaError("WebSocket support not available; install the 'ws' package or run in a browser/Node 22+");
499
- }
500
- return wsModule.default;
501
- }
502
- translateError(err) {
503
- if (errorStatus(err) === 410) {
504
- const body = errorBody(err);
505
- const e = body?.error;
506
- if (e?.name === 'SessionInvalidated' && e.sessionId && e.invalidatedAt) {
507
- return new SessionInvalidatedError(e.sessionId, e.invalidatedAt);
508
- }
509
- if (e?.name === 'SessionExpired' && e.sessionId && e.expiredAt && e.reason) {
510
- return new SessionExpiredError(e.sessionId, e.expiredAt, e.reason);
511
- }
512
- }
513
- return err;
514
- }
515
- }
516
- //# sourceMappingURL=Session.js.map