@daytona/sdk 0.175.1-alpha.1 → 0.179.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 (95) hide show
  1. package/cjs/CodeInterpreter.d.ts +3 -2
  2. package/cjs/CodeInterpreter.js.map +1 -1
  3. package/cjs/ComputerUse.d.ts +104 -2
  4. package/cjs/ComputerUse.js +851 -763
  5. package/cjs/ComputerUse.js.map +1 -1
  6. package/cjs/Daytona.d.ts +4 -3
  7. package/cjs/Daytona.js +429 -443
  8. package/cjs/Daytona.js.map +1 -1
  9. package/cjs/FileSystem.d.ts +2 -2
  10. package/cjs/FileSystem.js +492 -521
  11. package/cjs/FileSystem.js.map +1 -1
  12. package/cjs/Git.d.ts +2 -1
  13. package/cjs/Git.js +287 -310
  14. package/cjs/Git.js.map +1 -1
  15. package/cjs/LspServer.d.ts +2 -1
  16. package/cjs/LspServer.js +209 -226
  17. package/cjs/LspServer.js.map +1 -1
  18. package/cjs/ObjectStorage.js +170 -166
  19. package/cjs/ObjectStorage.js.map +1 -1
  20. package/cjs/Process.d.ts +4 -3
  21. package/cjs/Process.js +562 -600
  22. package/cjs/Process.js.map +1 -1
  23. package/cjs/PtyHandle.d.ts +2 -2
  24. package/cjs/PtyHandle.js +327 -338
  25. package/cjs/PtyHandle.js.map +1 -1
  26. package/cjs/Sandbox.d.ts +4 -3
  27. package/cjs/Sandbox.js +756 -821
  28. package/cjs/Sandbox.js.map +1 -1
  29. package/cjs/Snapshot.d.ts +3 -2
  30. package/cjs/Snapshot.js +203 -213
  31. package/cjs/Snapshot.js.map +1 -1
  32. package/cjs/Volume.d.ts +2 -1
  33. package/cjs/Volume.js +90 -92
  34. package/cjs/Volume.js.map +1 -1
  35. package/cjs/errors/DaytonaError.d.ts +2 -1
  36. package/cjs/errors/DaytonaError.js.map +1 -1
  37. package/cjs/index.d.ts +2 -2
  38. package/cjs/index.js +2 -1
  39. package/cjs/index.js.map +1 -1
  40. package/cjs/types/CodeInterpreter.d.ts +1 -1
  41. package/cjs/utils/Binary.js +14 -2
  42. package/cjs/utils/Binary.js.map +1 -1
  43. package/cjs/utils/FileTransfer.js +1 -1
  44. package/cjs/utils/FileTransfer.js.map +1 -1
  45. package/cjs/utils/otel.decorator.d.ts +7 -8
  46. package/cjs/utils/otel.decorator.js +24 -30
  47. package/cjs/utils/otel.decorator.js.map +1 -1
  48. package/esm/CodeInterpreter.d.ts +3 -2
  49. package/esm/CodeInterpreter.js.map +1 -1
  50. package/esm/ComputerUse.d.ts +104 -2
  51. package/esm/ComputerUse.js +857 -763
  52. package/esm/ComputerUse.js.map +1 -1
  53. package/esm/Daytona.d.ts +4 -3
  54. package/esm/Daytona.js +431 -444
  55. package/esm/Daytona.js.map +1 -1
  56. package/esm/FileSystem.d.ts +2 -2
  57. package/esm/FileSystem.js +494 -522
  58. package/esm/FileSystem.js.map +1 -1
  59. package/esm/Git.d.ts +2 -1
  60. package/esm/Git.js +289 -311
  61. package/esm/Git.js.map +1 -1
  62. package/esm/LspServer.d.ts +2 -1
  63. package/esm/LspServer.js +211 -227
  64. package/esm/LspServer.js.map +1 -1
  65. package/esm/ObjectStorage.js +172 -167
  66. package/esm/ObjectStorage.js.map +1 -1
  67. package/esm/Process.d.ts +4 -3
  68. package/esm/Process.js +564 -601
  69. package/esm/Process.js.map +1 -1
  70. package/esm/PtyHandle.d.ts +2 -2
  71. package/esm/PtyHandle.js +329 -339
  72. package/esm/PtyHandle.js.map +1 -1
  73. package/esm/Sandbox.d.ts +4 -3
  74. package/esm/Sandbox.js +759 -823
  75. package/esm/Sandbox.js.map +1 -1
  76. package/esm/Snapshot.d.ts +3 -2
  77. package/esm/Snapshot.js +206 -215
  78. package/esm/Snapshot.js.map +1 -1
  79. package/esm/Volume.d.ts +2 -1
  80. package/esm/Volume.js +92 -93
  81. package/esm/Volume.js.map +1 -1
  82. package/esm/errors/DaytonaError.d.ts +2 -1
  83. package/esm/errors/DaytonaError.js.map +1 -1
  84. package/esm/index.d.ts +2 -2
  85. package/esm/index.js +1 -1
  86. package/esm/index.js.map +1 -1
  87. package/esm/types/CodeInterpreter.d.ts +1 -1
  88. package/esm/utils/Binary.js +14 -2
  89. package/esm/utils/Binary.js.map +1 -1
  90. package/esm/utils/FileTransfer.js +1 -1
  91. package/esm/utils/FileTransfer.js.map +1 -1
  92. package/esm/utils/otel.decorator.d.ts +7 -8
  93. package/esm/utils/otel.decorator.js +26 -32
  94. package/esm/utils/otel.decorator.js.map +1 -1
  95. package/package.json +4 -4
package/cjs/FileSystem.js CHANGED
@@ -24,552 +24,523 @@ function createFileDownloadError(error, errorDetails) {
24
24
  *
25
25
  * @class
26
26
  */
27
- class FileSystem {
28
- clientConfig;
29
- apiClient;
30
- constructor(clientConfig, apiClient) {
31
- this.clientConfig = clientConfig;
32
- this.apiClient = apiClient;
33
- }
34
- /**
35
- * Create a new directory in the Sandbox with specified permissions.
36
- *
37
- * @param {string} path - Path where the directory should be created. Relative paths are resolved based on the sandbox working directory.
38
- * @param {string} mode - Directory permissions in octal format (e.g. "755")
39
- * @returns {Promise<void>}
40
- *
41
- * @example
42
- * // Create a directory with standard permissions
43
- * await fs.createFolder('app/data', '755');
44
- */
45
- async createFolder(path, mode) {
46
- const response = await this.apiClient.createFolder(path, mode);
47
- return response.data;
48
- }
49
- /**
50
- * Deletes a file or directory from the Sandbox.
51
- *
52
- * @param {string} path - Path to the file or directory to delete. Relative paths are resolved based on the sandbox working directory.
53
- * @param {boolean} [recursive] - If the file is a directory, this must be true to delete it.
54
- * @returns {Promise<void>}
55
- *
56
- * @example
57
- * // Delete a file
58
- * await fs.deleteFile('app/temp.log');
59
- */
60
- async deleteFile(path, recursive) {
61
- const response = await this.apiClient.deleteFile(path, recursive);
62
- return response.data;
63
- }
64
- async downloadFile(src, dst, timeout = 30 * 60) {
65
- const remotePath = src;
66
- if (typeof dst !== 'string') {
67
- if (dst) {
68
- timeout = dst;
69
- }
70
- const response = await this.downloadFiles([{ source: remotePath }], timeout);
71
- if (response[0].error) {
72
- throw createFileDownloadError(response[0].error, response[0].errorDetails);
73
- }
74
- return response[0].result;
75
- }
76
- const response = await this.downloadFiles([{ source: remotePath, destination: dst }], timeout);
77
- if (response[0].error) {
78
- throw createFileDownloadError(response[0].error, response[0].errorDetails);
27
+ let FileSystem = (() => {
28
+ let _instanceExtraInitializers = [];
29
+ let _createFolder_decorators;
30
+ let _deleteFile_decorators;
31
+ let _downloadFile_decorators;
32
+ let _downloadFileStream_decorators;
33
+ let _downloadFiles_decorators;
34
+ let _findFiles_decorators;
35
+ let _getFileDetails_decorators;
36
+ let _listFiles_decorators;
37
+ let _moveFiles_decorators;
38
+ let _replaceInFiles_decorators;
39
+ let _searchFiles_decorators;
40
+ let _setFilePermissions_decorators;
41
+ let _uploadFile_decorators;
42
+ let _uploadFileStream_decorators;
43
+ let _uploadFiles_decorators;
44
+ return class FileSystem {
45
+ static {
46
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
47
+ _createFolder_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
48
+ _deleteFile_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
49
+ _downloadFile_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
50
+ _downloadFileStream_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
51
+ _downloadFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
52
+ _findFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
53
+ _getFileDetails_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
54
+ _listFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
55
+ _moveFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
56
+ _replaceInFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
57
+ _searchFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
58
+ _setFilePermissions_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
59
+ _uploadFile_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
60
+ _uploadFileStream_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
61
+ _uploadFiles_decorators = [(0, otel_decorator_1.WithInstrumentation)()];
62
+ tslib_1.__esDecorate(this, null, _createFolder_decorators, { kind: "method", name: "createFolder", static: false, private: false, access: { has: obj => "createFolder" in obj, get: obj => obj.createFolder }, metadata: _metadata }, null, _instanceExtraInitializers);
63
+ tslib_1.__esDecorate(this, null, _deleteFile_decorators, { kind: "method", name: "deleteFile", static: false, private: false, access: { has: obj => "deleteFile" in obj, get: obj => obj.deleteFile }, metadata: _metadata }, null, _instanceExtraInitializers);
64
+ tslib_1.__esDecorate(this, null, _downloadFile_decorators, { kind: "method", name: "downloadFile", static: false, private: false, access: { has: obj => "downloadFile" in obj, get: obj => obj.downloadFile }, metadata: _metadata }, null, _instanceExtraInitializers);
65
+ tslib_1.__esDecorate(this, null, _downloadFileStream_decorators, { kind: "method", name: "downloadFileStream", static: false, private: false, access: { has: obj => "downloadFileStream" in obj, get: obj => obj.downloadFileStream }, metadata: _metadata }, null, _instanceExtraInitializers);
66
+ tslib_1.__esDecorate(this, null, _downloadFiles_decorators, { kind: "method", name: "downloadFiles", static: false, private: false, access: { has: obj => "downloadFiles" in obj, get: obj => obj.downloadFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
67
+ tslib_1.__esDecorate(this, null, _findFiles_decorators, { kind: "method", name: "findFiles", static: false, private: false, access: { has: obj => "findFiles" in obj, get: obj => obj.findFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
68
+ tslib_1.__esDecorate(this, null, _getFileDetails_decorators, { kind: "method", name: "getFileDetails", static: false, private: false, access: { has: obj => "getFileDetails" in obj, get: obj => obj.getFileDetails }, metadata: _metadata }, null, _instanceExtraInitializers);
69
+ tslib_1.__esDecorate(this, null, _listFiles_decorators, { kind: "method", name: "listFiles", static: false, private: false, access: { has: obj => "listFiles" in obj, get: obj => obj.listFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
70
+ tslib_1.__esDecorate(this, null, _moveFiles_decorators, { kind: "method", name: "moveFiles", static: false, private: false, access: { has: obj => "moveFiles" in obj, get: obj => obj.moveFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
71
+ tslib_1.__esDecorate(this, null, _replaceInFiles_decorators, { kind: "method", name: "replaceInFiles", static: false, private: false, access: { has: obj => "replaceInFiles" in obj, get: obj => obj.replaceInFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
72
+ tslib_1.__esDecorate(this, null, _searchFiles_decorators, { kind: "method", name: "searchFiles", static: false, private: false, access: { has: obj => "searchFiles" in obj, get: obj => obj.searchFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
73
+ tslib_1.__esDecorate(this, null, _setFilePermissions_decorators, { kind: "method", name: "setFilePermissions", static: false, private: false, access: { has: obj => "setFilePermissions" in obj, get: obj => obj.setFilePermissions }, metadata: _metadata }, null, _instanceExtraInitializers);
74
+ tslib_1.__esDecorate(this, null, _uploadFile_decorators, { kind: "method", name: "uploadFile", static: false, private: false, access: { has: obj => "uploadFile" in obj, get: obj => obj.uploadFile }, metadata: _metadata }, null, _instanceExtraInitializers);
75
+ tslib_1.__esDecorate(this, null, _uploadFileStream_decorators, { kind: "method", name: "uploadFileStream", static: false, private: false, access: { has: obj => "uploadFileStream" in obj, get: obj => obj.uploadFileStream }, metadata: _metadata }, null, _instanceExtraInitializers);
76
+ tslib_1.__esDecorate(this, null, _uploadFiles_decorators, { kind: "method", name: "uploadFiles", static: false, private: false, access: { has: obj => "uploadFiles" in obj, get: obj => obj.uploadFiles }, metadata: _metadata }, null, _instanceExtraInitializers);
77
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
79
78
  }
80
- }
81
- async downloadFileStream(remotePath, timeoutOrOptions) {
82
- const options = typeof timeoutOrOptions === 'number' ? { timeout: timeoutOrOptions } : (timeoutOrOptions ?? {});
83
- const timeout = options.timeout ?? 30 * 60;
84
- const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
85
- if (isNonStreamingRuntime) {
86
- throw new DaytonaError_1.DaytonaError('downloadFileStream is not supported in browser or serverless environments. Use downloadFile instead.');
79
+ clientConfig = tslib_1.__runInitializers(this, _instanceExtraInitializers);
80
+ apiClient;
81
+ constructor(clientConfig, apiClient) {
82
+ this.clientConfig = clientConfig;
83
+ this.apiClient = apiClient;
87
84
  }
88
- if (options.signal?.aborted) {
89
- throw new DaytonaError_1.DaytonaError('Download cancelled');
85
+ /**
86
+ * Create a new directory in the Sandbox with specified permissions.
87
+ *
88
+ * @param {string} path - Path where the directory should be created. Relative paths are resolved based on the sandbox working directory.
89
+ * @param {string} mode - Directory permissions in octal format (e.g. "755")
90
+ * @returns {Promise<void>}
91
+ *
92
+ * @example
93
+ * // Create a directory with standard permissions
94
+ * await fs.createFolder('app/data', '755');
95
+ */
96
+ async createFolder(path, mode) {
97
+ const response = await this.apiClient.createFolder(path, mode);
98
+ return response.data;
90
99
  }
91
- const toDownloadCancelledError = () => new DaytonaError_1.DaytonaError('Download cancelled');
92
- const isCanceledError = (err) => {
93
- const error = err;
94
- return Boolean(axios_1.default.isCancel?.(err) || error?.name === 'CanceledError' || error?.code === 'ERR_CANCELED');
95
- };
96
- let response;
97
- try {
98
- response = await this.apiClient.downloadFiles({ paths: [remotePath] }, {
99
- responseType: 'stream',
100
- timeout: timeout * 1000,
101
- signal: options.signal,
102
- });
100
+ /**
101
+ * Deletes a file or directory from the Sandbox.
102
+ *
103
+ * @param {string} path - Path to the file or directory to delete. Relative paths are resolved based on the sandbox working directory.
104
+ * @param {boolean} [recursive] - If the file is a directory, this must be true to delete it.
105
+ * @returns {Promise<void>}
106
+ *
107
+ * @example
108
+ * // Delete a file
109
+ * await fs.deleteFile('app/temp.log');
110
+ */
111
+ async deleteFile(path, recursive) {
112
+ const response = await this.apiClient.deleteFile(path, recursive);
113
+ return response.data;
103
114
  }
104
- catch (err) {
105
- if (options.signal?.aborted || isCanceledError(err)) {
106
- throw toDownloadCancelledError();
115
+ async downloadFile(src, dst, timeout = 30 * 60) {
116
+ const remotePath = src;
117
+ if (typeof dst !== 'string') {
118
+ if (dst) {
119
+ timeout = dst;
120
+ }
121
+ const response = await this.downloadFiles([{ source: remotePath }], timeout);
122
+ if (response[0].error) {
123
+ throw createFileDownloadError(response[0].error, response[0].errorDetails);
124
+ }
125
+ return response[0].result;
126
+ }
127
+ const response = await this.downloadFiles([{ source: remotePath, destination: dst }], timeout);
128
+ if (response[0].error) {
129
+ throw createFileDownloadError(response[0].error, response[0].errorDetails);
107
130
  }
108
- throw err;
109
131
  }
110
- const responseStream = (0, FileTransfer_1.normalizeResponseStream)(response.data);
111
- const metadataMap = new Map();
112
- metadataMap.set(remotePath, {});
113
- return new Promise((resolve, reject) => {
114
- let resolvedStream = null;
115
- (0, FileTransfer_1.processDownloadFilesResponseWithBusboy)(responseStream, response.headers, metadataMap, (_source, fileStream, totalBytes) => {
116
- if (options.onProgress) {
117
- const { Transform } = require('stream');
118
- let bytesReceived = 0;
119
- const progress = new Transform({
120
- transform(chunk, _encoding, callback) {
121
- bytesReceived += chunk.length;
122
- options.onProgress({ bytesReceived, totalBytes });
123
- callback(null, chunk);
124
- },
125
- });
126
- fileStream.pipe(progress);
127
- fileStream.on('error', (err) => {
128
- if (!progress.destroyed)
129
- progress.destroy(err);
130
- });
131
- resolvedStream = progress;
132
- }
133
- else {
134
- resolvedStream = fileStream;
132
+ async downloadFileStream(remotePath, timeoutOrOptions) {
133
+ const options = typeof timeoutOrOptions === 'number' ? { timeout: timeoutOrOptions } : (timeoutOrOptions ?? {});
134
+ const timeout = options.timeout ?? 30 * 60;
135
+ const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
136
+ if (isNonStreamingRuntime) {
137
+ throw new DaytonaError_1.DaytonaError('downloadFileStream is not supported in browser or serverless environments. Use downloadFile instead.');
138
+ }
139
+ if (options.signal?.aborted) {
140
+ throw new DaytonaError_1.DaytonaError('Download cancelled');
141
+ }
142
+ // Pre-resolve `stream` so the sync `onFileStream` callback below is await-free.
143
+ const { Transform } = await (0, Import_1.dynamicImport)('stream', 'downloadFileStream progress tracking is not supported: ');
144
+ const toDownloadCancelledError = () => new DaytonaError_1.DaytonaError('Download cancelled');
145
+ const isCanceledError = (err) => {
146
+ const error = err;
147
+ return Boolean(axios_1.default.isCancel?.(err) || error?.name === 'CanceledError' || error?.code === 'ERR_CANCELED');
148
+ };
149
+ let response;
150
+ try {
151
+ response = await this.apiClient.downloadFiles({ paths: [remotePath] }, {
152
+ responseType: 'stream',
153
+ timeout: timeout * 1000,
154
+ signal: options.signal,
155
+ });
156
+ }
157
+ catch (err) {
158
+ if (options.signal?.aborted || isCanceledError(err)) {
159
+ throw toDownloadCancelledError();
135
160
  }
136
- resolve(resolvedStream);
137
- })
138
- .then(() => {
139
- if (!resolvedStream) {
140
- const metadata = metadataMap.get(remotePath);
141
- if (metadata?.error) {
142
- reject(createFileDownloadError(metadata.error, metadata.errorDetails));
161
+ throw err;
162
+ }
163
+ const responseStream = (0, FileTransfer_1.normalizeResponseStream)(response.data);
164
+ const metadataMap = new Map();
165
+ metadataMap.set(remotePath, {});
166
+ return new Promise((resolve, reject) => {
167
+ let resolvedStream = null;
168
+ (0, FileTransfer_1.processDownloadFilesResponseWithBusboy)(responseStream, response.headers, metadataMap, (_source, fileStream, totalBytes) => {
169
+ if (options.onProgress) {
170
+ let bytesReceived = 0;
171
+ const progress = new Transform({
172
+ transform(chunk, _encoding, callback) {
173
+ bytesReceived += chunk.length;
174
+ options.onProgress({ bytesReceived, totalBytes });
175
+ callback(null, chunk);
176
+ },
177
+ });
178
+ fileStream.pipe(progress);
179
+ // busboy's teardown can emit 'error' on the file stream after 'end',
180
+ // even when every byte was delivered — ignore those late errors.
181
+ let fileStreamEnded = false;
182
+ fileStream.once('end', () => {
183
+ fileStreamEnded = true;
184
+ });
185
+ fileStream.on('error', (err) => {
186
+ if (fileStreamEnded)
187
+ return;
188
+ if (!progress.destroyed)
189
+ progress.destroy(err);
190
+ });
191
+ resolvedStream = progress;
143
192
  }
144
193
  else {
145
- reject(new DaytonaError_1.DaytonaError(`No file data received for: ${remotePath}`));
194
+ resolvedStream = fileStream;
146
195
  }
196
+ resolve(resolvedStream);
197
+ })
198
+ .then(() => {
199
+ if (!resolvedStream) {
200
+ const metadata = metadataMap.get(remotePath);
201
+ if (metadata?.error) {
202
+ reject(createFileDownloadError(metadata.error, metadata.errorDetails));
203
+ }
204
+ else {
205
+ reject(new DaytonaError_1.DaytonaError(`No file data received for: ${remotePath}`));
206
+ }
207
+ }
208
+ })
209
+ .catch((err) => {
210
+ const normalizedError = options.signal?.aborted || isCanceledError(err) ? toDownloadCancelledError() : err;
211
+ if (!resolvedStream) {
212
+ reject(normalizedError);
213
+ return;
214
+ }
215
+ const stream = resolvedStream;
216
+ if (stream.destroyed || stream.readableEnded) {
217
+ return;
218
+ }
219
+ stream.destroy(normalizedError instanceof Error ? normalizedError : new Error(String(normalizedError)));
220
+ });
221
+ });
222
+ }
223
+ /**
224
+ * Downloads multiple files from the Sandbox. If the files already exist locally, they will be overwritten.
225
+ *
226
+ * @param {FileDownloadRequest[]} files - Array of file download requests.
227
+ * @param {number} [timeoutSec] - Timeout for the download operation in seconds. 0 means no timeout.
228
+ * Default is 30 minutes.
229
+ * @returns {Promise<FileDownloadResponse[]>} Array of download results.
230
+ *
231
+ * @throws {DaytonaError} If the request itself fails (network issues, invalid request/response, etc.). Individual
232
+ * file download errors are returned in `FileDownloadResponse.error`. When the daemon provides structured
233
+ * per-file metadata, it is also available in `FileDownloadResponse.errorDetails`.
234
+ *
235
+ * @example
236
+ * // Download multiple files
237
+ * const results = await fs.downloadFiles([
238
+ * { source: 'tmp/data.json' },
239
+ * { source: 'tmp/config.json', destination: 'local_config.json' }
240
+ * ]);
241
+ * results.forEach(result => {
242
+ * if (result.error) {
243
+ * console.error(`Error downloading ${result.source}: ${result.error}`);
244
+ * } else if (result.result) {
245
+ * console.log(`Downloaded ${result.source} to ${result.result}`);
246
+ * }
247
+ * });
248
+ */
249
+ async downloadFiles(files, timeoutSec = 30 * 60) {
250
+ if (files.length === 0)
251
+ return [];
252
+ const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
253
+ // Prepare destinations and metadata
254
+ const metadataMap = new Map();
255
+ for (const f of files) {
256
+ metadataMap.set(f.source, { destination: f.destination });
257
+ if (f.destination) {
258
+ const fs = await (0, Import_1.dynamicImport)('fs', 'Downloading files to local files is not supported: ');
259
+ await fs.promises.mkdir(pathe.dirname(f.destination), { recursive: true });
147
260
  }
148
- })
149
- .catch((err) => {
150
- const normalizedError = options.signal?.aborted || isCanceledError(err) ? toDownloadCancelledError() : err;
151
- if (!resolvedStream) {
152
- reject(normalizedError);
153
- return;
154
- }
155
- const stream = resolvedStream;
156
- if (stream.destroyed || stream.readableEnded) {
157
- return;
158
- }
159
- stream.destroy(normalizedError instanceof Error ? normalizedError : new Error(String(normalizedError)));
261
+ }
262
+ const response = await this.apiClient.downloadFiles({ paths: files.map((f) => f.source) }, {
263
+ responseType: isNonStreamingRuntime ? 'arraybuffer' : 'stream',
264
+ timeout: timeoutSec * 1000,
160
265
  });
161
- });
162
- }
163
- /**
164
- * Downloads multiple files from the Sandbox. If the files already exist locally, they will be overwritten.
165
- *
166
- * @param {FileDownloadRequest[]} files - Array of file download requests.
167
- * @param {number} [timeoutSec] - Timeout for the download operation in seconds. 0 means no timeout.
168
- * Default is 30 minutes.
169
- * @returns {Promise<FileDownloadResponse[]>} Array of download results.
170
- *
171
- * @throws {DaytonaError} If the request itself fails (network issues, invalid request/response, etc.). Individual
172
- * file download errors are returned in `FileDownloadResponse.error`. When the daemon provides structured
173
- * per-file metadata, it is also available in `FileDownloadResponse.errorDetails`.
174
- *
175
- * @example
176
- * // Download multiple files
177
- * const results = await fs.downloadFiles([
178
- * { source: 'tmp/data.json' },
179
- * { source: 'tmp/config.json', destination: 'local_config.json' }
180
- * ]);
181
- * results.forEach(result => {
182
- * if (result.error) {
183
- * console.error(`Error downloading ${result.source}: ${result.error}`);
184
- * } else if (result.result) {
185
- * console.log(`Downloaded ${result.source} to ${result.result}`);
186
- * }
187
- * });
188
- */
189
- async downloadFiles(files, timeoutSec = 30 * 60) {
190
- if (files.length === 0)
191
- return [];
192
- const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
193
- // Prepare destinations and metadata
194
- const metadataMap = new Map();
195
- for (const f of files) {
196
- metadataMap.set(f.source, { destination: f.destination });
197
- if (f.destination) {
198
- const fs = await (0, Import_1.dynamicImport)('fs', 'Downloading files to local files is not supported: ');
199
- await fs.promises.mkdir(pathe.dirname(f.destination), { recursive: true });
266
+ const stream = (0, FileTransfer_1.normalizeResponseStream)(response.data);
267
+ // Node.js path: use busboy for efficient streaming
268
+ if (isNonStreamingRuntime) {
269
+ await (0, FileTransfer_1.processDownloadFilesResponseWithBuffered)(stream, response.headers, metadataMap);
270
+ }
271
+ else {
272
+ await (0, FileTransfer_1.processDownloadFilesResponseWithBusboy)(stream, response.headers, metadataMap);
200
273
  }
274
+ return files.map((f) => {
275
+ const metadata = metadataMap.get(f.source);
276
+ const error = metadata?.error || (!metadata?.result ? 'No data received for this file' : undefined);
277
+ return {
278
+ source: f.source,
279
+ result: error ? undefined : metadata.result,
280
+ error,
281
+ errorDetails: error ? metadata?.errorDetails : undefined,
282
+ };
283
+ });
284
+ }
285
+ /**
286
+ * Searches for text patterns within files in the Sandbox.
287
+ *
288
+ * @param {string} path - Directory to search in. Relative paths are resolved based on the sandbox working directory.
289
+ * @param {string} pattern - Search pattern
290
+ * @returns {Promise<Array<Match>>} Array of matches with file and line information
291
+ *
292
+ * @example
293
+ * // Find all TODO comments in TypeScript files
294
+ * const matches = await fs.findFiles('app/src', 'TODO:');
295
+ * matches.forEach(match => {
296
+ * console.log(`${match.file}:${match.line}: ${match.content}`);
297
+ * });
298
+ */
299
+ async findFiles(path, pattern) {
300
+ const response = await this.apiClient.findInFiles(path, pattern);
301
+ return response.data;
201
302
  }
202
- const response = await this.apiClient.downloadFiles({ paths: files.map((f) => f.source) }, {
203
- responseType: isNonStreamingRuntime ? 'arraybuffer' : 'stream',
204
- timeout: timeoutSec * 1000,
205
- });
206
- const stream = (0, FileTransfer_1.normalizeResponseStream)(response.data);
207
- // Node.js path: use busboy for efficient streaming
208
- if (isNonStreamingRuntime) {
209
- await (0, FileTransfer_1.processDownloadFilesResponseWithBuffered)(stream, response.headers, metadataMap);
303
+ /**
304
+ * Retrieves detailed information about a file or directory.
305
+ *
306
+ * @param {string} path - Path to the file or directory. Relative paths are resolved based on the sandbox working directory.
307
+ * @returns {Promise<FileInfo>} Detailed file information including size, permissions, modification time
308
+ *
309
+ * @example
310
+ * // Get file details
311
+ * const info = await fs.getFileDetails('app/config.json');
312
+ * console.log(`Size: ${info.size}, Modified: ${info.modTime}`);
313
+ */
314
+ async getFileDetails(path) {
315
+ const response = await this.apiClient.getFileInfo(path);
316
+ return response.data;
210
317
  }
211
- else {
212
- await (0, FileTransfer_1.processDownloadFilesResponseWithBusboy)(stream, response.headers, metadataMap);
318
+ /**
319
+ * Lists contents of a directory in the Sandbox.
320
+ *
321
+ * @param {string} path - Directory path to list. Relative paths are resolved based on the sandbox working directory.
322
+ * @returns {Promise<FileInfo[]>} Array of file and directory information
323
+ *
324
+ * @example
325
+ * // List directory contents
326
+ * const files = await fs.listFiles('app/src');
327
+ * files.forEach(file => {
328
+ * console.log(`${file.name} (${file.size} bytes)`);
329
+ * });
330
+ */
331
+ async listFiles(path) {
332
+ const response = await this.apiClient.listFiles(path);
333
+ return response.data;
213
334
  }
214
- return files.map((f) => {
215
- const metadata = metadataMap.get(f.source);
216
- const error = metadata?.error || (!metadata?.result ? 'No data received for this file' : undefined);
217
- return {
218
- source: f.source,
219
- result: error ? undefined : metadata.result,
220
- error,
221
- errorDetails: error ? metadata?.errorDetails : undefined,
335
+ /**
336
+ * Moves or renames a file or directory.
337
+ *
338
+ * @param {string} source - Source path. Relative paths are resolved based on the sandbox working directory.
339
+ * @param {string} destination - Destination path. Relative paths are resolved based on the sandbox working directory.
340
+ * @returns {Promise<void>}
341
+ *
342
+ * @example
343
+ * // Move a file to a new location
344
+ * await fs.moveFiles('app/temp/data.json', 'app/data/data.json');
345
+ */
346
+ async moveFiles(source, destination) {
347
+ const response = await this.apiClient.moveFile(source, destination);
348
+ return response.data;
349
+ }
350
+ /**
351
+ * Replaces text content in multiple files.
352
+ *
353
+ * @param {string[]} files - Array of file paths to process. Relative paths are resolved based on the sandbox working directory.
354
+ * @param {string} pattern - Pattern to replace
355
+ * @param {string} newValue - Replacement text
356
+ * @returns {Promise<Array<ReplaceResult>>} Results of the replace operation for each file
357
+ *
358
+ * @example
359
+ * // Update version number across multiple files
360
+ * const results = await fs.replaceInFiles(
361
+ * ['app/package.json', 'app/version.ts'],
362
+ * '"version": "1.0.0"',
363
+ * '"version": "1.1.0"'
364
+ * );
365
+ */
366
+ async replaceInFiles(files, pattern, newValue) {
367
+ const replaceRequest = {
368
+ files,
369
+ newValue,
370
+ pattern,
222
371
  };
223
- });
224
- }
225
- /**
226
- * Searches for text patterns within files in the Sandbox.
227
- *
228
- * @param {string} path - Directory to search in. Relative paths are resolved based on the sandbox working directory.
229
- * @param {string} pattern - Search pattern
230
- * @returns {Promise<Array<Match>>} Array of matches with file and line information
231
- *
232
- * @example
233
- * // Find all TODO comments in TypeScript files
234
- * const matches = await fs.findFiles('app/src', 'TODO:');
235
- * matches.forEach(match => {
236
- * console.log(`${match.file}:${match.line}: ${match.content}`);
237
- * });
238
- */
239
- async findFiles(path, pattern) {
240
- const response = await this.apiClient.findInFiles(path, pattern);
241
- return response.data;
242
- }
243
- /**
244
- * Retrieves detailed information about a file or directory.
245
- *
246
- * @param {string} path - Path to the file or directory. Relative paths are resolved based on the sandbox working directory.
247
- * @returns {Promise<FileInfo>} Detailed file information including size, permissions, modification time
248
- *
249
- * @example
250
- * // Get file details
251
- * const info = await fs.getFileDetails('app/config.json');
252
- * console.log(`Size: ${info.size}, Modified: ${info.modTime}`);
253
- */
254
- async getFileDetails(path) {
255
- const response = await this.apiClient.getFileInfo(path);
256
- return response.data;
257
- }
258
- /**
259
- * Lists contents of a directory in the Sandbox.
260
- *
261
- * @param {string} path - Directory path to list. Relative paths are resolved based on the sandbox working directory.
262
- * @returns {Promise<FileInfo[]>} Array of file and directory information
263
- *
264
- * @example
265
- * // List directory contents
266
- * const files = await fs.listFiles('app/src');
267
- * files.forEach(file => {
268
- * console.log(`${file.name} (${file.size} bytes)`);
269
- * });
270
- */
271
- async listFiles(path) {
272
- const response = await this.apiClient.listFiles(path);
273
- return response.data;
274
- }
275
- /**
276
- * Moves or renames a file or directory.
277
- *
278
- * @param {string} source - Source path. Relative paths are resolved based on the sandbox working directory.
279
- * @param {string} destination - Destination path. Relative paths are resolved based on the sandbox working directory.
280
- * @returns {Promise<void>}
281
- *
282
- * @example
283
- * // Move a file to a new location
284
- * await fs.moveFiles('app/temp/data.json', 'app/data/data.json');
285
- */
286
- async moveFiles(source, destination) {
287
- const response = await this.apiClient.moveFile(source, destination);
288
- return response.data;
289
- }
290
- /**
291
- * Replaces text content in multiple files.
292
- *
293
- * @param {string[]} files - Array of file paths to process. Relative paths are resolved based on the sandbox working directory.
294
- * @param {string} pattern - Pattern to replace
295
- * @param {string} newValue - Replacement text
296
- * @returns {Promise<Array<ReplaceResult>>} Results of the replace operation for each file
297
- *
298
- * @example
299
- * // Update version number across multiple files
300
- * const results = await fs.replaceInFiles(
301
- * ['app/package.json', 'app/version.ts'],
302
- * '"version": "1.0.0"',
303
- * '"version": "1.1.0"'
304
- * );
305
- */
306
- async replaceInFiles(files, pattern, newValue) {
307
- const replaceRequest = {
308
- files,
309
- newValue,
310
- pattern,
311
- };
312
- const response = await this.apiClient.replaceInFiles(replaceRequest);
313
- return response.data;
314
- }
315
- /**
316
- * Searches for files and directories by name pattern in the Sandbox.
317
- *
318
- * @param {string} path - Directory to search in. Relative paths are resolved based on the sandbox working directory.
319
- * @param {string} pattern - File name pattern (supports globs)
320
- * @returns {Promise<SearchFilesResponse>} Search results with matching files
321
- *
322
- * @example
323
- * // Find all TypeScript files
324
- * const result = await fs.searchFiles('app', '*.ts');
325
- * result.files.forEach(file => console.log(file));
326
- */
327
- async searchFiles(path, pattern) {
328
- const response = await this.apiClient.searchFiles(path, pattern);
329
- return response.data;
330
- }
331
- /**
332
- * Sets permissions and ownership for a file or directory.
333
- *
334
- * @param {string} path - Path to the file or directory. Relative paths are resolved based on the sandbox working directory.
335
- * @param {FilePermissionsParams} permissions - Permission settings
336
- * @returns {Promise<void>}
337
- *
338
- * @example
339
- * // Set file permissions and ownership
340
- * await fs.setFilePermissions('app/script.sh', {
341
- * owner: 'daytona',
342
- * group: 'users',
343
- * mode: '755' // Execute permission for shell script
344
- * });
345
- */
346
- async setFilePermissions(path, permissions) {
347
- const response = await this.apiClient.setFilePermissions(path, permissions.owner, permissions.group, permissions.mode);
348
- return response.data;
349
- }
350
- async uploadFile(src, dst, timeout = 30 * 60) {
351
- await this.uploadFiles([{ source: src, destination: dst }], timeout);
352
- }
353
- /**
354
- * Uploads a single file to the Sandbox using true streaming, with optional progress
355
- * tracking and cancellation. Memory usage stays flat regardless of source size: the
356
- * SDK pipes the source through a transform that counts bytes and forwards to the
357
- * underlying multipart upload without buffering the whole payload. The HTTP layer
358
- * uses chunked transfer encoding, so the source's natural EOF terminates the upload —
359
- * no advance size is needed.
360
- *
361
- * @param {UploadSource} source - The data to upload. Accepts the same `Buffer | string`
362
- * inputs as {@link FileSystem.uploadFile}, plus Node `Readable` streams and Web
363
- * `ReadableStream` instances. When a string is passed, it is treated as a local
364
- * file path and read in streaming chunks.
365
- * @param {string} remotePath - Destination path in the Sandbox. Relative paths are
366
- * resolved against the sandbox working directory.
367
- * @param {UploadStreamOptions} [options] - Streaming options: AbortSignal, onProgress
368
- * callback, timeout.
369
- * @returns {Promise<void>}
370
- *
371
- * @example
372
- * // Upload a 2 GB file with progress tracking and the ability to cancel
373
- * import { createReadStream } from 'fs';
374
- * const controller = new AbortController();
375
- * await sandbox.fs.uploadFileStream(createReadStream('big.bin'), 'tmp/big.bin', {
376
- * signal: controller.signal,
377
- * onProgress: ({ bytesSent }) => console.log(`${bytesSent} bytes sent`),
378
- * });
379
- */
380
- async uploadFileStream(source, remotePath, options = {}) {
381
- const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.DENO || Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
382
- if (isNonStreamingRuntime) {
383
- throw new DaytonaError_1.DaytonaError('uploadFileStream is not supported in browser, Deno, or serverless runtimes. Use uploadFile instead.');
372
+ const response = await this.apiClient.replaceInFiles(replaceRequest);
373
+ return response.data;
384
374
  }
385
- if (options.signal?.aborted) {
386
- throw (0, FileTransfer_1.createAbortError)(remotePath);
375
+ /**
376
+ * Searches for files and directories by name pattern in the Sandbox.
377
+ *
378
+ * @param {string} path - Directory to search in. Relative paths are resolved based on the sandbox working directory.
379
+ * @param {string} pattern - File name pattern (supports globs)
380
+ * @returns {Promise<SearchFilesResponse>} Search results with matching files
381
+ *
382
+ * @example
383
+ * // Find all TypeScript files
384
+ * const result = await fs.searchFiles('app', '*.ts');
385
+ * result.files.forEach(file => console.log(file));
386
+ */
387
+ async searchFiles(path, pattern) {
388
+ const response = await this.apiClient.searchFiles(path, pattern);
389
+ return response.data;
387
390
  }
388
- const timeout = options.timeout ?? 30 * 60;
389
- const sourceStream = await (0, FileTransfer_1.coerceUploadSource)(source);
390
- const tracked = (0, FileTransfer_1.wrapWithUploadProgress)(sourceStream, options.onProgress, options.signal);
391
- const FormDataClass = (await (0, Import_1.dynamicImport)('form-data', 'Uploading files is not supported: '));
392
- const form = new FormDataClass();
393
- form.append('files[0].path', remotePath);
394
- // No knownLength: form-data falls back to chunked transfer encoding, which the
395
- // daemon's MultipartReader handles transparently. The source's EOF terminates
396
- // the upload no advance byte count needed.
397
- form.append('files[0].file', tracked, { filename: remotePath });
398
- try {
399
- await this.apiClient.uploadFiles({
400
- data: form,
401
- maxRedirects: 0,
402
- timeout: timeout * 1000,
403
- signal: options.signal,
404
- });
391
+ /**
392
+ * Sets permissions and ownership for a file or directory.
393
+ *
394
+ * @param {string} path - Path to the file or directory. Relative paths are resolved based on the sandbox working directory.
395
+ * @param {FilePermissionsParams} permissions - Permission settings
396
+ * @returns {Promise<void>}
397
+ *
398
+ * @example
399
+ * // Set file permissions and ownership
400
+ * await fs.setFilePermissions('app/script.sh', {
401
+ * owner: 'daytona',
402
+ * group: 'users',
403
+ * mode: '755' // Execute permission for shell script
404
+ * });
405
+ */
406
+ async setFilePermissions(path, permissions) {
407
+ const response = await this.apiClient.setFilePermissions(path, permissions.owner, permissions.group, permissions.mode);
408
+ return response.data;
409
+ }
410
+ async uploadFile(src, dst, timeout = 30 * 60) {
411
+ await this.uploadFiles([{ source: src, destination: dst }], timeout);
405
412
  }
406
- catch (err) {
413
+ /**
414
+ * Uploads a single file to the Sandbox using true streaming, with optional progress
415
+ * tracking and cancellation. Memory usage stays flat regardless of source size: the
416
+ * SDK pipes the source through a transform that counts bytes and forwards to the
417
+ * underlying multipart upload without buffering the whole payload. The HTTP layer
418
+ * uses chunked transfer encoding, so the source's natural EOF terminates the upload —
419
+ * no advance size is needed.
420
+ *
421
+ * @param {UploadSource} source - The data to upload. Accepts the same `Buffer | string`
422
+ * inputs as {@link FileSystem.uploadFile}, plus Node `Readable` streams and Web
423
+ * `ReadableStream` instances. When a string is passed, it is treated as a local
424
+ * file path and read in streaming chunks.
425
+ * @param {string} remotePath - Destination path in the Sandbox. Relative paths are
426
+ * resolved against the sandbox working directory.
427
+ * @param {UploadStreamOptions} [options] - Streaming options: AbortSignal, onProgress
428
+ * callback, timeout.
429
+ * @returns {Promise<void>}
430
+ *
431
+ * @example
432
+ * // Upload a 2 GB file with progress tracking and the ability to cancel
433
+ * import { createReadStream } from 'fs';
434
+ * const controller = new AbortController();
435
+ * await sandbox.fs.uploadFileStream(createReadStream('big.bin'), 'tmp/big.bin', {
436
+ * signal: controller.signal,
437
+ * onProgress: ({ bytesSent }) => console.log(`${bytesSent} bytes sent`),
438
+ * });
439
+ */
440
+ async uploadFileStream(source, remotePath, options = {}) {
441
+ const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.DENO || Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
442
+ if (isNonStreamingRuntime) {
443
+ throw new DaytonaError_1.DaytonaError('uploadFileStream is not supported in browser, Deno, or serverless runtimes. Use uploadFile instead.');
444
+ }
407
445
  if (options.signal?.aborted) {
408
446
  throw (0, FileTransfer_1.createAbortError)(remotePath);
409
447
  }
410
- throw err;
411
- }
412
- }
413
- /**
414
- * Uploads multiple files to the Sandbox. If files already exist at the destination paths,
415
- * they will be overwritten.
416
- *
417
- * @param {FileUpload[]} files - Array of files to upload.
418
- * @param {number} [timeout] - Timeout for the upload operation in seconds. 0 means no timeout.
419
- * Default is 30 minutes.
420
- * @returns {Promise<void>}
421
- *
422
- * @example
423
- * // Upload multiple text files
424
- * const files = [
425
- * {
426
- * source: Buffer.from('Content of file 1'),
427
- * destination: '/tmp/file1.txt'
428
- * },
429
- * {
430
- * source: 'app/data/file2.txt',
431
- * destination: '/tmp/file2.txt'
432
- * },
433
- * {
434
- * source: Buffer.from('{"key": "value"}'),
435
- * destination: '/tmp/config.json'
436
- * }
437
- * ];
438
- * await fs.uploadFiles(files);
439
- */
440
- async uploadFiles(files, timeout = 30 * 60) {
441
- const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.DENO || Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
442
- const FormDataClass = isNonStreamingRuntime
443
- ? FormData
444
- : (await (0, Import_1.dynamicImport)('form-data', 'Uploading files is not supported: '));
445
- const form = new FormDataClass();
446
- for (const [i, { source, destination }] of files.entries()) {
447
- form.append(`files[${i}].path`, destination);
448
- const payload = await this.makeFilePayload(source);
449
- form.append(`files[${i}].file`, payload, destination);
450
- }
451
- if (isNonStreamingRuntime) {
452
- const url = `${this.clientConfig.basePath}/files/bulk-upload`;
453
- await fetch(url, {
454
- method: 'POST',
455
- headers: this.clientConfig.baseOptions.headers,
456
- body: form,
457
- signal: timeout ? AbortSignal.timeout(timeout * 1000) : undefined,
458
- });
459
- }
460
- else {
461
- await this.apiClient.uploadFiles({
462
- data: form,
463
- maxRedirects: 0,
464
- timeout: timeout * 1000,
465
- });
448
+ const timeout = options.timeout ?? 30 * 60;
449
+ const sourceStream = await (0, FileTransfer_1.coerceUploadSource)(source);
450
+ const tracked = (0, FileTransfer_1.wrapWithUploadProgress)(sourceStream, options.onProgress, options.signal);
451
+ const FormDataClass = (await (0, Import_1.dynamicImport)('form-data', 'Uploading files is not supported: '));
452
+ const form = new FormDataClass();
453
+ form.append('files[0].path', remotePath);
454
+ // No knownLength: form-data falls back to chunked transfer encoding, which the
455
+ // daemon's MultipartReader handles transparently. The source's EOF terminates
456
+ // the upload no advance byte count needed.
457
+ form.append('files[0].file', tracked, { filename: remotePath });
458
+ try {
459
+ await this.apiClient.uploadFiles({
460
+ data: form,
461
+ maxRedirects: 0,
462
+ timeout: timeout * 1000,
463
+ signal: options.signal,
464
+ });
465
+ }
466
+ catch (err) {
467
+ if (options.signal?.aborted) {
468
+ throw (0, FileTransfer_1.createAbortError)(remotePath);
469
+ }
470
+ throw err;
471
+ }
466
472
  }
467
- }
468
- async makeFilePayload(source) {
469
- // String = file path
470
- if (typeof source === 'string') {
471
- const fs = await (0, Import_1.dynamicImport)('fs', 'Uploading file from local file system is not supported: ');
472
- return fs.createReadStream(source);
473
+ /**
474
+ * Uploads multiple files to the Sandbox. If files already exist at the destination paths,
475
+ * they will be overwritten.
476
+ *
477
+ * @param {FileUpload[]} files - Array of files to upload.
478
+ * @param {number} [timeout] - Timeout for the upload operation in seconds. 0 means no timeout.
479
+ * Default is 30 minutes.
480
+ * @returns {Promise<void>}
481
+ *
482
+ * @example
483
+ * // Upload multiple text files
484
+ * const files = [
485
+ * {
486
+ * source: Buffer.from('Content of file 1'),
487
+ * destination: '/tmp/file1.txt'
488
+ * },
489
+ * {
490
+ * source: 'app/data/file2.txt',
491
+ * destination: '/tmp/file2.txt'
492
+ * },
493
+ * {
494
+ * source: Buffer.from('{"key": "value"}'),
495
+ * destination: '/tmp/config.json'
496
+ * }
497
+ * ];
498
+ * await fs.uploadFiles(files);
499
+ */
500
+ async uploadFiles(files, timeout = 30 * 60) {
501
+ const isNonStreamingRuntime = Runtime_1.RUNTIME === Runtime_1.Runtime.DENO || Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS;
502
+ const FormDataClass = isNonStreamingRuntime
503
+ ? FormData
504
+ : (await (0, Import_1.dynamicImport)('form-data', 'Uploading files is not supported: '));
505
+ const form = new FormDataClass();
506
+ for (const [i, { source, destination }] of files.entries()) {
507
+ form.append(`files[${i}].path`, destination);
508
+ const payload = await this.makeFilePayload(source);
509
+ form.append(`files[${i}].file`, payload, destination);
510
+ }
511
+ if (isNonStreamingRuntime) {
512
+ const url = `${this.clientConfig.basePath}/files/bulk-upload`;
513
+ await fetch(url, {
514
+ method: 'POST',
515
+ headers: this.clientConfig.baseOptions.headers,
516
+ body: form,
517
+ signal: timeout ? AbortSignal.timeout(timeout * 1000) : undefined,
518
+ });
519
+ }
520
+ else {
521
+ await this.apiClient.uploadFiles({
522
+ data: form,
523
+ maxRedirects: 0,
524
+ timeout: timeout * 1000,
525
+ });
526
+ }
473
527
  }
474
- // Blob
475
- if (Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS || Runtime_1.RUNTIME === Runtime_1.Runtime.DENO) {
476
- // Use .slice() to ensure we have a concrete ArrayBuffer, not ArrayBufferLike
477
- return new Blob([source.slice()], { type: 'application/octet-stream' });
528
+ async makeFilePayload(source) {
529
+ // String = file path
530
+ if (typeof source === 'string') {
531
+ const fs = await (0, Import_1.dynamicImport)('fs', 'Uploading file from local file system is not supported: ');
532
+ return fs.createReadStream(source);
533
+ }
534
+ // Blob
535
+ if (Runtime_1.RUNTIME === Runtime_1.Runtime.BROWSER || Runtime_1.RUNTIME === Runtime_1.Runtime.SERVERLESS || Runtime_1.RUNTIME === Runtime_1.Runtime.DENO) {
536
+ // Use .slice() to ensure we have a concrete ArrayBuffer, not ArrayBufferLike
537
+ return new Blob([source.slice()], { type: 'application/octet-stream' });
538
+ }
539
+ // Readable stream
540
+ const stream = await (0, Import_1.dynamicImport)('stream', 'Uploading file is not supported: ');
541
+ return stream.Readable.from(source);
478
542
  }
479
- // Readable stream
480
- const stream = await (0, Import_1.dynamicImport)('stream', 'Uploading file is not supported: ');
481
- return stream.Readable.from(source);
482
- }
483
- }
543
+ };
544
+ })();
484
545
  exports.FileSystem = FileSystem;
485
- tslib_1.__decorate([
486
- (0, otel_decorator_1.WithInstrumentation)(),
487
- tslib_1.__metadata("design:type", Function),
488
- tslib_1.__metadata("design:paramtypes", [String, String]),
489
- tslib_1.__metadata("design:returntype", Promise)
490
- ], FileSystem.prototype, "createFolder", null);
491
- tslib_1.__decorate([
492
- (0, otel_decorator_1.WithInstrumentation)(),
493
- tslib_1.__metadata("design:type", Function),
494
- tslib_1.__metadata("design:paramtypes", [String, Boolean]),
495
- tslib_1.__metadata("design:returntype", Promise)
496
- ], FileSystem.prototype, "deleteFile", null);
497
- tslib_1.__decorate([
498
- (0, otel_decorator_1.WithInstrumentation)(),
499
- tslib_1.__metadata("design:type", Function),
500
- tslib_1.__metadata("design:paramtypes", [String, Object, Number]),
501
- tslib_1.__metadata("design:returntype", Promise)
502
- ], FileSystem.prototype, "downloadFile", null);
503
- tslib_1.__decorate([
504
- (0, otel_decorator_1.WithInstrumentation)(),
505
- tslib_1.__metadata("design:type", Function),
506
- tslib_1.__metadata("design:paramtypes", [String, Object]),
507
- tslib_1.__metadata("design:returntype", Promise)
508
- ], FileSystem.prototype, "downloadFileStream", null);
509
- tslib_1.__decorate([
510
- (0, otel_decorator_1.WithInstrumentation)(),
511
- tslib_1.__metadata("design:type", Function),
512
- tslib_1.__metadata("design:paramtypes", [Array, Number]),
513
- tslib_1.__metadata("design:returntype", Promise)
514
- ], FileSystem.prototype, "downloadFiles", null);
515
- tslib_1.__decorate([
516
- (0, otel_decorator_1.WithInstrumentation)(),
517
- tslib_1.__metadata("design:type", Function),
518
- tslib_1.__metadata("design:paramtypes", [String, String]),
519
- tslib_1.__metadata("design:returntype", Promise)
520
- ], FileSystem.prototype, "findFiles", null);
521
- tslib_1.__decorate([
522
- (0, otel_decorator_1.WithInstrumentation)(),
523
- tslib_1.__metadata("design:type", Function),
524
- tslib_1.__metadata("design:paramtypes", [String]),
525
- tslib_1.__metadata("design:returntype", Promise)
526
- ], FileSystem.prototype, "getFileDetails", null);
527
- tslib_1.__decorate([
528
- (0, otel_decorator_1.WithInstrumentation)(),
529
- tslib_1.__metadata("design:type", Function),
530
- tslib_1.__metadata("design:paramtypes", [String]),
531
- tslib_1.__metadata("design:returntype", Promise)
532
- ], FileSystem.prototype, "listFiles", null);
533
- tslib_1.__decorate([
534
- (0, otel_decorator_1.WithInstrumentation)(),
535
- tslib_1.__metadata("design:type", Function),
536
- tslib_1.__metadata("design:paramtypes", [String, String]),
537
- tslib_1.__metadata("design:returntype", Promise)
538
- ], FileSystem.prototype, "moveFiles", null);
539
- tslib_1.__decorate([
540
- (0, otel_decorator_1.WithInstrumentation)(),
541
- tslib_1.__metadata("design:type", Function),
542
- tslib_1.__metadata("design:paramtypes", [Array, String, String]),
543
- tslib_1.__metadata("design:returntype", Promise)
544
- ], FileSystem.prototype, "replaceInFiles", null);
545
- tslib_1.__decorate([
546
- (0, otel_decorator_1.WithInstrumentation)(),
547
- tslib_1.__metadata("design:type", Function),
548
- tslib_1.__metadata("design:paramtypes", [String, String]),
549
- tslib_1.__metadata("design:returntype", Promise)
550
- ], FileSystem.prototype, "searchFiles", null);
551
- tslib_1.__decorate([
552
- (0, otel_decorator_1.WithInstrumentation)(),
553
- tslib_1.__metadata("design:type", Function),
554
- tslib_1.__metadata("design:paramtypes", [String, Object]),
555
- tslib_1.__metadata("design:returntype", Promise)
556
- ], FileSystem.prototype, "setFilePermissions", null);
557
- tslib_1.__decorate([
558
- (0, otel_decorator_1.WithInstrumentation)(),
559
- tslib_1.__metadata("design:type", Function),
560
- tslib_1.__metadata("design:paramtypes", [Object, String, Number]),
561
- tslib_1.__metadata("design:returntype", Promise)
562
- ], FileSystem.prototype, "uploadFile", null);
563
- tslib_1.__decorate([
564
- (0, otel_decorator_1.WithInstrumentation)(),
565
- tslib_1.__metadata("design:type", Function),
566
- tslib_1.__metadata("design:paramtypes", [Object, String, Object]),
567
- tslib_1.__metadata("design:returntype", Promise)
568
- ], FileSystem.prototype, "uploadFileStream", null);
569
- tslib_1.__decorate([
570
- (0, otel_decorator_1.WithInstrumentation)(),
571
- tslib_1.__metadata("design:type", Function),
572
- tslib_1.__metadata("design:paramtypes", [Array, Number]),
573
- tslib_1.__metadata("design:returntype", Promise)
574
- ], FileSystem.prototype, "uploadFiles", null);
575
546
  //# sourceMappingURL=FileSystem.js.map