@alibaba-group/opensandbox 0.1.0-dev1

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.
Files changed (92) hide show
  1. package/README.md +212 -0
  2. package/dist/adapters/commandsAdapter.d.ts +22 -0
  3. package/dist/adapters/commandsAdapter.d.ts.map +1 -0
  4. package/dist/adapters/commandsAdapter.js +76 -0
  5. package/dist/adapters/filesystemAdapter.d.ts +52 -0
  6. package/dist/adapters/filesystemAdapter.d.ts.map +1 -0
  7. package/dist/adapters/filesystemAdapter.js +398 -0
  8. package/dist/adapters/healthAdapter.d.ts +8 -0
  9. package/dist/adapters/healthAdapter.d.ts.map +1 -0
  10. package/dist/adapters/healthAdapter.js +25 -0
  11. package/dist/adapters/metricsAdapter.d.ts +9 -0
  12. package/dist/adapters/metricsAdapter.d.ts.map +1 -0
  13. package/dist/adapters/metricsAdapter.js +43 -0
  14. package/dist/adapters/openapiError.d.ts +5 -0
  15. package/dist/adapters/openapiError.d.ts.map +1 -0
  16. package/dist/adapters/openapiError.js +33 -0
  17. package/dist/adapters/sandboxesAdapter.d.ts +18 -0
  18. package/dist/adapters/sandboxesAdapter.d.ts.map +1 -0
  19. package/dist/adapters/sandboxesAdapter.js +146 -0
  20. package/dist/adapters/sse.d.ts +9 -0
  21. package/dist/adapters/sse.d.ts.map +1 -0
  22. package/dist/adapters/sse.js +84 -0
  23. package/dist/api/execd.d.ts +1555 -0
  24. package/dist/api/execd.d.ts.map +1 -0
  25. package/dist/api/execd.js +14 -0
  26. package/dist/api/lifecycle.d.ts +787 -0
  27. package/dist/api/lifecycle.d.ts.map +1 -0
  28. package/dist/api/lifecycle.js +14 -0
  29. package/dist/config/connection.d.ts +58 -0
  30. package/dist/config/connection.d.ts.map +1 -0
  31. package/dist/config/connection.js +171 -0
  32. package/dist/core/constants.d.ts +9 -0
  33. package/dist/core/constants.d.ts.map +1 -0
  34. package/dist/core/constants.js +24 -0
  35. package/dist/core/exceptions.d.ts +74 -0
  36. package/dist/core/exceptions.d.ts.map +1 -0
  37. package/dist/core/exceptions.js +103 -0
  38. package/dist/factory/adapterFactory.d.ts +33 -0
  39. package/dist/factory/adapterFactory.d.ts.map +1 -0
  40. package/dist/factory/adapterFactory.js +14 -0
  41. package/dist/factory/defaultAdapterFactory.d.ts +7 -0
  42. package/dist/factory/defaultAdapterFactory.d.ts.map +1 -0
  43. package/dist/factory/defaultAdapterFactory.js +61 -0
  44. package/dist/index.d.ts +22 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +20 -0
  47. package/dist/internal.d.ts +22 -0
  48. package/dist/internal.d.ts.map +1 -0
  49. package/dist/internal.js +30 -0
  50. package/dist/manager.d.ts +40 -0
  51. package/dist/manager.d.ts.map +1 -0
  52. package/dist/manager.js +71 -0
  53. package/dist/models/execd.d.ts +54 -0
  54. package/dist/models/execd.d.ts.map +1 -0
  55. package/dist/models/execd.js +14 -0
  56. package/dist/models/execution.d.ts +52 -0
  57. package/dist/models/execution.d.ts.map +1 -0
  58. package/dist/models/execution.js +14 -0
  59. package/dist/models/executionEventDispatcher.d.ts +15 -0
  60. package/dist/models/executionEventDispatcher.d.ts.map +1 -0
  61. package/dist/models/executionEventDispatcher.js +95 -0
  62. package/dist/models/filesystem.d.ts +77 -0
  63. package/dist/models/filesystem.d.ts.map +1 -0
  64. package/dist/models/filesystem.js +14 -0
  65. package/dist/models/sandboxes.d.ts +105 -0
  66. package/dist/models/sandboxes.d.ts.map +1 -0
  67. package/dist/models/sandboxes.js +15 -0
  68. package/dist/openapi/execdClient.d.ts +25 -0
  69. package/dist/openapi/execdClient.d.ts.map +1 -0
  70. package/dist/openapi/execdClient.js +21 -0
  71. package/dist/openapi/lifecycleClient.d.ts +28 -0
  72. package/dist/openapi/lifecycleClient.d.ts.map +1 -0
  73. package/dist/openapi/lifecycleClient.js +35 -0
  74. package/dist/sandbox.d.ts +132 -0
  75. package/dist/sandbox.d.ts.map +1 -0
  76. package/dist/sandbox.js +250 -0
  77. package/dist/services/execdCommands.d.ts +19 -0
  78. package/dist/services/execdCommands.d.ts.map +1 -0
  79. package/dist/services/execdCommands.js +14 -0
  80. package/dist/services/execdHealth.d.ts +4 -0
  81. package/dist/services/execdHealth.d.ts.map +1 -0
  82. package/dist/services/execdHealth.js +14 -0
  83. package/dist/services/execdMetrics.d.ts +5 -0
  84. package/dist/services/execdMetrics.d.ts.map +1 -0
  85. package/dist/services/execdMetrics.js +14 -0
  86. package/dist/services/filesystem.d.ts +30 -0
  87. package/dist/services/filesystem.d.ts.map +1 -0
  88. package/dist/services/filesystem.js +14 -0
  89. package/dist/services/sandboxes.d.ts +12 -0
  90. package/dist/services/sandboxes.d.ts.map +1 -0
  91. package/dist/services/sandboxes.js +14 -0
  92. package/package.json +52 -0
@@ -0,0 +1,398 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { throwOnOpenApiFetchError } from "./openapiError.js";
15
+ import { SandboxApiException, SandboxError } from "../core/exceptions.js";
16
+ function joinUrl(baseUrl, pathname) {
17
+ const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
18
+ const path = pathname.startsWith("/") ? pathname : `/${pathname}`;
19
+ return `${base}${path}`;
20
+ }
21
+ function toUploadBlob(data) {
22
+ if (typeof data === "string")
23
+ return new Blob([data]);
24
+ if (data instanceof Blob)
25
+ return data;
26
+ if (data instanceof ArrayBuffer)
27
+ return new Blob([data]);
28
+ // Copy into a new Uint8Array backed by ArrayBuffer (not SharedArrayBuffer)
29
+ const copied = Uint8Array.from(data);
30
+ return new Blob([copied.buffer]);
31
+ }
32
+ function isReadableStream(v) {
33
+ return !!v && typeof v.getReader === "function";
34
+ }
35
+ function isAsyncIterable(v) {
36
+ return !!v && typeof v[Symbol.asyncIterator] === "function";
37
+ }
38
+ function toReadableStream(it) {
39
+ const RS = ReadableStream;
40
+ if (typeof RS?.from === "function")
41
+ return RS.from(it);
42
+ const iterator = it[Symbol.asyncIterator]();
43
+ return new ReadableStream({
44
+ async pull(controller) {
45
+ const r = await iterator.next();
46
+ if (r.done) {
47
+ controller.close();
48
+ return;
49
+ }
50
+ controller.enqueue(r.value);
51
+ },
52
+ async cancel() {
53
+ await iterator.return?.();
54
+ },
55
+ });
56
+ }
57
+ function basename(p) {
58
+ const parts = p.split("/").filter(Boolean);
59
+ return parts.length ? parts[parts.length - 1] : "file";
60
+ }
61
+ function encodeUtf8(s) {
62
+ return new TextEncoder().encode(s);
63
+ }
64
+ async function* multipartUploadBody(opts) {
65
+ const b = opts.boundary;
66
+ // Part 1: metadata (application/json)
67
+ yield encodeUtf8(`--${b}\r\n`);
68
+ yield encodeUtf8(`Content-Disposition: form-data; name="metadata"; filename="metadata"\r\n`);
69
+ yield encodeUtf8(`Content-Type: application/json\r\n\r\n`);
70
+ yield encodeUtf8(opts.metadataJson);
71
+ yield encodeUtf8(`\r\n`);
72
+ // Part 2: file
73
+ yield encodeUtf8(`--${b}\r\n`);
74
+ yield encodeUtf8(`Content-Disposition: form-data; name="file"; filename="${opts.fileName}"\r\n`);
75
+ yield encodeUtf8(`Content-Type: ${opts.fileContentType}\r\n\r\n`);
76
+ if (isReadableStream(opts.file)) {
77
+ const reader = opts.file.getReader();
78
+ try {
79
+ while (true) {
80
+ const { done, value } = await reader.read();
81
+ if (done)
82
+ break;
83
+ if (value)
84
+ yield value;
85
+ }
86
+ }
87
+ finally {
88
+ reader.releaseLock();
89
+ }
90
+ }
91
+ else {
92
+ for await (const chunk of opts.file) {
93
+ yield chunk;
94
+ }
95
+ }
96
+ yield encodeUtf8(`\r\n--${b}--\r\n`);
97
+ }
98
+ function toPermission(e) {
99
+ return {
100
+ mode: e.mode ?? 755,
101
+ owner: e.owner,
102
+ group: e.group,
103
+ };
104
+ }
105
+ /**
106
+ * Filesystem adapter that exposes user-facing file APIs (`sandbox.files`).
107
+ *
108
+ * This adapter owns all request/response conversions:
109
+ * - Maps friendly method shapes to API payloads
110
+ * - Parses timestamps into `Date`
111
+ * - Implements streaming upload/download helpers
112
+ */
113
+ export class FilesystemAdapter {
114
+ client;
115
+ opts;
116
+ fetch;
117
+ static Api = {
118
+ // This is intentionally derived from OpenAPI schema types so API changes surface quickly.
119
+ SearchFilesOk: null,
120
+ FilesInfoOk: null,
121
+ MakeDirsRequest: null,
122
+ SetPermissionsRequest: null,
123
+ MoveFilesRequest: null,
124
+ ReplaceContentsRequest: null,
125
+ };
126
+ constructor(client, opts) {
127
+ this.client = client;
128
+ this.opts = opts;
129
+ this.fetch = opts.fetch ?? fetch;
130
+ }
131
+ parseIsoDate(field, v) {
132
+ if (typeof v !== "string" || !v) {
133
+ throw new Error(`Invalid ${field}: expected ISO string, got ${typeof v}`);
134
+ }
135
+ const d = new Date(v);
136
+ if (Number.isNaN(d.getTime())) {
137
+ throw new Error(`Invalid ${field}: ${v}`);
138
+ }
139
+ return d;
140
+ }
141
+ static _ApiFileInfo = null;
142
+ mapApiFileInfo(raw) {
143
+ const { path, size, created_at, modified_at, mode, owner, group, ...rest } = raw;
144
+ return {
145
+ ...rest,
146
+ path,
147
+ size,
148
+ mode,
149
+ owner,
150
+ group,
151
+ createdAt: created_at
152
+ ? this.parseIsoDate("createdAt", created_at)
153
+ : undefined,
154
+ modifiedAt: modified_at
155
+ ? this.parseIsoDate("modifiedAt", modified_at)
156
+ : undefined,
157
+ };
158
+ }
159
+ async getFileInfo(paths) {
160
+ const { data, error, response } = await this.client.GET("/files/info", {
161
+ params: { query: { path: paths } },
162
+ });
163
+ throwOnOpenApiFetchError({ error, response }, "Get file info failed");
164
+ const raw = data;
165
+ if (!raw)
166
+ return {};
167
+ if (typeof raw !== "object") {
168
+ throw new Error(`Get file info failed: unexpected response shape (got ${typeof raw})`);
169
+ }
170
+ const out = {};
171
+ for (const [k, v] of Object.entries(raw)) {
172
+ if (!v || typeof v !== "object") {
173
+ throw new Error(`Get file info failed: invalid file info for path=${k}`);
174
+ }
175
+ out[k] = this.mapApiFileInfo(v);
176
+ }
177
+ return out;
178
+ }
179
+ async deleteFiles(paths) {
180
+ const { error, response } = await this.client.DELETE("/files", {
181
+ params: { query: { path: paths } },
182
+ });
183
+ throwOnOpenApiFetchError({ error, response }, "Delete files failed");
184
+ }
185
+ async createDirectories(entries) {
186
+ const map = {};
187
+ for (const e of entries) {
188
+ map[e.path] = toPermission(e);
189
+ }
190
+ const body = map;
191
+ const { error, response } = await this.client.POST("/directories", {
192
+ body,
193
+ });
194
+ throwOnOpenApiFetchError({ error, response }, "Create directories failed");
195
+ }
196
+ async deleteDirectories(paths) {
197
+ const { error, response } = await this.client.DELETE("/directories", {
198
+ params: { query: { path: paths } },
199
+ });
200
+ throwOnOpenApiFetchError({ error, response }, "Delete directories failed");
201
+ }
202
+ async setPermissions(entries) {
203
+ const req = {};
204
+ for (const e of entries) {
205
+ req[e.path] = toPermission(e);
206
+ }
207
+ const body = req;
208
+ const { error, response } = await this.client.POST("/files/permissions", {
209
+ body,
210
+ });
211
+ throwOnOpenApiFetchError({ error, response }, "Set permissions failed");
212
+ }
213
+ async moveFiles(entries) {
214
+ const req = entries.map((e) => ({
215
+ src: e.src,
216
+ dest: e.dest,
217
+ }));
218
+ const body = req;
219
+ const { error, response } = await this.client.POST("/files/mv", {
220
+ body,
221
+ });
222
+ throwOnOpenApiFetchError({ error, response }, "Move files failed");
223
+ }
224
+ async replaceContents(entries) {
225
+ const req = {};
226
+ for (const e of entries) {
227
+ req[e.path] = { old: e.oldContent, new: e.newContent };
228
+ }
229
+ const body = req;
230
+ const { error, response } = await this.client.POST("/files/replace", {
231
+ body,
232
+ });
233
+ throwOnOpenApiFetchError({ error, response }, "Replace contents failed");
234
+ }
235
+ async search(entry) {
236
+ const { data, error, response } = await this.client.GET("/files/search", {
237
+ params: { query: { path: entry.path, pattern: entry.pattern } },
238
+ });
239
+ throwOnOpenApiFetchError({ error, response }, "Search files failed");
240
+ // Make the OpenAPI contract explicit (and fail loudly on unexpected shapes).
241
+ const ok = data;
242
+ if (!ok)
243
+ return [];
244
+ if (!Array.isArray(ok)) {
245
+ throw new Error(`Search files failed: unexpected response shape (expected array, got ${typeof ok})`);
246
+ }
247
+ return ok.map((x) => this.mapApiFileInfo(x));
248
+ }
249
+ async uploadFile(meta, data) {
250
+ const url = joinUrl(this.opts.baseUrl, "/files/upload");
251
+ const fileName = basename(meta.path);
252
+ const metadataJson = JSON.stringify(meta);
253
+ // Streaming path (large files): build multipart body manually to avoid buffering.
254
+ if (isReadableStream(data) || isAsyncIterable(data)) {
255
+ const boundary = `opensandbox_${Math.random()
256
+ .toString(16)
257
+ .slice(2)}_${Date.now()}`;
258
+ const bodyIt = multipartUploadBody({
259
+ boundary,
260
+ metadataJson,
261
+ fileName,
262
+ fileContentType: "application/octet-stream",
263
+ file: data,
264
+ });
265
+ const stream = toReadableStream(bodyIt);
266
+ const res = await this.fetch(url, {
267
+ method: "POST",
268
+ headers: {
269
+ "content-type": `multipart/form-data; boundary=${boundary}`,
270
+ ...(this.opts.headers ?? {}),
271
+ },
272
+ body: stream,
273
+ // Node fetch (undici) requires duplex for streaming request bodies.
274
+ duplex: "half",
275
+ });
276
+ if (!res.ok) {
277
+ const requestId = res.headers.get("x-request-id") ?? undefined;
278
+ const rawBody = await res.text().catch(() => undefined);
279
+ throw new SandboxApiException({
280
+ message: `Upload failed (status=${res.status})`,
281
+ statusCode: res.status,
282
+ requestId,
283
+ error: new SandboxError(SandboxError.UNEXPECTED_RESPONSE, "Upload failed"),
284
+ rawBody,
285
+ });
286
+ }
287
+ return;
288
+ }
289
+ // In-memory path (small files): use FormData.
290
+ const form = new FormData();
291
+ form.append("metadata", new Blob([metadataJson], { type: "application/json" }), "metadata");
292
+ if (typeof data === "string") {
293
+ const textBlob = new Blob([data], { type: "text/plain; charset=utf-8" });
294
+ form.append("file", textBlob, fileName);
295
+ }
296
+ else {
297
+ const blob = toUploadBlob(data);
298
+ const fileBlob = blob.type
299
+ ? blob
300
+ : new Blob([blob], { type: "application/octet-stream" });
301
+ form.append("file", fileBlob, fileName);
302
+ }
303
+ const res = await this.fetch(url, {
304
+ method: "POST",
305
+ headers: {
306
+ ...(this.opts.headers ?? {}),
307
+ },
308
+ body: form,
309
+ });
310
+ if (!res.ok) {
311
+ const requestId = res.headers.get("x-request-id") ?? undefined;
312
+ const rawBody = await res.text().catch(() => undefined);
313
+ throw new SandboxApiException({
314
+ message: `Upload failed (status=${res.status})`,
315
+ statusCode: res.status,
316
+ requestId,
317
+ error: new SandboxError(SandboxError.UNEXPECTED_RESPONSE, "Upload failed"),
318
+ rawBody,
319
+ });
320
+ }
321
+ }
322
+ async readBytes(path, opts) {
323
+ const url = joinUrl(this.opts.baseUrl, "/files/download") +
324
+ `?path=${encodeURIComponent(path)}`;
325
+ const res = await this.fetch(url, {
326
+ method: "GET",
327
+ headers: {
328
+ ...(this.opts.headers ?? {}),
329
+ ...(opts?.range ? { Range: opts.range } : {}),
330
+ },
331
+ });
332
+ if (!res.ok) {
333
+ const requestId = res.headers.get("x-request-id") ?? undefined;
334
+ const rawBody = await res.text().catch(() => undefined);
335
+ throw new SandboxApiException({
336
+ message: "Download failed",
337
+ statusCode: res.status,
338
+ requestId,
339
+ error: new SandboxError(SandboxError.UNEXPECTED_RESPONSE, "Download failed"),
340
+ rawBody,
341
+ });
342
+ }
343
+ const ab = await res.arrayBuffer();
344
+ return new Uint8Array(ab);
345
+ }
346
+ readBytesStream(path, opts) {
347
+ return this.downloadStream(path, opts);
348
+ }
349
+ async *downloadStream(path, opts) {
350
+ const url = joinUrl(this.opts.baseUrl, "/files/download") +
351
+ `?path=${encodeURIComponent(path)}`;
352
+ const res = await this.fetch(url, {
353
+ method: "GET",
354
+ headers: {
355
+ ...(this.opts.headers ?? {}),
356
+ ...(opts?.range ? { Range: opts.range } : {}),
357
+ },
358
+ });
359
+ if (!res.ok) {
360
+ const requestId = res.headers.get("x-request-id") ?? undefined;
361
+ const rawBody = await res.text().catch(() => undefined);
362
+ throw new SandboxApiException({
363
+ message: "Download stream failed",
364
+ statusCode: res.status,
365
+ requestId,
366
+ error: new SandboxError(SandboxError.UNEXPECTED_RESPONSE, "Download stream failed"),
367
+ rawBody,
368
+ });
369
+ }
370
+ const body = res.body;
371
+ if (!body)
372
+ return;
373
+ const reader = body.getReader();
374
+ while (true) {
375
+ const { done, value } = await reader.read();
376
+ if (done)
377
+ return;
378
+ if (value)
379
+ yield value;
380
+ }
381
+ }
382
+ async readFile(path, opts) {
383
+ const bytes = await this.readBytes(path, { range: opts?.range });
384
+ const encoding = opts?.encoding ?? "utf-8";
385
+ return new TextDecoder(encoding).decode(bytes);
386
+ }
387
+ async writeFiles(entries) {
388
+ for (const e of entries) {
389
+ const meta = {
390
+ path: e.path,
391
+ owner: e.owner,
392
+ group: e.group,
393
+ mode: e.mode,
394
+ };
395
+ await this.uploadFile(meta, e.data ?? "");
396
+ }
397
+ }
398
+ }
@@ -0,0 +1,8 @@
1
+ import type { ExecdClient } from "../openapi/execdClient.js";
2
+ import type { ExecdHealth } from "../services/execdHealth.js";
3
+ export declare class HealthAdapter implements ExecdHealth {
4
+ private readonly client;
5
+ constructor(client: ExecdClient);
6
+ ping(): Promise<boolean>;
7
+ }
8
+ //# sourceMappingURL=healthAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/healthAdapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,qBAAa,aAAc,YAAW,WAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAE1C,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAK/B"}
@@ -0,0 +1,25 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { throwOnOpenApiFetchError } from "./openapiError.js";
15
+ export class HealthAdapter {
16
+ client;
17
+ constructor(client) {
18
+ this.client = client;
19
+ }
20
+ async ping() {
21
+ const { error, response } = await this.client.GET("/ping");
22
+ throwOnOpenApiFetchError({ error, response }, "Execd ping failed");
23
+ return true;
24
+ }
25
+ }
@@ -0,0 +1,9 @@
1
+ import type { ExecdClient } from "../openapi/execdClient.js";
2
+ import type { SandboxMetrics } from "../models/execd.js";
3
+ import type { ExecdMetrics } from "../services/execdMetrics.js";
4
+ export declare class MetricsAdapter implements ExecdMetrics {
5
+ private readonly client;
6
+ constructor(client: ExecdClient);
7
+ getMetrics(): Promise<SandboxMetrics>;
8
+ }
9
+ //# sourceMappingURL=metricsAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/metricsAdapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAG7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAoBhE,qBAAa,cAAe,YAAW,YAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAE1C,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC;CAS5C"}
@@ -0,0 +1,43 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { throwOnOpenApiFetchError } from "./openapiError.js";
15
+ function normalizeMetrics(m) {
16
+ const cpuCount = m.cpu_count ?? 0;
17
+ const cpuUsedPercentage = m.cpu_used_pct ?? 0;
18
+ const memoryTotalMiB = m.mem_total_mib ?? 0;
19
+ const memoryUsedMiB = m.mem_used_mib ?? 0;
20
+ const timestamp = m.timestamp ?? 0;
21
+ return {
22
+ cpuCount: Number(cpuCount),
23
+ cpuUsedPercentage: Number(cpuUsedPercentage),
24
+ memoryTotalMiB: Number(memoryTotalMiB),
25
+ memoryUsedMiB: Number(memoryUsedMiB),
26
+ timestamp: Number(timestamp),
27
+ };
28
+ }
29
+ export class MetricsAdapter {
30
+ client;
31
+ constructor(client) {
32
+ this.client = client;
33
+ }
34
+ async getMetrics() {
35
+ const { data, error, response } = await this.client.GET("/metrics");
36
+ throwOnOpenApiFetchError({ error, response }, "Get execd metrics failed");
37
+ const ok = data;
38
+ if (!ok || typeof ok !== "object") {
39
+ throw new Error("Get execd metrics failed: unexpected response shape");
40
+ }
41
+ return normalizeMetrics(ok);
42
+ }
43
+ }
@@ -0,0 +1,5 @@
1
+ export declare function throwOnOpenApiFetchError(result: {
2
+ error?: unknown;
3
+ response: Response;
4
+ }, fallbackMessage: string): void;
5
+ //# sourceMappingURL=openapiError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapiError.d.ts","sourceRoot":"","sources":["../../src/adapters/openapiError.ts"],"names":[],"mappings":"AAgBA,wBAAgB,wBAAwB,CACtC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,EAC/C,eAAe,EAAE,MAAM,GACtB,IAAI,CAsBN"}
@@ -0,0 +1,33 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { SandboxApiException, SandboxError } from "../core/exceptions.js";
15
+ export function throwOnOpenApiFetchError(result, fallbackMessage) {
16
+ if (!result.error)
17
+ return;
18
+ const requestId = result.response.headers.get("x-request-id") ?? undefined;
19
+ const status = result.response.status ?? 0;
20
+ const err = result.error;
21
+ const message = err?.message ??
22
+ err?.error?.message ??
23
+ fallbackMessage;
24
+ const code = err?.code ?? err?.error?.code;
25
+ const msg = err?.message ?? err?.error?.message ?? message;
26
+ throw new SandboxApiException({
27
+ message: msg,
28
+ statusCode: status,
29
+ requestId,
30
+ error: code ? new SandboxError(String(code), String(msg ?? "")) : new SandboxError(SandboxError.UNEXPECTED_RESPONSE, String(msg ?? "")),
31
+ rawBody: result.error,
32
+ });
33
+ }
@@ -0,0 +1,18 @@
1
+ import type { LifecycleClient } from "../openapi/lifecycleClient.js";
2
+ import type { Sandboxes } from "../services/sandboxes.js";
3
+ import type { CreateSandboxRequest, CreateSandboxResponse, Endpoint, ListSandboxesParams, ListSandboxesResponse, RenewSandboxExpirationRequest, RenewSandboxExpirationResponse, SandboxId, SandboxInfo } from "../models/sandboxes.js";
4
+ export declare class SandboxesAdapter implements Sandboxes {
5
+ private readonly client;
6
+ constructor(client: LifecycleClient);
7
+ private parseIsoDate;
8
+ private mapSandboxInfo;
9
+ createSandbox(req: CreateSandboxRequest): Promise<CreateSandboxResponse>;
10
+ getSandbox(sandboxId: SandboxId): Promise<SandboxInfo>;
11
+ listSandboxes(params?: ListSandboxesParams): Promise<ListSandboxesResponse>;
12
+ deleteSandbox(sandboxId: SandboxId): Promise<void>;
13
+ pauseSandbox(sandboxId: SandboxId): Promise<void>;
14
+ resumeSandbox(sandboxId: SandboxId): Promise<void>;
15
+ renewSandboxExpiration(sandboxId: SandboxId, req: RenewSandboxExpirationRequest): Promise<RenewSandboxExpirationResponse>;
16
+ getSandboxEndpoint(sandboxId: SandboxId, port: number): Promise<Endpoint>;
17
+ }
18
+ //# sourceMappingURL=sandboxesAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxesAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/sandboxesAdapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,KAAK,EACV,SAAS,EACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,6BAA6B,EAC7B,8BAA8B,EAC9B,SAAS,EACT,WAAW,EACZ,MAAM,wBAAwB,CAAC;AA2BhC,qBAAa,gBAAiB,YAAW,SAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAEpD,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,cAAc;IAQhB,aAAa,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAkBxE,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IAYtD,aAAa,CAAC,MAAM,GAAE,mBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAyB/E,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,sBAAsB,CAC1B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,8BAA8B,CAAC;IAiBpC,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAWhF"}