@sylphx/sdk 0.2.0 → 0.2.1

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
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  NotFoundError: () => NotFoundError,
40
40
  RETRYABLE_CODES: () => RETRYABLE_CODES,
41
41
  RateLimitError: () => RateLimitError,
42
+ SandboxClient: () => SandboxClient,
42
43
  SylphxError: () => SylphxError,
43
44
  TimeoutError: () => TimeoutError,
44
45
  ValidationError: () => ValidationError,
@@ -3084,6 +3085,172 @@ async function captureMessage(config, message, options = {}) {
3084
3085
  body: request
3085
3086
  });
3086
3087
  }
3088
+
3089
+ // src/sandbox.ts
3090
+ var DEFAULT_IMAGE = "registry.sylphx.com/library/exec-server:latest";
3091
+ var SandboxClient = class _SandboxClient {
3092
+ id;
3093
+ config;
3094
+ constructor(id, config) {
3095
+ this.id = id;
3096
+ this.config = config;
3097
+ }
3098
+ // ---------------------------------------------------------------------------
3099
+ // Factory
3100
+ // ---------------------------------------------------------------------------
3101
+ /**
3102
+ * Create a new sandbox.
3103
+ *
3104
+ * The sandbox pod starts asynchronously — it will be in `starting` status
3105
+ * after creation. File/run operations will block until the pod is ready.
3106
+ *
3107
+ * @param config - Sylphx config with a secret key (sk_*) and project ref
3108
+ * @param options - Sandbox creation options
3109
+ */
3110
+ static async create(config, options) {
3111
+ const record = await callApi(config, `/sandboxes`, {
3112
+ method: "POST",
3113
+ body: {
3114
+ image: options?.image ?? DEFAULT_IMAGE,
3115
+ idleTimeoutMs: options?.idleTimeoutMs ?? 3e5,
3116
+ resources: options?.resources,
3117
+ env: options?.env,
3118
+ storage: options?.storageGi !== void 0 ? { enabled: true, sizeGi: options.storageGi } : void 0
3119
+ }
3120
+ });
3121
+ return new _SandboxClient(record.id, config);
3122
+ }
3123
+ /**
3124
+ * Reconnect to an existing sandbox by ID.
3125
+ *
3126
+ * Use this to resume operations on a sandbox created in a previous request.
3127
+ */
3128
+ static fromId(config, sandboxId) {
3129
+ return new _SandboxClient(sandboxId, config);
3130
+ }
3131
+ // ---------------------------------------------------------------------------
3132
+ // Lifecycle
3133
+ // ---------------------------------------------------------------------------
3134
+ /**
3135
+ * Get the current status of this sandbox.
3136
+ */
3137
+ async getStatus() {
3138
+ return callApi(
3139
+ this.config,
3140
+ `/sandboxes/${this.id}`,
3141
+ { method: "GET" }
3142
+ );
3143
+ }
3144
+ /**
3145
+ * Terminate the sandbox immediately.
3146
+ *
3147
+ * Deletes the K8s Pod and Service. PVC (storage) is preserved for reuse.
3148
+ * This operation is idempotent — safe to call multiple times.
3149
+ */
3150
+ async terminate() {
3151
+ await callApi(
3152
+ this.config,
3153
+ `/sandboxes/${this.id}`,
3154
+ { method: "DELETE" }
3155
+ );
3156
+ }
3157
+ // ---------------------------------------------------------------------------
3158
+ // File Operations
3159
+ // ---------------------------------------------------------------------------
3160
+ /**
3161
+ * Write a file to the sandbox filesystem.
3162
+ *
3163
+ * @param path - Absolute path inside the sandbox (e.g. '/workspace/file.py')
3164
+ * @param content - File content as string or Buffer
3165
+ * @param encoding - 'utf8' (default) or 'base64' for binary files
3166
+ */
3167
+ async writeFile(path, content, encoding = "utf8") {
3168
+ const contentStr = Buffer.isBuffer(content) ? content.toString("base64") : content;
3169
+ const effectiveEncoding = Buffer.isBuffer(content) ? "base64" : encoding;
3170
+ await callApi(
3171
+ this.config,
3172
+ `/sandboxes/${this.id}/files`,
3173
+ {
3174
+ method: "POST",
3175
+ body: { path, content: contentStr, encoding: effectiveEncoding }
3176
+ }
3177
+ );
3178
+ }
3179
+ /**
3180
+ * Read a file from the sandbox filesystem.
3181
+ *
3182
+ * @param path - Absolute path inside the sandbox
3183
+ * @returns File content as a string
3184
+ */
3185
+ async readFile(path) {
3186
+ const result = await callApi(
3187
+ this.config,
3188
+ `/sandboxes/${this.id}/files`,
3189
+ {
3190
+ method: "GET",
3191
+ query: { path }
3192
+ }
3193
+ );
3194
+ return result.content;
3195
+ }
3196
+ /**
3197
+ * Delete a file from the sandbox filesystem.
3198
+ *
3199
+ * @param path - Absolute path inside the sandbox
3200
+ */
3201
+ async deleteFile(path) {
3202
+ await callApi(
3203
+ this.config,
3204
+ `/sandboxes/${this.id}/files`,
3205
+ {
3206
+ method: "DELETE",
3207
+ query: { path }
3208
+ }
3209
+ );
3210
+ }
3211
+ /**
3212
+ * List files in a directory.
3213
+ *
3214
+ * @param path - Directory path inside the sandbox (default: '/')
3215
+ * @returns Array of file/directory paths
3216
+ */
3217
+ async listFiles(path = "/") {
3218
+ const result = await callApi(
3219
+ this.config,
3220
+ `/sandboxes/${this.id}/list`,
3221
+ {
3222
+ method: "GET",
3223
+ query: { path }
3224
+ }
3225
+ );
3226
+ return result.files;
3227
+ }
3228
+ // ---------------------------------------------------------------------------
3229
+ // Command Execution
3230
+ // ---------------------------------------------------------------------------
3231
+ /**
3232
+ * Run a command inside the sandbox.
3233
+ *
3234
+ * The command runs synchronously inside the exec pod and returns when complete.
3235
+ *
3236
+ * @param command - Full command + args as array (e.g. ['python3', 'script.py'])
3237
+ * @param options - Optional cwd, env, timeout, stdin
3238
+ * @returns { stdout, stderr, exitCode, durationMs }
3239
+ *
3240
+ * @example
3241
+ * ```typescript
3242
+ * const { stdout, exitCode } = await sandbox.run(['python3', '-c', 'print(1+1)'])
3243
+ * console.log(stdout) // "2\n"
3244
+ * console.log(exitCode) // 0
3245
+ * ```
3246
+ */
3247
+ async run(command, options) {
3248
+ return callApi(this.config, `/sandboxes/${this.id}/run`, {
3249
+ method: "POST",
3250
+ body: { command, ...options }
3251
+ });
3252
+ }
3253
+ };
3087
3254
  // Annotate the CommonJS export names for ESM import in node:
3088
3255
  0 && (module.exports = {
3089
3256
  ACHIEVEMENT_TIER_CONFIG,
@@ -3095,6 +3262,7 @@ async function captureMessage(config, message, options = {}) {
3095
3262
  NotFoundError,
3096
3263
  RETRYABLE_CODES,
3097
3264
  RateLimitError,
3265
+ SandboxClient,
3098
3266
  SylphxError,
3099
3267
  TimeoutError,
3100
3268
  ValidationError,