lexmount 0.2.2 → 0.2.4

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
@@ -37,11 +37,17 @@ __export(index_exports, {
37
37
  ContextLockedError: () => ContextLockedError,
38
38
  ContextNotFoundError: () => ContextNotFoundError,
39
39
  ContextsResource: () => ContextsResource,
40
+ ExtensionInfo: () => ExtensionInfo,
41
+ ExtensionsResource: () => ExtensionsResource,
40
42
  Lexmount: () => Lexmount,
41
43
  LexmountError: () => LexmountError,
42
44
  LexmountLogger: () => LexmountLogger,
43
45
  NetworkError: () => NetworkError,
44
46
  PaginationInfo: () => PaginationInfo,
47
+ SessionDownloadInfo: () => SessionDownloadInfo,
48
+ SessionDownloadsDeleteResponse: () => SessionDownloadsDeleteResponse,
49
+ SessionDownloadsListResponse: () => SessionDownloadsListResponse,
50
+ SessionDownloadsResource: () => SessionDownloadsResource,
45
51
  SessionInfo: () => SessionInfo,
46
52
  SessionListResponse: () => SessionListResponse,
47
53
  SessionNotFoundError: () => SessionNotFoundError,
@@ -459,13 +465,120 @@ var ContextsResource = class {
459
465
  }
460
466
  };
461
467
 
462
- // src/sessions.ts
468
+ // src/extensions.ts
469
+ var import_promises = require("fs/promises");
470
+ var import_node_path = __toESM(require("path"));
463
471
  function asRecord2(value) {
464
472
  return typeof value === "object" && value !== null ? value : {};
465
473
  }
466
474
  function getString2(value) {
467
475
  return typeof value === "string" ? value : void 0;
468
476
  }
477
+ var ExtensionInfo = class {
478
+ constructor(shape) {
479
+ this.id = shape.id;
480
+ this.name = shape.name;
481
+ this.projectId = shape.projectId;
482
+ this.createdAt = shape.createdAt;
483
+ this.updatedAt = shape.updatedAt;
484
+ }
485
+ };
486
+ var ExtensionsResource = class {
487
+ constructor(client) {
488
+ this.client = client;
489
+ }
490
+ async upload(filePath, options = {}) {
491
+ const fileBuffer = await (0, import_promises.readFile)(filePath);
492
+ const form = new FormData();
493
+ const usedProjectId = options.projectId ?? this.client.projectId;
494
+ form.append("project_id", usedProjectId);
495
+ if (options.name) {
496
+ form.append("name", options.name);
497
+ }
498
+ form.append(
499
+ "file",
500
+ new Blob([fileBuffer], { type: "application/octet-stream" }),
501
+ import_node_path.default.basename(filePath)
502
+ );
503
+ const response = await this.client._post(
504
+ `${this.client.baseUrl}/instance/v1/extension/upload`,
505
+ form,
506
+ {
507
+ headers: {
508
+ project_id: usedProjectId
509
+ }
510
+ }
511
+ );
512
+ if (response.status >= 400) {
513
+ this.handleError("upload extension", response);
514
+ }
515
+ getLogger().info(`Extension uploaded successfully: ${filePath}`);
516
+ return this.parseInfo(response.data);
517
+ }
518
+ async list(options = {}) {
519
+ const response = await this.client._post(`${this.client.baseUrl}/instance/v1/extension/list`, {
520
+ project_id: options.projectId ?? this.client.projectId,
521
+ limit: options.limit ?? 20,
522
+ offset: options.offset ?? 0
523
+ });
524
+ if (response.status >= 400) {
525
+ this.handleError("list extensions", response);
526
+ }
527
+ const result = asRecord2(response.data);
528
+ const items = Array.isArray(result.data) ? result.data : [];
529
+ return items.map((item) => this.parseInfo(item));
530
+ }
531
+ async get(extensionId, projectId) {
532
+ const response = await this.client._post(`${this.client.baseUrl}/instance/v1/extension/info`, {
533
+ project_id: projectId ?? this.client.projectId,
534
+ extension_id: extensionId
535
+ });
536
+ if (response.status >= 400) {
537
+ this.handleError("get extension", response);
538
+ }
539
+ return this.parseInfo(response.data);
540
+ }
541
+ async delete(extensionId) {
542
+ const response = await this.client._delete(
543
+ `${this.client.baseUrl}/instance/v1/extension/${extensionId}`
544
+ );
545
+ if (response.status >= 400) {
546
+ this.handleError("delete extension", response);
547
+ }
548
+ getLogger().info(`Extension deleted successfully: ${extensionId}`);
549
+ }
550
+ parseInfo(data) {
551
+ const item = asRecord2(data);
552
+ return new ExtensionInfo({
553
+ id: getString2(item.id) ?? "",
554
+ name: getString2(item.name) ?? "",
555
+ projectId: getString2(item.project_id) ?? "",
556
+ createdAt: getString2(item.created_at),
557
+ updatedAt: getString2(item.updated_at)
558
+ });
559
+ }
560
+ handleError(action, response) {
561
+ const errorData = asRecord2(response.data);
562
+ const errorMessage = getString2(errorData.message) ?? getString2(errorData.error) ?? "Unknown error";
563
+ if (response.status === 401) {
564
+ throw new AuthenticationError(
565
+ `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
566
+ );
567
+ }
568
+ throw new APIError(`Failed to ${action}: ${errorMessage}`, {
569
+ statusCode: response.status,
570
+ response: response.data
571
+ });
572
+ }
573
+ };
574
+
575
+ // src/sessions.ts
576
+ function asRecord3(value) {
577
+ return typeof value === "object" && value !== null ? value : {};
578
+ }
579
+ function getString3(value) {
580
+ return typeof value === "string" ? value : void 0;
581
+ }
469
582
  function getNumber(value) {
470
583
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
471
584
  }
@@ -498,7 +611,6 @@ var SessionInfo = class {
498
611
  this.createdAt = options.createdAt;
499
612
  this.inspectUrl = options.inspectUrl;
500
613
  this.containerId = options.containerId;
501
- this.inspectUrlDbg = options.inspectUrlDbg;
502
614
  this.ws = options.ws ?? null;
503
615
  this.client = options.client;
504
616
  }
@@ -562,9 +674,134 @@ var SessionListResponse = class {
562
674
  return this.sessions[index];
563
675
  }
564
676
  };
677
+ var SessionDownloadInfo = class {
678
+ constructor(shape) {
679
+ this.id = shape.id;
680
+ this.filename = shape.filename;
681
+ this.contentType = shape.contentType;
682
+ this.size = shape.size;
683
+ this.sha256 = shape.sha256;
684
+ this.status = shape.status;
685
+ this.createdAt = shape.createdAt;
686
+ }
687
+ };
688
+ var SessionDownloadsListResponse = class {
689
+ constructor(downloads, summary) {
690
+ this.downloads = downloads;
691
+ this.summary = summary;
692
+ }
693
+ };
694
+ var SessionDownloadsDeleteResponse = class {
695
+ constructor(shape) {
696
+ this.status = shape.status;
697
+ this.deletedCount = shape.deletedCount;
698
+ }
699
+ };
700
+ var SessionDownloadsResource = class {
701
+ constructor(client) {
702
+ this.client = client;
703
+ }
704
+ async list(sessionId, projectId) {
705
+ const response = await this.client._post(
706
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/list`,
707
+ {
708
+ api_key: this.client.apiKey,
709
+ project_id: projectId ?? this.client.projectId
710
+ }
711
+ );
712
+ if (response.status >= 400) {
713
+ this.handleError("list session downloads", response, sessionId);
714
+ }
715
+ const result = asRecord3(response.data);
716
+ const items = Array.isArray(result.downloads) ? result.downloads : [];
717
+ const downloads = items.map((item) => {
718
+ const download = asRecord3(item);
719
+ return new SessionDownloadInfo({
720
+ id: getString3(download.id) ?? "",
721
+ filename: getString3(download.filename) ?? "",
722
+ contentType: getString3(download.content_type) ?? null,
723
+ size: getNumber(download.size) ?? 0,
724
+ sha256: getString3(download.sha256) ?? null,
725
+ status: getString3(download.status) ?? "available",
726
+ createdAt: getString3(download.created_at) ?? ""
727
+ });
728
+ });
729
+ const summary = asRecord3(result.summary);
730
+ return new SessionDownloadsListResponse(downloads, {
731
+ count: getNumber(summary.count) ?? downloads.length,
732
+ totalSize: getNumber(summary.total_size) ?? 0
733
+ });
734
+ }
735
+ async get(sessionId, downloadId, projectId) {
736
+ const response = await this.client._get(
737
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/${downloadId}`,
738
+ {
739
+ api_key: this.client.apiKey,
740
+ project_id: projectId ?? this.client.projectId
741
+ },
742
+ {
743
+ responseType: "arraybuffer"
744
+ }
745
+ );
746
+ if (response.status >= 400) {
747
+ this.handleError("fetch session download", response, sessionId);
748
+ }
749
+ return Buffer.from(response.data);
750
+ }
751
+ async archive(sessionId, projectId) {
752
+ const response = await this.client._get(
753
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/archive`,
754
+ {
755
+ api_key: this.client.apiKey,
756
+ project_id: projectId ?? this.client.projectId
757
+ },
758
+ {
759
+ responseType: "arraybuffer"
760
+ }
761
+ );
762
+ if (response.status >= 400) {
763
+ this.handleError("archive session downloads", response, sessionId);
764
+ }
765
+ return Buffer.from(response.data);
766
+ }
767
+ async delete(sessionId, projectId) {
768
+ const response = await this.client._delete(
769
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads`,
770
+ {
771
+ api_key: this.client.apiKey,
772
+ project_id: projectId ?? this.client.projectId
773
+ }
774
+ );
775
+ if (response.status >= 400) {
776
+ this.handleError("delete session downloads", response, sessionId);
777
+ }
778
+ const result = asRecord3(response.data);
779
+ return new SessionDownloadsDeleteResponse({
780
+ status: getString3(result.status) ?? "",
781
+ deletedCount: getNumber(result.deleted_count) ?? 0
782
+ });
783
+ }
784
+ handleError(action, response, sessionId) {
785
+ const errorData = asRecord3(response.data);
786
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
787
+ if (response.status === 401) {
788
+ throw new AuthenticationError(
789
+ `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
790
+ );
791
+ }
792
+ if (response.status === 404) {
793
+ throw new SessionNotFoundError(`Session downloads not found for ${sessionId}: ${errorMessage}`);
794
+ }
795
+ throw new APIError(`Failed to ${action}: ${errorMessage}`, {
796
+ statusCode: response.status,
797
+ response: response.data
798
+ });
799
+ }
800
+ };
565
801
  var SessionsResource = class {
566
802
  constructor(client) {
567
803
  this.client = client;
804
+ this.downloads = new SessionDownloadsResource(client);
568
805
  }
569
806
  /**
570
807
  * Create a new browser session.
@@ -588,19 +825,25 @@ var SessionsResource = class {
588
825
  } else {
589
826
  getLogger().debug(`Creating session with browser_mode=${payload.browser_mode}`);
590
827
  }
828
+ if (options.extensionIds && options.extensionIds.length > 0) {
829
+ payload.extension_ids = options.extensionIds;
830
+ }
831
+ if (options.proxy) {
832
+ payload.proxy = this.normalizeProxy(options.proxy);
833
+ }
591
834
  const response = await this.client._post(url, payload);
592
835
  if (response.status >= 400) {
593
836
  this.handleCreateError(response);
594
837
  }
595
- const result = asRecord2(response.data);
596
- const sessionId = getString2(result.session_id);
838
+ const result = asRecord3(response.data);
839
+ const sessionId = getString3(result.session_id);
597
840
  if (!sessionId) {
598
841
  throw new APIError("Failed to create session: session_id missing from response", {
599
842
  statusCode: response.status,
600
843
  response: response.data
601
844
  });
602
845
  }
603
- const containerId = getString2(result.container_id) ?? null;
846
+ const containerId = getString3(result.container_id) ?? null;
604
847
  const wsUrl = await this._getWebSocketDebuggerUrl(sessionId);
605
848
  const projectId = options.projectId ?? this.client.projectId;
606
849
  getLogger().info(`Session created successfully: id=${sessionId}, container_id=${containerId}`);
@@ -633,23 +876,22 @@ var SessionsResource = class {
633
876
  if (response.status >= 400) {
634
877
  this.handleListError(response);
635
878
  }
636
- const result = asRecord2(response.data);
879
+ const result = asRecord3(response.data);
637
880
  const sessionsData = Array.isArray(result.sessions) ? result.sessions : [];
638
- const paginationData = asRecord2(result.pagination);
881
+ const paginationData = asRecord3(result.pagination);
639
882
  const sessions = sessionsData.map((item) => {
640
- const session = asRecord2(item);
641
- const sessionId = getString2(session.id) ?? "";
883
+ const session = asRecord3(item);
884
+ const sessionId = getString3(session.id) ?? "";
642
885
  return new SessionInfo({
643
886
  id: sessionId,
644
- status: getString2(session.status) ?? "active",
645
- apiKey: getString2(session.api_key) ?? this.client.apiKey,
646
- projectId: getString2(session.project_id) ?? (options.projectId ?? this.client.projectId),
647
- browserType: getString2(session.browser_type) ?? "normal",
648
- createdAt: getString2(session.created_at) ?? "",
649
- inspectUrl: getString2(session.inspect_url) ?? `${this.client.baseUrl}/inspect?session_id=${sessionId}`,
650
- containerId: getString2(session.container_id) ?? null,
651
- inspectUrlDbg: getString2(session.inspect_url_dbg),
652
- ws: getString2(session.ws) ?? null,
887
+ status: getString3(session.status) ?? "active",
888
+ apiKey: getString3(session.api_key) ?? this.client.apiKey,
889
+ projectId: getString3(session.project_id) ?? (options.projectId ?? this.client.projectId),
890
+ browserType: getString3(session.browser_type) ?? "normal",
891
+ createdAt: getString3(session.created_at) ?? "",
892
+ inspectUrl: getString3(session.inspect_url) ?? `${this.client.baseUrl}/inspect?session_id=${sessionId}`,
893
+ containerId: getString3(session.container_id) ?? null,
894
+ ws: getString3(session.ws) ?? null,
653
895
  client: this.client
654
896
  });
655
897
  });
@@ -696,18 +938,34 @@ var SessionsResource = class {
696
938
  getLogger().error("Error getting WebSocket debugger URL:", response.data);
697
939
  return null;
698
940
  }
699
- const result = asRecord2(response.data);
700
- return getString2(result.webSocketDebuggerUrlTransformed) ?? getString2(result.webSocketDebuggerUrl) ?? null;
941
+ const result = asRecord3(response.data);
942
+ return getString3(result.webSocketDebuggerUrlTransformed) ?? getString3(result.webSocketDebuggerUrl) ?? null;
701
943
  } catch (error) {
702
944
  getLogger().error("Error getting WebSocket debugger URL:", error);
703
945
  return null;
704
946
  }
705
947
  }
948
+ normalizeProxy(proxy) {
949
+ if (!proxy.server) {
950
+ throw new ValidationError("proxy.server is required when proxy is provided");
951
+ }
952
+ const normalizedProxy = {
953
+ type: proxy.type ?? "external",
954
+ server: proxy.server
955
+ };
956
+ if (proxy.username) {
957
+ normalizedProxy.username = proxy.username;
958
+ }
959
+ if (proxy.password) {
960
+ normalizedProxy.password = proxy.password;
961
+ }
962
+ return normalizedProxy;
963
+ }
706
964
  handleCreateError(response) {
707
- const errorData = asRecord2(response.data);
708
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
709
- const errorCode = getString2(errorData.code);
710
- const metadata = asRecord2(errorData.metadata);
965
+ const errorData = asRecord3(response.data);
966
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
967
+ const errorCode = getString3(errorData.code);
968
+ const metadata = asRecord3(errorData.metadata);
711
969
  if (response.status === 401) {
712
970
  throw new AuthenticationError(
713
971
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -721,7 +979,7 @@ var SessionsResource = class {
721
979
  }
722
980
  if (response.status === 409 && errorCode === "context_locked") {
723
981
  throw new ContextLockedError(errorMessage, {
724
- activeSessionId: getString2(metadata.activeSessionId),
982
+ activeSessionId: getString3(metadata.activeSessionId),
725
983
  retryAfter: getNumber(metadata.retryAfter)
726
984
  });
727
985
  }
@@ -731,8 +989,8 @@ var SessionsResource = class {
731
989
  });
732
990
  }
733
991
  handleListError(response) {
734
- const errorData = asRecord2(response.data);
735
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
992
+ const errorData = asRecord3(response.data);
993
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
736
994
  if (response.status === 401) {
737
995
  throw new AuthenticationError(
738
996
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -744,8 +1002,8 @@ var SessionsResource = class {
744
1002
  });
745
1003
  }
746
1004
  handleDeleteError(response, sessionId) {
747
- const errorData = asRecord2(response.data);
748
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
1005
+ const errorData = asRecord3(response.data);
1006
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
749
1007
  if (response.status === 401) {
750
1008
  throw new AuthenticationError(
751
1009
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -785,37 +1043,35 @@ var Lexmount = class {
785
1043
  }
786
1044
  this.httpClient = import_axios2.default.create({
787
1045
  timeout: config2.timeout ?? 6e4,
788
- validateStatus: () => true,
789
- headers: {
790
- "Content-Type": "application/json"
791
- }
1046
+ validateStatus: () => true
792
1047
  });
793
1048
  this.sessions = new SessionsResource(this);
794
1049
  this.contexts = new ContextsResource(this);
1050
+ this.extensions = new ExtensionsResource(this);
795
1051
  }
796
1052
  /**
797
1053
  * Internal POST request helper with timeout and network error mapping.
798
1054
  *
799
1055
  * @internal
800
1056
  */
801
- async _post(url, data) {
802
- return this.request("POST", url, { data });
1057
+ async _post(url, data, config2 = {}) {
1058
+ return this.request("POST", url, { ...config2, data });
803
1059
  }
804
1060
  /**
805
1061
  * Internal GET request helper with timeout and network error mapping.
806
1062
  *
807
1063
  * @internal
808
1064
  */
809
- async _get(url, params) {
810
- return this.request("GET", url, { params });
1065
+ async _get(url, params, config2 = {}) {
1066
+ return this.request("GET", url, { ...config2, params });
811
1067
  }
812
1068
  /**
813
1069
  * Internal DELETE request helper with timeout and network error mapping.
814
1070
  *
815
1071
  * @internal
816
1072
  */
817
- async _delete(url, data) {
818
- return this.request("DELETE", url, { data });
1073
+ async _delete(url, data, config2 = {}) {
1074
+ return this.request("DELETE", url, { ...config2, data });
819
1075
  }
820
1076
  /**
821
1077
  * Close the client.
@@ -836,10 +1092,17 @@ var Lexmount = class {
836
1092
  const startTime = Date.now();
837
1093
  logger2.debug(`${method} request to ${url}`);
838
1094
  try {
1095
+ const headers = {
1096
+ api_key: this.apiKey,
1097
+ project_id: this.projectId,
1098
+ ...this.getDefaultHeaders(config2.data),
1099
+ ...config2.headers ?? {}
1100
+ };
839
1101
  const response = await this.httpClient.request({
840
1102
  method,
841
1103
  url,
842
- ...config2
1104
+ ...config2,
1105
+ headers
843
1106
  });
844
1107
  const elapsed = Date.now() - startTime;
845
1108
  logger2.debug(`${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`);
@@ -870,10 +1133,21 @@ var Lexmount = class {
870
1133
  logger2.error(`Network error after ${elapsedMs.toFixed(2)}ms:`, axiosError.message);
871
1134
  return new NetworkError(`Network error: ${axiosError.message}`);
872
1135
  }
1136
+ getDefaultHeaders(data) {
1137
+ if (typeof data === "undefined") {
1138
+ return {};
1139
+ }
1140
+ if (typeof FormData !== "undefined" && data instanceof FormData) {
1141
+ return {};
1142
+ }
1143
+ return {
1144
+ "Content-Type": "application/json"
1145
+ };
1146
+ }
873
1147
  };
874
1148
 
875
1149
  // src/index.ts
876
- var VERSION = "0.2.0";
1150
+ var VERSION = "0.2.4";
877
1151
  // Annotate the CommonJS export names for ESM import in node:
878
1152
  0 && (module.exports = {
879
1153
  APIError,
@@ -883,11 +1157,17 @@ var VERSION = "0.2.0";
883
1157
  ContextLockedError,
884
1158
  ContextNotFoundError,
885
1159
  ContextsResource,
1160
+ ExtensionInfo,
1161
+ ExtensionsResource,
886
1162
  Lexmount,
887
1163
  LexmountError,
888
1164
  LexmountLogger,
889
1165
  NetworkError,
890
1166
  PaginationInfo,
1167
+ SessionDownloadInfo,
1168
+ SessionDownloadsDeleteResponse,
1169
+ SessionDownloadsListResponse,
1170
+ SessionDownloadsResource,
891
1171
  SessionInfo,
892
1172
  SessionListResponse,
893
1173
  SessionNotFoundError,