instavm 0.8.1 → 0.11.0

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
@@ -139,7 +139,7 @@ var HTTPClient = class {
139
139
  timeout: config.timeout,
140
140
  headers: {
141
141
  "Content-Type": "application/json",
142
- "User-Agent": "instavm-js-sdk/0.1.0"
142
+ "User-Agent": "instavm-js-sdk/0.11.0"
143
143
  }
144
144
  });
145
145
  this.setupInterceptors();
@@ -160,7 +160,7 @@ var HTTPClient = class {
160
160
  const axiosError = error;
161
161
  const status = axiosError.response?.status;
162
162
  const data = axiosError.response?.data;
163
- const message = data?.message || data?.error || axiosError.message;
163
+ const message = data?.message || data?.error || data?.detail || axiosError.message;
164
164
  switch (status) {
165
165
  case 401:
166
166
  throw new AuthenticationError(message, {
@@ -172,14 +172,16 @@ var HTTPClient = class {
172
172
  statusCode: status,
173
173
  response: data
174
174
  });
175
- case 429:
175
+ case 429: {
176
176
  const retryAfter = parseInt(
177
177
  axiosError.response?.headers["retry-after"] || "60"
178
178
  );
179
- throw new RateLimitError(message, retryAfter, {
179
+ const rateLimitMessage = data?.detail || message;
180
+ throw new RateLimitError(rateLimitMessage, retryAfter, {
180
181
  statusCode: status,
181
182
  response: data
182
183
  });
184
+ }
183
185
  case 500:
184
186
  case 502:
185
187
  case 503:
@@ -257,6 +259,7 @@ var HTTPClient = class {
257
259
  */
258
260
  async postFormData(url, formData, headers) {
259
261
  const requestHeaders = {
262
+ "X-API-Key": this.config.apiKey,
260
263
  ...formData.getHeaders(),
261
264
  ...headers
262
265
  };
@@ -308,6 +311,39 @@ var HTTPClient = class {
308
311
  headers
309
312
  });
310
313
  }
314
+ /**
315
+ * PUT request
316
+ */
317
+ async put(url, data, headers) {
318
+ return this.request({
319
+ method: "PUT",
320
+ url,
321
+ data,
322
+ headers
323
+ });
324
+ }
325
+ /**
326
+ * PATCH request
327
+ */
328
+ async patch(url, data, headers) {
329
+ return this.request({
330
+ method: "PATCH",
331
+ url,
332
+ data,
333
+ headers
334
+ });
335
+ }
336
+ /**
337
+ * OPTIONS request
338
+ */
339
+ async options(url, headers, params) {
340
+ return this.request({
341
+ method: "OPTIONS",
342
+ url,
343
+ headers,
344
+ params
345
+ });
346
+ }
311
347
  /**
312
348
  * POST request that returns raw binary data (for file downloads)
313
349
  */
@@ -874,13 +910,525 @@ var BrowserManager = class {
874
910
  }
875
911
  };
876
912
 
913
+ // src/utils/path.ts
914
+ function encodePathSegment(value) {
915
+ return encodeURIComponent(String(value));
916
+ }
917
+ function encodePathSegments(path) {
918
+ const segments = path.replace(/^\/+/, "").split("/").filter((segment) => segment.length > 0 && segment !== ".");
919
+ if (segments.some((segment) => segment === "..")) {
920
+ throw new Error("Path traversal not allowed in proxy path");
921
+ }
922
+ return segments.map((segment) => encodeURIComponent(segment)).join("/");
923
+ }
924
+
925
+ // src/client/VMsManager.ts
926
+ var VMsManager = class {
927
+ constructor(httpClient, local = false) {
928
+ this.httpClient = httpClient;
929
+ this.local = local;
930
+ }
931
+ ensureCloud(operation) {
932
+ if (this.local) {
933
+ throw new UnsupportedOperationError(
934
+ `${operation} is not supported in local mode.`
935
+ );
936
+ }
937
+ }
938
+ async create(payload = {}, wait = true) {
939
+ this.ensureCloud("VM creation");
940
+ return this.httpClient.request({
941
+ method: "POST",
942
+ url: "/v1/vms",
943
+ params: { wait },
944
+ data: payload,
945
+ headers: { "X-API-Key": this.httpClient.apiKey }
946
+ });
947
+ }
948
+ async list() {
949
+ this.ensureCloud("VM listing");
950
+ return this.httpClient.get(
951
+ "/v1/vms",
952
+ void 0,
953
+ { "X-API-Key": this.httpClient.apiKey }
954
+ );
955
+ }
956
+ async listAll() {
957
+ return this.listAllRecords();
958
+ }
959
+ /**
960
+ * Calls GET /v1/vms/ (trailing slash), a distinct route from GET /v1/vms.
961
+ */
962
+ async listAllRecords() {
963
+ this.ensureCloud("VM listing");
964
+ return this.httpClient.get(
965
+ "/v1/vms/",
966
+ void 0,
967
+ { "X-API-Key": this.httpClient.apiKey }
968
+ );
969
+ }
970
+ async get(itemId) {
971
+ this.ensureCloud("VM lookup");
972
+ const safeItemId = encodePathSegment(itemId);
973
+ return this.httpClient.get(
974
+ `/v1/vms/${safeItemId}`,
975
+ void 0,
976
+ { "X-API-Key": this.httpClient.apiKey }
977
+ );
978
+ }
979
+ async update(vmId, payload = {}) {
980
+ this.ensureCloud("VM update");
981
+ const safeVmId = encodePathSegment(vmId);
982
+ return this.httpClient.patch(
983
+ `/v1/vms/${safeVmId}`,
984
+ payload,
985
+ { "X-API-Key": this.httpClient.apiKey }
986
+ );
987
+ }
988
+ async delete(vmId) {
989
+ this.ensureCloud("VM deletion");
990
+ const safeVmId = encodePathSegment(vmId);
991
+ return this.httpClient.delete(
992
+ `/v1/vms/${safeVmId}`,
993
+ { "X-API-Key": this.httpClient.apiKey }
994
+ );
995
+ }
996
+ async clone(vmId, payload = {}, wait = true) {
997
+ this.ensureCloud("VM clone");
998
+ const safeVmId = encodePathSegment(vmId);
999
+ return this.httpClient.request({
1000
+ method: "POST",
1001
+ url: `/v1/vms/${safeVmId}/clone`,
1002
+ params: { wait },
1003
+ data: payload,
1004
+ headers: { "X-API-Key": this.httpClient.apiKey }
1005
+ });
1006
+ }
1007
+ async snapshot(vmId, payload = {}, wait = true) {
1008
+ this.ensureCloud("VM snapshot");
1009
+ const safeVmId = encodePathSegment(vmId);
1010
+ return this.httpClient.request({
1011
+ method: "POST",
1012
+ url: `/v1/vms/${safeVmId}/snapshot`,
1013
+ params: { wait },
1014
+ data: payload,
1015
+ headers: { "X-API-Key": this.httpClient.apiKey }
1016
+ });
1017
+ }
1018
+ };
1019
+
1020
+ // src/client/SnapshotsManager.ts
1021
+ var SnapshotsManager = class {
1022
+ constructor(httpClient, local = false) {
1023
+ this.httpClient = httpClient;
1024
+ this.local = local;
1025
+ }
1026
+ ensureCloud(operation) {
1027
+ if (this.local) {
1028
+ throw new UnsupportedOperationError(
1029
+ `${operation} is not supported in local mode.`
1030
+ );
1031
+ }
1032
+ }
1033
+ async create(payload) {
1034
+ this.ensureCloud("Snapshot creation");
1035
+ return this.httpClient.post(
1036
+ "/v1/snapshots",
1037
+ payload,
1038
+ { "X-API-Key": this.httpClient.apiKey }
1039
+ );
1040
+ }
1041
+ async list(options = {}) {
1042
+ this.ensureCloud("Snapshot listing");
1043
+ return this.httpClient.get(
1044
+ "/v1/snapshots",
1045
+ options,
1046
+ { "X-API-Key": this.httpClient.apiKey }
1047
+ );
1048
+ }
1049
+ async get(snapshotId) {
1050
+ this.ensureCloud("Snapshot lookup");
1051
+ const safeSnapshotId = encodePathSegment(snapshotId);
1052
+ return this.httpClient.get(
1053
+ `/v1/snapshots/${safeSnapshotId}`,
1054
+ void 0,
1055
+ { "X-API-Key": this.httpClient.apiKey }
1056
+ );
1057
+ }
1058
+ async delete(snapshotId) {
1059
+ this.ensureCloud("Snapshot deletion");
1060
+ const safeSnapshotId = encodePathSegment(snapshotId);
1061
+ return this.httpClient.delete(
1062
+ `/v1/snapshots/${safeSnapshotId}`,
1063
+ { "X-API-Key": this.httpClient.apiKey }
1064
+ );
1065
+ }
1066
+ };
1067
+
1068
+ // src/client/SharesManager.ts
1069
+ var SharesManager = class {
1070
+ constructor(httpClient, local = false, getSessionId = () => null) {
1071
+ this.httpClient = httpClient;
1072
+ this.local = local;
1073
+ this.getSessionId = getSessionId;
1074
+ }
1075
+ ensureCloud(operation) {
1076
+ if (this.local) {
1077
+ throw new UnsupportedOperationError(
1078
+ `${operation} is not supported in local mode.`
1079
+ );
1080
+ }
1081
+ }
1082
+ async create(payload) {
1083
+ this.ensureCloud("Share creation");
1084
+ const body = { ...payload };
1085
+ if (!body.session_id && !body.vm_id) {
1086
+ const sid = this.getSessionId();
1087
+ if (!sid) {
1088
+ throw new SessionError(
1089
+ "Provide session_id/vm_id or create a session before creating a share."
1090
+ );
1091
+ }
1092
+ body.session_id = sid;
1093
+ }
1094
+ return this.httpClient.post(
1095
+ "/v1/shares",
1096
+ body,
1097
+ { "X-API-Key": this.httpClient.apiKey }
1098
+ );
1099
+ }
1100
+ async update(shareId, payload) {
1101
+ this.ensureCloud("Share update");
1102
+ const safeShareId = encodePathSegment(shareId);
1103
+ return this.httpClient.patch(
1104
+ `/v1/shares/${safeShareId}`,
1105
+ payload,
1106
+ { "X-API-Key": this.httpClient.apiKey }
1107
+ );
1108
+ }
1109
+ };
1110
+
1111
+ // src/client/CustomDomainsManager.ts
1112
+ var CustomDomainsManager = class {
1113
+ constructor(httpClient, local = false) {
1114
+ this.httpClient = httpClient;
1115
+ this.local = local;
1116
+ }
1117
+ ensureCloud(operation) {
1118
+ if (this.local) {
1119
+ throw new UnsupportedOperationError(
1120
+ `${operation} is not supported in local mode.`
1121
+ );
1122
+ }
1123
+ }
1124
+ async create(payload) {
1125
+ this.ensureCloud("Custom domain creation");
1126
+ return this.httpClient.post(
1127
+ "/v1/custom-domains",
1128
+ payload,
1129
+ { "X-API-Key": this.httpClient.apiKey }
1130
+ );
1131
+ }
1132
+ async list() {
1133
+ this.ensureCloud("Custom domain listing");
1134
+ return this.httpClient.get(
1135
+ "/v1/custom-domains",
1136
+ void 0,
1137
+ { "X-API-Key": this.httpClient.apiKey }
1138
+ );
1139
+ }
1140
+ async health(domainId) {
1141
+ this.ensureCloud("Custom domain health");
1142
+ const safeDomainId = encodePathSegment(domainId);
1143
+ return this.httpClient.get(
1144
+ `/v1/custom-domains/${safeDomainId}/health`,
1145
+ void 0,
1146
+ { "X-API-Key": this.httpClient.apiKey }
1147
+ );
1148
+ }
1149
+ async verify(domainId) {
1150
+ this.ensureCloud("Custom domain verification");
1151
+ const safeDomainId = encodePathSegment(domainId);
1152
+ return this.httpClient.post(
1153
+ `/v1/custom-domains/${safeDomainId}/verify`,
1154
+ {},
1155
+ { "X-API-Key": this.httpClient.apiKey }
1156
+ );
1157
+ }
1158
+ async delete(domainId) {
1159
+ this.ensureCloud("Custom domain deletion");
1160
+ const safeDomainId = encodePathSegment(domainId);
1161
+ return this.httpClient.delete(
1162
+ `/v1/custom-domains/${safeDomainId}`,
1163
+ { "X-API-Key": this.httpClient.apiKey }
1164
+ );
1165
+ }
1166
+ };
1167
+
1168
+ // src/client/ComputerUseManager.ts
1169
+ var ComputerUseManager = class {
1170
+ constructor(httpClient, local = false) {
1171
+ this.httpClient = httpClient;
1172
+ this.local = local;
1173
+ }
1174
+ ensureCloud(operation) {
1175
+ if (this.local) {
1176
+ throw new UnsupportedOperationError(
1177
+ `${operation} is not supported in local mode.`
1178
+ );
1179
+ }
1180
+ }
1181
+ async viewerUrl(sessionId) {
1182
+ this.ensureCloud("Computer-use viewer URL");
1183
+ const safeSessionId = encodePathSegment(sessionId);
1184
+ return this.httpClient.get(
1185
+ `/v1/computeruse/${safeSessionId}/viewer-url`,
1186
+ void 0,
1187
+ { "X-API-Key": this.httpClient.apiKey }
1188
+ );
1189
+ }
1190
+ async proxy(sessionId, path, method = "GET", options = {}) {
1191
+ this.ensureCloud("Computer-use proxy");
1192
+ const safeSessionId = encodePathSegment(sessionId);
1193
+ const cleanPath = encodePathSegments(path);
1194
+ return this.httpClient.request({
1195
+ method,
1196
+ url: `/v1/computeruse/${safeSessionId}/${cleanPath}`,
1197
+ params: options.params,
1198
+ data: options.body,
1199
+ headers: { "X-API-Key": this.httpClient.apiKey }
1200
+ });
1201
+ }
1202
+ async get(sessionId, path, params) {
1203
+ return this.proxy(sessionId, path, "GET", { params });
1204
+ }
1205
+ async post(sessionId, path, body) {
1206
+ return this.proxy(sessionId, path, "POST", { body });
1207
+ }
1208
+ async put(sessionId, path, body) {
1209
+ return this.proxy(sessionId, path, "PUT", { body });
1210
+ }
1211
+ async patch(sessionId, path, body) {
1212
+ return this.proxy(sessionId, path, "PATCH", { body });
1213
+ }
1214
+ async delete(sessionId, path, params) {
1215
+ return this.proxy(sessionId, path, "DELETE", { params });
1216
+ }
1217
+ async options(sessionId, path, params) {
1218
+ return this.proxy(sessionId, path, "OPTIONS", { params });
1219
+ }
1220
+ };
1221
+
1222
+ // src/client/APIKeysManager.ts
1223
+ var APIKeysManager = class {
1224
+ constructor(httpClient, local = false) {
1225
+ this.httpClient = httpClient;
1226
+ this.local = local;
1227
+ }
1228
+ ensureCloud(operation) {
1229
+ if (this.local) {
1230
+ throw new UnsupportedOperationError(
1231
+ `${operation} is not supported in local mode.`
1232
+ );
1233
+ }
1234
+ }
1235
+ async create(payload = {}) {
1236
+ this.ensureCloud("API key creation");
1237
+ return this.httpClient.post(
1238
+ "/v1/api-keys/",
1239
+ payload,
1240
+ { "X-API-Key": this.httpClient.apiKey }
1241
+ );
1242
+ }
1243
+ async list() {
1244
+ this.ensureCloud("API key listing");
1245
+ return this.httpClient.get(
1246
+ "/v1/api-keys/",
1247
+ void 0,
1248
+ { "X-API-Key": this.httpClient.apiKey }
1249
+ );
1250
+ }
1251
+ async get(itemId) {
1252
+ this.ensureCloud("API key lookup");
1253
+ const safeItemId = encodePathSegment(itemId);
1254
+ return this.httpClient.get(
1255
+ `/v1/api-keys/${safeItemId}`,
1256
+ void 0,
1257
+ { "X-API-Key": this.httpClient.apiKey }
1258
+ );
1259
+ }
1260
+ async update(itemId, payload) {
1261
+ this.ensureCloud("API key update");
1262
+ const safeItemId = encodePathSegment(itemId);
1263
+ return this.httpClient.patch(
1264
+ `/v1/api-keys/${safeItemId}`,
1265
+ payload,
1266
+ { "X-API-Key": this.httpClient.apiKey }
1267
+ );
1268
+ }
1269
+ async delete(itemId) {
1270
+ this.ensureCloud("API key deletion");
1271
+ const safeItemId = encodePathSegment(itemId);
1272
+ return this.httpClient.delete(
1273
+ `/v1/api-keys/${safeItemId}`,
1274
+ { "X-API-Key": this.httpClient.apiKey }
1275
+ );
1276
+ }
1277
+ };
1278
+
1279
+ // src/client/AuditManager.ts
1280
+ var AuditManager = class {
1281
+ constructor(httpClient, local = false) {
1282
+ this.httpClient = httpClient;
1283
+ this.local = local;
1284
+ }
1285
+ ensureCloud(operation) {
1286
+ if (this.local) {
1287
+ throw new UnsupportedOperationError(
1288
+ `${operation} is not supported in local mode.`
1289
+ );
1290
+ }
1291
+ }
1292
+ async catalog() {
1293
+ this.ensureCloud("Audit catalog");
1294
+ return this.httpClient.get(
1295
+ "/v1/audit/catalog",
1296
+ void 0,
1297
+ { "X-API-Key": this.httpClient.apiKey }
1298
+ );
1299
+ }
1300
+ async events(query = {}) {
1301
+ this.ensureCloud("Audit event listing");
1302
+ return this.httpClient.get(
1303
+ "/v1/audit/events",
1304
+ query,
1305
+ { "X-API-Key": this.httpClient.apiKey }
1306
+ );
1307
+ }
1308
+ async getEvent(eventId) {
1309
+ this.ensureCloud("Audit event lookup");
1310
+ const safeEventId = encodePathSegment(eventId);
1311
+ return this.httpClient.get(
1312
+ `/v1/audit/events/${safeEventId}`,
1313
+ void 0,
1314
+ { "X-API-Key": this.httpClient.apiKey }
1315
+ );
1316
+ }
1317
+ };
1318
+
1319
+ // src/client/WebhooksManager.ts
1320
+ var WebhooksManager = class {
1321
+ constructor(httpClient, local = false) {
1322
+ this.httpClient = httpClient;
1323
+ this.local = local;
1324
+ }
1325
+ ensureCloud(operation) {
1326
+ if (this.local) {
1327
+ throw new UnsupportedOperationError(
1328
+ `${operation} is not supported in local mode.`
1329
+ );
1330
+ }
1331
+ }
1332
+ async createEndpoint(payload) {
1333
+ this.ensureCloud("Webhook endpoint creation");
1334
+ return this.httpClient.post(
1335
+ "/v1/webhooks/endpoints",
1336
+ payload,
1337
+ { "X-API-Key": this.httpClient.apiKey }
1338
+ );
1339
+ }
1340
+ async listEndpoints() {
1341
+ this.ensureCloud("Webhook endpoint listing");
1342
+ return this.httpClient.get(
1343
+ "/v1/webhooks/endpoints",
1344
+ void 0,
1345
+ { "X-API-Key": this.httpClient.apiKey }
1346
+ );
1347
+ }
1348
+ async getEndpoint(endpointId) {
1349
+ this.ensureCloud("Webhook endpoint lookup");
1350
+ const safeEndpointId = encodePathSegment(endpointId);
1351
+ return this.httpClient.get(
1352
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1353
+ void 0,
1354
+ { "X-API-Key": this.httpClient.apiKey }
1355
+ );
1356
+ }
1357
+ async updateEndpoint(endpointId, payload) {
1358
+ this.ensureCloud("Webhook endpoint update");
1359
+ const safeEndpointId = encodePathSegment(endpointId);
1360
+ return this.httpClient.patch(
1361
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1362
+ payload,
1363
+ { "X-API-Key": this.httpClient.apiKey }
1364
+ );
1365
+ }
1366
+ async deleteEndpoint(endpointId) {
1367
+ this.ensureCloud("Webhook endpoint deletion");
1368
+ const safeEndpointId = encodePathSegment(endpointId);
1369
+ return this.httpClient.delete(
1370
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1371
+ { "X-API-Key": this.httpClient.apiKey }
1372
+ );
1373
+ }
1374
+ async rotateSecret(endpointId) {
1375
+ this.ensureCloud("Webhook secret rotation");
1376
+ const safeEndpointId = encodePathSegment(endpointId);
1377
+ return this.httpClient.post(
1378
+ `/v1/webhooks/endpoints/${safeEndpointId}/rotate-secret`,
1379
+ {},
1380
+ { "X-API-Key": this.httpClient.apiKey }
1381
+ );
1382
+ }
1383
+ async sendTestEvent(endpointId) {
1384
+ this.ensureCloud("Webhook test event");
1385
+ const safeEndpointId = encodePathSegment(endpointId);
1386
+ return this.httpClient.post(
1387
+ `/v1/webhooks/endpoints/${safeEndpointId}/test`,
1388
+ {},
1389
+ { "X-API-Key": this.httpClient.apiKey }
1390
+ );
1391
+ }
1392
+ async verifyEndpoint(endpointId) {
1393
+ this.ensureCloud("Webhook endpoint verification");
1394
+ const safeEndpointId = encodePathSegment(endpointId);
1395
+ return this.httpClient.post(
1396
+ `/v1/webhooks/endpoints/${safeEndpointId}/verify`,
1397
+ {},
1398
+ { "X-API-Key": this.httpClient.apiKey }
1399
+ );
1400
+ }
1401
+ async listDeliveries(query = {}) {
1402
+ this.ensureCloud("Webhook delivery listing");
1403
+ return this.httpClient.get(
1404
+ "/v1/webhooks/deliveries",
1405
+ query,
1406
+ { "X-API-Key": this.httpClient.apiKey }
1407
+ );
1408
+ }
1409
+ async replayDelivery(deliveryId) {
1410
+ this.ensureCloud("Webhook delivery replay");
1411
+ const safeDeliveryId = encodePathSegment(deliveryId);
1412
+ return this.httpClient.post(
1413
+ `/v1/webhooks/deliveries/${safeDeliveryId}/replay`,
1414
+ {},
1415
+ { "X-API-Key": this.httpClient.apiKey }
1416
+ );
1417
+ }
1418
+ };
1419
+
877
1420
  // src/client/InstaVM.ts
878
1421
  import FormData from "form-data";
879
1422
  var InstaVM = class {
880
1423
  constructor(apiKey, options = {}) {
881
1424
  this._sessionId = null;
1425
+ this._vmUsed = false;
882
1426
  this.local = options.local || false;
883
1427
  this.timeout = options.timeout || 3e5;
1428
+ this.memory_mb = options.memory_mb;
1429
+ this.cpu_count = options.cpu_count;
1430
+ this.metadata = options.metadata;
1431
+ this.env = options.env;
884
1432
  if (!this.local && !apiKey) {
885
1433
  throw new AuthenticationError("API key is required for cloud mode");
886
1434
  }
@@ -893,6 +1441,14 @@ var InstaVM = class {
893
1441
  };
894
1442
  this.httpClient = new HTTPClient(config);
895
1443
  this.browser = new BrowserManager(this.httpClient, this.local);
1444
+ this.vms = new VMsManager(this.httpClient, this.local);
1445
+ this.snapshots = new SnapshotsManager(this.httpClient, this.local);
1446
+ this.shares = new SharesManager(this.httpClient, this.local, () => this._sessionId);
1447
+ this.customDomains = new CustomDomainsManager(this.httpClient, this.local);
1448
+ this.computerUse = new ComputerUseManager(this.httpClient, this.local);
1449
+ this.apiKeys = new APIKeysManager(this.httpClient, this.local);
1450
+ this.audit = new AuditManager(this.httpClient, this.local);
1451
+ this.webhooks = new WebhooksManager(this.httpClient, this.local);
896
1452
  }
897
1453
  /**
898
1454
  * Ensure operation is not called in local mode
@@ -938,10 +1494,16 @@ var InstaVM = class {
938
1494
  if (response.session_id) {
939
1495
  this._sessionId = response.session_id;
940
1496
  }
1497
+ if (!this.local) {
1498
+ this._vmUsed = true;
1499
+ }
941
1500
  return {
942
- output: response.stdout || response.output || "",
1501
+ stdout: response.stdout || "",
1502
+ stderr: response.stderr || "",
943
1503
  success: response.success !== false,
944
- executionTime: response.execution_time || 0,
1504
+ executionTime: response.execution_time,
1505
+ cpuTime: response.cpu_time,
1506
+ createdAt: response.created_at,
945
1507
  sessionId: response.session_id,
946
1508
  error: response.error
947
1509
  };
@@ -978,6 +1540,7 @@ var InstaVM = class {
978
1540
  if (response.session_id) {
979
1541
  this._sessionId = response.session_id;
980
1542
  }
1543
+ this._vmUsed = true;
981
1544
  return {
982
1545
  taskId: response.task_id,
983
1546
  status: response.status || "pending",
@@ -997,11 +1560,58 @@ var InstaVM = class {
997
1560
  );
998
1561
  }
999
1562
  }
1563
+ /**
1564
+ * Poll for async task result
1565
+ *
1566
+ * @param taskId - The task ID from executeAsync
1567
+ * @param pollInterval - Seconds between polls (default: 1)
1568
+ * @param timeout - Maximum seconds to wait (default: 60)
1569
+ * @returns Task result with stdout, stderr, execution time, etc.
1570
+ * @throws Error if task doesn't complete within timeout
1571
+ */
1572
+ async getTaskResult(taskId, pollInterval = 1, timeout = 60) {
1573
+ this.ensureNotLocal("Async task result retrieval");
1574
+ const startTime = Date.now();
1575
+ while (Date.now() - startTime < timeout * 1e3) {
1576
+ try {
1577
+ const response = await this.httpClient.get(
1578
+ `/v1/executions/${taskId}`,
1579
+ void 0,
1580
+ { "X-API-Key": this.httpClient.apiKey }
1581
+ );
1582
+ if (response.is_complete) {
1583
+ return {
1584
+ stdout: response.serialized_stdout || "",
1585
+ stderr: response.serialized_stderr || "",
1586
+ cpuTime: response.cpu_time,
1587
+ executionTime: response.execution_time,
1588
+ createdAt: response.created_at
1589
+ };
1590
+ }
1591
+ await new Promise((resolve) => setTimeout(resolve, pollInterval * 1e3));
1592
+ } catch (error) {
1593
+ if (error instanceof AuthenticationError || error instanceof RateLimitError || error instanceof NetworkError) {
1594
+ throw error;
1595
+ }
1596
+ if (Date.now() - startTime >= timeout * 1e3) {
1597
+ throw new ExecutionError(
1598
+ `Failed to get task result: ${error instanceof Error ? error.message : String(error)}`
1599
+ );
1600
+ }
1601
+ await new Promise((resolve) => setTimeout(resolve, pollInterval * 1e3));
1602
+ }
1603
+ }
1604
+ throw new ExecutionError(`Task ${taskId} timed out after ${timeout}s`);
1605
+ }
1000
1606
  /**
1001
1607
  * Upload files to the execution environment
1002
1608
  */
1003
1609
  async upload(files, options = {}) {
1004
1610
  this.ensureNotLocal("File upload");
1611
+ const sessionId = options.sessionId || this._sessionId;
1612
+ if (!sessionId) {
1613
+ throw new SessionError("Session ID not set. Please create a session first using createSession().");
1614
+ }
1005
1615
  const formData = new FormData();
1006
1616
  for (const file of files) {
1007
1617
  if (Buffer.isBuffer(file.content)) {
@@ -1013,9 +1623,7 @@ var InstaVM = class {
1013
1623
  formData.append("paths", file.path);
1014
1624
  }
1015
1625
  }
1016
- if (options.sessionId || this._sessionId) {
1017
- formData.append("session_id", options.sessionId || this._sessionId);
1018
- }
1626
+ formData.append("session_id", sessionId);
1019
1627
  if (options.remotePath) {
1020
1628
  formData.append("remote_path", options.remotePath);
1021
1629
  }
@@ -1046,10 +1654,26 @@ var InstaVM = class {
1046
1654
  async createSession() {
1047
1655
  this.ensureNotLocal("Session management");
1048
1656
  try {
1049
- const response = await this.httpClient.post("/v1/sessions/session", {
1657
+ const requestBody = {
1050
1658
  api_key: this.httpClient.apiKey,
1051
1659
  vm_lifetime_seconds: Math.floor(this.timeout / 1e3)
1052
- });
1660
+ };
1661
+ if (this.memory_mb !== void 0) {
1662
+ requestBody.memory_mb = this.memory_mb;
1663
+ }
1664
+ if (this.cpu_count !== void 0) {
1665
+ requestBody.vcpu_count = this.cpu_count;
1666
+ }
1667
+ if (this.metadata !== void 0) {
1668
+ requestBody.metadata = this.metadata;
1669
+ }
1670
+ if (this.env !== void 0) {
1671
+ requestBody.env = this.env;
1672
+ }
1673
+ const response = await this.httpClient.post(
1674
+ "/v1/sessions/session",
1675
+ requestBody
1676
+ );
1053
1677
  if (response.session_id) {
1054
1678
  this._sessionId = response.session_id;
1055
1679
  return response.session_id;
@@ -1076,6 +1700,30 @@ var InstaVM = class {
1076
1700
  this._sessionId = null;
1077
1701
  }
1078
1702
  }
1703
+ /**
1704
+ * Check if current session is still active by checking VM status
1705
+ *
1706
+ * @returns true if session is active, false otherwise
1707
+ */
1708
+ async isSessionActive(sessionId) {
1709
+ const targetSessionId = sessionId || this._sessionId;
1710
+ if (!targetSessionId) {
1711
+ return false;
1712
+ }
1713
+ try {
1714
+ const response = await this.httpClient.get(
1715
+ `/v1/sessions/status/${targetSessionId}`,
1716
+ void 0,
1717
+ { "X-API-Key": this.httpClient.apiKey }
1718
+ );
1719
+ return response.vm_status === "active";
1720
+ } catch (error) {
1721
+ if (error instanceof SessionError || error instanceof AuthenticationError || error instanceof NetworkError) {
1722
+ return false;
1723
+ }
1724
+ return false;
1725
+ }
1726
+ }
1079
1727
  /**
1080
1728
  * Get usage statistics for a session
1081
1729
  */
@@ -1139,17 +1787,193 @@ var InstaVM = class {
1139
1787
  get sessionId() {
1140
1788
  return this._sessionId;
1141
1789
  }
1790
+ /**
1791
+ * Kill the VM associated with a session
1792
+ *
1793
+ * @param sessionId - The session UUID whose VM should be killed. If not provided, uses current sessionId
1794
+ * @returns Result containing success message and killed VM ID
1795
+ */
1796
+ async kill(sessionId) {
1797
+ this.ensureNotLocal("VM kill operation");
1798
+ const targetSessionId = sessionId || this._sessionId;
1799
+ if (!targetSessionId) {
1800
+ throw new SessionError("Session ID not set. Please provide a sessionId or start a session first.");
1801
+ }
1802
+ try {
1803
+ const response = await this.httpClient.post(
1804
+ "/kill",
1805
+ { session_id: targetSessionId },
1806
+ { "X-API-Key": this.httpClient.apiKey }
1807
+ );
1808
+ if (!sessionId && this._sessionId === targetSessionId) {
1809
+ this._sessionId = null;
1810
+ }
1811
+ return response;
1812
+ } catch (error) {
1813
+ if (error instanceof Error && "statusCode" in error) {
1814
+ const statusCode = error.statusCode;
1815
+ if (statusCode === 403) {
1816
+ throw new AuthenticationError("You don't own this session", { cause: error });
1817
+ }
1818
+ if (statusCode === 404) {
1819
+ throw new SessionError("Session not found or no VM assigned to session (has execute() been called?)", { cause: error });
1820
+ }
1821
+ }
1822
+ const errorMessage = error instanceof Error ? error.message : String(error);
1823
+ throw new SessionError(
1824
+ `Failed to kill VM: ${errorMessage}`,
1825
+ { cause: error }
1826
+ );
1827
+ }
1828
+ }
1829
+ // --- Egress Policy Methods ---
1830
+ /**
1831
+ * Set egress policy for a session
1832
+ */
1833
+ async setSessionEgress(options = {}, sessionId) {
1834
+ this.ensureNotLocal("Egress policy management");
1835
+ const targetSessionId = sessionId || this._sessionId;
1836
+ if (!targetSessionId) {
1837
+ throw new SessionError("Session ID not set. Please create a session first.");
1838
+ }
1839
+ const response = await this.httpClient.post(
1840
+ `/v1/egress/session/${targetSessionId}`,
1841
+ {
1842
+ allow_public_repos: options.allowPackageManagers ?? true,
1843
+ allow_http: options.allowHttp ?? true,
1844
+ allow_https: options.allowHttps ?? true,
1845
+ allowed_domains: options.allowedDomains ?? [],
1846
+ allowed_cidrs: options.allowedCidrs ?? []
1847
+ },
1848
+ { "X-API-Key": this.httpClient.apiKey }
1849
+ );
1850
+ return response;
1851
+ }
1852
+ /**
1853
+ * Get egress policy for a session
1854
+ */
1855
+ async getSessionEgress(sessionId) {
1856
+ this.ensureNotLocal("Egress policy management");
1857
+ const targetSessionId = sessionId || this._sessionId;
1858
+ if (!targetSessionId) {
1859
+ throw new SessionError("Session ID not set. Please create a session first.");
1860
+ }
1861
+ const response = await this.httpClient.get(
1862
+ `/v1/egress/session/${targetSessionId}`,
1863
+ void 0,
1864
+ { "X-API-Key": this.httpClient.apiKey }
1865
+ );
1866
+ return {
1867
+ allowPackageManagers: response.allow_public_repos,
1868
+ allowHttp: response.allow_http,
1869
+ allowHttps: response.allow_https,
1870
+ allowedDomains: response.allowed_domains || [],
1871
+ allowedCidrs: response.allowed_cidrs || []
1872
+ };
1873
+ }
1874
+ /**
1875
+ * Set egress policy for a specific VM
1876
+ */
1877
+ async setVmEgress(vmId, options = {}) {
1878
+ this.ensureNotLocal("Egress policy management");
1879
+ const response = await this.httpClient.post(
1880
+ `/v1/egress/vm/${vmId}`,
1881
+ {
1882
+ allow_public_repos: options.allowPackageManagers ?? true,
1883
+ allow_http: options.allowHttp ?? true,
1884
+ allow_https: options.allowHttps ?? true,
1885
+ allowed_domains: options.allowedDomains ?? [],
1886
+ allowed_cidrs: options.allowedCidrs ?? []
1887
+ },
1888
+ { "X-API-Key": this.httpClient.apiKey }
1889
+ );
1890
+ return response;
1891
+ }
1892
+ /**
1893
+ * Get egress policy for a specific VM
1894
+ */
1895
+ async getVmEgress(vmId) {
1896
+ this.ensureNotLocal("Egress policy management");
1897
+ const response = await this.httpClient.get(
1898
+ `/v1/egress/vm/${vmId}`,
1899
+ void 0,
1900
+ { "X-API-Key": this.httpClient.apiKey }
1901
+ );
1902
+ return {
1903
+ allowPackageManagers: response.allow_public_repos,
1904
+ allowHttp: response.allow_http,
1905
+ allowHttps: response.allow_https,
1906
+ allowedDomains: response.allowed_domains || [],
1907
+ allowedCidrs: response.allowed_cidrs || []
1908
+ };
1909
+ }
1910
+ // --- SSH Key Methods ---
1911
+ /**
1912
+ * Add an SSH public key
1913
+ */
1914
+ async addSshKey(publicKey) {
1915
+ this.ensureNotLocal("SSH key management");
1916
+ const response = await this.httpClient.post(
1917
+ "/v1/ssh-keys",
1918
+ { public_key: publicKey },
1919
+ { "X-API-Key": this.httpClient.apiKey }
1920
+ );
1921
+ return {
1922
+ id: response.id,
1923
+ fingerprint: response.fingerprint,
1924
+ keyType: response.key_type,
1925
+ comment: response.comment ?? null,
1926
+ createdAt: response.created_at
1927
+ };
1928
+ }
1929
+ /**
1930
+ * List all active SSH keys
1931
+ */
1932
+ async listSshKeys() {
1933
+ this.ensureNotLocal("SSH key management");
1934
+ const response = await this.httpClient.get(
1935
+ "/v1/ssh-keys",
1936
+ void 0,
1937
+ { "X-API-Key": this.httpClient.apiKey }
1938
+ );
1939
+ const keys = response.keys || [];
1940
+ return keys.map((k) => ({
1941
+ id: k.id,
1942
+ fingerprint: k.fingerprint,
1943
+ keyType: k.key_type,
1944
+ comment: k.comment ?? null,
1945
+ createdAt: k.created_at
1946
+ }));
1947
+ }
1948
+ /**
1949
+ * Delete an SSH key by ID
1950
+ */
1951
+ async deleteSshKey(keyId) {
1952
+ this.ensureNotLocal("SSH key management");
1953
+ const response = await this.httpClient.delete(
1954
+ `/v1/ssh-keys/${keyId}`,
1955
+ { "X-API-Key": this.httpClient.apiKey }
1956
+ );
1957
+ return response;
1958
+ }
1142
1959
  /**
1143
1960
  * Clean up resources
1144
1961
  */
1145
1962
  async dispose() {
1146
- if (this._sessionId) {
1963
+ if (this._sessionId && !this.local && this._vmUsed) {
1964
+ try {
1965
+ await this.kill();
1966
+ } catch (e) {
1967
+ }
1968
+ } else if (this._sessionId) {
1147
1969
  await this.closeSession();
1148
1970
  }
1149
1971
  await this.browser.dispose();
1150
1972
  }
1151
1973
  };
1152
1974
  export {
1975
+ APIKeysManager,
1976
+ AuditManager,
1153
1977
  AuthenticationError,
1154
1978
  BrowserError,
1155
1979
  BrowserInteractionError,
@@ -1158,6 +1982,8 @@ export {
1158
1982
  BrowserSession,
1159
1983
  BrowserSessionError,
1160
1984
  BrowserTimeoutError,
1985
+ ComputerUseManager,
1986
+ CustomDomainsManager,
1161
1987
  ElementNotFoundError,
1162
1988
  ExecutionError,
1163
1989
  InstaVM,
@@ -1166,6 +1992,10 @@ export {
1166
1992
  QuotaExceededError,
1167
1993
  RateLimitError,
1168
1994
  SessionError,
1169
- UnsupportedOperationError
1995
+ SharesManager,
1996
+ SnapshotsManager,
1997
+ UnsupportedOperationError,
1998
+ VMsManager,
1999
+ WebhooksManager
1170
2000
  };
1171
2001
  //# sourceMappingURL=index.mjs.map