Conversation
- Add ts-case-convert for automatic case conversion - Implement HTTP layer auto-transform (request → snake_case, response → camelCase) - Refactor all response types to use camelCase - Update examples and documentation BREAKING CHANGE: All response fields now use camelCase instead of snake_case (e.g., sandbox_id → sandboxId, exit_code → exitCode)
- Fix getStatus URL to use sandbox_id instead of sandboxId - Fix logger getLogLevel to use lowercase for level matching
- Rename write_file() to writeFile() - Rename read_file() to readFile() - Add ESLint naming-convention rule to enforce camelCase - Update examples to use new method names
- Modify HttpUtils.get/post/postMultipart to return structured response
with {status, result, headers}
- Add HeaderFieldsSchema with cluster, requestId, eagleeyeTraceid
- Update all Response types to include header-derived fields
- Extract headers in all Sandbox methods and merge into results
- Fix HttpUtils generic type parameter usage in client methods - Fix EnvHubClient to use response.result from new HttpUtils return type
This reverts commit 2ec4dcf.
This reverts commit 829b7aa.
This reverts commit 2368f86.
dengwx2026
left a comment
There was a problem hiding this comment.
TypeScript SDK Review
Overall this is a solid foundation for the TS SDK — good module structure, nice mirroring of the Python SDK patterns, and sensible use of Zod for type definitions. However, there are several critical bugs that will cause runtime failures, plus some architectural concerns worth addressing before merging.
Summary
- 5 Critical issues — will cause runtime failures (stub
uploadDir, broken multipart uploads,__dirnamein ESM, heredoc expansion bug, malformed URL) - 8 Major issues — should be fixed (version mismatch, command injection, infinite loops, unused exception system, etc.)
- 9 Minor issues — code quality improvements (duplication, hardcoded values, dead code)
Architectural Suggestions
-
Use typed exceptions or remove them:
RockException,BadRequestRockError,raiseForCode()etc. are well-designed but never called anywhere. All errors are thrown as genericnew Error(...). Either integrateraiseForCode()into the HTTP layer, or remove the unused exception hierarchy. -
Validate with Zod or drop it: Zod schemas are defined for all request/response types but
.parse()/.safeParse()is never called on API data. They only serve asz.infer<>type extraction — plain TypeScript interfaces would eliminate the Zod dependency with the same result. -
Remove browser compatibility stubs: The SDK imports
fs,crypto,child_process,https,Buffer— it fundamentally cannot work in browsers. TheisBrowser()checks insystem.tsare misleading. -
Consolidate duplicated code:
RunModeType/RunModeare duplicated insandbox/types.tsandcommon/constants.ts.extractNohupPidis duplicated insandbox/utils.tsandutils/http.ts.sleepis duplicated inmodel/client.tsandutils/retry.ts. -
Add cancellation support:
ModelClientpolling loops (while(true)) needAbortControlleror timeout mechanisms to avoid blocking forever.
Minor Issues (not inlined)
utils/retry.ts:26— Defaultbackoff = 1.0means no actual exponential backoff. Should default to2.0.sandbox/client.ts:396—String(e).includes('already exists')for session detection is fragile and will break if the server message changes or is localized.logger.ts:69—loggerCacheMap grows without bound — potential memory leak in long-running processes.common/constants.ts:22-29—Constantsclass with all empty string static properties and@deprecatedtag is dead code.utils/deprecated.ts— Usesconsole.warninstead of the project's Winston logger, and fires on every call (standard practice is warn-once-per-function).
| failureReason: '', | ||
| expectString: '', | ||
| }; | ||
| } |
There was a problem hiding this comment.
Critical: uploadDir is a stub that always returns { exitCode: 0, output: '' } without actually uploading anything. Deploy.deployWorkingDir at deploy.ts:60 depends on this method, so deployments will silently do nothing.
This should either be implemented or throw a NotImplementedError so callers know the feature isn't available.
rock/ts-sdk/src/utils/http.ts
Outdated
| const client = this.createClient({ | ||
| headers: { | ||
| ...headers, | ||
| 'Content-Type': 'multipart/form-data', |
There was a problem hiding this comment.
Critical: Manually setting 'Content-Type': 'multipart/form-data' prevents axios from appending the boundary parameter. The server will reject all multipart uploads because it can't parse the boundary.
Remove this header and let axios auto-detect it from the FormData object:
const headers = {
...HttpUtils.getCommonHeaders(),
// Do NOT set Content-Type here — axios sets it automatically with the boundary
};There was a problem hiding this comment.
在 Node.js 环境下,axios 不会自动为 FormData 设置 Content-Type。这与浏览器环境不同。
|
|
||
| const command = cmd[0] ?? 'node'; | ||
| this.process = spawn(command, cmd.slice(1), { | ||
| cwd: resolve(__dirname, 'server'), |
There was a problem hiding this comment.
Critical: __dirname is not available in ESM modules. Since the project uses "module": "ESNext" in tsconfig and tsup builds ESM output, __dirname will be undefined at runtime, causing resolve(undefined, 'server') to produce an incorrect path.
Use import.meta.url instead:
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);There was a problem hiding this comment.
会使用 tsup 的 shims 功能处理。
|
|
||
| private buildAptSpeedupCommand(mirrorUrl: string): string { | ||
| return `cat > /etc/apt/sources.list << 'EOF' | ||
| deb ${mirrorUrl} $(lsb_release -cs) main restricted universe multiverse |
There was a problem hiding this comment.
Critical: Using a single-quoted heredoc delimiter (<< 'EOF') prevents all shell expansion inside the heredoc. This means $(lsb_release -cs) will be written literally into the sources.list file instead of being evaluated to the Ubuntu codename (e.g., jammy).
Use an unquoted heredoc delimiter instead:
cat << EOF > /etc/apt/sources.list
rock/ts-sdk/src/env_vars.ts
Outdated
| get ROCK_RTENV_PYTHON_V31212_INSTALL_CMD(): string { | ||
| return getEnv( | ||
| 'ROCK_RTENV_PYTHON_V31212_INSTALL_CMD', | ||
| '[ -f cpython-3.12.12.tar.gz ] && rm cpython-3.12.12.tar.gz; [ -d python ] && rm -rf python; wget -q -O cpython-3.12.12.tar.gz https://github.com/astral-sh/python-build-standalone/releases/20251217/cpython-3.12.12+20251217-x86_64-unknown-linux-gnu-install_only.tar.gz && tar -xzf cpython-3.12.12.tar.gz && mv python runtime-env' |
There was a problem hiding this comment.
Critical: The URL is missing the /download/ path segment. This:
https://github.com/astral-sh/python-build-standalone/releases/20251217/cpython-...
should be:
https://github.com/astral-sh/python-build-standalone/releases/download/20251217/cpython-...
The current default will result in a 404 error.
| * Base configuration schema | ||
| */ | ||
| export const BaseConfigSchema = z.object({ | ||
| baseUrl: z.string().default(envVars.ROCK_BASE_URL), |
There was a problem hiding this comment.
Minor: Zod .default(envVars.ROCK_BASE_URL) captures the value eagerly at import time. If the environment variable changes after module load, the schema still uses the stale value. Consider using .default() with a transform or a factory function pattern.
| // Pip | ||
| get ROCK_PIP_INDEX_URL(): string { | ||
| return getEnv('ROCK_PIP_INDEX_URL', 'https://mirrors.aliyun.com/pypi/simple/')!; | ||
| }, |
There was a problem hiding this comment.
Minor: ROCK_PIP_INDEX_URL defaults to mirrors.aliyun.com which is a China-specific mirror. For a public open-source SDK, this should default to https://pypi.org/simple/.
| cpus: z.number().default(2), | ||
| userId: z.string().optional(), | ||
| experimentId: z.string().optional(), | ||
| cluster: z.string().default('zb'), |
There was a problem hiding this comment.
Minor: cluster defaults to hardcoded 'zb'. Should come from an environment variable (e.g., ROCK_DEFAULT_CLUSTER) for flexibility across deployments.
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/Timandes/ROCK.git" | ||
| }, |
There was a problem hiding this comment.
Minor: Repository URL points to Timandes/ROCK (fork) instead of alibaba/ROCK. Should be updated before publishing:
"url": "https://github.com/alibaba/ROCK.git"| } | ||
|
|
||
| private buildGithubSpeedupCommand(ipAddress: string): string { | ||
| return `echo "${ipAddress} github.com" >> /etc/hosts`; |
There was a problem hiding this comment.
Minor: No input validation on ipAddress. If it contains shell metacharacters, this could inject commands via echo "${ipAddress} github.com" >> /etc/hosts. While this runs inside a sandbox, it's still good practice to validate the format (e.g., check against an IP regex).
- Configure Jest projects to separate unit and integration tests - Unit tests run from src/, integration tests from tests/integration/ - Add test:unit and test:integration npm scripts - Add sandbox lifecycle integration test (start, isAlive, stop)
- Implement uploadDir method in LinuxFileSystem following Python SDK pattern - Add arun method to AbstractSandbox interface for command execution - Support validation, local tar packing, upload, remote extraction, and cleanup - Add integration tests for uploadDir functionality
…quests - Remove manual Content-Type header that prevented axios from adding boundary - Set Content-Type to null in post config to allow axios auto-detection - Add unit tests for postMultipart method
__dirname is not available in ESM modules. Enable tsup shims option to inject proper polyfill using fileURLToPath(import.meta.url).
Using single-quoted heredoc delimiter (<< 'EOF') prevented shell variable expansion, causing $(lsb_release -cs) to be written literally instead of being evaluated to the Ubuntu codename (e.g., 'jammy'). This fix ensures the command substitution is properly expanded when configuring APT mirror sources.
VERSION constant was hardcoded to '1.2.1' while package.json declared '1.2.4', causing version mismatch. Now reads version from package.json at runtime to ensure consistency.
关联Issue #495 。
包地址:https://www.npmjs.com/package/rl-rock
支持:
🚀 沙箱管理 - 创建、启动、停止远程容器沙箱
📁 文件系统 - 上传、下载、读取、写入文件
🖥️ 命令执行 - 同步/异步执行 Shell 命令
🔧 运行时环境 - 支持 Python、Node.js 运行时环境管理
🤖 Agent 框架 - 内置 Agent 支持自动化任务
📦 EnvHub - 环境注册与管理
🔄 双模式构建 - 同时支持 ESM 和 CommonJS