instavm 0.11.0 → 0.15.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.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- "use strict";
3
2
  var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -55,6 +54,7 @@ __export(index_exports, {
55
54
  SnapshotsManager: () => SnapshotsManager,
56
55
  UnsupportedOperationError: () => UnsupportedOperationError,
57
56
  VMsManager: () => VMsManager,
57
+ VolumesManager: () => VolumesManager,
58
58
  WebhooksManager: () => WebhooksManager
59
59
  });
60
60
  module.exports = __toCommonJS(index_exports);
@@ -198,7 +198,7 @@ var HTTPClient = class {
198
198
  timeout: config.timeout,
199
199
  headers: {
200
200
  "Content-Type": "application/json",
201
- "User-Agent": "instavm-js-sdk/0.11.0"
201
+ "User-Agent": "instavm-js-sdk/0.15.0"
202
202
  }
203
203
  });
204
204
  this.setupInterceptors();
@@ -971,10 +971,14 @@ var BrowserManager = class {
971
971
 
972
972
  // src/utils/path.ts
973
973
  function encodePathSegment(value) {
974
- return encodeURIComponent(String(value));
974
+ const segment = String(value);
975
+ if (segment === "." || segment === "..") {
976
+ throw new Error("Path traversal not allowed in path segment");
977
+ }
978
+ return encodeURIComponent(segment);
975
979
  }
976
- function encodePathSegments(path) {
977
- const segments = path.replace(/^\/+/, "").split("/").filter((segment) => segment.length > 0 && segment !== ".");
980
+ function encodePathSegments(path2) {
981
+ const segments = path2.replace(/^\/+/, "").split("/").filter((segment) => segment.length > 0 && segment !== ".");
978
982
  if (segments.some((segment) => segment === "..")) {
979
983
  throw new Error("Path traversal not allowed in proxy path");
980
984
  }
@@ -1074,6 +1078,37 @@ var VMsManager = class {
1074
1078
  headers: { "X-API-Key": this.httpClient.apiKey }
1075
1079
  });
1076
1080
  }
1081
+ async mountVolume(vmId, payload, wait = true) {
1082
+ this.ensureCloud("VM volume mount");
1083
+ const safeVmId = encodePathSegment(vmId);
1084
+ return this.httpClient.request({
1085
+ method: "POST",
1086
+ url: `/v1/vms/${safeVmId}/volumes`,
1087
+ params: { wait },
1088
+ data: payload,
1089
+ headers: { "X-API-Key": this.httpClient.apiKey }
1090
+ });
1091
+ }
1092
+ async listVolumes(vmId) {
1093
+ this.ensureCloud("VM volume listing");
1094
+ const safeVmId = encodePathSegment(vmId);
1095
+ return this.httpClient.get(
1096
+ `/v1/vms/${safeVmId}/volumes`,
1097
+ void 0,
1098
+ { "X-API-Key": this.httpClient.apiKey }
1099
+ );
1100
+ }
1101
+ async unmountVolume(vmId, volumeId, mountPath, wait = true) {
1102
+ this.ensureCloud("VM volume unmount");
1103
+ const safeVmId = encodePathSegment(vmId);
1104
+ const safeVolumeId = encodePathSegment(volumeId);
1105
+ return this.httpClient.request({
1106
+ method: "DELETE",
1107
+ url: `/v1/vms/${safeVmId}/volumes/${safeVolumeId}`,
1108
+ params: { mount_path: mountPath, wait },
1109
+ headers: { "X-API-Key": this.httpClient.apiKey }
1110
+ });
1111
+ }
1077
1112
  };
1078
1113
 
1079
1114
  // src/client/SnapshotsManager.ts
@@ -1246,10 +1281,10 @@ var ComputerUseManager = class {
1246
1281
  { "X-API-Key": this.httpClient.apiKey }
1247
1282
  );
1248
1283
  }
1249
- async proxy(sessionId, path, method = "GET", options = {}) {
1284
+ async proxy(sessionId, path2, method = "GET", options = {}) {
1250
1285
  this.ensureCloud("Computer-use proxy");
1251
1286
  const safeSessionId = encodePathSegment(sessionId);
1252
- const cleanPath = encodePathSegments(path);
1287
+ const cleanPath = encodePathSegments(path2);
1253
1288
  return this.httpClient.request({
1254
1289
  method,
1255
1290
  url: `/v1/computeruse/${safeSessionId}/${cleanPath}`,
@@ -1258,23 +1293,39 @@ var ComputerUseManager = class {
1258
1293
  headers: { "X-API-Key": this.httpClient.apiKey }
1259
1294
  });
1260
1295
  }
1261
- async get(sessionId, path, params) {
1262
- return this.proxy(sessionId, path, "GET", { params });
1296
+ async get(sessionId, path2, params) {
1297
+ return this.proxy(sessionId, path2, "GET", { params });
1263
1298
  }
1264
- async post(sessionId, path, body) {
1265
- return this.proxy(sessionId, path, "POST", { body });
1299
+ async post(sessionId, path2, body) {
1300
+ return this.proxy(sessionId, path2, "POST", { body });
1266
1301
  }
1267
- async put(sessionId, path, body) {
1268
- return this.proxy(sessionId, path, "PUT", { body });
1302
+ async put(sessionId, path2, body) {
1303
+ return this.proxy(sessionId, path2, "PUT", { body });
1269
1304
  }
1270
- async patch(sessionId, path, body) {
1271
- return this.proxy(sessionId, path, "PATCH", { body });
1305
+ async patch(sessionId, path2, body) {
1306
+ return this.proxy(sessionId, path2, "PATCH", { body });
1272
1307
  }
1273
- async delete(sessionId, path, params) {
1274
- return this.proxy(sessionId, path, "DELETE", { params });
1308
+ async delete(sessionId, path2, params) {
1309
+ return this.proxy(sessionId, path2, "DELETE", { params });
1275
1310
  }
1276
- async options(sessionId, path, params) {
1277
- return this.proxy(sessionId, path, "OPTIONS", { params });
1311
+ async options(sessionId, path2, params) {
1312
+ return this.proxy(sessionId, path2, "OPTIONS", { params });
1313
+ }
1314
+ async head(sessionId, path2, params) {
1315
+ return this.proxy(sessionId, path2, "HEAD", { params });
1316
+ }
1317
+ /**
1318
+ * Get the VNC WebSocket URL for a computer-use session.
1319
+ * Returns the URL to connect to; the actual connection requires a WebSocket client.
1320
+ */
1321
+ async vncWebsockify(sessionId) {
1322
+ this.ensureCloud("Computer-use VNC websockify");
1323
+ const safeSessionId = encodePathSegment(sessionId);
1324
+ return this.httpClient.get(
1325
+ `/v1/computeruse/${safeSessionId}/vnc/websockify`,
1326
+ void 0,
1327
+ { "X-API-Key": this.httpClient.apiKey }
1328
+ );
1278
1329
  }
1279
1330
  };
1280
1331
 
@@ -1476,8 +1527,164 @@ var WebhooksManager = class {
1476
1527
  }
1477
1528
  };
1478
1529
 
1479
- // src/client/InstaVM.ts
1530
+ // src/client/VolumesManager.ts
1531
+ var import_fs = __toESM(require("fs"));
1532
+ var import_path9 = __toESM(require("path"));
1480
1533
  var import_form_data = __toESM(require("form-data"));
1534
+ var VolumesManager = class {
1535
+ constructor(httpClient, local = false) {
1536
+ this.httpClient = httpClient;
1537
+ this.local = local;
1538
+ }
1539
+ ensureCloud(operation) {
1540
+ if (this.local) {
1541
+ throw new UnsupportedOperationError(
1542
+ `${operation} is not supported in local mode.`
1543
+ );
1544
+ }
1545
+ }
1546
+ async create(payload) {
1547
+ this.ensureCloud("Volume creation");
1548
+ return this.httpClient.post(
1549
+ "/v1/volumes",
1550
+ payload,
1551
+ { "X-API-Key": this.httpClient.apiKey }
1552
+ );
1553
+ }
1554
+ async list(refreshUsage = false) {
1555
+ this.ensureCloud("Volume listing");
1556
+ return this.httpClient.get(
1557
+ "/v1/volumes",
1558
+ { refresh_usage: refreshUsage },
1559
+ { "X-API-Key": this.httpClient.apiKey }
1560
+ );
1561
+ }
1562
+ async get(volumeId, refreshUsage = false) {
1563
+ this.ensureCloud("Volume lookup");
1564
+ const safeVolumeId = encodePathSegment(volumeId);
1565
+ return this.httpClient.get(
1566
+ `/v1/volumes/${safeVolumeId}`,
1567
+ { refresh_usage: refreshUsage },
1568
+ { "X-API-Key": this.httpClient.apiKey }
1569
+ );
1570
+ }
1571
+ async update(volumeId, payload) {
1572
+ this.ensureCloud("Volume update");
1573
+ const safeVolumeId = encodePathSegment(volumeId);
1574
+ return this.httpClient.patch(
1575
+ `/v1/volumes/${safeVolumeId}`,
1576
+ payload,
1577
+ { "X-API-Key": this.httpClient.apiKey }
1578
+ );
1579
+ }
1580
+ async delete(volumeId) {
1581
+ this.ensureCloud("Volume deletion");
1582
+ const safeVolumeId = encodePathSegment(volumeId);
1583
+ return this.httpClient.delete(
1584
+ `/v1/volumes/${safeVolumeId}`,
1585
+ { "X-API-Key": this.httpClient.apiKey }
1586
+ );
1587
+ }
1588
+ async createCheckpoint(volumeId, payload = {}) {
1589
+ this.ensureCloud("Volume checkpoint creation");
1590
+ const safeVolumeId = encodePathSegment(volumeId);
1591
+ return this.httpClient.post(
1592
+ `/v1/volumes/${safeVolumeId}/checkpoints`,
1593
+ payload,
1594
+ { "X-API-Key": this.httpClient.apiKey }
1595
+ );
1596
+ }
1597
+ async listCheckpoints(volumeId) {
1598
+ this.ensureCloud("Volume checkpoint listing");
1599
+ const safeVolumeId = encodePathSegment(volumeId);
1600
+ return this.httpClient.get(
1601
+ `/v1/volumes/${safeVolumeId}/checkpoints`,
1602
+ void 0,
1603
+ { "X-API-Key": this.httpClient.apiKey }
1604
+ );
1605
+ }
1606
+ async deleteCheckpoint(volumeId, checkpointId) {
1607
+ this.ensureCloud("Volume checkpoint deletion");
1608
+ const safeVolumeId = encodePathSegment(volumeId);
1609
+ const safeCheckpointId = encodePathSegment(checkpointId);
1610
+ return this.httpClient.delete(
1611
+ `/v1/volumes/${safeVolumeId}/checkpoints/${safeCheckpointId}`,
1612
+ { "X-API-Key": this.httpClient.apiKey }
1613
+ );
1614
+ }
1615
+ async uploadFile(volumeId, payload) {
1616
+ this.ensureCloud("Volume file upload");
1617
+ if (!payload.path || payload.path.trim().length === 0) {
1618
+ throw new Error("payload.path is required");
1619
+ }
1620
+ const hasFilePath = typeof payload.filePath === "string" && payload.filePath.length > 0;
1621
+ const hasFileContent = payload.fileContent !== void 0;
1622
+ if (hasFilePath === hasFileContent) {
1623
+ throw new Error("Provide exactly one of payload.filePath or payload.fileContent");
1624
+ }
1625
+ const safeVolumeId = encodePathSegment(volumeId);
1626
+ const formData = new import_form_data.default();
1627
+ if (hasFilePath) {
1628
+ const sourcePath = payload.filePath;
1629
+ const filename = payload.filename || import_path9.default.basename(sourcePath);
1630
+ formData.append("file", import_fs.default.createReadStream(sourcePath), { filename });
1631
+ } else {
1632
+ const filename = payload.filename || "upload.bin";
1633
+ const raw = payload.fileContent;
1634
+ const buffer = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
1635
+ formData.append("file", buffer, { filename });
1636
+ }
1637
+ formData.append("path", payload.path);
1638
+ if (payload.overwrite !== void 0) {
1639
+ formData.append("overwrite", String(payload.overwrite));
1640
+ }
1641
+ return this.httpClient.postFormData(
1642
+ `/v1/volumes/${safeVolumeId}/files/upload`,
1643
+ formData
1644
+ );
1645
+ }
1646
+ async downloadFile(volumeId, path2) {
1647
+ this.ensureCloud("Volume file download");
1648
+ const safeVolumeId = encodePathSegment(volumeId);
1649
+ const response = await this.httpClient.post(
1650
+ `/v1/volumes/${safeVolumeId}/files/download`,
1651
+ { path: path2 },
1652
+ { "X-API-Key": this.httpClient.apiKey }
1653
+ );
1654
+ return {
1655
+ path: response.path,
1656
+ filename: response.filename,
1657
+ size: response.size,
1658
+ content: Buffer.from(response.content || "", "base64")
1659
+ };
1660
+ }
1661
+ async listFiles(volumeId, options = {}) {
1662
+ this.ensureCloud("Volume file listing");
1663
+ const safeVolumeId = encodePathSegment(volumeId);
1664
+ return this.httpClient.get(
1665
+ `/v1/volumes/${safeVolumeId}/files`,
1666
+ {
1667
+ prefix: options.prefix ?? "",
1668
+ recursive: options.recursive ?? true,
1669
+ limit: options.limit ?? 1e3
1670
+ },
1671
+ { "X-API-Key": this.httpClient.apiKey }
1672
+ );
1673
+ }
1674
+ async deleteFile(volumeId, targetPath) {
1675
+ this.ensureCloud("Volume file deletion");
1676
+ const safeVolumeId = encodePathSegment(volumeId);
1677
+ return this.httpClient.request({
1678
+ method: "DELETE",
1679
+ url: `/v1/volumes/${safeVolumeId}/files`,
1680
+ params: { path: targetPath },
1681
+ headers: { "X-API-Key": this.httpClient.apiKey }
1682
+ });
1683
+ }
1684
+ };
1685
+
1686
+ // src/client/InstaVM.ts
1687
+ var import_form_data2 = __toESM(require("form-data"));
1481
1688
  var InstaVM = class {
1482
1689
  constructor(apiKey, options = {}) {
1483
1690
  this._sessionId = null;
@@ -1508,6 +1715,7 @@ var InstaVM = class {
1508
1715
  this.apiKeys = new APIKeysManager(this.httpClient, this.local);
1509
1716
  this.audit = new AuditManager(this.httpClient, this.local);
1510
1717
  this.webhooks = new WebhooksManager(this.httpClient, this.local);
1718
+ this.volumes = new VolumesManager(this.httpClient, this.local);
1511
1719
  }
1512
1720
  /**
1513
1721
  * Ensure operation is not called in local mode
@@ -1671,7 +1879,7 @@ var InstaVM = class {
1671
1879
  if (!sessionId) {
1672
1880
  throw new SessionError("Session ID not set. Please create a session first using createSession().");
1673
1881
  }
1674
- const formData = new import_form_data.default();
1882
+ const formData = new import_form_data2.default();
1675
1883
  for (const file of files) {
1676
1884
  if (Buffer.isBuffer(file.content)) {
1677
1885
  formData.append("files", file.content, file.name);
@@ -1783,6 +1991,49 @@ var InstaVM = class {
1783
1991
  return false;
1784
1992
  }
1785
1993
  }
1994
+ /**
1995
+ * Get the app URL for a session
1996
+ *
1997
+ * @param sessionId - Session ID (uses current session if not provided)
1998
+ * @param port - Port to expose (1-65535, default: 80)
1999
+ */
2000
+ async getSessionAppUrl(sessionId, port) {
2001
+ this.ensureNotLocal("Session app URL");
2002
+ const targetSessionId = sessionId || this._sessionId;
2003
+ if (!targetSessionId) {
2004
+ throw new SessionError("Session ID not set. Please create a session first.");
2005
+ }
2006
+ const params = {};
2007
+ if (port !== void 0) {
2008
+ params.port = port;
2009
+ }
2010
+ return this.httpClient.get(
2011
+ `/v1/sessions/app-url/${targetSessionId}`,
2012
+ params,
2013
+ { "X-API-Key": this.httpClient.apiKey }
2014
+ );
2015
+ }
2016
+ /**
2017
+ * List sandbox records with optional filtering
2018
+ *
2019
+ * @param options.metadata - JSON-serializable metadata filters
2020
+ * @param options.limit - Maximum number of results (1-1000, default: 100)
2021
+ */
2022
+ async listSandboxes(options = {}) {
2023
+ this.ensureNotLocal("Sandbox listing");
2024
+ const params = {};
2025
+ if (options.metadata !== void 0) {
2026
+ params.metadata = JSON.stringify(options.metadata);
2027
+ }
2028
+ if (options.limit !== void 0) {
2029
+ params.limit = options.limit;
2030
+ }
2031
+ return this.httpClient.get(
2032
+ "/v1/sessions/sandboxes",
2033
+ params,
2034
+ { "X-API-Key": this.httpClient.apiKey }
2035
+ );
2036
+ }
1786
2037
  /**
1787
2038
  * Get usage statistics for a session
1788
2039
  */
@@ -1794,7 +2045,9 @@ var InstaVM = class {
1794
2045
  }
1795
2046
  try {
1796
2047
  const response = await this.httpClient.get(
1797
- `/v1/sessions/usage/${targetSessionId}`
2048
+ `/v1/sessions/usage/${targetSessionId}`,
2049
+ void 0,
2050
+ { "X-API-Key": this.httpClient.apiKey }
1798
2051
  );
1799
2052
  return {
1800
2053
  sessionsUsed: response.sessions_used || 0,
@@ -1810,6 +2063,32 @@ var InstaVM = class {
1810
2063
  );
1811
2064
  }
1812
2065
  }
2066
+ /**
2067
+ * Get the current user profile.
2068
+ */
2069
+ async getCurrentUser() {
2070
+ this.ensureNotLocal("User profile lookup");
2071
+ return this.httpClient.get(
2072
+ "/v1/me",
2073
+ void 0,
2074
+ { "X-API-Key": this.httpClient.apiKey }
2075
+ );
2076
+ }
2077
+ /**
2078
+ * Get the current status of a session.
2079
+ */
2080
+ async getSessionStatus(sessionId) {
2081
+ this.ensureNotLocal("Session management");
2082
+ const targetSessionId = sessionId || this._sessionId;
2083
+ if (!targetSessionId) {
2084
+ throw new SessionError("Session ID not set. Please create a session first.");
2085
+ }
2086
+ return this.httpClient.get(
2087
+ `/v1/sessions/status/${targetSessionId}`,
2088
+ void 0,
2089
+ { "X-API-Key": this.httpClient.apiKey }
2090
+ );
2091
+ }
1813
2092
  /**
1814
2093
  * Download a file from the remote VM
1815
2094
  */
@@ -2056,6 +2335,7 @@ var InstaVM = class {
2056
2335
  SnapshotsManager,
2057
2336
  UnsupportedOperationError,
2058
2337
  VMsManager,
2338
+ VolumesManager,
2059
2339
  WebhooksManager
2060
2340
  });
2061
2341
  //# sourceMappingURL=index.js.map