@fastgpt-sdk/sandbox-adapter 0.0.39 → 0.0.40-beta.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.
@@ -74,6 +74,8 @@ export declare class OpenSandboxAdapter extends BaseSandboxAdapter {
74
74
  private parseResourceLimits;
75
75
  private extractExitCode;
76
76
  private getSandboxBySessionId;
77
+ private waitUntilSessionDeleted;
78
+ private killSandboxById;
77
79
  ensureRunning(): Promise<void>;
78
80
  create(): Promise<void>;
79
81
  connect(sandboxId: string): Promise<void>;
@@ -36,6 +36,7 @@ export declare class SealosDevboxAdapter extends BaseSandboxAdapter {
36
36
  private StatusAdapt;
37
37
  private buildCreateRequest;
38
38
  private removeUndefined;
39
+ private assertMutationSuccess;
39
40
  getInfo(): Promise<SandboxInfo | null>;
40
41
  ensureRunning(): Promise<void>;
41
42
  create(): Promise<void>;
package/dist/index.cjs CHANGED
@@ -17393,7 +17393,7 @@ var require_fetch = __commonJS((exports2, module2) => {
17393
17393
  request.cache = "no-store";
17394
17394
  }
17395
17395
  const newConnection = forceNewConnection ? "yes" : "no";
17396
- if (request.mode === "websocket") {} else {}
17396
+ if (request.mode === "websocket") {}
17397
17397
  let requestBody = null;
17398
17398
  if (request.body == null && fetchParams.processRequestEndOfBody) {
17399
17399
  queueMicrotask(() => fetchParams.processRequestEndOfBody());
@@ -45788,8 +45788,12 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45788
45788
  case "Pending" /* Pending */:
45789
45789
  return "Creating";
45790
45790
  case "Paused" /* Paused */:
45791
+ case "Stopped" /* Stopped */:
45792
+ case "Shutdown" /* Shutdown */:
45791
45793
  return "Stopped";
45792
45794
  case "Pausing" /* Pausing */:
45795
+ case "Stopping" /* Stopping */:
45796
+ case "Shutting" /* Shutting */:
45793
45797
  return "Stopping";
45794
45798
  default:
45795
45799
  return "Error";
@@ -45815,6 +45819,12 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45815
45819
  removeUndefined(obj) {
45816
45820
  return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
45817
45821
  }
45822
+ assertMutationSuccess(res, action, okCodes = []) {
45823
+ if (res.code >= 200 && res.code < 300 || okCodes.includes(res.code)) {
45824
+ return;
45825
+ }
45826
+ throw new Error(res.message || `Devbox ${action} failed with code ${res.code}`);
45827
+ }
45818
45828
  async getInfo() {
45819
45829
  try {
45820
45830
  const res = await this.api.info(this._id);
@@ -45823,7 +45833,11 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45823
45833
  if (!res.data)
45824
45834
  return Promise.reject(res.message);
45825
45835
  const data = res.data;
45826
- this._status = { state: this.StatusAdapt(data), message: res.message };
45836
+ this._status = {
45837
+ state: this.StatusAdapt(data),
45838
+ reason: data.state.phase,
45839
+ message: res.message
45840
+ };
45827
45841
  return {
45828
45842
  id: data.name,
45829
45843
  image: parseImageSpec(data.image),
@@ -45855,12 +45869,17 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45855
45869
  await this.waitUntilDeleted();
45856
45870
  await this.create();
45857
45871
  return;
45872
+ case "Error":
45873
+ throw new ConnectionError(`Sandbox ${sandbox.id} is in error state: ${sandbox.status.reason ?? sandbox.status.message ?? "unknown"}`, this.config.baseUrl);
45858
45874
  default:
45859
- throw new ConnectionError(`Failed to ensure sandbox running`);
45875
+ throw new ConnectionError(`Sandbox state ${status} not supported`, this.config.baseUrl);
45860
45876
  }
45861
45877
  }
45862
45878
  await this.create();
45863
45879
  } catch (error) {
45880
+ if (error instanceof ConnectionError) {
45881
+ throw error;
45882
+ }
45864
45883
  throw new ConnectionError(`Failed to ensure sandbox running`, this.config.baseUrl, error);
45865
45884
  }
45866
45885
  }
@@ -45868,9 +45887,7 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45868
45887
  try {
45869
45888
  this._status = { state: "Creating" };
45870
45889
  const res = await this.api.create(this.buildCreateRequest());
45871
- if (res.code !== 200 && res.code !== 201) {
45872
- throw new Error(res.message || `Devbox create failed with code ${res.code}`);
45873
- }
45890
+ this.assertMutationSuccess(res, "create");
45874
45891
  await this.waitUntilReady();
45875
45892
  await new Promise((resolve) => setTimeout(resolve, 1000));
45876
45893
  this._status = { state: "Running" };
@@ -45881,7 +45898,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45881
45898
  async stop() {
45882
45899
  try {
45883
45900
  this._status = { state: "Stopping" };
45884
- await this.api.stop(this._id);
45901
+ const res = await this.api.stop(this._id);
45902
+ this.assertMutationSuccess(res, "stop");
45885
45903
  this._status = { state: "Stopped" };
45886
45904
  } catch (error) {
45887
45905
  throw new CommandExecutionError("Failed to stop sandbox", "stop", error instanceof Error ? error : undefined);
@@ -45890,7 +45908,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45890
45908
  async start() {
45891
45909
  try {
45892
45910
  this._status = { state: "Starting" };
45893
- await this.api.resume(this._id);
45911
+ const res = await this.api.resume(this._id);
45912
+ this.assertMutationSuccess(res, "resume");
45894
45913
  await this.waitUntilReady();
45895
45914
  this._status = { state: "Running" };
45896
45915
  } catch (error) {
@@ -45901,7 +45920,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45901
45920
  try {
45902
45921
  const targetId = sandboxId ?? this._id;
45903
45922
  this._status = { state: "Deleting" };
45904
- await this.api.delete(targetId);
45923
+ const res = await this.api.delete(targetId);
45924
+ this.assertMutationSuccess(res, "delete", [404]);
45905
45925
  this._id = targetId;
45906
45926
  await this.waitUntilDeleted();
45907
45927
  this._status = { state: "UnExist" };
@@ -48362,16 +48382,44 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48362
48382
  }
48363
48383
  async getSandboxBySessionId() {
48364
48384
  const manager = SandboxManager.create({ connectionConfig: this._connection });
48365
- const result = await manager.listSandboxInfos({
48366
- metadata: { sessionId: this.connectionConfig.sessionId }
48367
- });
48368
- const val = result.items[0];
48369
- if (val) {
48370
- const status = this.mapStatus(val.status);
48371
- return {
48372
- id: val.id,
48373
- status
48374
- };
48385
+ try {
48386
+ const result = await manager.listSandboxInfos({
48387
+ metadata: { sessionId: this.connectionConfig.sessionId }
48388
+ });
48389
+ const val = result.items[0];
48390
+ if (val) {
48391
+ const status = this.mapStatus(val.status);
48392
+ return {
48393
+ id: val.id,
48394
+ status
48395
+ };
48396
+ }
48397
+ } finally {
48398
+ await manager.close().catch(() => {
48399
+ return;
48400
+ });
48401
+ }
48402
+ }
48403
+ async waitUntilSessionDeleted(timeoutMs = 120000) {
48404
+ const startTime = Date.now();
48405
+ const checkInterval = 1000;
48406
+ while (Date.now() - startTime < timeoutMs) {
48407
+ const sandbox = await this.getSandboxBySessionId();
48408
+ if (!sandbox) {
48409
+ return;
48410
+ }
48411
+ await this.sleep(checkInterval);
48412
+ }
48413
+ throw new SandboxStateError(`Sandbox session ${this.connectionConfig.sessionId} was not deleted within ${timeoutMs}ms`, "Deleting", "UnExist");
48414
+ }
48415
+ async killSandboxById(sandboxId) {
48416
+ const manager = SandboxManager.create({ connectionConfig: this._connection });
48417
+ try {
48418
+ await manager.killSandbox(sandboxId);
48419
+ } finally {
48420
+ await manager.close().catch(() => {
48421
+ return;
48422
+ });
48375
48423
  }
48376
48424
  }
48377
48425
  async ensureRunning() {
@@ -48386,14 +48434,14 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48386
48434
  break;
48387
48435
  case "Creating":
48388
48436
  case "Starting":
48389
- await this.waitUntilReady();
48437
+ await this.connect(sandbox.id);
48390
48438
  break;
48391
48439
  case "Stopping":
48392
48440
  case "Stopped":
48393
48441
  await this.resume(sandbox.id);
48394
48442
  break;
48395
48443
  case "Deleting":
48396
- await this.waitUntilDeleted();
48444
+ await this.waitUntilSessionDeleted();
48397
48445
  await this.create();
48398
48446
  break;
48399
48447
  case "Error":
@@ -48490,7 +48538,15 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48490
48538
  async stop() {
48491
48539
  try {
48492
48540
  this._status = { state: "Stopping" };
48493
- await this.sandbox.kill();
48541
+ const existing = await this.getSandboxBySessionId();
48542
+ if (!existing) {
48543
+ this._status = { state: "Stopped" };
48544
+ return;
48545
+ }
48546
+ await this.killSandboxById(existing.id);
48547
+ if (existing.id === this._id) {
48548
+ this.sandbox = undefined;
48549
+ }
48494
48550
  this._status = { state: "Stopped" };
48495
48551
  } catch (error) {
48496
48552
  const message = error instanceof SandboxException2 ? error.error.message : undefined;
@@ -48506,23 +48562,22 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48506
48562
  async delete(sandboxId) {
48507
48563
  try {
48508
48564
  this._status = { state: "Deleting" };
48509
- if (sandboxId) {
48510
- const manager = SandboxManager.create({ connectionConfig: this._connection });
48511
- try {
48512
- await manager.killSandbox(sandboxId);
48513
- } finally {
48514
- await manager.close().catch(() => {
48515
- return;
48516
- });
48517
- }
48518
- if (sandboxId === this._id) {
48565
+ const targetId = sandboxId ?? this._id;
48566
+ if (targetId) {
48567
+ await this.killSandboxById(targetId);
48568
+ if (targetId === this._id) {
48519
48569
  this.sandbox = undefined;
48520
48570
  }
48521
48571
  this._status = { state: "UnExist" };
48522
48572
  return;
48523
48573
  }
48524
- await this.sandbox.kill();
48525
- this.sandbox = undefined;
48574
+ const existing = await this.getSandboxBySessionId();
48575
+ if (existing) {
48576
+ await this.killSandboxById(existing.id);
48577
+ if (existing.id === this._id) {
48578
+ this.sandbox = undefined;
48579
+ }
48580
+ }
48526
48581
  this._status = { state: "UnExist" };
48527
48582
  } catch (error) {
48528
48583
  throw new CommandExecutionError("Failed to delete sandbox", "delete", error instanceof Error ? error : undefined);
package/dist/index.js CHANGED
@@ -17395,7 +17395,7 @@ var require_fetch = __commonJS((exports, module) => {
17395
17395
  request.cache = "no-store";
17396
17396
  }
17397
17397
  const newConnection = forceNewConnection ? "yes" : "no";
17398
- if (request.mode === "websocket") {} else {}
17398
+ if (request.mode === "websocket") {}
17399
17399
  let requestBody = null;
17400
17400
  if (request.body == null && fetchParams.processRequestEndOfBody) {
17401
17401
  queueMicrotask(() => fetchParams.processRequestEndOfBody());
@@ -45772,8 +45772,12 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45772
45772
  case "Pending" /* Pending */:
45773
45773
  return "Creating";
45774
45774
  case "Paused" /* Paused */:
45775
+ case "Stopped" /* Stopped */:
45776
+ case "Shutdown" /* Shutdown */:
45775
45777
  return "Stopped";
45776
45778
  case "Pausing" /* Pausing */:
45779
+ case "Stopping" /* Stopping */:
45780
+ case "Shutting" /* Shutting */:
45777
45781
  return "Stopping";
45778
45782
  default:
45779
45783
  return "Error";
@@ -45799,6 +45803,12 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45799
45803
  removeUndefined(obj) {
45800
45804
  return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
45801
45805
  }
45806
+ assertMutationSuccess(res, action, okCodes = []) {
45807
+ if (res.code >= 200 && res.code < 300 || okCodes.includes(res.code)) {
45808
+ return;
45809
+ }
45810
+ throw new Error(res.message || `Devbox ${action} failed with code ${res.code}`);
45811
+ }
45802
45812
  async getInfo() {
45803
45813
  try {
45804
45814
  const res = await this.api.info(this._id);
@@ -45807,7 +45817,11 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45807
45817
  if (!res.data)
45808
45818
  return Promise.reject(res.message);
45809
45819
  const data = res.data;
45810
- this._status = { state: this.StatusAdapt(data), message: res.message };
45820
+ this._status = {
45821
+ state: this.StatusAdapt(data),
45822
+ reason: data.state.phase,
45823
+ message: res.message
45824
+ };
45811
45825
  return {
45812
45826
  id: data.name,
45813
45827
  image: parseImageSpec(data.image),
@@ -45839,12 +45853,17 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45839
45853
  await this.waitUntilDeleted();
45840
45854
  await this.create();
45841
45855
  return;
45856
+ case "Error":
45857
+ throw new ConnectionError(`Sandbox ${sandbox.id} is in error state: ${sandbox.status.reason ?? sandbox.status.message ?? "unknown"}`, this.config.baseUrl);
45842
45858
  default:
45843
- throw new ConnectionError(`Failed to ensure sandbox running`);
45859
+ throw new ConnectionError(`Sandbox state ${status} not supported`, this.config.baseUrl);
45844
45860
  }
45845
45861
  }
45846
45862
  await this.create();
45847
45863
  } catch (error) {
45864
+ if (error instanceof ConnectionError) {
45865
+ throw error;
45866
+ }
45848
45867
  throw new ConnectionError(`Failed to ensure sandbox running`, this.config.baseUrl, error);
45849
45868
  }
45850
45869
  }
@@ -45852,9 +45871,7 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45852
45871
  try {
45853
45872
  this._status = { state: "Creating" };
45854
45873
  const res = await this.api.create(this.buildCreateRequest());
45855
- if (res.code !== 200 && res.code !== 201) {
45856
- throw new Error(res.message || `Devbox create failed with code ${res.code}`);
45857
- }
45874
+ this.assertMutationSuccess(res, "create");
45858
45875
  await this.waitUntilReady();
45859
45876
  await new Promise((resolve) => setTimeout(resolve, 1000));
45860
45877
  this._status = { state: "Running" };
@@ -45865,7 +45882,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45865
45882
  async stop() {
45866
45883
  try {
45867
45884
  this._status = { state: "Stopping" };
45868
- await this.api.stop(this._id);
45885
+ const res = await this.api.stop(this._id);
45886
+ this.assertMutationSuccess(res, "stop");
45869
45887
  this._status = { state: "Stopped" };
45870
45888
  } catch (error) {
45871
45889
  throw new CommandExecutionError("Failed to stop sandbox", "stop", error instanceof Error ? error : undefined);
@@ -45874,7 +45892,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45874
45892
  async start() {
45875
45893
  try {
45876
45894
  this._status = { state: "Starting" };
45877
- await this.api.resume(this._id);
45895
+ const res = await this.api.resume(this._id);
45896
+ this.assertMutationSuccess(res, "resume");
45878
45897
  await this.waitUntilReady();
45879
45898
  this._status = { state: "Running" };
45880
45899
  } catch (error) {
@@ -45885,7 +45904,8 @@ class SealosDevboxAdapter extends BaseSandboxAdapter {
45885
45904
  try {
45886
45905
  const targetId = sandboxId ?? this._id;
45887
45906
  this._status = { state: "Deleting" };
45888
- await this.api.delete(targetId);
45907
+ const res = await this.api.delete(targetId);
45908
+ this.assertMutationSuccess(res, "delete", [404]);
45889
45909
  this._id = targetId;
45890
45910
  await this.waitUntilDeleted();
45891
45911
  this._status = { state: "UnExist" };
@@ -48346,16 +48366,44 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48346
48366
  }
48347
48367
  async getSandboxBySessionId() {
48348
48368
  const manager = SandboxManager.create({ connectionConfig: this._connection });
48349
- const result = await manager.listSandboxInfos({
48350
- metadata: { sessionId: this.connectionConfig.sessionId }
48351
- });
48352
- const val = result.items[0];
48353
- if (val) {
48354
- const status = this.mapStatus(val.status);
48355
- return {
48356
- id: val.id,
48357
- status
48358
- };
48369
+ try {
48370
+ const result = await manager.listSandboxInfos({
48371
+ metadata: { sessionId: this.connectionConfig.sessionId }
48372
+ });
48373
+ const val = result.items[0];
48374
+ if (val) {
48375
+ const status = this.mapStatus(val.status);
48376
+ return {
48377
+ id: val.id,
48378
+ status
48379
+ };
48380
+ }
48381
+ } finally {
48382
+ await manager.close().catch(() => {
48383
+ return;
48384
+ });
48385
+ }
48386
+ }
48387
+ async waitUntilSessionDeleted(timeoutMs = 120000) {
48388
+ const startTime = Date.now();
48389
+ const checkInterval = 1000;
48390
+ while (Date.now() - startTime < timeoutMs) {
48391
+ const sandbox = await this.getSandboxBySessionId();
48392
+ if (!sandbox) {
48393
+ return;
48394
+ }
48395
+ await this.sleep(checkInterval);
48396
+ }
48397
+ throw new SandboxStateError(`Sandbox session ${this.connectionConfig.sessionId} was not deleted within ${timeoutMs}ms`, "Deleting", "UnExist");
48398
+ }
48399
+ async killSandboxById(sandboxId) {
48400
+ const manager = SandboxManager.create({ connectionConfig: this._connection });
48401
+ try {
48402
+ await manager.killSandbox(sandboxId);
48403
+ } finally {
48404
+ await manager.close().catch(() => {
48405
+ return;
48406
+ });
48359
48407
  }
48360
48408
  }
48361
48409
  async ensureRunning() {
@@ -48370,14 +48418,14 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48370
48418
  break;
48371
48419
  case "Creating":
48372
48420
  case "Starting":
48373
- await this.waitUntilReady();
48421
+ await this.connect(sandbox.id);
48374
48422
  break;
48375
48423
  case "Stopping":
48376
48424
  case "Stopped":
48377
48425
  await this.resume(sandbox.id);
48378
48426
  break;
48379
48427
  case "Deleting":
48380
- await this.waitUntilDeleted();
48428
+ await this.waitUntilSessionDeleted();
48381
48429
  await this.create();
48382
48430
  break;
48383
48431
  case "Error":
@@ -48474,7 +48522,15 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48474
48522
  async stop() {
48475
48523
  try {
48476
48524
  this._status = { state: "Stopping" };
48477
- await this.sandbox.kill();
48525
+ const existing = await this.getSandboxBySessionId();
48526
+ if (!existing) {
48527
+ this._status = { state: "Stopped" };
48528
+ return;
48529
+ }
48530
+ await this.killSandboxById(existing.id);
48531
+ if (existing.id === this._id) {
48532
+ this.sandbox = undefined;
48533
+ }
48478
48534
  this._status = { state: "Stopped" };
48479
48535
  } catch (error) {
48480
48536
  const message = error instanceof SandboxException2 ? error.error.message : undefined;
@@ -48490,23 +48546,22 @@ class OpenSandboxAdapter extends BaseSandboxAdapter {
48490
48546
  async delete(sandboxId) {
48491
48547
  try {
48492
48548
  this._status = { state: "Deleting" };
48493
- if (sandboxId) {
48494
- const manager = SandboxManager.create({ connectionConfig: this._connection });
48495
- try {
48496
- await manager.killSandbox(sandboxId);
48497
- } finally {
48498
- await manager.close().catch(() => {
48499
- return;
48500
- });
48501
- }
48502
- if (sandboxId === this._id) {
48549
+ const targetId = sandboxId ?? this._id;
48550
+ if (targetId) {
48551
+ await this.killSandboxById(targetId);
48552
+ if (targetId === this._id) {
48503
48553
  this.sandbox = undefined;
48504
48554
  }
48505
48555
  this._status = { state: "UnExist" };
48506
48556
  return;
48507
48557
  }
48508
- await this.sandbox.kill();
48509
- this.sandbox = undefined;
48558
+ const existing = await this.getSandboxBySessionId();
48559
+ if (existing) {
48560
+ await this.killSandboxById(existing.id);
48561
+ if (existing.id === this._id) {
48562
+ this.sandbox = undefined;
48563
+ }
48564
+ }
48510
48565
  this._status = { state: "UnExist" };
48511
48566
  } catch (error) {
48512
48567
  throw new CommandExecutionError("Failed to delete sandbox", "delete", error instanceof Error ? error : undefined);
@@ -28,7 +28,7 @@ export interface ISandboxLifecycle {
28
28
  /**
29
29
  * Delete the sandbox permanently.
30
30
  *
31
- * When `sandboxId` is provided, implementations should delete that provider
31
+ * When `sandboxId` is provided, implementations should delete that target
32
32
  * sandbox directly without requiring callers to first bind the adapter via
33
33
  * `connect()`.
34
34
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastgpt-sdk/sandbox-adapter",
3
- "version": "0.0.39",
3
+ "version": "0.0.40-beta.1",
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.cjs",