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.d.mts +216 -26
- package/dist/index.d.ts +216 -26
- package/dist/index.js +193 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +193 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1335,10 +1335,15 @@ var Server = class {
|
|
|
1335
1335
|
this.stopHandler = handlers.stop;
|
|
1336
1336
|
this.restartHandler = handlers.restart;
|
|
1337
1337
|
this.updateStatusHandler = handlers.updateStatus;
|
|
1338
|
+
this.logsHandler = handlers.logs;
|
|
1338
1339
|
}
|
|
1339
1340
|
/**
|
|
1340
1341
|
* Start a new managed server with optional supervisor settings
|
|
1341
1342
|
*
|
|
1343
|
+
* **Install Phase:**
|
|
1344
|
+
* If `install` is provided, it runs blocking before `start` (e.g., "npm install").
|
|
1345
|
+
* The server status will be `installing` during this phase.
|
|
1346
|
+
*
|
|
1342
1347
|
* **Restart Policies:**
|
|
1343
1348
|
* - `never` (default): No automatic restart on exit
|
|
1344
1349
|
* - `on-failure`: Restart only on non-zero exit code
|
|
@@ -1356,14 +1361,15 @@ var Server = class {
|
|
|
1356
1361
|
* // Basic server
|
|
1357
1362
|
* const server = await sandbox.server.start({
|
|
1358
1363
|
* slug: 'web',
|
|
1359
|
-
*
|
|
1364
|
+
* start: 'npm run dev',
|
|
1360
1365
|
* path: '/app',
|
|
1361
1366
|
* });
|
|
1362
1367
|
*
|
|
1363
|
-
* // With
|
|
1368
|
+
* // With install command
|
|
1364
1369
|
* const server = await sandbox.server.start({
|
|
1365
1370
|
* slug: 'api',
|
|
1366
|
-
*
|
|
1371
|
+
* install: 'npm install',
|
|
1372
|
+
* start: 'node server.js',
|
|
1367
1373
|
* environment: { NODE_ENV: 'production' },
|
|
1368
1374
|
* restart_policy: 'always',
|
|
1369
1375
|
* max_restarts: 0, // unlimited
|
|
@@ -1415,6 +1421,29 @@ var Server = class {
|
|
|
1415
1421
|
async updateStatus(slug, status) {
|
|
1416
1422
|
await this.updateStatusHandler(slug, status);
|
|
1417
1423
|
}
|
|
1424
|
+
/**
|
|
1425
|
+
* Retrieve captured output (logs) for a managed server
|
|
1426
|
+
* @param slug - The server slug
|
|
1427
|
+
* @param options - Options for log retrieval
|
|
1428
|
+
* @returns Server logs info
|
|
1429
|
+
*
|
|
1430
|
+
* @example
|
|
1431
|
+
* ```typescript
|
|
1432
|
+
* // Get combined logs (default)
|
|
1433
|
+
* const logs = await sandbox.server.logs('api');
|
|
1434
|
+
* console.log(logs.logs);
|
|
1435
|
+
*
|
|
1436
|
+
* // Get only stdout
|
|
1437
|
+
* const stdout = await sandbox.server.logs('api', { stream: 'stdout' });
|
|
1438
|
+
*
|
|
1439
|
+
* // Get only stderr
|
|
1440
|
+
* const stderr = await sandbox.server.logs('api', { stream: 'stderr' });
|
|
1441
|
+
* ```
|
|
1442
|
+
*/
|
|
1443
|
+
async logs(slug, options) {
|
|
1444
|
+
const response = await this.logsHandler(slug, options);
|
|
1445
|
+
return response.data;
|
|
1446
|
+
}
|
|
1418
1447
|
};
|
|
1419
1448
|
|
|
1420
1449
|
// src/client/resources/watcher.ts
|
|
@@ -1773,6 +1802,7 @@ var Run = class {
|
|
|
1773
1802
|
constructor(handlers) {
|
|
1774
1803
|
this.codeHandler = handlers.code;
|
|
1775
1804
|
this.commandHandler = handlers.command;
|
|
1805
|
+
this.waitHandler = handlers.wait;
|
|
1776
1806
|
}
|
|
1777
1807
|
/**
|
|
1778
1808
|
* Execute code with automatic language detection
|
|
@@ -1796,10 +1826,38 @@ var Run = class {
|
|
|
1796
1826
|
* @param options.background - Run in background (optional)
|
|
1797
1827
|
* @param options.cwd - Working directory for the command (optional)
|
|
1798
1828
|
* @param options.env - Environment variables (optional)
|
|
1829
|
+
* @param options.waitForCompletion - If true (with background), wait for command to complete
|
|
1799
1830
|
* @returns Command execution result with stdout, stderr, exit code, and duration
|
|
1800
1831
|
*/
|
|
1801
1832
|
async command(command, options) {
|
|
1802
|
-
|
|
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);
|
|
1803
1861
|
}
|
|
1804
1862
|
};
|
|
1805
1863
|
|
|
@@ -1856,18 +1914,25 @@ var Overlay = class {
|
|
|
1856
1914
|
/**
|
|
1857
1915
|
* Create a new overlay from a template directory
|
|
1858
1916
|
*
|
|
1859
|
-
* The overlay
|
|
1860
|
-
*
|
|
1861
|
-
*
|
|
1917
|
+
* The overlay copies files from the source directory into the target path
|
|
1918
|
+
* for better isolation. Heavy directories (node_modules, .venv, etc.) are
|
|
1919
|
+
* copied in the background. Use the `ignore` option to exclude files/directories.
|
|
1862
1920
|
*
|
|
1863
1921
|
* @param options - Overlay creation options
|
|
1864
1922
|
* @param options.source - Absolute path to source directory
|
|
1865
1923
|
* @param options.target - Relative path in sandbox
|
|
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
|
|
1866
1926
|
* @returns Overlay info with copy status
|
|
1867
1927
|
*/
|
|
1868
1928
|
async create(options) {
|
|
1869
1929
|
const response = await this.createHandler(options);
|
|
1870
|
-
|
|
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;
|
|
1871
1936
|
}
|
|
1872
1937
|
/**
|
|
1873
1938
|
* List all overlays for the current sandbox
|
|
@@ -1896,6 +1961,48 @@ var Overlay = class {
|
|
|
1896
1961
|
async destroy(id) {
|
|
1897
1962
|
return this.destroyHandler(id);
|
|
1898
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
|
+
}
|
|
1899
2006
|
/**
|
|
1900
2007
|
* Convert API response to OverlayInfo
|
|
1901
2008
|
*/
|
|
@@ -1906,8 +2013,8 @@ var Overlay = class {
|
|
|
1906
2013
|
target: response.target,
|
|
1907
2014
|
createdAt: response.created_at,
|
|
1908
2015
|
stats: {
|
|
1909
|
-
|
|
1910
|
-
|
|
2016
|
+
copiedFiles: response.stats.copied_files,
|
|
2017
|
+
copiedDirs: response.stats.copied_dirs,
|
|
1911
2018
|
skipped: response.stats.skipped
|
|
1912
2019
|
},
|
|
1913
2020
|
copyStatus: this.validateCopyStatus(response.copy_status),
|
|
@@ -1939,6 +2046,7 @@ function isCommandExitError(error) {
|
|
|
1939
2046
|
}
|
|
1940
2047
|
|
|
1941
2048
|
// src/client/index.ts
|
|
2049
|
+
var MAX_TUNNEL_TIMEOUT_SECONDS = 300;
|
|
1942
2050
|
var Sandbox = class {
|
|
1943
2051
|
constructor(config) {
|
|
1944
2052
|
this._token = null;
|
|
@@ -2057,8 +2165,15 @@ var Sandbox = class {
|
|
|
2057
2165
|
stdout: result.data.stdout,
|
|
2058
2166
|
stderr: result.data.stderr,
|
|
2059
2167
|
exitCode: result.data.exit_code ?? 0,
|
|
2060
|
-
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
|
|
2061
2173
|
};
|
|
2174
|
+
},
|
|
2175
|
+
wait: async (terminalId, cmdId, options) => {
|
|
2176
|
+
return this.waitForCommandCompletion(terminalId, cmdId, options);
|
|
2062
2177
|
}
|
|
2063
2178
|
});
|
|
2064
2179
|
this.server = new Server({
|
|
@@ -2071,7 +2186,8 @@ var Sandbox = class {
|
|
|
2071
2186
|
restart: async (slug) => this.restartServer(slug),
|
|
2072
2187
|
updateStatus: async (slug, status) => {
|
|
2073
2188
|
await this.updateServerStatus(slug, status);
|
|
2074
|
-
}
|
|
2189
|
+
},
|
|
2190
|
+
logs: async (slug, options) => this.getServerLogs(slug, options)
|
|
2075
2191
|
});
|
|
2076
2192
|
this.watcher = new Watcher({
|
|
2077
2193
|
create: async (path, options) => this.createWatcher(path, options),
|
|
@@ -2728,6 +2844,47 @@ API request failed (${response.status}): ${error}`
|
|
|
2728
2844
|
const endpoint = `/terminals/${terminalId}/commands/${cmdId}/wait${params ? `?${params}` : ""}`;
|
|
2729
2845
|
return this.request(endpoint);
|
|
2730
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
|
+
}
|
|
2731
2888
|
// ============================================================================
|
|
2732
2889
|
// File Watchers
|
|
2733
2890
|
// ============================================================================
|
|
@@ -2916,7 +3073,8 @@ API request failed (${response.status}): ${error}`
|
|
|
2916
3073
|
*
|
|
2917
3074
|
* @param options - Server configuration
|
|
2918
3075
|
* @param options.slug - Unique server identifier
|
|
2919
|
-
* @param options.
|
|
3076
|
+
* @param options.install - Install command (optional, runs blocking before start, e.g., "npm install")
|
|
3077
|
+
* @param options.start - Command to start the server (e.g., "npm run dev")
|
|
2920
3078
|
* @param options.path - Working directory (optional)
|
|
2921
3079
|
* @param options.env_file - Path to .env file relative to path (optional)
|
|
2922
3080
|
* @param options.environment - Inline environment variables (merged with env_file if both provided)
|
|
@@ -2930,14 +3088,15 @@ API request failed (${response.status}): ${error}`
|
|
|
2930
3088
|
* // Basic server
|
|
2931
3089
|
* await sandbox.startServer({
|
|
2932
3090
|
* slug: 'web',
|
|
2933
|
-
*
|
|
3091
|
+
* start: 'npm run dev',
|
|
2934
3092
|
* path: '/app',
|
|
2935
3093
|
* });
|
|
2936
3094
|
*
|
|
2937
|
-
* // With supervisor settings
|
|
3095
|
+
* // With install command and supervisor settings
|
|
2938
3096
|
* await sandbox.startServer({
|
|
2939
3097
|
* slug: 'api',
|
|
2940
|
-
*
|
|
3098
|
+
* install: 'npm install',
|
|
3099
|
+
* start: 'node server.js',
|
|
2941
3100
|
* path: '/app',
|
|
2942
3101
|
* environment: { NODE_ENV: 'production', PORT: '3000' },
|
|
2943
3102
|
* restart_policy: 'on-failure',
|
|
@@ -2984,6 +3143,21 @@ API request failed (${response.status}): ${error}`
|
|
|
2984
3143
|
}
|
|
2985
3144
|
);
|
|
2986
3145
|
}
|
|
3146
|
+
/**
|
|
3147
|
+
* Get logs for a managed server
|
|
3148
|
+
* @param slug - Server slug
|
|
3149
|
+
* @param options - Options for log retrieval
|
|
3150
|
+
*/
|
|
3151
|
+
async getServerLogs(slug, options) {
|
|
3152
|
+
const params = new URLSearchParams();
|
|
3153
|
+
if (options?.stream) {
|
|
3154
|
+
params.set("stream", options.stream);
|
|
3155
|
+
}
|
|
3156
|
+
const queryString = params.toString();
|
|
3157
|
+
return this.request(
|
|
3158
|
+
`/servers/${encodeURIComponent(slug)}/logs${queryString ? `?${queryString}` : ""}`
|
|
3159
|
+
);
|
|
3160
|
+
}
|
|
2987
3161
|
/**
|
|
2988
3162
|
* Update server status (internal use)
|
|
2989
3163
|
* @param slug - Server slug
|
|
@@ -3265,7 +3439,9 @@ var PROVIDER_HEADERS = {
|
|
|
3265
3439
|
tokenSecret: "X-Modal-Token-Secret"
|
|
3266
3440
|
},
|
|
3267
3441
|
railway: {
|
|
3268
|
-
apiToken: "X-Railway-API-
|
|
3442
|
+
apiToken: "X-Railway-API-Key",
|
|
3443
|
+
projectId: "X-Railway-Project-ID",
|
|
3444
|
+
environmentId: "X-Railway-Environment-ID"
|
|
3269
3445
|
},
|
|
3270
3446
|
daytona: {
|
|
3271
3447
|
apiKey: "X-Daytona-API-Key"
|