instavm 0.8.3 → 0.13.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.12.0"
143
143
  }
144
144
  });
145
145
  this.setupInterceptors();
@@ -311,6 +311,39 @@ var HTTPClient = class {
311
311
  headers
312
312
  });
313
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
+ }
314
347
  /**
315
348
  * POST request that returns raw binary data (for file downloads)
316
349
  */
@@ -877,13 +910,732 @@ var BrowserManager = class {
877
910
  }
878
911
  };
879
912
 
880
- // src/client/InstaVM.ts
913
+ // src/utils/path.ts
914
+ function encodePathSegment(value) {
915
+ const segment = String(value);
916
+ if (segment === "." || segment === "..") {
917
+ throw new Error("Path traversal not allowed in path segment");
918
+ }
919
+ return encodeURIComponent(segment);
920
+ }
921
+ function encodePathSegments(path2) {
922
+ const segments = path2.replace(/^\/+/, "").split("/").filter((segment) => segment.length > 0 && segment !== ".");
923
+ if (segments.some((segment) => segment === "..")) {
924
+ throw new Error("Path traversal not allowed in proxy path");
925
+ }
926
+ return segments.map((segment) => encodeURIComponent(segment)).join("/");
927
+ }
928
+
929
+ // src/client/VMsManager.ts
930
+ var VMsManager = class {
931
+ constructor(httpClient, local = false) {
932
+ this.httpClient = httpClient;
933
+ this.local = local;
934
+ }
935
+ ensureCloud(operation) {
936
+ if (this.local) {
937
+ throw new UnsupportedOperationError(
938
+ `${operation} is not supported in local mode.`
939
+ );
940
+ }
941
+ }
942
+ async create(payload = {}, wait = true) {
943
+ this.ensureCloud("VM creation");
944
+ return this.httpClient.request({
945
+ method: "POST",
946
+ url: "/v1/vms",
947
+ params: { wait },
948
+ data: payload,
949
+ headers: { "X-API-Key": this.httpClient.apiKey }
950
+ });
951
+ }
952
+ async list() {
953
+ this.ensureCloud("VM listing");
954
+ return this.httpClient.get(
955
+ "/v1/vms",
956
+ void 0,
957
+ { "X-API-Key": this.httpClient.apiKey }
958
+ );
959
+ }
960
+ async listAll() {
961
+ return this.listAllRecords();
962
+ }
963
+ /**
964
+ * Calls GET /v1/vms/ (trailing slash), a distinct route from GET /v1/vms.
965
+ */
966
+ async listAllRecords() {
967
+ this.ensureCloud("VM listing");
968
+ return this.httpClient.get(
969
+ "/v1/vms/",
970
+ void 0,
971
+ { "X-API-Key": this.httpClient.apiKey }
972
+ );
973
+ }
974
+ async get(itemId) {
975
+ this.ensureCloud("VM lookup");
976
+ const safeItemId = encodePathSegment(itemId);
977
+ return this.httpClient.get(
978
+ `/v1/vms/${safeItemId}`,
979
+ void 0,
980
+ { "X-API-Key": this.httpClient.apiKey }
981
+ );
982
+ }
983
+ async update(vmId, payload = {}) {
984
+ this.ensureCloud("VM update");
985
+ const safeVmId = encodePathSegment(vmId);
986
+ return this.httpClient.patch(
987
+ `/v1/vms/${safeVmId}`,
988
+ payload,
989
+ { "X-API-Key": this.httpClient.apiKey }
990
+ );
991
+ }
992
+ async delete(vmId) {
993
+ this.ensureCloud("VM deletion");
994
+ const safeVmId = encodePathSegment(vmId);
995
+ return this.httpClient.delete(
996
+ `/v1/vms/${safeVmId}`,
997
+ { "X-API-Key": this.httpClient.apiKey }
998
+ );
999
+ }
1000
+ async clone(vmId, payload = {}, wait = true) {
1001
+ this.ensureCloud("VM clone");
1002
+ const safeVmId = encodePathSegment(vmId);
1003
+ return this.httpClient.request({
1004
+ method: "POST",
1005
+ url: `/v1/vms/${safeVmId}/clone`,
1006
+ params: { wait },
1007
+ data: payload,
1008
+ headers: { "X-API-Key": this.httpClient.apiKey }
1009
+ });
1010
+ }
1011
+ async snapshot(vmId, payload = {}, wait = true) {
1012
+ this.ensureCloud("VM snapshot");
1013
+ const safeVmId = encodePathSegment(vmId);
1014
+ return this.httpClient.request({
1015
+ method: "POST",
1016
+ url: `/v1/vms/${safeVmId}/snapshot`,
1017
+ params: { wait },
1018
+ data: payload,
1019
+ headers: { "X-API-Key": this.httpClient.apiKey }
1020
+ });
1021
+ }
1022
+ async mountVolume(vmId, payload, wait = true) {
1023
+ this.ensureCloud("VM volume mount");
1024
+ const safeVmId = encodePathSegment(vmId);
1025
+ return this.httpClient.request({
1026
+ method: "POST",
1027
+ url: `/v1/vms/${safeVmId}/volumes`,
1028
+ params: { wait },
1029
+ data: payload,
1030
+ headers: { "X-API-Key": this.httpClient.apiKey }
1031
+ });
1032
+ }
1033
+ async listVolumes(vmId) {
1034
+ this.ensureCloud("VM volume listing");
1035
+ const safeVmId = encodePathSegment(vmId);
1036
+ return this.httpClient.get(
1037
+ `/v1/vms/${safeVmId}/volumes`,
1038
+ void 0,
1039
+ { "X-API-Key": this.httpClient.apiKey }
1040
+ );
1041
+ }
1042
+ async unmountVolume(vmId, volumeId, mountPath, wait = true) {
1043
+ this.ensureCloud("VM volume unmount");
1044
+ const safeVmId = encodePathSegment(vmId);
1045
+ const safeVolumeId = encodePathSegment(volumeId);
1046
+ return this.httpClient.request({
1047
+ method: "DELETE",
1048
+ url: `/v1/vms/${safeVmId}/volumes/${safeVolumeId}`,
1049
+ params: { mount_path: mountPath, wait },
1050
+ headers: { "X-API-Key": this.httpClient.apiKey }
1051
+ });
1052
+ }
1053
+ };
1054
+
1055
+ // src/client/SnapshotsManager.ts
1056
+ var SnapshotsManager = class {
1057
+ constructor(httpClient, local = false) {
1058
+ this.httpClient = httpClient;
1059
+ this.local = local;
1060
+ }
1061
+ ensureCloud(operation) {
1062
+ if (this.local) {
1063
+ throw new UnsupportedOperationError(
1064
+ `${operation} is not supported in local mode.`
1065
+ );
1066
+ }
1067
+ }
1068
+ async create(payload) {
1069
+ this.ensureCloud("Snapshot creation");
1070
+ return this.httpClient.post(
1071
+ "/v1/snapshots",
1072
+ payload,
1073
+ { "X-API-Key": this.httpClient.apiKey }
1074
+ );
1075
+ }
1076
+ async list(options = {}) {
1077
+ this.ensureCloud("Snapshot listing");
1078
+ return this.httpClient.get(
1079
+ "/v1/snapshots",
1080
+ options,
1081
+ { "X-API-Key": this.httpClient.apiKey }
1082
+ );
1083
+ }
1084
+ async get(snapshotId) {
1085
+ this.ensureCloud("Snapshot lookup");
1086
+ const safeSnapshotId = encodePathSegment(snapshotId);
1087
+ return this.httpClient.get(
1088
+ `/v1/snapshots/${safeSnapshotId}`,
1089
+ void 0,
1090
+ { "X-API-Key": this.httpClient.apiKey }
1091
+ );
1092
+ }
1093
+ async delete(snapshotId) {
1094
+ this.ensureCloud("Snapshot deletion");
1095
+ const safeSnapshotId = encodePathSegment(snapshotId);
1096
+ return this.httpClient.delete(
1097
+ `/v1/snapshots/${safeSnapshotId}`,
1098
+ { "X-API-Key": this.httpClient.apiKey }
1099
+ );
1100
+ }
1101
+ };
1102
+
1103
+ // src/client/SharesManager.ts
1104
+ var SharesManager = class {
1105
+ constructor(httpClient, local = false, getSessionId = () => null) {
1106
+ this.httpClient = httpClient;
1107
+ this.local = local;
1108
+ this.getSessionId = getSessionId;
1109
+ }
1110
+ ensureCloud(operation) {
1111
+ if (this.local) {
1112
+ throw new UnsupportedOperationError(
1113
+ `${operation} is not supported in local mode.`
1114
+ );
1115
+ }
1116
+ }
1117
+ async create(payload) {
1118
+ this.ensureCloud("Share creation");
1119
+ const body = { ...payload };
1120
+ if (!body.session_id && !body.vm_id) {
1121
+ const sid = this.getSessionId();
1122
+ if (!sid) {
1123
+ throw new SessionError(
1124
+ "Provide session_id/vm_id or create a session before creating a share."
1125
+ );
1126
+ }
1127
+ body.session_id = sid;
1128
+ }
1129
+ return this.httpClient.post(
1130
+ "/v1/shares",
1131
+ body,
1132
+ { "X-API-Key": this.httpClient.apiKey }
1133
+ );
1134
+ }
1135
+ async update(shareId, payload) {
1136
+ this.ensureCloud("Share update");
1137
+ const safeShareId = encodePathSegment(shareId);
1138
+ return this.httpClient.patch(
1139
+ `/v1/shares/${safeShareId}`,
1140
+ payload,
1141
+ { "X-API-Key": this.httpClient.apiKey }
1142
+ );
1143
+ }
1144
+ };
1145
+
1146
+ // src/client/CustomDomainsManager.ts
1147
+ var CustomDomainsManager = class {
1148
+ constructor(httpClient, local = false) {
1149
+ this.httpClient = httpClient;
1150
+ this.local = local;
1151
+ }
1152
+ ensureCloud(operation) {
1153
+ if (this.local) {
1154
+ throw new UnsupportedOperationError(
1155
+ `${operation} is not supported in local mode.`
1156
+ );
1157
+ }
1158
+ }
1159
+ async create(payload) {
1160
+ this.ensureCloud("Custom domain creation");
1161
+ return this.httpClient.post(
1162
+ "/v1/custom-domains",
1163
+ payload,
1164
+ { "X-API-Key": this.httpClient.apiKey }
1165
+ );
1166
+ }
1167
+ async list() {
1168
+ this.ensureCloud("Custom domain listing");
1169
+ return this.httpClient.get(
1170
+ "/v1/custom-domains",
1171
+ void 0,
1172
+ { "X-API-Key": this.httpClient.apiKey }
1173
+ );
1174
+ }
1175
+ async health(domainId) {
1176
+ this.ensureCloud("Custom domain health");
1177
+ const safeDomainId = encodePathSegment(domainId);
1178
+ return this.httpClient.get(
1179
+ `/v1/custom-domains/${safeDomainId}/health`,
1180
+ void 0,
1181
+ { "X-API-Key": this.httpClient.apiKey }
1182
+ );
1183
+ }
1184
+ async verify(domainId) {
1185
+ this.ensureCloud("Custom domain verification");
1186
+ const safeDomainId = encodePathSegment(domainId);
1187
+ return this.httpClient.post(
1188
+ `/v1/custom-domains/${safeDomainId}/verify`,
1189
+ {},
1190
+ { "X-API-Key": this.httpClient.apiKey }
1191
+ );
1192
+ }
1193
+ async delete(domainId) {
1194
+ this.ensureCloud("Custom domain deletion");
1195
+ const safeDomainId = encodePathSegment(domainId);
1196
+ return this.httpClient.delete(
1197
+ `/v1/custom-domains/${safeDomainId}`,
1198
+ { "X-API-Key": this.httpClient.apiKey }
1199
+ );
1200
+ }
1201
+ };
1202
+
1203
+ // src/client/ComputerUseManager.ts
1204
+ var ComputerUseManager = class {
1205
+ constructor(httpClient, local = false) {
1206
+ this.httpClient = httpClient;
1207
+ this.local = local;
1208
+ }
1209
+ ensureCloud(operation) {
1210
+ if (this.local) {
1211
+ throw new UnsupportedOperationError(
1212
+ `${operation} is not supported in local mode.`
1213
+ );
1214
+ }
1215
+ }
1216
+ async viewerUrl(sessionId) {
1217
+ this.ensureCloud("Computer-use viewer URL");
1218
+ const safeSessionId = encodePathSegment(sessionId);
1219
+ return this.httpClient.get(
1220
+ `/v1/computeruse/${safeSessionId}/viewer-url`,
1221
+ void 0,
1222
+ { "X-API-Key": this.httpClient.apiKey }
1223
+ );
1224
+ }
1225
+ async proxy(sessionId, path2, method = "GET", options = {}) {
1226
+ this.ensureCloud("Computer-use proxy");
1227
+ const safeSessionId = encodePathSegment(sessionId);
1228
+ const cleanPath = encodePathSegments(path2);
1229
+ return this.httpClient.request({
1230
+ method,
1231
+ url: `/v1/computeruse/${safeSessionId}/${cleanPath}`,
1232
+ params: options.params,
1233
+ data: options.body,
1234
+ headers: { "X-API-Key": this.httpClient.apiKey }
1235
+ });
1236
+ }
1237
+ async get(sessionId, path2, params) {
1238
+ return this.proxy(sessionId, path2, "GET", { params });
1239
+ }
1240
+ async post(sessionId, path2, body) {
1241
+ return this.proxy(sessionId, path2, "POST", { body });
1242
+ }
1243
+ async put(sessionId, path2, body) {
1244
+ return this.proxy(sessionId, path2, "PUT", { body });
1245
+ }
1246
+ async patch(sessionId, path2, body) {
1247
+ return this.proxy(sessionId, path2, "PATCH", { body });
1248
+ }
1249
+ async delete(sessionId, path2, params) {
1250
+ return this.proxy(sessionId, path2, "DELETE", { params });
1251
+ }
1252
+ async options(sessionId, path2, params) {
1253
+ return this.proxy(sessionId, path2, "OPTIONS", { params });
1254
+ }
1255
+ async head(sessionId, path2, params) {
1256
+ return this.proxy(sessionId, path2, "HEAD", { params });
1257
+ }
1258
+ /**
1259
+ * Get the VNC WebSocket URL for a computer-use session.
1260
+ * Returns the URL to connect to; the actual connection requires a WebSocket client.
1261
+ */
1262
+ async vncWebsockify(sessionId) {
1263
+ this.ensureCloud("Computer-use VNC websockify");
1264
+ const safeSessionId = encodePathSegment(sessionId);
1265
+ return this.httpClient.get(
1266
+ `/v1/computeruse/${safeSessionId}/vnc/websockify`,
1267
+ void 0,
1268
+ { "X-API-Key": this.httpClient.apiKey }
1269
+ );
1270
+ }
1271
+ };
1272
+
1273
+ // src/client/APIKeysManager.ts
1274
+ var APIKeysManager = class {
1275
+ constructor(httpClient, local = false) {
1276
+ this.httpClient = httpClient;
1277
+ this.local = local;
1278
+ }
1279
+ ensureCloud(operation) {
1280
+ if (this.local) {
1281
+ throw new UnsupportedOperationError(
1282
+ `${operation} is not supported in local mode.`
1283
+ );
1284
+ }
1285
+ }
1286
+ async create(payload = {}) {
1287
+ this.ensureCloud("API key creation");
1288
+ return this.httpClient.post(
1289
+ "/v1/api-keys/",
1290
+ payload,
1291
+ { "X-API-Key": this.httpClient.apiKey }
1292
+ );
1293
+ }
1294
+ async list() {
1295
+ this.ensureCloud("API key listing");
1296
+ return this.httpClient.get(
1297
+ "/v1/api-keys/",
1298
+ void 0,
1299
+ { "X-API-Key": this.httpClient.apiKey }
1300
+ );
1301
+ }
1302
+ async get(itemId) {
1303
+ this.ensureCloud("API key lookup");
1304
+ const safeItemId = encodePathSegment(itemId);
1305
+ return this.httpClient.get(
1306
+ `/v1/api-keys/${safeItemId}`,
1307
+ void 0,
1308
+ { "X-API-Key": this.httpClient.apiKey }
1309
+ );
1310
+ }
1311
+ async update(itemId, payload) {
1312
+ this.ensureCloud("API key update");
1313
+ const safeItemId = encodePathSegment(itemId);
1314
+ return this.httpClient.patch(
1315
+ `/v1/api-keys/${safeItemId}`,
1316
+ payload,
1317
+ { "X-API-Key": this.httpClient.apiKey }
1318
+ );
1319
+ }
1320
+ async delete(itemId) {
1321
+ this.ensureCloud("API key deletion");
1322
+ const safeItemId = encodePathSegment(itemId);
1323
+ return this.httpClient.delete(
1324
+ `/v1/api-keys/${safeItemId}`,
1325
+ { "X-API-Key": this.httpClient.apiKey }
1326
+ );
1327
+ }
1328
+ };
1329
+
1330
+ // src/client/AuditManager.ts
1331
+ var AuditManager = class {
1332
+ constructor(httpClient, local = false) {
1333
+ this.httpClient = httpClient;
1334
+ this.local = local;
1335
+ }
1336
+ ensureCloud(operation) {
1337
+ if (this.local) {
1338
+ throw new UnsupportedOperationError(
1339
+ `${operation} is not supported in local mode.`
1340
+ );
1341
+ }
1342
+ }
1343
+ async catalog() {
1344
+ this.ensureCloud("Audit catalog");
1345
+ return this.httpClient.get(
1346
+ "/v1/audit/catalog",
1347
+ void 0,
1348
+ { "X-API-Key": this.httpClient.apiKey }
1349
+ );
1350
+ }
1351
+ async events(query = {}) {
1352
+ this.ensureCloud("Audit event listing");
1353
+ return this.httpClient.get(
1354
+ "/v1/audit/events",
1355
+ query,
1356
+ { "X-API-Key": this.httpClient.apiKey }
1357
+ );
1358
+ }
1359
+ async getEvent(eventId) {
1360
+ this.ensureCloud("Audit event lookup");
1361
+ const safeEventId = encodePathSegment(eventId);
1362
+ return this.httpClient.get(
1363
+ `/v1/audit/events/${safeEventId}`,
1364
+ void 0,
1365
+ { "X-API-Key": this.httpClient.apiKey }
1366
+ );
1367
+ }
1368
+ };
1369
+
1370
+ // src/client/WebhooksManager.ts
1371
+ var WebhooksManager = class {
1372
+ constructor(httpClient, local = false) {
1373
+ this.httpClient = httpClient;
1374
+ this.local = local;
1375
+ }
1376
+ ensureCloud(operation) {
1377
+ if (this.local) {
1378
+ throw new UnsupportedOperationError(
1379
+ `${operation} is not supported in local mode.`
1380
+ );
1381
+ }
1382
+ }
1383
+ async createEndpoint(payload) {
1384
+ this.ensureCloud("Webhook endpoint creation");
1385
+ return this.httpClient.post(
1386
+ "/v1/webhooks/endpoints",
1387
+ payload,
1388
+ { "X-API-Key": this.httpClient.apiKey }
1389
+ );
1390
+ }
1391
+ async listEndpoints() {
1392
+ this.ensureCloud("Webhook endpoint listing");
1393
+ return this.httpClient.get(
1394
+ "/v1/webhooks/endpoints",
1395
+ void 0,
1396
+ { "X-API-Key": this.httpClient.apiKey }
1397
+ );
1398
+ }
1399
+ async getEndpoint(endpointId) {
1400
+ this.ensureCloud("Webhook endpoint lookup");
1401
+ const safeEndpointId = encodePathSegment(endpointId);
1402
+ return this.httpClient.get(
1403
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1404
+ void 0,
1405
+ { "X-API-Key": this.httpClient.apiKey }
1406
+ );
1407
+ }
1408
+ async updateEndpoint(endpointId, payload) {
1409
+ this.ensureCloud("Webhook endpoint update");
1410
+ const safeEndpointId = encodePathSegment(endpointId);
1411
+ return this.httpClient.patch(
1412
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1413
+ payload,
1414
+ { "X-API-Key": this.httpClient.apiKey }
1415
+ );
1416
+ }
1417
+ async deleteEndpoint(endpointId) {
1418
+ this.ensureCloud("Webhook endpoint deletion");
1419
+ const safeEndpointId = encodePathSegment(endpointId);
1420
+ return this.httpClient.delete(
1421
+ `/v1/webhooks/endpoints/${safeEndpointId}`,
1422
+ { "X-API-Key": this.httpClient.apiKey }
1423
+ );
1424
+ }
1425
+ async rotateSecret(endpointId) {
1426
+ this.ensureCloud("Webhook secret rotation");
1427
+ const safeEndpointId = encodePathSegment(endpointId);
1428
+ return this.httpClient.post(
1429
+ `/v1/webhooks/endpoints/${safeEndpointId}/rotate-secret`,
1430
+ {},
1431
+ { "X-API-Key": this.httpClient.apiKey }
1432
+ );
1433
+ }
1434
+ async sendTestEvent(endpointId) {
1435
+ this.ensureCloud("Webhook test event");
1436
+ const safeEndpointId = encodePathSegment(endpointId);
1437
+ return this.httpClient.post(
1438
+ `/v1/webhooks/endpoints/${safeEndpointId}/test`,
1439
+ {},
1440
+ { "X-API-Key": this.httpClient.apiKey }
1441
+ );
1442
+ }
1443
+ async verifyEndpoint(endpointId) {
1444
+ this.ensureCloud("Webhook endpoint verification");
1445
+ const safeEndpointId = encodePathSegment(endpointId);
1446
+ return this.httpClient.post(
1447
+ `/v1/webhooks/endpoints/${safeEndpointId}/verify`,
1448
+ {},
1449
+ { "X-API-Key": this.httpClient.apiKey }
1450
+ );
1451
+ }
1452
+ async listDeliveries(query = {}) {
1453
+ this.ensureCloud("Webhook delivery listing");
1454
+ return this.httpClient.get(
1455
+ "/v1/webhooks/deliveries",
1456
+ query,
1457
+ { "X-API-Key": this.httpClient.apiKey }
1458
+ );
1459
+ }
1460
+ async replayDelivery(deliveryId) {
1461
+ this.ensureCloud("Webhook delivery replay");
1462
+ const safeDeliveryId = encodePathSegment(deliveryId);
1463
+ return this.httpClient.post(
1464
+ `/v1/webhooks/deliveries/${safeDeliveryId}/replay`,
1465
+ {},
1466
+ { "X-API-Key": this.httpClient.apiKey }
1467
+ );
1468
+ }
1469
+ };
1470
+
1471
+ // src/client/VolumesManager.ts
1472
+ import fs from "fs";
1473
+ import path from "path";
881
1474
  import FormData from "form-data";
1475
+ var VolumesManager = class {
1476
+ constructor(httpClient, local = false) {
1477
+ this.httpClient = httpClient;
1478
+ this.local = local;
1479
+ }
1480
+ ensureCloud(operation) {
1481
+ if (this.local) {
1482
+ throw new UnsupportedOperationError(
1483
+ `${operation} is not supported in local mode.`
1484
+ );
1485
+ }
1486
+ }
1487
+ async create(payload) {
1488
+ this.ensureCloud("Volume creation");
1489
+ return this.httpClient.post(
1490
+ "/v1/volumes",
1491
+ payload,
1492
+ { "X-API-Key": this.httpClient.apiKey }
1493
+ );
1494
+ }
1495
+ async list(refreshUsage = false) {
1496
+ this.ensureCloud("Volume listing");
1497
+ return this.httpClient.get(
1498
+ "/v1/volumes",
1499
+ { refresh_usage: refreshUsage },
1500
+ { "X-API-Key": this.httpClient.apiKey }
1501
+ );
1502
+ }
1503
+ async get(volumeId, refreshUsage = false) {
1504
+ this.ensureCloud("Volume lookup");
1505
+ const safeVolumeId = encodePathSegment(volumeId);
1506
+ return this.httpClient.get(
1507
+ `/v1/volumes/${safeVolumeId}`,
1508
+ { refresh_usage: refreshUsage },
1509
+ { "X-API-Key": this.httpClient.apiKey }
1510
+ );
1511
+ }
1512
+ async update(volumeId, payload) {
1513
+ this.ensureCloud("Volume update");
1514
+ const safeVolumeId = encodePathSegment(volumeId);
1515
+ return this.httpClient.patch(
1516
+ `/v1/volumes/${safeVolumeId}`,
1517
+ payload,
1518
+ { "X-API-Key": this.httpClient.apiKey }
1519
+ );
1520
+ }
1521
+ async delete(volumeId) {
1522
+ this.ensureCloud("Volume deletion");
1523
+ const safeVolumeId = encodePathSegment(volumeId);
1524
+ return this.httpClient.delete(
1525
+ `/v1/volumes/${safeVolumeId}`,
1526
+ { "X-API-Key": this.httpClient.apiKey }
1527
+ );
1528
+ }
1529
+ async createCheckpoint(volumeId, payload = {}) {
1530
+ this.ensureCloud("Volume checkpoint creation");
1531
+ const safeVolumeId = encodePathSegment(volumeId);
1532
+ return this.httpClient.post(
1533
+ `/v1/volumes/${safeVolumeId}/checkpoints`,
1534
+ payload,
1535
+ { "X-API-Key": this.httpClient.apiKey }
1536
+ );
1537
+ }
1538
+ async listCheckpoints(volumeId) {
1539
+ this.ensureCloud("Volume checkpoint listing");
1540
+ const safeVolumeId = encodePathSegment(volumeId);
1541
+ return this.httpClient.get(
1542
+ `/v1/volumes/${safeVolumeId}/checkpoints`,
1543
+ void 0,
1544
+ { "X-API-Key": this.httpClient.apiKey }
1545
+ );
1546
+ }
1547
+ async deleteCheckpoint(volumeId, checkpointId) {
1548
+ this.ensureCloud("Volume checkpoint deletion");
1549
+ const safeVolumeId = encodePathSegment(volumeId);
1550
+ const safeCheckpointId = encodePathSegment(checkpointId);
1551
+ return this.httpClient.delete(
1552
+ `/v1/volumes/${safeVolumeId}/checkpoints/${safeCheckpointId}`,
1553
+ { "X-API-Key": this.httpClient.apiKey }
1554
+ );
1555
+ }
1556
+ async uploadFile(volumeId, payload) {
1557
+ this.ensureCloud("Volume file upload");
1558
+ if (!payload.path || payload.path.trim().length === 0) {
1559
+ throw new Error("payload.path is required");
1560
+ }
1561
+ const hasFilePath = typeof payload.filePath === "string" && payload.filePath.length > 0;
1562
+ const hasFileContent = payload.fileContent !== void 0;
1563
+ if (hasFilePath === hasFileContent) {
1564
+ throw new Error("Provide exactly one of payload.filePath or payload.fileContent");
1565
+ }
1566
+ const safeVolumeId = encodePathSegment(volumeId);
1567
+ const formData = new FormData();
1568
+ if (hasFilePath) {
1569
+ const sourcePath = payload.filePath;
1570
+ const filename = payload.filename || path.basename(sourcePath);
1571
+ formData.append("file", fs.createReadStream(sourcePath), { filename });
1572
+ } else {
1573
+ const filename = payload.filename || "upload.bin";
1574
+ const raw = payload.fileContent;
1575
+ const buffer = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
1576
+ formData.append("file", buffer, { filename });
1577
+ }
1578
+ formData.append("path", payload.path);
1579
+ if (payload.overwrite !== void 0) {
1580
+ formData.append("overwrite", String(payload.overwrite));
1581
+ }
1582
+ return this.httpClient.postFormData(
1583
+ `/v1/volumes/${safeVolumeId}/files/upload`,
1584
+ formData
1585
+ );
1586
+ }
1587
+ async downloadFile(volumeId, path2) {
1588
+ this.ensureCloud("Volume file download");
1589
+ const safeVolumeId = encodePathSegment(volumeId);
1590
+ const response = await this.httpClient.post(
1591
+ `/v1/volumes/${safeVolumeId}/files/download`,
1592
+ { path: path2 },
1593
+ { "X-API-Key": this.httpClient.apiKey }
1594
+ );
1595
+ return {
1596
+ path: response.path,
1597
+ filename: response.filename,
1598
+ size: response.size,
1599
+ content: Buffer.from(response.content || "", "base64")
1600
+ };
1601
+ }
1602
+ async listFiles(volumeId, options = {}) {
1603
+ this.ensureCloud("Volume file listing");
1604
+ const safeVolumeId = encodePathSegment(volumeId);
1605
+ return this.httpClient.get(
1606
+ `/v1/volumes/${safeVolumeId}/files`,
1607
+ {
1608
+ prefix: options.prefix ?? "",
1609
+ recursive: options.recursive ?? true,
1610
+ limit: options.limit ?? 1e3
1611
+ },
1612
+ { "X-API-Key": this.httpClient.apiKey }
1613
+ );
1614
+ }
1615
+ async deleteFile(volumeId, targetPath) {
1616
+ this.ensureCloud("Volume file deletion");
1617
+ const safeVolumeId = encodePathSegment(volumeId);
1618
+ return this.httpClient.request({
1619
+ method: "DELETE",
1620
+ url: `/v1/volumes/${safeVolumeId}/files`,
1621
+ params: { path: targetPath },
1622
+ headers: { "X-API-Key": this.httpClient.apiKey }
1623
+ });
1624
+ }
1625
+ };
1626
+
1627
+ // src/client/InstaVM.ts
1628
+ import FormData2 from "form-data";
882
1629
  var InstaVM = class {
883
1630
  constructor(apiKey, options = {}) {
884
1631
  this._sessionId = null;
1632
+ this._vmUsed = false;
885
1633
  this.local = options.local || false;
886
1634
  this.timeout = options.timeout || 3e5;
1635
+ this.memory_mb = options.memory_mb;
1636
+ this.cpu_count = options.cpu_count;
1637
+ this.metadata = options.metadata;
1638
+ this.env = options.env;
887
1639
  if (!this.local && !apiKey) {
888
1640
  throw new AuthenticationError("API key is required for cloud mode");
889
1641
  }
@@ -896,6 +1648,15 @@ var InstaVM = class {
896
1648
  };
897
1649
  this.httpClient = new HTTPClient(config);
898
1650
  this.browser = new BrowserManager(this.httpClient, this.local);
1651
+ this.vms = new VMsManager(this.httpClient, this.local);
1652
+ this.snapshots = new SnapshotsManager(this.httpClient, this.local);
1653
+ this.shares = new SharesManager(this.httpClient, this.local, () => this._sessionId);
1654
+ this.customDomains = new CustomDomainsManager(this.httpClient, this.local);
1655
+ this.computerUse = new ComputerUseManager(this.httpClient, this.local);
1656
+ this.apiKeys = new APIKeysManager(this.httpClient, this.local);
1657
+ this.audit = new AuditManager(this.httpClient, this.local);
1658
+ this.webhooks = new WebhooksManager(this.httpClient, this.local);
1659
+ this.volumes = new VolumesManager(this.httpClient, this.local);
899
1660
  }
900
1661
  /**
901
1662
  * Ensure operation is not called in local mode
@@ -941,6 +1702,9 @@ var InstaVM = class {
941
1702
  if (response.session_id) {
942
1703
  this._sessionId = response.session_id;
943
1704
  }
1705
+ if (!this.local) {
1706
+ this._vmUsed = true;
1707
+ }
944
1708
  return {
945
1709
  stdout: response.stdout || "",
946
1710
  stderr: response.stderr || "",
@@ -984,6 +1748,7 @@ var InstaVM = class {
984
1748
  if (response.session_id) {
985
1749
  this._sessionId = response.session_id;
986
1750
  }
1751
+ this._vmUsed = true;
987
1752
  return {
988
1753
  taskId: response.task_id,
989
1754
  status: response.status || "pending",
@@ -1055,7 +1820,7 @@ var InstaVM = class {
1055
1820
  if (!sessionId) {
1056
1821
  throw new SessionError("Session ID not set. Please create a session first using createSession().");
1057
1822
  }
1058
- const formData = new FormData();
1823
+ const formData = new FormData2();
1059
1824
  for (const file of files) {
1060
1825
  if (Buffer.isBuffer(file.content)) {
1061
1826
  formData.append("files", file.content, file.name);
@@ -1097,10 +1862,26 @@ var InstaVM = class {
1097
1862
  async createSession() {
1098
1863
  this.ensureNotLocal("Session management");
1099
1864
  try {
1100
- const response = await this.httpClient.post("/v1/sessions/session", {
1865
+ const requestBody = {
1101
1866
  api_key: this.httpClient.apiKey,
1102
1867
  vm_lifetime_seconds: Math.floor(this.timeout / 1e3)
1103
- });
1868
+ };
1869
+ if (this.memory_mb !== void 0) {
1870
+ requestBody.memory_mb = this.memory_mb;
1871
+ }
1872
+ if (this.cpu_count !== void 0) {
1873
+ requestBody.vcpu_count = this.cpu_count;
1874
+ }
1875
+ if (this.metadata !== void 0) {
1876
+ requestBody.metadata = this.metadata;
1877
+ }
1878
+ if (this.env !== void 0) {
1879
+ requestBody.env = this.env;
1880
+ }
1881
+ const response = await this.httpClient.post(
1882
+ "/v1/sessions/session",
1883
+ requestBody
1884
+ );
1104
1885
  if (response.session_id) {
1105
1886
  this._sessionId = response.session_id;
1106
1887
  return response.session_id;
@@ -1151,6 +1932,49 @@ var InstaVM = class {
1151
1932
  return false;
1152
1933
  }
1153
1934
  }
1935
+ /**
1936
+ * Get the app URL for a session
1937
+ *
1938
+ * @param sessionId - Session ID (uses current session if not provided)
1939
+ * @param port - Port to expose (1-65535, default: 80)
1940
+ */
1941
+ async getSessionAppUrl(sessionId, port) {
1942
+ this.ensureNotLocal("Session app URL");
1943
+ const targetSessionId = sessionId || this._sessionId;
1944
+ if (!targetSessionId) {
1945
+ throw new SessionError("Session ID not set. Please create a session first.");
1946
+ }
1947
+ const params = {};
1948
+ if (port !== void 0) {
1949
+ params.port = port;
1950
+ }
1951
+ return this.httpClient.get(
1952
+ `/v1/sessions/app-url/${targetSessionId}`,
1953
+ params,
1954
+ { "X-API-Key": this.httpClient.apiKey }
1955
+ );
1956
+ }
1957
+ /**
1958
+ * List sandbox records with optional filtering
1959
+ *
1960
+ * @param options.metadata - JSON-serializable metadata filters
1961
+ * @param options.limit - Maximum number of results (1-1000, default: 100)
1962
+ */
1963
+ async listSandboxes(options = {}) {
1964
+ this.ensureNotLocal("Sandbox listing");
1965
+ const params = {};
1966
+ if (options.metadata !== void 0) {
1967
+ params.metadata = JSON.stringify(options.metadata);
1968
+ }
1969
+ if (options.limit !== void 0) {
1970
+ params.limit = options.limit;
1971
+ }
1972
+ return this.httpClient.get(
1973
+ "/v1/sessions/sandboxes",
1974
+ params,
1975
+ { "X-API-Key": this.httpClient.apiKey }
1976
+ );
1977
+ }
1154
1978
  /**
1155
1979
  * Get usage statistics for a session
1156
1980
  */
@@ -1214,17 +2038,193 @@ var InstaVM = class {
1214
2038
  get sessionId() {
1215
2039
  return this._sessionId;
1216
2040
  }
2041
+ /**
2042
+ * Kill the VM associated with a session
2043
+ *
2044
+ * @param sessionId - The session UUID whose VM should be killed. If not provided, uses current sessionId
2045
+ * @returns Result containing success message and killed VM ID
2046
+ */
2047
+ async kill(sessionId) {
2048
+ this.ensureNotLocal("VM kill operation");
2049
+ const targetSessionId = sessionId || this._sessionId;
2050
+ if (!targetSessionId) {
2051
+ throw new SessionError("Session ID not set. Please provide a sessionId or start a session first.");
2052
+ }
2053
+ try {
2054
+ const response = await this.httpClient.post(
2055
+ "/kill",
2056
+ { session_id: targetSessionId },
2057
+ { "X-API-Key": this.httpClient.apiKey }
2058
+ );
2059
+ if (!sessionId && this._sessionId === targetSessionId) {
2060
+ this._sessionId = null;
2061
+ }
2062
+ return response;
2063
+ } catch (error) {
2064
+ if (error instanceof Error && "statusCode" in error) {
2065
+ const statusCode = error.statusCode;
2066
+ if (statusCode === 403) {
2067
+ throw new AuthenticationError("You don't own this session", { cause: error });
2068
+ }
2069
+ if (statusCode === 404) {
2070
+ throw new SessionError("Session not found or no VM assigned to session (has execute() been called?)", { cause: error });
2071
+ }
2072
+ }
2073
+ const errorMessage = error instanceof Error ? error.message : String(error);
2074
+ throw new SessionError(
2075
+ `Failed to kill VM: ${errorMessage}`,
2076
+ { cause: error }
2077
+ );
2078
+ }
2079
+ }
2080
+ // --- Egress Policy Methods ---
2081
+ /**
2082
+ * Set egress policy for a session
2083
+ */
2084
+ async setSessionEgress(options = {}, sessionId) {
2085
+ this.ensureNotLocal("Egress policy management");
2086
+ const targetSessionId = sessionId || this._sessionId;
2087
+ if (!targetSessionId) {
2088
+ throw new SessionError("Session ID not set. Please create a session first.");
2089
+ }
2090
+ const response = await this.httpClient.post(
2091
+ `/v1/egress/session/${targetSessionId}`,
2092
+ {
2093
+ allow_public_repos: options.allowPackageManagers ?? true,
2094
+ allow_http: options.allowHttp ?? true,
2095
+ allow_https: options.allowHttps ?? true,
2096
+ allowed_domains: options.allowedDomains ?? [],
2097
+ allowed_cidrs: options.allowedCidrs ?? []
2098
+ },
2099
+ { "X-API-Key": this.httpClient.apiKey }
2100
+ );
2101
+ return response;
2102
+ }
2103
+ /**
2104
+ * Get egress policy for a session
2105
+ */
2106
+ async getSessionEgress(sessionId) {
2107
+ this.ensureNotLocal("Egress policy management");
2108
+ const targetSessionId = sessionId || this._sessionId;
2109
+ if (!targetSessionId) {
2110
+ throw new SessionError("Session ID not set. Please create a session first.");
2111
+ }
2112
+ const response = await this.httpClient.get(
2113
+ `/v1/egress/session/${targetSessionId}`,
2114
+ void 0,
2115
+ { "X-API-Key": this.httpClient.apiKey }
2116
+ );
2117
+ return {
2118
+ allowPackageManagers: response.allow_public_repos,
2119
+ allowHttp: response.allow_http,
2120
+ allowHttps: response.allow_https,
2121
+ allowedDomains: response.allowed_domains || [],
2122
+ allowedCidrs: response.allowed_cidrs || []
2123
+ };
2124
+ }
2125
+ /**
2126
+ * Set egress policy for a specific VM
2127
+ */
2128
+ async setVmEgress(vmId, options = {}) {
2129
+ this.ensureNotLocal("Egress policy management");
2130
+ const response = await this.httpClient.post(
2131
+ `/v1/egress/vm/${vmId}`,
2132
+ {
2133
+ allow_public_repos: options.allowPackageManagers ?? true,
2134
+ allow_http: options.allowHttp ?? true,
2135
+ allow_https: options.allowHttps ?? true,
2136
+ allowed_domains: options.allowedDomains ?? [],
2137
+ allowed_cidrs: options.allowedCidrs ?? []
2138
+ },
2139
+ { "X-API-Key": this.httpClient.apiKey }
2140
+ );
2141
+ return response;
2142
+ }
2143
+ /**
2144
+ * Get egress policy for a specific VM
2145
+ */
2146
+ async getVmEgress(vmId) {
2147
+ this.ensureNotLocal("Egress policy management");
2148
+ const response = await this.httpClient.get(
2149
+ `/v1/egress/vm/${vmId}`,
2150
+ void 0,
2151
+ { "X-API-Key": this.httpClient.apiKey }
2152
+ );
2153
+ return {
2154
+ allowPackageManagers: response.allow_public_repos,
2155
+ allowHttp: response.allow_http,
2156
+ allowHttps: response.allow_https,
2157
+ allowedDomains: response.allowed_domains || [],
2158
+ allowedCidrs: response.allowed_cidrs || []
2159
+ };
2160
+ }
2161
+ // --- SSH Key Methods ---
2162
+ /**
2163
+ * Add an SSH public key
2164
+ */
2165
+ async addSshKey(publicKey) {
2166
+ this.ensureNotLocal("SSH key management");
2167
+ const response = await this.httpClient.post(
2168
+ "/v1/ssh-keys",
2169
+ { public_key: publicKey },
2170
+ { "X-API-Key": this.httpClient.apiKey }
2171
+ );
2172
+ return {
2173
+ id: response.id,
2174
+ fingerprint: response.fingerprint,
2175
+ keyType: response.key_type,
2176
+ comment: response.comment ?? null,
2177
+ createdAt: response.created_at
2178
+ };
2179
+ }
2180
+ /**
2181
+ * List all active SSH keys
2182
+ */
2183
+ async listSshKeys() {
2184
+ this.ensureNotLocal("SSH key management");
2185
+ const response = await this.httpClient.get(
2186
+ "/v1/ssh-keys",
2187
+ void 0,
2188
+ { "X-API-Key": this.httpClient.apiKey }
2189
+ );
2190
+ const keys = response.keys || [];
2191
+ return keys.map((k) => ({
2192
+ id: k.id,
2193
+ fingerprint: k.fingerprint,
2194
+ keyType: k.key_type,
2195
+ comment: k.comment ?? null,
2196
+ createdAt: k.created_at
2197
+ }));
2198
+ }
2199
+ /**
2200
+ * Delete an SSH key by ID
2201
+ */
2202
+ async deleteSshKey(keyId) {
2203
+ this.ensureNotLocal("SSH key management");
2204
+ const response = await this.httpClient.delete(
2205
+ `/v1/ssh-keys/${keyId}`,
2206
+ { "X-API-Key": this.httpClient.apiKey }
2207
+ );
2208
+ return response;
2209
+ }
1217
2210
  /**
1218
2211
  * Clean up resources
1219
2212
  */
1220
2213
  async dispose() {
1221
- if (this._sessionId) {
2214
+ if (this._sessionId && !this.local && this._vmUsed) {
2215
+ try {
2216
+ await this.kill();
2217
+ } catch (e) {
2218
+ }
2219
+ } else if (this._sessionId) {
1222
2220
  await this.closeSession();
1223
2221
  }
1224
2222
  await this.browser.dispose();
1225
2223
  }
1226
2224
  };
1227
2225
  export {
2226
+ APIKeysManager,
2227
+ AuditManager,
1228
2228
  AuthenticationError,
1229
2229
  BrowserError,
1230
2230
  BrowserInteractionError,
@@ -1233,6 +2233,8 @@ export {
1233
2233
  BrowserSession,
1234
2234
  BrowserSessionError,
1235
2235
  BrowserTimeoutError,
2236
+ ComputerUseManager,
2237
+ CustomDomainsManager,
1236
2238
  ElementNotFoundError,
1237
2239
  ExecutionError,
1238
2240
  InstaVM,
@@ -1241,6 +2243,11 @@ export {
1241
2243
  QuotaExceededError,
1242
2244
  RateLimitError,
1243
2245
  SessionError,
1244
- UnsupportedOperationError
2246
+ SharesManager,
2247
+ SnapshotsManager,
2248
+ UnsupportedOperationError,
2249
+ VMsManager,
2250
+ VolumesManager,
2251
+ WebhooksManager
1245
2252
  };
1246
2253
  //# sourceMappingURL=index.mjs.map