@alibaba-group/opensandbox 0.1.4 → 0.1.6
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/README.md +102 -34
- package/dist/{chunk-OYTPXLWE.js → chunk-AFWIGM3C.js} +139 -29
- package/dist/chunk-AFWIGM3C.js.map +1 -0
- package/dist/cjs/index.cjs +277 -53
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/internal.cjs +137 -28
- package/dist/cjs/internal.cjs.map +1 -1
- package/dist/index.d.ts +33 -8
- package/dist/index.js +140 -25
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +292 -15
- package/dist/internal.js +1 -1
- package/dist/{sandboxes-Dc0G4ShU.d.ts → sandboxes-C-AZxcv6.d.ts} +234 -158
- package/package.json +4 -2
- package/src/adapters/commandsAdapter.ts +189 -27
- package/src/adapters/egressAdapter.ts +46 -0
- package/src/adapters/sandboxesAdapter.ts +8 -3
- package/src/api/egress.ts +184 -0
- package/src/api/execd.ts +216 -1
- package/src/api/lifecycle.ts +59 -13
- package/src/core/constants.ts +2 -1
- package/src/core/exceptions.ts +5 -4
- package/src/factory/adapterFactory.ts +13 -1
- package/src/factory/defaultAdapterFactory.ts +27 -2
- package/src/index.ts +3 -1
- package/src/models/execd.ts +12 -0
- package/src/models/execution.ts +2 -1
- package/src/models/sandboxes.ts +52 -7
- package/src/openapi/egressClient.ts +45 -0
- package/src/sandbox.ts +102 -25
- package/src/services/egress.ts +27 -0
- package/src/services/execdCommands.ts +27 -1
- package/src/services/sandboxes.ts +1 -1
- package/dist/chunk-OYTPXLWE.js.map +0 -1
package/dist/cjs/internal.cjs
CHANGED
|
@@ -90,25 +90,26 @@ var SandboxException = class extends Error {
|
|
|
90
90
|
name = "SandboxException";
|
|
91
91
|
error;
|
|
92
92
|
cause;
|
|
93
|
+
requestId;
|
|
93
94
|
constructor(opts = {}) {
|
|
94
95
|
super(opts.message);
|
|
95
96
|
this.cause = opts.cause;
|
|
96
97
|
this.error = opts.error ?? new SandboxError(SandboxError.INTERNAL_UNKNOWN_ERROR);
|
|
98
|
+
this.requestId = opts.requestId;
|
|
97
99
|
}
|
|
98
100
|
};
|
|
99
101
|
var SandboxApiException = class extends SandboxException {
|
|
100
102
|
name = "SandboxApiException";
|
|
101
103
|
statusCode;
|
|
102
|
-
requestId;
|
|
103
104
|
rawBody;
|
|
104
105
|
constructor(opts) {
|
|
105
106
|
super({
|
|
106
107
|
message: opts.message,
|
|
107
108
|
cause: opts.cause,
|
|
108
|
-
error: opts.error ?? new SandboxError(SandboxError.UNEXPECTED_RESPONSE, opts.message)
|
|
109
|
+
error: opts.error ?? new SandboxError(SandboxError.UNEXPECTED_RESPONSE, opts.message),
|
|
110
|
+
requestId: opts.requestId
|
|
109
111
|
});
|
|
110
112
|
this.statusCode = opts.statusCode;
|
|
111
|
-
this.requestId = opts.requestId;
|
|
112
113
|
this.rawBody = opts.rawBody;
|
|
113
114
|
}
|
|
114
115
|
};
|
|
@@ -153,11 +154,15 @@ var SandboxesAdapter = class {
|
|
|
153
154
|
}
|
|
154
155
|
return d;
|
|
155
156
|
}
|
|
157
|
+
parseOptionalIsoDate(field, v) {
|
|
158
|
+
if (v == null) return null;
|
|
159
|
+
return this.parseIsoDate(field, v);
|
|
160
|
+
}
|
|
156
161
|
mapSandboxInfo(raw) {
|
|
157
162
|
return {
|
|
158
163
|
...raw ?? {},
|
|
159
164
|
createdAt: this.parseIsoDate("createdAt", raw?.createdAt),
|
|
160
|
-
expiresAt: this.
|
|
165
|
+
expiresAt: this.parseOptionalIsoDate("expiresAt", raw?.expiresAt)
|
|
161
166
|
};
|
|
162
167
|
}
|
|
163
168
|
async createSandbox(req) {
|
|
@@ -173,7 +178,7 @@ var SandboxesAdapter = class {
|
|
|
173
178
|
return {
|
|
174
179
|
...raw ?? {},
|
|
175
180
|
createdAt: this.parseIsoDate("createdAt", raw?.createdAt),
|
|
176
|
-
expiresAt: this.
|
|
181
|
+
expiresAt: this.parseOptionalIsoDate("expiresAt", raw?.expiresAt)
|
|
177
182
|
};
|
|
178
183
|
}
|
|
179
184
|
async getSandbox(sandboxId) {
|
|
@@ -858,6 +863,9 @@ function joinUrl2(baseUrl, pathname) {
|
|
|
858
863
|
return `${base}${path}`;
|
|
859
864
|
}
|
|
860
865
|
function toRunCommandRequest(command, opts) {
|
|
866
|
+
if (opts?.gid != null && opts.uid == null) {
|
|
867
|
+
throw new Error("uid is required when gid is provided");
|
|
868
|
+
}
|
|
861
869
|
const body = {
|
|
862
870
|
command,
|
|
863
871
|
cwd: opts?.workingDirectory,
|
|
@@ -866,8 +874,39 @@ function toRunCommandRequest(command, opts) {
|
|
|
866
874
|
if (opts?.timeoutSeconds != null) {
|
|
867
875
|
body.timeout = Math.round(opts.timeoutSeconds * 1e3);
|
|
868
876
|
}
|
|
877
|
+
if (opts?.uid != null) {
|
|
878
|
+
body.uid = opts.uid;
|
|
879
|
+
}
|
|
880
|
+
if (opts?.gid != null) {
|
|
881
|
+
body.gid = opts.gid;
|
|
882
|
+
}
|
|
883
|
+
if (opts?.envs != null) {
|
|
884
|
+
body.envs = opts.envs;
|
|
885
|
+
}
|
|
886
|
+
return body;
|
|
887
|
+
}
|
|
888
|
+
function toRunInSessionRequest(command, opts) {
|
|
889
|
+
const body = {
|
|
890
|
+
command
|
|
891
|
+
};
|
|
892
|
+
if (opts?.workingDirectory != null) {
|
|
893
|
+
body.cwd = opts.workingDirectory;
|
|
894
|
+
}
|
|
895
|
+
if (opts?.timeoutSeconds != null) {
|
|
896
|
+
body.timeout = Math.round(opts.timeoutSeconds * 1e3);
|
|
897
|
+
}
|
|
869
898
|
return body;
|
|
870
899
|
}
|
|
900
|
+
function inferForegroundExitCode(execution) {
|
|
901
|
+
const errorValue = execution.error?.value?.trim();
|
|
902
|
+
const parsedExitCode = errorValue && /^-?\d+$/.test(errorValue) ? Number(errorValue) : Number.NaN;
|
|
903
|
+
return execution.error != null ? Number.isFinite(parsedExitCode) ? parsedExitCode : null : execution.complete ? 0 : null;
|
|
904
|
+
}
|
|
905
|
+
function assertNonBlank(value, field) {
|
|
906
|
+
if (!value.trim()) {
|
|
907
|
+
throw new Error(`${field} cannot be empty`);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
871
910
|
function parseOptionalDate(value, field) {
|
|
872
911
|
if (value == null) return void 0;
|
|
873
912
|
if (value instanceof Date) return value;
|
|
@@ -887,6 +926,58 @@ var CommandsAdapter = class {
|
|
|
887
926
|
this.fetch = opts.fetch ?? fetch;
|
|
888
927
|
}
|
|
889
928
|
fetch;
|
|
929
|
+
buildRunStreamSpec(command, opts) {
|
|
930
|
+
assertNonBlank(command, "command");
|
|
931
|
+
return {
|
|
932
|
+
pathname: "/command",
|
|
933
|
+
body: toRunCommandRequest(command, opts),
|
|
934
|
+
fallbackErrorMessage: "Run command failed"
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
buildRunInSessionStreamSpec(sessionId, command, opts) {
|
|
938
|
+
assertNonBlank(sessionId, "sessionId");
|
|
939
|
+
assertNonBlank(command, "command");
|
|
940
|
+
return {
|
|
941
|
+
pathname: `/session/${encodeURIComponent(sessionId)}/run`,
|
|
942
|
+
body: toRunInSessionRequest(command, opts),
|
|
943
|
+
fallbackErrorMessage: "Run in session failed"
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
async *streamExecution(spec, signal) {
|
|
947
|
+
const url = joinUrl2(this.opts.baseUrl, spec.pathname);
|
|
948
|
+
const res = await this.fetch(url, {
|
|
949
|
+
method: "POST",
|
|
950
|
+
headers: {
|
|
951
|
+
accept: "text/event-stream",
|
|
952
|
+
"content-type": "application/json",
|
|
953
|
+
...this.opts.headers ?? {}
|
|
954
|
+
},
|
|
955
|
+
body: JSON.stringify(spec.body),
|
|
956
|
+
signal
|
|
957
|
+
});
|
|
958
|
+
for await (const ev of parseJsonEventStream(res, {
|
|
959
|
+
fallbackErrorMessage: spec.fallbackErrorMessage
|
|
960
|
+
})) {
|
|
961
|
+
yield ev;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
async consumeExecutionStream(stream, handlers, inferExitCode = false) {
|
|
965
|
+
const execution = {
|
|
966
|
+
logs: { stdout: [], stderr: [] },
|
|
967
|
+
result: []
|
|
968
|
+
};
|
|
969
|
+
const dispatcher = new ExecutionEventDispatcher(execution, handlers);
|
|
970
|
+
for await (const ev of stream) {
|
|
971
|
+
if (ev.type === "init" && (ev.text ?? "") === "" && execution.id) {
|
|
972
|
+
ev.text = execution.id;
|
|
973
|
+
}
|
|
974
|
+
await dispatcher.dispatch(ev);
|
|
975
|
+
}
|
|
976
|
+
if (inferExitCode) {
|
|
977
|
+
execution.exitCode = inferForegroundExitCode(execution);
|
|
978
|
+
}
|
|
979
|
+
return execution;
|
|
980
|
+
}
|
|
890
981
|
async interrupt(sessionId) {
|
|
891
982
|
const { error, response } = await this.client.DELETE("/command", {
|
|
892
983
|
params: { query: { id: sessionId } }
|
|
@@ -930,35 +1021,53 @@ var CommandsAdapter = class {
|
|
|
930
1021
|
};
|
|
931
1022
|
}
|
|
932
1023
|
async *runStream(command, opts, signal) {
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
const res = await this.fetch(url, {
|
|
936
|
-
method: "POST",
|
|
937
|
-
headers: {
|
|
938
|
-
"accept": "text/event-stream",
|
|
939
|
-
"content-type": "application/json",
|
|
940
|
-
...this.opts.headers ?? {}
|
|
941
|
-
},
|
|
942
|
-
body,
|
|
1024
|
+
for await (const ev of this.streamExecution(
|
|
1025
|
+
this.buildRunStreamSpec(command, opts),
|
|
943
1026
|
signal
|
|
944
|
-
|
|
945
|
-
for await (const ev of parseJsonEventStream(res, { fallbackErrorMessage: "Run command failed" })) {
|
|
1027
|
+
)) {
|
|
946
1028
|
yield ev;
|
|
947
1029
|
}
|
|
948
1030
|
}
|
|
949
1031
|
async run(command, opts, handlers, signal) {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1032
|
+
return this.consumeExecutionStream(
|
|
1033
|
+
this.runStream(command, opts, signal),
|
|
1034
|
+
handlers,
|
|
1035
|
+
!opts?.background
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
async createSession(options) {
|
|
1039
|
+
const body = options?.workingDirectory != null ? { cwd: options.workingDirectory } : {};
|
|
1040
|
+
const { data, error, response } = await this.client.POST("/session", {
|
|
1041
|
+
body
|
|
1042
|
+
});
|
|
1043
|
+
throwOnOpenApiFetchError({ error, response }, "Create session failed");
|
|
1044
|
+
const ok = data;
|
|
1045
|
+
if (!ok || typeof ok.session_id !== "string") {
|
|
1046
|
+
throw new Error("Create session failed: unexpected response shape");
|
|
960
1047
|
}
|
|
961
|
-
return
|
|
1048
|
+
return ok.session_id;
|
|
1049
|
+
}
|
|
1050
|
+
async *runInSessionStream(sessionId, command, opts, signal) {
|
|
1051
|
+
for await (const ev of this.streamExecution(
|
|
1052
|
+
this.buildRunInSessionStreamSpec(sessionId, command, opts),
|
|
1053
|
+
signal
|
|
1054
|
+
)) {
|
|
1055
|
+
yield ev;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
async runInSession(sessionId, command, options, handlers, signal) {
|
|
1059
|
+
return this.consumeExecutionStream(
|
|
1060
|
+
this.runInSessionStream(sessionId, command, options, signal),
|
|
1061
|
+
handlers,
|
|
1062
|
+
true
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
async deleteSession(sessionId) {
|
|
1066
|
+
const { error, response } = await this.client.DELETE(
|
|
1067
|
+
"/session/{sessionId}",
|
|
1068
|
+
{ params: { path: { sessionId } } }
|
|
1069
|
+
);
|
|
1070
|
+
throwOnOpenApiFetchError({ error, response }, "Delete session failed");
|
|
962
1071
|
}
|
|
963
1072
|
};
|
|
964
1073
|
// Annotate the CommonJS export names for ESM import in node:
|