@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.mjs CHANGED
@@ -2852,6 +2852,172 @@ async function captureMessage(config, message, options = {}) {
2852
2852
  body: request
2853
2853
  });
2854
2854
  }
2855
+
2856
+ // src/sandbox.ts
2857
+ var DEFAULT_IMAGE = "registry.sylphx.com/library/exec-server:latest";
2858
+ var SandboxClient = class _SandboxClient {
2859
+ id;
2860
+ config;
2861
+ constructor(id, config) {
2862
+ this.id = id;
2863
+ this.config = config;
2864
+ }
2865
+ // ---------------------------------------------------------------------------
2866
+ // Factory
2867
+ // ---------------------------------------------------------------------------
2868
+ /**
2869
+ * Create a new sandbox.
2870
+ *
2871
+ * The sandbox pod starts asynchronously — it will be in `starting` status
2872
+ * after creation. File/run operations will block until the pod is ready.
2873
+ *
2874
+ * @param config - Sylphx config with a secret key (sk_*) and project ref
2875
+ * @param options - Sandbox creation options
2876
+ */
2877
+ static async create(config, options) {
2878
+ const record = await callApi(config, `/sandboxes`, {
2879
+ method: "POST",
2880
+ body: {
2881
+ image: options?.image ?? DEFAULT_IMAGE,
2882
+ idleTimeoutMs: options?.idleTimeoutMs ?? 3e5,
2883
+ resources: options?.resources,
2884
+ env: options?.env,
2885
+ storage: options?.storageGi !== void 0 ? { enabled: true, sizeGi: options.storageGi } : void 0
2886
+ }
2887
+ });
2888
+ return new _SandboxClient(record.id, config);
2889
+ }
2890
+ /**
2891
+ * Reconnect to an existing sandbox by ID.
2892
+ *
2893
+ * Use this to resume operations on a sandbox created in a previous request.
2894
+ */
2895
+ static fromId(config, sandboxId) {
2896
+ return new _SandboxClient(sandboxId, config);
2897
+ }
2898
+ // ---------------------------------------------------------------------------
2899
+ // Lifecycle
2900
+ // ---------------------------------------------------------------------------
2901
+ /**
2902
+ * Get the current status of this sandbox.
2903
+ */
2904
+ async getStatus() {
2905
+ return callApi(
2906
+ this.config,
2907
+ `/sandboxes/${this.id}`,
2908
+ { method: "GET" }
2909
+ );
2910
+ }
2911
+ /**
2912
+ * Terminate the sandbox immediately.
2913
+ *
2914
+ * Deletes the K8s Pod and Service. PVC (storage) is preserved for reuse.
2915
+ * This operation is idempotent — safe to call multiple times.
2916
+ */
2917
+ async terminate() {
2918
+ await callApi(
2919
+ this.config,
2920
+ `/sandboxes/${this.id}`,
2921
+ { method: "DELETE" }
2922
+ );
2923
+ }
2924
+ // ---------------------------------------------------------------------------
2925
+ // File Operations
2926
+ // ---------------------------------------------------------------------------
2927
+ /**
2928
+ * Write a file to the sandbox filesystem.
2929
+ *
2930
+ * @param path - Absolute path inside the sandbox (e.g. '/workspace/file.py')
2931
+ * @param content - File content as string or Buffer
2932
+ * @param encoding - 'utf8' (default) or 'base64' for binary files
2933
+ */
2934
+ async writeFile(path, content, encoding = "utf8") {
2935
+ const contentStr = Buffer.isBuffer(content) ? content.toString("base64") : content;
2936
+ const effectiveEncoding = Buffer.isBuffer(content) ? "base64" : encoding;
2937
+ await callApi(
2938
+ this.config,
2939
+ `/sandboxes/${this.id}/files`,
2940
+ {
2941
+ method: "POST",
2942
+ body: { path, content: contentStr, encoding: effectiveEncoding }
2943
+ }
2944
+ );
2945
+ }
2946
+ /**
2947
+ * Read a file from the sandbox filesystem.
2948
+ *
2949
+ * @param path - Absolute path inside the sandbox
2950
+ * @returns File content as a string
2951
+ */
2952
+ async readFile(path) {
2953
+ const result = await callApi(
2954
+ this.config,
2955
+ `/sandboxes/${this.id}/files`,
2956
+ {
2957
+ method: "GET",
2958
+ query: { path }
2959
+ }
2960
+ );
2961
+ return result.content;
2962
+ }
2963
+ /**
2964
+ * Delete a file from the sandbox filesystem.
2965
+ *
2966
+ * @param path - Absolute path inside the sandbox
2967
+ */
2968
+ async deleteFile(path) {
2969
+ await callApi(
2970
+ this.config,
2971
+ `/sandboxes/${this.id}/files`,
2972
+ {
2973
+ method: "DELETE",
2974
+ query: { path }
2975
+ }
2976
+ );
2977
+ }
2978
+ /**
2979
+ * List files in a directory.
2980
+ *
2981
+ * @param path - Directory path inside the sandbox (default: '/')
2982
+ * @returns Array of file/directory paths
2983
+ */
2984
+ async listFiles(path = "/") {
2985
+ const result = await callApi(
2986
+ this.config,
2987
+ `/sandboxes/${this.id}/list`,
2988
+ {
2989
+ method: "GET",
2990
+ query: { path }
2991
+ }
2992
+ );
2993
+ return result.files;
2994
+ }
2995
+ // ---------------------------------------------------------------------------
2996
+ // Command Execution
2997
+ // ---------------------------------------------------------------------------
2998
+ /**
2999
+ * Run a command inside the sandbox.
3000
+ *
3001
+ * The command runs synchronously inside the exec pod and returns when complete.
3002
+ *
3003
+ * @param command - Full command + args as array (e.g. ['python3', 'script.py'])
3004
+ * @param options - Optional cwd, env, timeout, stdin
3005
+ * @returns { stdout, stderr, exitCode, durationMs }
3006
+ *
3007
+ * @example
3008
+ * ```typescript
3009
+ * const { stdout, exitCode } = await sandbox.run(['python3', '-c', 'print(1+1)'])
3010
+ * console.log(stdout) // "2\n"
3011
+ * console.log(exitCode) // 0
3012
+ * ```
3013
+ */
3014
+ async run(command, options) {
3015
+ return callApi(this.config, `/sandboxes/${this.id}/run`, {
3016
+ method: "POST",
3017
+ body: { command, ...options }
3018
+ });
3019
+ }
3020
+ };
2855
3021
  export {
2856
3022
  ACHIEVEMENT_TIER_CONFIG,
2857
3023
  AuthenticationError,
@@ -2862,6 +3028,7 @@ export {
2862
3028
  NotFoundError,
2863
3029
  RETRYABLE_CODES,
2864
3030
  RateLimitError,
3031
+ SandboxClient,
2865
3032
  SylphxError,
2866
3033
  TimeoutError,
2867
3034
  ValidationError,