computesdk 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1802,6 +1802,7 @@ var Run = class {
1802
1802
  constructor(handlers) {
1803
1803
  this.codeHandler = handlers.code;
1804
1804
  this.commandHandler = handlers.command;
1805
+ this.waitHandler = handlers.wait;
1805
1806
  }
1806
1807
  /**
1807
1808
  * Execute code with automatic language detection
@@ -1825,10 +1826,38 @@ var Run = class {
1825
1826
  * @param options.background - Run in background (optional)
1826
1827
  * @param options.cwd - Working directory for the command (optional)
1827
1828
  * @param options.env - Environment variables (optional)
1829
+ * @param options.waitForCompletion - If true (with background), wait for command to complete
1828
1830
  * @returns Command execution result with stdout, stderr, exit code, and duration
1829
1831
  */
1830
1832
  async command(command, options) {
1831
- return this.commandHandler(command, options);
1833
+ const result = await this.commandHandler(command, options);
1834
+ if (options?.background && options?.waitForCompletion && result.cmdId && result.terminalId) {
1835
+ if (!this.waitHandler) {
1836
+ throw new Error("Wait handler not configured");
1837
+ }
1838
+ const waitOptions = typeof options.waitForCompletion === "object" ? options.waitForCompletion : void 0;
1839
+ return this.waitHandler(result.terminalId, result.cmdId, waitOptions);
1840
+ }
1841
+ return result;
1842
+ }
1843
+ /**
1844
+ * Wait for a background command to complete
1845
+ *
1846
+ * Uses the configured wait handler to block until the command
1847
+ * is complete or fails (typically via server-side long-polling).
1848
+ * Throws an error if the command fails or times out.
1849
+ *
1850
+ * @param terminalId - Terminal ID from background command result
1851
+ * @param cmdId - Command ID from background command result
1852
+ * @param options - Wait options passed to the handler
1853
+ * @returns Command result with final status
1854
+ * @throws Error if command fails or times out
1855
+ */
1856
+ async waitForCompletion(terminalId, cmdId, options) {
1857
+ if (!this.waitHandler) {
1858
+ throw new Error("Wait handler not configured");
1859
+ }
1860
+ return this.waitHandler(terminalId, cmdId, options);
1832
1861
  }
1833
1862
  };
1834
1863
 
@@ -1893,11 +1922,17 @@ var Overlay = class {
1893
1922
  * @param options.source - Absolute path to source directory
1894
1923
  * @param options.target - Relative path in sandbox
1895
1924
  * @param options.ignore - Glob patterns to ignore (e.g., ["node_modules", "*.log"])
1925
+ * @param options.waitForCompletion - If true or options object, wait for background copy to complete
1896
1926
  * @returns Overlay info with copy status
1897
1927
  */
1898
1928
  async create(options) {
1899
1929
  const response = await this.createHandler(options);
1900
- return this.toOverlayInfo(response);
1930
+ const overlay = this.toOverlayInfo(response);
1931
+ if (options.waitForCompletion) {
1932
+ const waitOptions = typeof options.waitForCompletion === "object" ? options.waitForCompletion : void 0;
1933
+ return this.waitForCompletion(overlay.id, waitOptions);
1934
+ }
1935
+ return overlay;
1901
1936
  }
1902
1937
  /**
1903
1938
  * List all overlays for the current sandbox
@@ -1926,6 +1961,48 @@ var Overlay = class {
1926
1961
  async destroy(id) {
1927
1962
  return this.destroyHandler(id);
1928
1963
  }
1964
+ /**
1965
+ * Wait for an overlay's background copy to complete
1966
+ *
1967
+ * Polls the overlay status with exponential backoff until the copy
1968
+ * is complete or fails. Throws an error if the copy fails or times out.
1969
+ *
1970
+ * @param id - Overlay ID
1971
+ * @param options - Polling options
1972
+ * @returns Overlay info with final copy status
1973
+ * @throws Error if copy fails or times out
1974
+ */
1975
+ async waitForCompletion(id, options = {}) {
1976
+ const maxRetries = options.maxRetries ?? 60;
1977
+ const initialDelayMs = options.initialDelayMs ?? 500;
1978
+ const maxDelayMs = options.maxDelayMs ?? 5e3;
1979
+ const backoffFactor = options.backoffFactor ?? 1.5;
1980
+ let currentDelay = initialDelayMs;
1981
+ for (let i = 0; i < maxRetries; i++) {
1982
+ const overlay = await this.retrieve(id);
1983
+ if (overlay.copyStatus === "complete") {
1984
+ return overlay;
1985
+ }
1986
+ if (overlay.copyStatus === "failed") {
1987
+ throw new Error(
1988
+ `Overlay copy failed: ${overlay.copyError || "Unknown error"}
1989
+ Overlay ID: ${id}`
1990
+ );
1991
+ }
1992
+ if (i < maxRetries - 1) {
1993
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
1994
+ currentDelay = Math.min(currentDelay * backoffFactor, maxDelayMs);
1995
+ }
1996
+ }
1997
+ const finalOverlay = await this.retrieve(id);
1998
+ throw new Error(
1999
+ `Overlay copy timed out after ${maxRetries} attempts.
2000
+ Overlay ID: ${id}
2001
+ Current status: ${finalOverlay.copyStatus}
2002
+
2003
+ Try increasing maxRetries or check if the source directory is very large.`
2004
+ );
2005
+ }
1929
2006
  /**
1930
2007
  * Convert API response to OverlayInfo
1931
2008
  */
@@ -1969,6 +2046,7 @@ function isCommandExitError(error) {
1969
2046
  }
1970
2047
 
1971
2048
  // src/client/index.ts
2049
+ var MAX_TUNNEL_TIMEOUT_SECONDS = 300;
1972
2050
  var Sandbox = class {
1973
2051
  constructor(config) {
1974
2052
  this._token = null;
@@ -2087,8 +2165,15 @@ var Sandbox = class {
2087
2165
  stdout: result.data.stdout,
2088
2166
  stderr: result.data.stderr,
2089
2167
  exitCode: result.data.exit_code ?? 0,
2090
- durationMs: result.data.duration_ms ?? 0
2168
+ durationMs: result.data.duration_ms ?? 0,
2169
+ // Include cmdId and terminalId for background commands
2170
+ cmdId: result.data.cmd_id,
2171
+ terminalId: result.data.terminal_id,
2172
+ status: result.data.status
2091
2173
  };
2174
+ },
2175
+ wait: async (terminalId, cmdId, options) => {
2176
+ return this.waitForCommandCompletion(terminalId, cmdId, options);
2092
2177
  }
2093
2178
  });
2094
2179
  this.server = new Server({
@@ -2759,6 +2844,47 @@ API request failed (${response.status}): ${error}`
2759
2844
  const endpoint = `/terminals/${terminalId}/commands/${cmdId}/wait${params ? `?${params}` : ""}`;
2760
2845
  return this.request(endpoint);
2761
2846
  }
2847
+ /**
2848
+ * Wait for a background command to complete using long-polling
2849
+ *
2850
+ * Uses the server's long-polling endpoint with configurable timeout.
2851
+ * The tunnel supports up to 5 minutes (300 seconds) via X-Request-Timeout header.
2852
+ *
2853
+ * @param terminalId - The terminal ID
2854
+ * @param cmdId - The command ID
2855
+ * @param options - Wait options (timeoutSeconds, default 300)
2856
+ * @returns Command result with final status
2857
+ * @throws Error if command fails or times out
2858
+ * @internal
2859
+ */
2860
+ async waitForCommandCompletion(terminalId, cmdId, options) {
2861
+ const timeoutSeconds = options?.timeoutSeconds ?? MAX_TUNNEL_TIMEOUT_SECONDS;
2862
+ const response = await this.waitForCommandWithTimeout(terminalId, cmdId, timeoutSeconds);
2863
+ return {
2864
+ stdout: response.data.stdout,
2865
+ stderr: response.data.stderr,
2866
+ exitCode: response.data.exit_code ?? 0,
2867
+ durationMs: response.data.duration_ms ?? 0,
2868
+ cmdId: response.data.cmd_id,
2869
+ terminalId,
2870
+ status: response.data.status
2871
+ };
2872
+ }
2873
+ /**
2874
+ * Wait for a command with extended timeout support
2875
+ * Uses X-Request-Timeout header for tunnel timeout configuration
2876
+ * @internal
2877
+ */
2878
+ async waitForCommandWithTimeout(terminalId, cmdId, timeoutSeconds) {
2879
+ const params = new URLSearchParams({ timeout: timeoutSeconds.toString() });
2880
+ const endpoint = `/terminals/${terminalId}/commands/${cmdId}/wait?${params}`;
2881
+ const requestTimeout = Math.min(timeoutSeconds, MAX_TUNNEL_TIMEOUT_SECONDS);
2882
+ return this.request(endpoint, {
2883
+ headers: {
2884
+ "X-Request-Timeout": requestTimeout.toString()
2885
+ }
2886
+ });
2887
+ }
2762
2888
  // ============================================================================
2763
2889
  // File Watchers
2764
2890
  // ============================================================================
@@ -3733,7 +3859,8 @@ Get your API key at: https://computesdk.com/dashboard`
3733
3859
  apiKey: computesdkApiKey,
3734
3860
  gatewayUrl: config.gatewayUrl || GATEWAY_URL,
3735
3861
  provider: config.provider,
3736
- providerHeaders
3862
+ providerHeaders,
3863
+ WebSocket: config.WebSocket
3737
3864
  };
3738
3865
  }
3739
3866
 
@@ -3874,7 +4001,7 @@ var ComputeManager = class {
3874
4001
  ...name && { name },
3875
4002
  ...namespace && { namespace }
3876
4003
  },
3877
- WebSocket: globalThis.WebSocket,
4004
+ WebSocket: config.WebSocket || globalThis.WebSocket,
3878
4005
  destroyHandler: async () => {
3879
4006
  await gatewayFetch(`${config.gatewayUrl}/v1/sandboxes/${sandboxId}`, config, {
3880
4007
  method: "DELETE"
@@ -3900,7 +4027,7 @@ var ComputeManager = class {
3900
4027
  provider,
3901
4028
  token: token || config.apiKey,
3902
4029
  metadata,
3903
- WebSocket: globalThis.WebSocket,
4030
+ WebSocket: config.WebSocket || globalThis.WebSocket,
3904
4031
  destroyHandler: async () => {
3905
4032
  await gatewayFetch(`${config.gatewayUrl}/v1/sandboxes/${sandboxId}`, config, {
3906
4033
  method: "DELETE"
@@ -3956,7 +4083,7 @@ var ComputeManager = class {
3956
4083
  name: result.data.name,
3957
4084
  namespace: result.data.namespace
3958
4085
  },
3959
- WebSocket: globalThis.WebSocket,
4086
+ WebSocket: config.WebSocket || globalThis.WebSocket,
3960
4087
  destroyHandler: async () => {
3961
4088
  await gatewayFetch(`${config.gatewayUrl}/v1/sandboxes/${sandboxId}`, config, {
3962
4089
  method: "DELETE"
@@ -3993,7 +4120,7 @@ var ComputeManager = class {
3993
4120
  name,
3994
4121
  namespace
3995
4122
  },
3996
- WebSocket: globalThis.WebSocket,
4123
+ WebSocket: config.WebSocket || globalThis.WebSocket,
3997
4124
  destroyHandler: async () => {
3998
4125
  await gatewayFetch(`${config.gatewayUrl}/v1/sandboxes/${sandboxId}`, config, {
3999
4126
  method: "DELETE"