computesdk 1.13.0 → 1.16.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.js CHANGED
@@ -1388,10 +1388,15 @@ var Server = class {
1388
1388
  this.stopHandler = handlers.stop;
1389
1389
  this.restartHandler = handlers.restart;
1390
1390
  this.updateStatusHandler = handlers.updateStatus;
1391
+ this.logsHandler = handlers.logs;
1391
1392
  }
1392
1393
  /**
1393
1394
  * Start a new managed server with optional supervisor settings
1394
1395
  *
1396
+ * **Install Phase:**
1397
+ * If `install` is provided, it runs blocking before `start` (e.g., "npm install").
1398
+ * The server status will be `installing` during this phase.
1399
+ *
1395
1400
  * **Restart Policies:**
1396
1401
  * - `never` (default): No automatic restart on exit
1397
1402
  * - `on-failure`: Restart only on non-zero exit code
@@ -1409,14 +1414,15 @@ var Server = class {
1409
1414
  * // Basic server
1410
1415
  * const server = await sandbox.server.start({
1411
1416
  * slug: 'web',
1412
- * command: 'npm run dev',
1417
+ * start: 'npm run dev',
1413
1418
  * path: '/app',
1414
1419
  * });
1415
1420
  *
1416
- * // With supervisor settings
1421
+ * // With install command
1417
1422
  * const server = await sandbox.server.start({
1418
1423
  * slug: 'api',
1419
- * command: 'node server.js',
1424
+ * install: 'npm install',
1425
+ * start: 'node server.js',
1420
1426
  * environment: { NODE_ENV: 'production' },
1421
1427
  * restart_policy: 'always',
1422
1428
  * max_restarts: 0, // unlimited
@@ -1468,6 +1474,29 @@ var Server = class {
1468
1474
  async updateStatus(slug, status) {
1469
1475
  await this.updateStatusHandler(slug, status);
1470
1476
  }
1477
+ /**
1478
+ * Retrieve captured output (logs) for a managed server
1479
+ * @param slug - The server slug
1480
+ * @param options - Options for log retrieval
1481
+ * @returns Server logs info
1482
+ *
1483
+ * @example
1484
+ * ```typescript
1485
+ * // Get combined logs (default)
1486
+ * const logs = await sandbox.server.logs('api');
1487
+ * console.log(logs.logs);
1488
+ *
1489
+ * // Get only stdout
1490
+ * const stdout = await sandbox.server.logs('api', { stream: 'stdout' });
1491
+ *
1492
+ * // Get only stderr
1493
+ * const stderr = await sandbox.server.logs('api', { stream: 'stderr' });
1494
+ * ```
1495
+ */
1496
+ async logs(slug, options) {
1497
+ const response = await this.logsHandler(slug, options);
1498
+ return response.data;
1499
+ }
1471
1500
  };
1472
1501
 
1473
1502
  // src/client/resources/watcher.ts
@@ -1826,6 +1855,7 @@ var Run = class {
1826
1855
  constructor(handlers) {
1827
1856
  this.codeHandler = handlers.code;
1828
1857
  this.commandHandler = handlers.command;
1858
+ this.waitHandler = handlers.wait;
1829
1859
  }
1830
1860
  /**
1831
1861
  * Execute code with automatic language detection
@@ -1849,10 +1879,38 @@ var Run = class {
1849
1879
  * @param options.background - Run in background (optional)
1850
1880
  * @param options.cwd - Working directory for the command (optional)
1851
1881
  * @param options.env - Environment variables (optional)
1882
+ * @param options.waitForCompletion - If true (with background), wait for command to complete
1852
1883
  * @returns Command execution result with stdout, stderr, exit code, and duration
1853
1884
  */
1854
1885
  async command(command, options) {
1855
- return this.commandHandler(command, options);
1886
+ const result = await this.commandHandler(command, options);
1887
+ if (options?.background && options?.waitForCompletion && result.cmdId && result.terminalId) {
1888
+ if (!this.waitHandler) {
1889
+ throw new Error("Wait handler not configured");
1890
+ }
1891
+ const waitOptions = typeof options.waitForCompletion === "object" ? options.waitForCompletion : void 0;
1892
+ return this.waitHandler(result.terminalId, result.cmdId, waitOptions);
1893
+ }
1894
+ return result;
1895
+ }
1896
+ /**
1897
+ * Wait for a background command to complete
1898
+ *
1899
+ * Uses the configured wait handler to block until the command
1900
+ * is complete or fails (typically via server-side long-polling).
1901
+ * Throws an error if the command fails or times out.
1902
+ *
1903
+ * @param terminalId - Terminal ID from background command result
1904
+ * @param cmdId - Command ID from background command result
1905
+ * @param options - Wait options passed to the handler
1906
+ * @returns Command result with final status
1907
+ * @throws Error if command fails or times out
1908
+ */
1909
+ async waitForCompletion(terminalId, cmdId, options) {
1910
+ if (!this.waitHandler) {
1911
+ throw new Error("Wait handler not configured");
1912
+ }
1913
+ return this.waitHandler(terminalId, cmdId, options);
1856
1914
  }
1857
1915
  };
1858
1916
 
@@ -1909,18 +1967,25 @@ var Overlay = class {
1909
1967
  /**
1910
1968
  * Create a new overlay from a template directory
1911
1969
  *
1912
- * The overlay symlinks files from the source directory into the target path,
1913
- * allowing instant access to template files. Heavy directories (node_modules,
1914
- * .venv, etc.) are copied in the background.
1970
+ * The overlay copies files from the source directory into the target path
1971
+ * for better isolation. Heavy directories (node_modules, .venv, etc.) are
1972
+ * copied in the background. Use the `ignore` option to exclude files/directories.
1915
1973
  *
1916
1974
  * @param options - Overlay creation options
1917
1975
  * @param options.source - Absolute path to source directory
1918
1976
  * @param options.target - Relative path in sandbox
1977
+ * @param options.ignore - Glob patterns to ignore (e.g., ["node_modules", "*.log"])
1978
+ * @param options.waitForCompletion - If true or options object, wait for background copy to complete
1919
1979
  * @returns Overlay info with copy status
1920
1980
  */
1921
1981
  async create(options) {
1922
1982
  const response = await this.createHandler(options);
1923
- return this.toOverlayInfo(response);
1983
+ const overlay = this.toOverlayInfo(response);
1984
+ if (options.waitForCompletion) {
1985
+ const waitOptions = typeof options.waitForCompletion === "object" ? options.waitForCompletion : void 0;
1986
+ return this.waitForCompletion(overlay.id, waitOptions);
1987
+ }
1988
+ return overlay;
1924
1989
  }
1925
1990
  /**
1926
1991
  * List all overlays for the current sandbox
@@ -1949,6 +2014,48 @@ var Overlay = class {
1949
2014
  async destroy(id) {
1950
2015
  return this.destroyHandler(id);
1951
2016
  }
2017
+ /**
2018
+ * Wait for an overlay's background copy to complete
2019
+ *
2020
+ * Polls the overlay status with exponential backoff until the copy
2021
+ * is complete or fails. Throws an error if the copy fails or times out.
2022
+ *
2023
+ * @param id - Overlay ID
2024
+ * @param options - Polling options
2025
+ * @returns Overlay info with final copy status
2026
+ * @throws Error if copy fails or times out
2027
+ */
2028
+ async waitForCompletion(id, options = {}) {
2029
+ const maxRetries = options.maxRetries ?? 60;
2030
+ const initialDelayMs = options.initialDelayMs ?? 500;
2031
+ const maxDelayMs = options.maxDelayMs ?? 5e3;
2032
+ const backoffFactor = options.backoffFactor ?? 1.5;
2033
+ let currentDelay = initialDelayMs;
2034
+ for (let i = 0; i < maxRetries; i++) {
2035
+ const overlay = await this.retrieve(id);
2036
+ if (overlay.copyStatus === "complete") {
2037
+ return overlay;
2038
+ }
2039
+ if (overlay.copyStatus === "failed") {
2040
+ throw new Error(
2041
+ `Overlay copy failed: ${overlay.copyError || "Unknown error"}
2042
+ Overlay ID: ${id}`
2043
+ );
2044
+ }
2045
+ if (i < maxRetries - 1) {
2046
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
2047
+ currentDelay = Math.min(currentDelay * backoffFactor, maxDelayMs);
2048
+ }
2049
+ }
2050
+ const finalOverlay = await this.retrieve(id);
2051
+ throw new Error(
2052
+ `Overlay copy timed out after ${maxRetries} attempts.
2053
+ Overlay ID: ${id}
2054
+ Current status: ${finalOverlay.copyStatus}
2055
+
2056
+ Try increasing maxRetries or check if the source directory is very large.`
2057
+ );
2058
+ }
1952
2059
  /**
1953
2060
  * Convert API response to OverlayInfo
1954
2061
  */
@@ -1959,8 +2066,8 @@ var Overlay = class {
1959
2066
  target: response.target,
1960
2067
  createdAt: response.created_at,
1961
2068
  stats: {
1962
- symlinkedFiles: response.stats.symlinked_files,
1963
- symlinkedDirs: response.stats.symlinked_dirs,
2069
+ copiedFiles: response.stats.copied_files,
2070
+ copiedDirs: response.stats.copied_dirs,
1964
2071
  skipped: response.stats.skipped
1965
2072
  },
1966
2073
  copyStatus: this.validateCopyStatus(response.copy_status),
@@ -1992,6 +2099,7 @@ function isCommandExitError(error) {
1992
2099
  }
1993
2100
 
1994
2101
  // src/client/index.ts
2102
+ var MAX_TUNNEL_TIMEOUT_SECONDS = 300;
1995
2103
  var Sandbox = class {
1996
2104
  constructor(config) {
1997
2105
  this._token = null;
@@ -2110,8 +2218,15 @@ var Sandbox = class {
2110
2218
  stdout: result.data.stdout,
2111
2219
  stderr: result.data.stderr,
2112
2220
  exitCode: result.data.exit_code ?? 0,
2113
- durationMs: result.data.duration_ms ?? 0
2221
+ durationMs: result.data.duration_ms ?? 0,
2222
+ // Include cmdId and terminalId for background commands
2223
+ cmdId: result.data.cmd_id,
2224
+ terminalId: result.data.terminal_id,
2225
+ status: result.data.status
2114
2226
  };
2227
+ },
2228
+ wait: async (terminalId, cmdId, options) => {
2229
+ return this.waitForCommandCompletion(terminalId, cmdId, options);
2115
2230
  }
2116
2231
  });
2117
2232
  this.server = new Server({
@@ -2124,7 +2239,8 @@ var Sandbox = class {
2124
2239
  restart: async (slug) => this.restartServer(slug),
2125
2240
  updateStatus: async (slug, status) => {
2126
2241
  await this.updateServerStatus(slug, status);
2127
- }
2242
+ },
2243
+ logs: async (slug, options) => this.getServerLogs(slug, options)
2128
2244
  });
2129
2245
  this.watcher = new Watcher({
2130
2246
  create: async (path, options) => this.createWatcher(path, options),
@@ -2781,6 +2897,47 @@ API request failed (${response.status}): ${error}`
2781
2897
  const endpoint = `/terminals/${terminalId}/commands/${cmdId}/wait${params ? `?${params}` : ""}`;
2782
2898
  return this.request(endpoint);
2783
2899
  }
2900
+ /**
2901
+ * Wait for a background command to complete using long-polling
2902
+ *
2903
+ * Uses the server's long-polling endpoint with configurable timeout.
2904
+ * The tunnel supports up to 5 minutes (300 seconds) via X-Request-Timeout header.
2905
+ *
2906
+ * @param terminalId - The terminal ID
2907
+ * @param cmdId - The command ID
2908
+ * @param options - Wait options (timeoutSeconds, default 300)
2909
+ * @returns Command result with final status
2910
+ * @throws Error if command fails or times out
2911
+ * @internal
2912
+ */
2913
+ async waitForCommandCompletion(terminalId, cmdId, options) {
2914
+ const timeoutSeconds = options?.timeoutSeconds ?? MAX_TUNNEL_TIMEOUT_SECONDS;
2915
+ const response = await this.waitForCommandWithTimeout(terminalId, cmdId, timeoutSeconds);
2916
+ return {
2917
+ stdout: response.data.stdout,
2918
+ stderr: response.data.stderr,
2919
+ exitCode: response.data.exit_code ?? 0,
2920
+ durationMs: response.data.duration_ms ?? 0,
2921
+ cmdId: response.data.cmd_id,
2922
+ terminalId,
2923
+ status: response.data.status
2924
+ };
2925
+ }
2926
+ /**
2927
+ * Wait for a command with extended timeout support
2928
+ * Uses X-Request-Timeout header for tunnel timeout configuration
2929
+ * @internal
2930
+ */
2931
+ async waitForCommandWithTimeout(terminalId, cmdId, timeoutSeconds) {
2932
+ const params = new URLSearchParams({ timeout: timeoutSeconds.toString() });
2933
+ const endpoint = `/terminals/${terminalId}/commands/${cmdId}/wait?${params}`;
2934
+ const requestTimeout = Math.min(timeoutSeconds, MAX_TUNNEL_TIMEOUT_SECONDS);
2935
+ return this.request(endpoint, {
2936
+ headers: {
2937
+ "X-Request-Timeout": requestTimeout.toString()
2938
+ }
2939
+ });
2940
+ }
2784
2941
  // ============================================================================
2785
2942
  // File Watchers
2786
2943
  // ============================================================================
@@ -2969,7 +3126,8 @@ API request failed (${response.status}): ${error}`
2969
3126
  *
2970
3127
  * @param options - Server configuration
2971
3128
  * @param options.slug - Unique server identifier
2972
- * @param options.command - Command to start the server
3129
+ * @param options.install - Install command (optional, runs blocking before start, e.g., "npm install")
3130
+ * @param options.start - Command to start the server (e.g., "npm run dev")
2973
3131
  * @param options.path - Working directory (optional)
2974
3132
  * @param options.env_file - Path to .env file relative to path (optional)
2975
3133
  * @param options.environment - Inline environment variables (merged with env_file if both provided)
@@ -2983,14 +3141,15 @@ API request failed (${response.status}): ${error}`
2983
3141
  * // Basic server
2984
3142
  * await sandbox.startServer({
2985
3143
  * slug: 'web',
2986
- * command: 'npm run dev',
3144
+ * start: 'npm run dev',
2987
3145
  * path: '/app',
2988
3146
  * });
2989
3147
  *
2990
- * // With supervisor settings
3148
+ * // With install command and supervisor settings
2991
3149
  * await sandbox.startServer({
2992
3150
  * slug: 'api',
2993
- * command: 'node server.js',
3151
+ * install: 'npm install',
3152
+ * start: 'node server.js',
2994
3153
  * path: '/app',
2995
3154
  * environment: { NODE_ENV: 'production', PORT: '3000' },
2996
3155
  * restart_policy: 'on-failure',
@@ -3037,6 +3196,21 @@ API request failed (${response.status}): ${error}`
3037
3196
  }
3038
3197
  );
3039
3198
  }
3199
+ /**
3200
+ * Get logs for a managed server
3201
+ * @param slug - Server slug
3202
+ * @param options - Options for log retrieval
3203
+ */
3204
+ async getServerLogs(slug, options) {
3205
+ const params = new URLSearchParams();
3206
+ if (options?.stream) {
3207
+ params.set("stream", options.stream);
3208
+ }
3209
+ const queryString = params.toString();
3210
+ return this.request(
3211
+ `/servers/${encodeURIComponent(slug)}/logs${queryString ? `?${queryString}` : ""}`
3212
+ );
3213
+ }
3040
3214
  /**
3041
3215
  * Update server status (internal use)
3042
3216
  * @param slug - Server slug
@@ -3318,7 +3492,9 @@ var PROVIDER_HEADERS = {
3318
3492
  tokenSecret: "X-Modal-Token-Secret"
3319
3493
  },
3320
3494
  railway: {
3321
- apiToken: "X-Railway-API-Token"
3495
+ apiToken: "X-Railway-API-Key",
3496
+ projectId: "X-Railway-Project-ID",
3497
+ environmentId: "X-Railway-Environment-ID"
3322
3498
  },
3323
3499
  daytona: {
3324
3500
  apiKey: "X-Daytona-API-Key"