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.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
|
-
*
|
|
1417
|
+
* start: 'npm run dev',
|
|
1413
1418
|
* path: '/app',
|
|
1414
1419
|
* });
|
|
1415
1420
|
*
|
|
1416
|
-
* // With
|
|
1421
|
+
* // With install command
|
|
1417
1422
|
* const server = await sandbox.server.start({
|
|
1418
1423
|
* slug: 'api',
|
|
1419
|
-
*
|
|
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
|
-
|
|
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
|
|
1913
|
-
*
|
|
1914
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
1963
|
-
|
|
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.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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-
|
|
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"
|