@fastgpt-sdk/sandbox-adapter 0.0.15 → 0.0.17

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.
@@ -54,4 +54,6 @@ export declare abstract class BaseSandboxAdapter implements ISandbox {
54
54
  getMetrics(): Promise<SandboxMetrics>;
55
55
  protected sleep(ms: number): Promise<void>;
56
56
  protected requirePolyfillService(feature: string, message: string): CommandPolyfillService;
57
+ protected escapeShellArg(arg: string): string;
58
+ protected buildCommand(command: string, workingDirectory?: string): string[];
57
59
  }
@@ -1,4 +1,4 @@
1
- import type { ExecuteOptions, ExecuteResult, SandboxId, SandboxInfo, SandboxMetrics, StreamHandlers } from '@/types';
1
+ import type { Endpoint, ExecuteOptions, ExecuteResult, SandboxId, SandboxInfo, SandboxMetrics, StreamHandlers } from '@/types';
2
2
  import { BaseSandboxAdapter } from '../BaseSandboxAdapter';
3
3
  import type { OpenSandboxConfigType } from './type';
4
4
  export type { OpenSandboxConfigType } from './type';
@@ -44,13 +44,13 @@ export interface OpenSandboxConnectionConfig {
44
44
  */
45
45
  export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
46
46
  private connectionConfig;
47
- private createConfig;
47
+ private createConfig?;
48
48
  readonly provider: "opensandbox";
49
49
  readonly runtime: SandboxRuntimeType;
50
50
  private _sandbox?;
51
51
  private _connection;
52
52
  private _id;
53
- constructor(connectionConfig: OpenSandboxConnectionConfig | undefined, createConfig: OpenSandboxConfigType);
53
+ constructor(connectionConfig?: OpenSandboxConnectionConfig, createConfig?: OpenSandboxConfigType | undefined);
54
54
  get id(): SandboxId;
55
55
  private get sandbox();
56
56
  private createConnectionConfig;
@@ -66,6 +66,23 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
66
66
  start(): Promise<void>;
67
67
  stop(): Promise<void>;
68
68
  delete(): Promise<void>;
69
+ /**
70
+ * Release client-side resources owned by this Sandbox instance.
71
+ * Does NOT stop or delete the container - the sandbox keeps running.
72
+ * Use this to disconnect from a sandbox without destroying it.
73
+ */
74
+ close(): Promise<void>;
75
+ /**
76
+ * Get endpoint information for a specific port exposed by the sandbox.
77
+ * @param port The port number to get endpoint for
78
+ * @returns Endpoint with host, port, protocol and url fields
79
+ */
80
+ getEndpoint(port: number): Promise<Endpoint>;
81
+ /**
82
+ * Convert SDK Endpoint (no-scheme string) to our Endpoint type.
83
+ * SDK format: "localhost:44772" or "domain/route/.../44772"
84
+ */
85
+ private convertSdkEndpoint;
69
86
  getInfo(): Promise<SandboxInfo | null>;
70
87
  renewExpiration(additionalSeconds: number): Promise<void>;
71
88
  execute(command: string, options?: ExecuteOptions): Promise<ExecuteResult>;
@@ -1,6 +1,10 @@
1
1
  import { type SealosDevboxConfig } from './SealosDevboxAdapter';
2
2
  import { type OpenSandboxConnectionConfig, type OpenSandboxConfigType } from './OpenSandboxAdapter';
3
3
  import { ISandbox } from '@/interfaces';
4
+ export { SealosDevboxAdapter } from './SealosDevboxAdapter';
5
+ export type { SealosDevboxConfig } from './SealosDevboxAdapter';
6
+ export { OpenSandboxAdapter } from './OpenSandboxAdapter';
7
+ export type { OpenSandboxConfigType, OpenSandboxConnectionConfig } from './OpenSandboxAdapter';
4
8
  export type SandboxProviderType = 'opensandbox' | 'sealosdevbox';
5
9
  /** Maps each provider name to the ISandbox config type it exposes. */
6
10
  interface SandboxConfigMap {
@@ -21,5 +25,4 @@ interface SandboxConnectionConfig {
21
25
  * @returns Configured sandbox instance
22
26
  * @throws Error if provider type is unknown
23
27
  */
24
- export declare function createSandbox<P extends SandboxProviderType>(provider: P, config: SandboxConnectionConfig[P], createConfig: SandboxConfigMap[P]): ISandbox;
25
- export {};
28
+ export declare function createSandbox<P extends SandboxProviderType>(provider: P, config: SandboxConnectionConfig[P], createConfig?: SandboxConfigMap[P]): ISandbox;
package/dist/index.js CHANGED
@@ -356,6 +356,8 @@ POLYFILL_EOF`);
356
356
  };
357
357
  }
358
358
  escapePath(path) {
359
+ if (!path)
360
+ return ".";
359
361
  return path.replace(/"/g, "\\\"");
360
362
  }
361
363
  parseLsOutput(output, basePath) {
@@ -624,6 +626,16 @@ class BaseSandboxAdapter {
624
626
  }
625
627
  return this.polyfillService;
626
628
  }
629
+ escapeShellArg(arg) {
630
+ return `'${arg.replace(/'/g, "'\\''")}'`;
631
+ }
632
+ buildCommand(command, workingDirectory) {
633
+ if (workingDirectory) {
634
+ const escapedDir = this.escapeShellArg(workingDirectory);
635
+ return ["sh", "-lc", `cd ${escapedDir} && ${command}`];
636
+ }
637
+ return ["sh", "-lc", command];
638
+ }
627
639
  }
628
640
 
629
641
  // src/adapters/SealosDevboxAdapter/api.ts
@@ -776,12 +788,13 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
776
788
  createdAt: new Date
777
789
  };
778
790
  } catch (error) {
779
- throw new CommandExecutionError("Failed to get sandbox info", "getInfo", error instanceof Error ? error : undefined);
791
+ throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
780
792
  }
781
793
  }
782
794
  async ensureRunning() {
783
795
  try {
784
796
  const sandbox = await this.getInfo();
797
+ console.log(sandbox, 2323232);
785
798
  if (sandbox) {
786
799
  const status = sandbox.status.state;
787
800
  switch (status) {
@@ -800,12 +813,12 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
800
813
  await this.create();
801
814
  return;
802
815
  default:
803
- throw new ConnectionError(`Failed to ensure sandbox running: ${status}, ${sandbox.status.message}`);
816
+ throw new ConnectionError(`Failed to ensure sandbox running`);
804
817
  }
805
818
  }
806
819
  await this.create();
807
820
  } catch (error) {
808
- throw new ConnectionError("Failed to ensure sandbox running", this.config.baseUrl, error);
821
+ throw new ConnectionError(`Failed to ensure sandbox running`, this.config.baseUrl, error);
809
822
  }
810
823
  }
811
824
  async create() {
@@ -848,7 +861,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
848
861
  }
849
862
  }
850
863
  async execute(command, options) {
851
- const cmd = options?.workingDirectory ? ["sh", "-lc", `cd ${options.workingDirectory} && ${command}`] : ["sh", "-lc", command];
864
+ const cmd = this.buildCommand(command, options?.workingDirectory);
865
+ console.log(cmd, 2322222222222);
852
866
  try {
853
867
  const res = await this.api.exec(this._id, {
854
868
  command: cmd,
@@ -879,7 +893,10 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
879
893
  }
880
894
 
881
895
  // src/adapters/OpenSandboxAdapter/index.ts
882
- import { ConnectionConfig, Sandbox } from "@alibaba-group/opensandbox";
896
+ import {
897
+ ConnectionConfig,
898
+ Sandbox
899
+ } from "@alibaba-group/opensandbox";
883
900
  class OpenSandboxAdapter extends BaseSandboxAdapter {
884
901
  connectionConfig;
885
902
  createConfig;
@@ -894,6 +911,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
894
911
  this.createConfig = createConfig;
895
912
  this.runtime = connectionConfig.runtime ?? "docker";
896
913
  this._connection = this.createConnectionConfig();
914
+ this.polyfillService = new CommandPolyfillService(this);
897
915
  }
898
916
  get id() {
899
917
  return this._id;
@@ -1000,18 +1018,22 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
1000
1018
  return this.create();
1001
1019
  }
1002
1020
  async create() {
1021
+ if (!this.createConfig) {
1022
+ throw new Error("createConfig is required to create a sandbox. Pass it as the third argument to createSandbox().");
1023
+ }
1024
+ const cfg = this.createConfig;
1003
1025
  try {
1004
1026
  this._status = { state: "Creating" };
1005
- const image = this.convertImageSpec(this.createConfig.image);
1006
- const resource = this.convertResourceLimits(this.createConfig.resourceLimits);
1027
+ const image = this.convertImageSpec(cfg.image);
1028
+ const resource = this.convertResourceLimits(cfg.resourceLimits);
1007
1029
  this._sandbox = await Sandbox.create({
1008
1030
  connectionConfig: this._connection,
1009
1031
  image,
1010
- entrypoint: this.createConfig.entrypoint,
1011
- timeoutSeconds: this.createConfig.timeout,
1032
+ entrypoint: cfg.entrypoint,
1033
+ timeoutSeconds: cfg.timeout,
1012
1034
  resource,
1013
- env: this.createConfig.env,
1014
- metadata: this.createConfig.metadata
1035
+ env: cfg.env,
1036
+ metadata: cfg.metadata
1015
1037
  });
1016
1038
  this._id = this._sandbox.id;
1017
1039
  this._status = { state: "Running" };
@@ -1067,6 +1089,33 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
1067
1089
  throw new CommandExecutionError("Failed to delete sandbox", "delete", error instanceof Error ? error : undefined);
1068
1090
  }
1069
1091
  }
1092
+ async close() {
1093
+ if (this._sandbox) {
1094
+ await this._sandbox.close();
1095
+ }
1096
+ }
1097
+ async getEndpoint(port) {
1098
+ const sdkEndpoint = await this.sandbox.getEndpoint(port);
1099
+ return this.convertSdkEndpoint(sdkEndpoint, port);
1100
+ }
1101
+ convertSdkEndpoint(sdkEndpoint, requestedPort) {
1102
+ const raw = sdkEndpoint.endpoint;
1103
+ const colonIdx = raw.lastIndexOf(":");
1104
+ const hasPathBeforeColon = colonIdx !== -1 && raw.slice(0, colonIdx).includes("/");
1105
+ if (colonIdx !== -1 && !hasPathBeforeColon) {
1106
+ const host = raw.slice(0, colonIdx);
1107
+ const parsedPort = parseInt(raw.slice(colonIdx + 1), 10);
1108
+ const port = isNaN(parsedPort) ? requestedPort : parsedPort;
1109
+ const protocol = port === 443 ? "https" : "http";
1110
+ return { host, port, protocol, url: `${protocol}://${raw}` };
1111
+ }
1112
+ return {
1113
+ host: raw,
1114
+ port: requestedPort,
1115
+ protocol: "https",
1116
+ url: `https://${raw}`
1117
+ };
1118
+ }
1070
1119
  async getInfo() {
1071
1120
  if (!this._sandbox)
1072
1121
  return null;
@@ -1083,7 +1132,7 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
1083
1132
  resourceLimits: this.parseResourceLimits(info.resourceLimits)
1084
1133
  };
1085
1134
  } catch (error) {
1086
- throw new CommandExecutionError(`Failed to get sandbox info: ${error?.message || error?.code}`, "getInfo", error instanceof Error ? error : undefined);
1135
+ throw new CommandExecutionError(`Failed to get sandbox info`, "getInfo", error instanceof Error ? error : undefined);
1087
1136
  }
1088
1137
  }
1089
1138
  async renewExpiration(additionalSeconds) {
@@ -1212,9 +1261,11 @@ function createSandbox(provider, config, createConfig) {
1212
1261
  export {
1213
1262
  createSandbox,
1214
1263
  TimeoutError,
1264
+ SealosDevboxAdapter,
1215
1265
  SandboxStateError,
1216
1266
  SandboxReadyTimeoutError,
1217
1267
  SandboxException,
1268
+ OpenSandboxAdapter,
1218
1269
  FileOperationError,
1219
1270
  FeatureNotSupportedError,
1220
1271
  ConnectionError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastgpt-sdk/sandbox-adapter",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Unified abstraction layer for cloud sandbox providers with adapter pattern and feature polyfilling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",