@hyperbrowser/sdk 0.92.7 → 1.0.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 (68) hide show
  1. package/README.md +190 -0
  2. package/dist/client.d.ts +4 -20
  3. package/dist/client.js +7 -17
  4. package/dist/error.d.ts +27 -0
  5. package/dist/error.js +32 -0
  6. package/dist/image-builds.d.ts +6 -0
  7. package/dist/image-builds.js +12 -0
  8. package/dist/index.d.ts +3 -0
  9. package/dist/index.js +12 -1
  10. package/dist/retry.d.ts +14 -0
  11. package/dist/retry.js +49 -0
  12. package/dist/sandbox/base.d.ts +27 -0
  13. package/dist/sandbox/base.js +298 -99
  14. package/dist/sandbox/files.d.ts +24 -25
  15. package/dist/sandbox/files.js +146 -37
  16. package/dist/sandbox/image-build/artifacts.d.ts +16 -0
  17. package/dist/sandbox/image-build/artifacts.js +16 -0
  18. package/dist/sandbox/image-build/blake2b.d.ts +2 -0
  19. package/dist/sandbox/image-build/blake2b.js +89 -0
  20. package/dist/sandbox/image-build/common.d.ts +19 -0
  21. package/dist/sandbox/image-build/common.js +109 -0
  22. package/dist/sandbox/image-build/context.d.ts +43 -0
  23. package/dist/sandbox/image-build/context.js +599 -0
  24. package/dist/sandbox/image-build/docker-image.d.ts +34 -0
  25. package/dist/sandbox/image-build/docker-image.js +472 -0
  26. package/dist/sandbox/image-build/dockerfile-analysis.d.ts +17 -0
  27. package/dist/sandbox/image-build/dockerfile-analysis.js +409 -0
  28. package/dist/sandbox/image-build/dockerignore.d.ts +18 -0
  29. package/dist/sandbox/image-build/dockerignore.js +275 -0
  30. package/dist/sandbox/image-build/gzip.d.ts +11 -0
  31. package/dist/sandbox/image-build/gzip.js +91 -0
  32. package/dist/sandbox/image-build/image-init.d.ts +5 -0
  33. package/dist/sandbox/image-build/image-init.js +97 -0
  34. package/dist/sandbox/image-build/index.d.ts +13 -0
  35. package/dist/sandbox/image-build/index.js +36 -0
  36. package/dist/sandbox/image-build/local-docker.d.ts +11 -0
  37. package/dist/sandbox/image-build/local-docker.js +72 -0
  38. package/dist/sandbox/image-build/resolution.d.ts +27 -0
  39. package/dist/sandbox/image-build/resolution.js +137 -0
  40. package/dist/sandbox/image-build/tar.d.ts +41 -0
  41. package/dist/sandbox/image-build/tar.js +378 -0
  42. package/dist/sandbox/image-build/upload.d.ts +10 -0
  43. package/dist/sandbox/image-build/upload.js +143 -0
  44. package/dist/sandbox/index.d.ts +2 -1
  45. package/dist/sandbox/index.js +4 -1
  46. package/dist/sandbox/process-output.d.ts +36 -0
  47. package/dist/sandbox/process-output.js +117 -0
  48. package/dist/sandbox/process.d.ts +25 -1
  49. package/dist/sandbox/process.js +197 -29
  50. package/dist/sandbox/terminal.js +9 -5
  51. package/dist/sandbox/ws.d.ts +4 -1
  52. package/dist/sandbox/ws.js +33 -7
  53. package/dist/services/agents/jev-computer-use.d.ts +30 -0
  54. package/dist/services/agents/jev-computer-use.js +103 -0
  55. package/dist/services/base.d.ts +2 -0
  56. package/dist/services/base.js +46 -30
  57. package/dist/services/normalize.d.ts +3 -0
  58. package/dist/services/normalize.js +21 -0
  59. package/dist/services/sandboxes.d.ts +40 -3
  60. package/dist/services/sandboxes.js +569 -53
  61. package/dist/services/volumes.js +29 -14
  62. package/dist/types/agents/jev-computer-use.d.ts +43 -0
  63. package/dist/types/agents/jev-computer-use.js +2 -0
  64. package/dist/types/constants.d.ts +5 -2
  65. package/dist/types/index.d.ts +4 -2
  66. package/dist/types/sandbox.d.ts +246 -30
  67. package/dist/types/volume.d.ts +7 -7
  68. package/package.json +24 -5
@@ -3,69 +3,184 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.RuntimeTransport = void 0;
6
+ exports.RuntimeTransport = exports.PROCESS_STREAM_IDLE_TIMEOUT_MS = void 0;
7
+ const stream_1 = require("stream");
8
+ const string_decoder_1 = require("string_decoder");
7
9
  const node_fetch_1 = __importDefault(require("node-fetch"));
8
- const client_1 = require("../client");
10
+ const error_1 = require("../error");
11
+ const retry_1 = require("../retry");
9
12
  const ws_1 = require("./ws");
10
- const RETRYABLE_STATUS_CODES = new Set([429, 502, 503, 504]);
11
- const RETRYABLE_NETWORK_CODES = new Set([
12
- "ECONNRESET",
13
- "ECONNREFUSED",
14
- "EAI_AGAIN",
15
- "ETIMEDOUT",
16
- "ESOCKETTIMEDOUT",
17
- ]);
13
+ // The receiver sends process SSE keepalives every 15 seconds.
14
+ exports.PROCESS_STREAM_IDLE_TIMEOUT_MS = 60000;
18
15
  const getRequestId = (response) => {
19
16
  return response.headers.get("x-request-id") || response.headers.get("request-id") || undefined;
20
17
  };
21
- const isRetryableNetworkError = (error) => {
22
- if (!(error instanceof Error)) {
23
- return false;
24
- }
25
- const networkError = error;
26
- return (networkError.name === "AbortError" ||
27
- networkError.type === "request-timeout" ||
28
- (networkError.code ? RETRYABLE_NETWORK_CODES.has(networkError.code) : false));
29
- };
18
+ const isEventStream = (response) => (response.headers.get("content-type") || "").includes("text/event-stream");
30
19
  class RuntimeTransport {
20
+ closeResponse(response) {
21
+ this.responseCleanup.get(response)?.();
22
+ }
23
+ failure(error, path, init, response) {
24
+ if (error instanceof error_1.HyperbrowserError) {
25
+ return new error_1.HyperbrowserError(error.message.replace(/^\[Hyperbrowser\]: /, ""), {
26
+ statusCode: error.statusCode ?? response?.status,
27
+ code: error.code,
28
+ requestId: error.requestId ?? (response ? getRequestId(response) : undefined),
29
+ service: error.service ?? "runtime",
30
+ retryable: error.retryable,
31
+ details: error.details,
32
+ cause: error.cause ?? error,
33
+ method: error.method ?? init?.method ?? "GET",
34
+ path: error.path ?? (0, error_1.errorRequestPath)(path),
35
+ });
36
+ }
37
+ const canceled = init?.signal?.aborted;
38
+ return new error_1.HyperbrowserError((0, error_1.networkErrorMessage)(error, "Runtime request failed"), {
39
+ code: canceled ? "request_aborted" : undefined,
40
+ statusCode: response?.status,
41
+ requestId: response ? getRequestId(response) : undefined,
42
+ service: "runtime",
43
+ retryable: !canceled && (0, retry_1.isRetryableNetworkError)(error),
44
+ method: init?.method ?? "GET",
45
+ path: (0, error_1.errorRequestPath)(path),
46
+ cause: error,
47
+ });
48
+ }
31
49
  constructor(resolveConnection, timeout = 30000, runtimeProxyOverride) {
32
50
  this.resolveConnection = resolveConnection;
33
51
  this.timeout = timeout;
34
52
  this.runtimeProxyOverride = runtimeProxyOverride;
53
+ this.responseCleanup = new WeakMap();
35
54
  }
36
55
  async requestJSON(path, init, params) {
37
56
  const response = await this.fetchWithAuth(path, init, params);
38
- if (response.headers.get("content-length") === "0") {
39
- return {};
40
- }
41
57
  try {
42
- return (await response.json());
43
- }
44
- catch {
45
- throw new client_1.HyperbrowserError("Failed to parse JSON response", {
46
- statusCode: response.status,
47
- requestId: getRequestId(response),
48
- retryable: false,
49
- service: "runtime",
50
- });
58
+ const text = await response.text();
59
+ if (!text)
60
+ return {};
61
+ try {
62
+ return JSON.parse(text);
63
+ }
64
+ catch (cause) {
65
+ throw new error_1.HyperbrowserError("Failed to parse JSON response", {
66
+ statusCode: response.status,
67
+ requestId: getRequestId(response),
68
+ service: "runtime",
69
+ cause,
70
+ method: init?.method ?? "GET",
71
+ path: (0, error_1.errorRequestPath)(path),
72
+ });
73
+ }
74
+ }
75
+ catch (error) {
76
+ throw this.failure(error, path, init, response);
77
+ }
78
+ finally {
79
+ this.closeResponse(response);
51
80
  }
52
81
  }
53
82
  async requestBuffer(path, init, params) {
54
83
  const response = await this.fetchWithAuth(path, init, params);
55
- return response.buffer();
84
+ try {
85
+ return await response.buffer();
86
+ }
87
+ catch (error) {
88
+ throw this.failure(error, path, init, response);
89
+ }
90
+ finally {
91
+ this.closeResponse(response);
92
+ }
93
+ }
94
+ /** Pull-based binary transfer. Breaking iteration closes the HTTP connection. */
95
+ async *streamBytes(path, init, params) {
96
+ const response = await this.fetchWithAuth(path, init, params, true, true);
97
+ try {
98
+ if (!response.body)
99
+ return;
100
+ const iterator = response.body[Symbol.asyncIterator]();
101
+ for (;;) {
102
+ const next = await this.readChunk(iterator, this.timeout);
103
+ if (next.done)
104
+ return;
105
+ yield Buffer.from(next.value);
106
+ }
107
+ }
108
+ catch (error) {
109
+ throw this.failure(error, path, init, response);
110
+ }
111
+ finally {
112
+ this.closeResponse(response);
113
+ }
114
+ }
115
+ readChunk(iterator, timeout) {
116
+ return new Promise((resolve, reject) => {
117
+ const timer = setTimeout(() => reject(new error_1.HyperbrowserError(`Runtime stream idle for ${timeout}ms without data or keepalives`, { code: "stream_idle_timeout", service: "runtime", retryable: true })), timeout);
118
+ iterator.next().then((value) => {
119
+ clearTimeout(timer);
120
+ resolve(value);
121
+ }, (error) => {
122
+ clearTimeout(timer);
123
+ reject(error);
124
+ });
125
+ });
56
126
  }
57
127
  async *streamSSE(path, params) {
58
- const response = await this.fetchWithAuth(path, {
59
- method: "GET",
60
- headers: {
61
- Accept: "text/event-stream",
62
- },
63
- }, params);
128
+ const stream = await this.openSSE(path, params);
129
+ try {
130
+ yield* stream.events;
131
+ }
132
+ finally {
133
+ stream.close();
134
+ }
135
+ }
136
+ /**
137
+ * Open a server-sent event stream. POST streams carry a JSON body and
138
+ * require an event-stream response, since the request may have side effects
139
+ * that must not be retried blindly.
140
+ */
141
+ async openSSE(path, params, init = {}) {
142
+ const method = init.method ?? "GET";
143
+ const headers = {
144
+ Accept: "text/event-stream",
145
+ ...(init.body !== undefined ? { "content-type": "application/json" } : {}),
146
+ ...(init.headers ?? {}),
147
+ };
148
+ const response = await this.fetchWithAuth(path, { method, headers, body: init.body, signal: init.signal }, params, true, true);
149
+ if (method === "POST" && !isEventStream(response)) {
150
+ this.closeResponse(response);
151
+ throw new error_1.HyperbrowserError("Receiver does not support streaming command start; update the receiver. " +
152
+ "The command may have started; do not retry it automatically.", { code: "streaming_not_supported", service: "runtime", retryable: false,
153
+ method, path: (0, error_1.errorRequestPath)(path), requestId: getRequestId(response), statusCode: response.status });
154
+ }
64
155
  const body = response.body;
156
+ const idleTimeoutMs = init.idleTimeoutMs ?? exports.PROCESS_STREAM_IDLE_TIMEOUT_MS;
157
+ let closed = false;
158
+ const close = () => {
159
+ if (closed) {
160
+ return;
161
+ }
162
+ closed = true;
163
+ this.closeResponse(response);
164
+ };
165
+ const parsed = this.parseSSE(body, idleTimeoutMs, () => closed, close, init.signal);
166
+ const failure = (error) => this.failure(error, path, { method, signal: init.signal }, response);
167
+ const events = (async function* () {
168
+ try {
169
+ yield* parsed;
170
+ }
171
+ catch (error) {
172
+ throw failure(error);
173
+ }
174
+ })();
175
+ return { events, close };
176
+ }
177
+ async *parseSSE(body, idleTimeoutMs, isClosed, close, signal) {
65
178
  if (!body) {
66
179
  return;
67
180
  }
68
181
  let buffer = "";
182
+ let skipLineFeed = false;
183
+ const decoder = new string_decoder_1.StringDecoder("utf8");
69
184
  let eventName = "message";
70
185
  let eventId;
71
186
  let dataLines = [];
@@ -93,88 +208,165 @@ class RuntimeTransport {
93
208
  dataLines = [];
94
209
  return event;
95
210
  };
96
- for await (const chunk of body) {
97
- buffer += Buffer.from(chunk).toString("utf8");
98
- while (true) {
99
- const newlineIndex = buffer.indexOf("\n");
100
- if (newlineIndex === -1) {
211
+ const readLine = (line) => {
212
+ if (line === "")
213
+ return flushEvent();
214
+ if (line.startsWith(":"))
215
+ return null;
216
+ const separator = line.indexOf(":");
217
+ const field = separator === -1 ? line : line.slice(0, separator);
218
+ // Match the Python transport's field-value space normalization.
219
+ const value = separator === -1 ? "" : line.slice(separator + 1).replace(/^ +/, "");
220
+ switch (field) {
221
+ case "event":
222
+ eventName = value || "message";
101
223
  break;
224
+ case "data":
225
+ dataLines.push(value);
226
+ break;
227
+ case "id":
228
+ eventId = value;
229
+ break;
230
+ }
231
+ return null;
232
+ };
233
+ const iterator = body[Symbol.asyncIterator]();
234
+ try {
235
+ for (;;) {
236
+ let next;
237
+ try {
238
+ next = await this.readChunk(iterator, idleTimeoutMs);
102
239
  }
103
- let line = buffer.slice(0, newlineIndex);
104
- buffer = buffer.slice(newlineIndex + 1);
105
- if (line.endsWith("\r")) {
106
- line = line.slice(0, -1);
107
- }
108
- if (line === "") {
109
- const event = flushEvent();
110
- if (event) {
111
- yield event;
240
+ catch (error) {
241
+ if (signal?.aborted)
242
+ throw new error_1.HyperbrowserError("Command collection canceled", {
243
+ code: "request_aborted",
244
+ service: "runtime",
245
+ cause: error,
246
+ });
247
+ if (isClosed()) {
248
+ return;
112
249
  }
113
- continue;
250
+ if (error instanceof error_1.HyperbrowserError) {
251
+ throw error;
252
+ }
253
+ throw new error_1.HyperbrowserError(error instanceof Error ? error.message : "Runtime stream failed", { service: "runtime", retryable: (0, retry_1.isRetryableNetworkError)(error), cause: error });
114
254
  }
115
- if (line.startsWith(":")) {
116
- continue;
255
+ if (next.done) {
256
+ break;
117
257
  }
118
- const separator = line.indexOf(":");
119
- const field = separator === -1 ? line : line.slice(0, separator);
120
- const value = separator === -1 ? "" : line.slice(separator + 1).replace(/^ /, "");
121
- switch (field) {
122
- case "event":
123
- eventName = value || "message";
124
- break;
125
- case "data":
126
- dataLines.push(value);
127
- break;
128
- case "id":
129
- eventId = value;
130
- break;
131
- default:
258
+ buffer += decoder.write(Buffer.from(next.value));
259
+ while (true) {
260
+ if (skipLineFeed) {
261
+ if (!buffer)
262
+ break;
263
+ if (buffer.startsWith("\n"))
264
+ buffer = buffer.slice(1);
265
+ skipLineFeed = false;
266
+ }
267
+ const newlineIndex = buffer.search(/[\r\n]/);
268
+ if (newlineIndex === -1) {
132
269
  break;
270
+ }
271
+ const line = buffer.slice(0, newlineIndex);
272
+ // Deliver bare CR immediately; absorb a following LF even across chunks.
273
+ skipLineFeed = buffer[newlineIndex] === "\r";
274
+ buffer = buffer.slice(newlineIndex + 1);
275
+ const event = readLine(line);
276
+ if (event)
277
+ yield event;
133
278
  }
134
279
  }
280
+ buffer += decoder.end();
281
+ if (buffer)
282
+ readLine(buffer);
283
+ const trailing = flushEvent();
284
+ if (trailing) {
285
+ yield trailing;
286
+ }
135
287
  }
136
- const trailing = flushEvent();
137
- if (trailing) {
138
- yield trailing;
288
+ finally {
289
+ close();
139
290
  }
140
291
  }
141
- async fetchWithAuth(path, init, params, allowRefresh = true) {
292
+ async fetchWithAuth(path, init, params, allowRefresh = true, streaming = false) {
142
293
  const connection = await this.resolveConnection(false);
143
- const response = await this.fetchForConnection(connection, path, init, params);
294
+ const response = await this.fetchForConnection(connection, path, init, params, streaming);
144
295
  if (response.status === 401 && allowRefresh) {
296
+ this.closeResponse(response);
297
+ if (init?.body instanceof stream_1.Readable) {
298
+ throw new error_1.HyperbrowserError("Runtime authentication expired during a streaming upload; obtain a new stream before retrying", {
299
+ statusCode: 401,
300
+ code: "stream_not_replayable",
301
+ service: "runtime",
302
+ retryable: false,
303
+ method: init?.method ?? "GET",
304
+ path: (0, error_1.errorRequestPath)(path),
305
+ requestId: getRequestId(response),
306
+ });
307
+ }
145
308
  const refreshed = await this.resolveConnection(true);
146
- const retryResponse = await this.fetchForConnection(refreshed, path, init, params);
147
- return this.assertResponse(retryResponse);
309
+ const retryResponse = await this.fetchForConnection(refreshed, path, init, params, streaming);
310
+ return this.assertResponse(retryResponse, path, init);
148
311
  }
149
- return this.assertResponse(response);
312
+ return this.assertResponse(response, path, init);
150
313
  }
151
- async fetchForConnection(connection, path, init, params) {
314
+ async fetchForConnection(connection, path, init, params, streaming = false) {
152
315
  const target = (0, ws_1.resolveRuntimeTransportTarget)(connection.baseUrl, this.buildRequestPath(path, params), this.runtimeProxyOverride);
153
316
  const headers = this.buildHeaders(connection, init?.headers, target.hostHeader);
154
317
  const controller = new AbortController();
155
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
318
+ let timer = setTimeout(() => controller.abort(), this.timeout);
319
+ const upload = init?.body instanceof stream_1.Readable ? init.body : undefined;
320
+ const uploadProgress = () => {
321
+ clearTimeout(timer);
322
+ timer = setTimeout(() => controller.abort(), this.timeout);
323
+ };
324
+ upload?.on("data", uploadProgress);
325
+ const callerSignal = init?.signal;
326
+ const abortFromCaller = () => controller.abort();
327
+ if (callerSignal?.aborted)
328
+ controller.abort();
329
+ else
330
+ callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
331
+ const detach = () => {
332
+ clearTimeout(timer);
333
+ timer = undefined;
334
+ callerSignal?.removeEventListener("abort", abortFromCaller);
335
+ upload?.removeListener("data", uploadProgress);
336
+ };
156
337
  try {
157
- return await (0, node_fetch_1.default)(target.url, {
158
- ...init,
159
- headers,
160
- signal: controller.signal,
161
- });
162
- }
163
- catch (error) {
164
- if (error instanceof client_1.HyperbrowserError) {
165
- throw error;
338
+ const response = await (0, node_fetch_1.default)(target.url, { ...init, headers, signal: controller.signal });
339
+ clearTimeout(timer);
340
+ upload?.removeListener("data", uploadProgress);
341
+ // Header and body budgets are separate. Streams use a read-idle budget.
342
+ timer =
343
+ streaming && response.ok ? undefined : setTimeout(() => controller.abort(), this.timeout);
344
+ const body = response.body;
345
+ let disposed = false;
346
+ const close = () => {
347
+ if (disposed)
348
+ return;
349
+ disposed = true;
350
+ detach();
351
+ if (!body?.readableEnded)
352
+ controller.abort();
353
+ body?.destroy();
354
+ };
355
+ this.responseCleanup.set(response, close);
356
+ if (body) {
357
+ body.once("end", detach);
358
+ body.once("close", close);
166
359
  }
167
- throw new client_1.HyperbrowserError(error instanceof Error ? error.message : "Unknown runtime request error", {
168
- retryable: isRetryableNetworkError(error),
169
- service: "runtime",
170
- cause: error,
171
- });
360
+ else
361
+ close();
362
+ return response;
172
363
  }
173
- finally {
174
- clearTimeout(timeoutId);
364
+ catch (error) {
365
+ detach();
366
+ throw this.failure(error, path, init);
175
367
  }
176
368
  }
177
- async assertResponse(response) {
369
+ async assertResponse(response, path, init) {
178
370
  if (response.ok) {
179
371
  return response;
180
372
  }
@@ -196,16 +388,23 @@ class RuntimeTransport {
196
388
  }
197
389
  }
198
390
  }
199
- catch {
391
+ catch (error) {
392
+ if (init?.signal?.aborted)
393
+ throw this.failure(error, path, init, response);
200
394
  // Keep the fallback message.
201
395
  }
202
- throw new client_1.HyperbrowserError(message, {
396
+ finally {
397
+ this.closeResponse(response);
398
+ }
399
+ throw new error_1.HyperbrowserError(message, {
203
400
  statusCode: response.status,
204
401
  code,
205
402
  requestId: getRequestId(response),
206
- retryable: RETRYABLE_STATUS_CODES.has(response.status),
403
+ retryable: retry_1.RETRYABLE_STATUS_CODES.has(response.status),
207
404
  service: "runtime",
208
405
  details,
406
+ method: init?.method ?? "GET",
407
+ path: (0, error_1.errorRequestPath)(path),
209
408
  });
210
409
  }
211
410
  buildHeaders(connection, rawHeaders, hostHeader) {
@@ -1,40 +1,26 @@
1
1
  import { Blob, Buffer } from "buffer";
2
2
  import { ReadableStream } from "node:stream/web";
3
3
  import { RuntimeTransport } from "./base";
4
- import { SandboxFileChmodParams, SandboxFileChownParams, SandboxFileCopyParams, SandboxFileInfo, SandboxFileListOptions, SandboxFileMakeDirOptions, SandboxFileReadOptions, SandboxFileSystemEvent, SandboxFileTransferResult, SandboxFileWriteData, SandboxFileWriteEntry, SandboxFileWriteInfo, SandboxFileBytesWriteOptions, SandboxFileTextWriteOptions, SandboxPresignFileParams, SandboxPresignedUrl, SandboxWatchDirOptions } from "../types/sandbox";
5
- interface RawFileWatchEvent {
6
- seq: number;
7
- path: string;
8
- op: string;
9
- timestamp: number;
10
- }
11
- interface RawFileWatchStatus {
12
- id: string;
13
- path: string;
14
- recursive: boolean;
15
- active: boolean;
16
- error?: string;
17
- createdAt: number;
18
- stoppedAt?: number;
19
- oldestSeq?: number;
20
- lastSeq?: number;
21
- eventCount?: number;
22
- }
4
+ import { SandboxFileUploadStream, SandboxFileUploadStreamOptions, SandboxFileDownloadStreamOptions, SandboxFileMoveParams, SandboxFileRenameOptions, SandboxFileWatchParams, SandboxFileWatchStatus, SandboxFileWatchEventsParams, SandboxFileWatchStreamEvent, SandboxFileChmodParams, SandboxFileChownParams, SandboxFileCopyParams, SandboxFileInfo, SandboxFileListOptions, SandboxFileMakeDirOptions, SandboxFileReadOptions, SandboxFileSystemEvent, SandboxFileTransferResult, SandboxFileWriteData, SandboxFileWriteEntry, SandboxFileWriteInfo, SandboxFileBytesWriteOptions, SandboxFileTextWriteOptions, SandboxPresignFileParams, SandboxPresignedUrl, SandboxWatchDirOptions } from "../types/sandbox";
23
5
  interface RuntimeConnectionInfo {
24
6
  sandboxId: string;
25
7
  baseUrl: string;
26
8
  token: string;
27
9
  }
28
- declare class RuntimeFileWatchHandle {
10
+ export declare class SandboxFileWatchHandle {
29
11
  private readonly transport;
30
12
  private readonly getConnectionInfo;
31
- private readonly status;
13
+ private status;
32
14
  private readonly runtimeProxyOverride?;
33
- constructor(transport: RuntimeTransport, getConnectionInfo: () => Promise<RuntimeConnectionInfo>, status: RawFileWatchStatus, runtimeProxyOverride?: string | undefined);
15
+ private readonly connections;
16
+ constructor(transport: RuntimeTransport, getConnectionInfo: () => Promise<RuntimeConnectionInfo>, status: SandboxFileWatchStatus, runtimeProxyOverride?: string | undefined);
34
17
  get id(): string;
35
18
  get path(): string;
19
+ get current(): SandboxFileWatchStatus;
20
+ toJSON(): SandboxFileWatchStatus;
21
+ refresh(includeEvents?: boolean): Promise<this>;
36
22
  stop(): Promise<void>;
37
- events(cursor?: number): AsyncGenerator<RawFileWatchEvent>;
23
+ events(options?: SandboxFileWatchEventsParams): AsyncGenerator<SandboxFileWatchStreamEvent>;
38
24
  }
39
25
  export declare class SandboxWatchDirHandle {
40
26
  private readonly watch;
@@ -43,7 +29,8 @@ export declare class SandboxWatchDirHandle {
43
29
  private timeout?;
44
30
  private stopRequested;
45
31
  private exitNotified;
46
- constructor(watch: RuntimeFileWatchHandle, onEvent: (event: SandboxFileSystemEvent) => void | Promise<void>, onExit?: ((error?: Error) => void | Promise<void>) | undefined, timeoutMs?: number);
32
+ private invokingCallback;
33
+ constructor(watch: SandboxFileWatchHandle, onEvent: (event: SandboxFileSystemEvent) => void | Promise<void>, onExit?: ((error?: Error) => void | Promise<void>) | undefined, timeoutMs?: number);
47
34
  stop(): Promise<void>;
48
35
  private run;
49
36
  }
@@ -78,7 +65,7 @@ export declare class SandboxFilesApi {
78
65
  upload(path: string, data: Buffer | Uint8Array | string): Promise<SandboxFileTransferResult>;
79
66
  download(path: string): Promise<Buffer>;
80
67
  makeDir(path: string, options?: SandboxFileMakeDirOptions): Promise<boolean>;
81
- rename(oldPath: string, newPath: string): Promise<SandboxFileInfo>;
68
+ rename(oldPath: string, newPath: string, options?: SandboxFileRenameOptions): Promise<SandboxFileInfo>;
82
69
  remove(path: string, options?: {
83
70
  recursive?: boolean;
84
71
  }): Promise<void>;
@@ -86,6 +73,18 @@ export declare class SandboxFilesApi {
86
73
  chmod(params: SandboxFileChmodParams): Promise<void>;
87
74
  chown(params: SandboxFileChownParams): Promise<void>;
88
75
  watchDir(path: string, onEvent: (event: SandboxFileSystemEvent) => void | Promise<void>, options?: SandboxWatchDirOptions): Promise<SandboxWatchDirHandle>;
76
+ watch(path: string, options?: SandboxFileWatchParams): Promise<SandboxFileWatchHandle>;
77
+ getWatch(id: string, includeEvents?: boolean): Promise<SandboxFileWatchHandle>;
78
+ stat(path: string): Promise<SandboxFileInfo>;
79
+ mkdir(path: string, options?: SandboxFileMakeDirOptions): Promise<boolean>;
80
+ move(params: SandboxFileMoveParams): Promise<SandboxFileInfo>;
81
+ delete(path: string, options?: {
82
+ recursive?: boolean;
83
+ }): Promise<void>;
84
+ /** Upload without buffering; the source is closed on completion, rejection or cancellation. */
85
+ uploadStream(path: string, source: SandboxFileUploadStream, options?: SandboxFileUploadStreamOptions): Promise<SandboxFileTransferResult>;
86
+ /** Pull-based download; consume with for-await or Readable.from(). */
87
+ downloadStream(path: string, options?: SandboxFileDownloadStreamOptions): AsyncGenerator<Buffer>;
89
88
  uploadUrl(path: string, options?: Omit<SandboxPresignFileParams, "path">): Promise<SandboxPresignedUrl>;
90
89
  downloadUrl(path: string, options?: Omit<SandboxPresignFileParams, "path">): Promise<SandboxPresignedUrl>;
91
90
  private readWire;