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.mjs CHANGED
@@ -402,13 +402,120 @@ var ContextsResource = class {
402
402
  }
403
403
  };
404
404
 
405
- // src/sessions.ts
405
+ // src/extensions.ts
406
+ import { readFile } from "fs/promises";
407
+ import path from "path";
406
408
  function asRecord2(value) {
407
409
  return typeof value === "object" && value !== null ? value : {};
408
410
  }
409
411
  function getString2(value) {
410
412
  return typeof value === "string" ? value : void 0;
411
413
  }
414
+ var ExtensionInfo = class {
415
+ constructor(shape) {
416
+ this.id = shape.id;
417
+ this.name = shape.name;
418
+ this.projectId = shape.projectId;
419
+ this.createdAt = shape.createdAt;
420
+ this.updatedAt = shape.updatedAt;
421
+ }
422
+ };
423
+ var ExtensionsResource = class {
424
+ constructor(client) {
425
+ this.client = client;
426
+ }
427
+ async upload(filePath, options = {}) {
428
+ const fileBuffer = await readFile(filePath);
429
+ const form = new FormData();
430
+ const usedProjectId = options.projectId ?? this.client.projectId;
431
+ form.append("project_id", usedProjectId);
432
+ if (options.name) {
433
+ form.append("name", options.name);
434
+ }
435
+ form.append(
436
+ "file",
437
+ new Blob([fileBuffer], { type: "application/octet-stream" }),
438
+ path.basename(filePath)
439
+ );
440
+ const response = await this.client._post(
441
+ `${this.client.baseUrl}/instance/v1/extension/upload`,
442
+ form,
443
+ {
444
+ headers: {
445
+ project_id: usedProjectId
446
+ }
447
+ }
448
+ );
449
+ if (response.status >= 400) {
450
+ this.handleError("upload extension", response);
451
+ }
452
+ getLogger().info(`Extension uploaded successfully: ${filePath}`);
453
+ return this.parseInfo(response.data);
454
+ }
455
+ async list(options = {}) {
456
+ const response = await this.client._post(`${this.client.baseUrl}/instance/v1/extension/list`, {
457
+ project_id: options.projectId ?? this.client.projectId,
458
+ limit: options.limit ?? 20,
459
+ offset: options.offset ?? 0
460
+ });
461
+ if (response.status >= 400) {
462
+ this.handleError("list extensions", response);
463
+ }
464
+ const result = asRecord2(response.data);
465
+ const items = Array.isArray(result.data) ? result.data : [];
466
+ return items.map((item) => this.parseInfo(item));
467
+ }
468
+ async get(extensionId, projectId) {
469
+ const response = await this.client._post(`${this.client.baseUrl}/instance/v1/extension/info`, {
470
+ project_id: projectId ?? this.client.projectId,
471
+ extension_id: extensionId
472
+ });
473
+ if (response.status >= 400) {
474
+ this.handleError("get extension", response);
475
+ }
476
+ return this.parseInfo(response.data);
477
+ }
478
+ async delete(extensionId) {
479
+ const response = await this.client._delete(
480
+ `${this.client.baseUrl}/instance/v1/extension/${extensionId}`
481
+ );
482
+ if (response.status >= 400) {
483
+ this.handleError("delete extension", response);
484
+ }
485
+ getLogger().info(`Extension deleted successfully: ${extensionId}`);
486
+ }
487
+ parseInfo(data) {
488
+ const item = asRecord2(data);
489
+ return new ExtensionInfo({
490
+ id: getString2(item.id) ?? "",
491
+ name: getString2(item.name) ?? "",
492
+ projectId: getString2(item.project_id) ?? "",
493
+ createdAt: getString2(item.created_at),
494
+ updatedAt: getString2(item.updated_at)
495
+ });
496
+ }
497
+ handleError(action, response) {
498
+ const errorData = asRecord2(response.data);
499
+ const errorMessage = getString2(errorData.message) ?? getString2(errorData.error) ?? "Unknown error";
500
+ if (response.status === 401) {
501
+ throw new AuthenticationError(
502
+ `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
503
+ );
504
+ }
505
+ throw new APIError(`Failed to ${action}: ${errorMessage}`, {
506
+ statusCode: response.status,
507
+ response: response.data
508
+ });
509
+ }
510
+ };
511
+
512
+ // src/sessions.ts
513
+ function asRecord3(value) {
514
+ return typeof value === "object" && value !== null ? value : {};
515
+ }
516
+ function getString3(value) {
517
+ return typeof value === "string" ? value : void 0;
518
+ }
412
519
  function getNumber(value) {
413
520
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
414
521
  }
@@ -441,7 +548,6 @@ var SessionInfo = class {
441
548
  this.createdAt = options.createdAt;
442
549
  this.inspectUrl = options.inspectUrl;
443
550
  this.containerId = options.containerId;
444
- this.inspectUrlDbg = options.inspectUrlDbg;
445
551
  this.ws = options.ws ?? null;
446
552
  this.client = options.client;
447
553
  }
@@ -505,9 +611,134 @@ var SessionListResponse = class {
505
611
  return this.sessions[index];
506
612
  }
507
613
  };
614
+ var SessionDownloadInfo = class {
615
+ constructor(shape) {
616
+ this.id = shape.id;
617
+ this.filename = shape.filename;
618
+ this.contentType = shape.contentType;
619
+ this.size = shape.size;
620
+ this.sha256 = shape.sha256;
621
+ this.status = shape.status;
622
+ this.createdAt = shape.createdAt;
623
+ }
624
+ };
625
+ var SessionDownloadsListResponse = class {
626
+ constructor(downloads, summary) {
627
+ this.downloads = downloads;
628
+ this.summary = summary;
629
+ }
630
+ };
631
+ var SessionDownloadsDeleteResponse = class {
632
+ constructor(shape) {
633
+ this.status = shape.status;
634
+ this.deletedCount = shape.deletedCount;
635
+ }
636
+ };
637
+ var SessionDownloadsResource = class {
638
+ constructor(client) {
639
+ this.client = client;
640
+ }
641
+ async list(sessionId, projectId) {
642
+ const response = await this.client._post(
643
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/list`,
644
+ {
645
+ api_key: this.client.apiKey,
646
+ project_id: projectId ?? this.client.projectId
647
+ }
648
+ );
649
+ if (response.status >= 400) {
650
+ this.handleError("list session downloads", response, sessionId);
651
+ }
652
+ const result = asRecord3(response.data);
653
+ const items = Array.isArray(result.downloads) ? result.downloads : [];
654
+ const downloads = items.map((item) => {
655
+ const download = asRecord3(item);
656
+ return new SessionDownloadInfo({
657
+ id: getString3(download.id) ?? "",
658
+ filename: getString3(download.filename) ?? "",
659
+ contentType: getString3(download.content_type) ?? null,
660
+ size: getNumber(download.size) ?? 0,
661
+ sha256: getString3(download.sha256) ?? null,
662
+ status: getString3(download.status) ?? "available",
663
+ createdAt: getString3(download.created_at) ?? ""
664
+ });
665
+ });
666
+ const summary = asRecord3(result.summary);
667
+ return new SessionDownloadsListResponse(downloads, {
668
+ count: getNumber(summary.count) ?? downloads.length,
669
+ totalSize: getNumber(summary.total_size) ?? 0
670
+ });
671
+ }
672
+ async get(sessionId, downloadId, projectId) {
673
+ const response = await this.client._get(
674
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/${downloadId}`,
675
+ {
676
+ api_key: this.client.apiKey,
677
+ project_id: projectId ?? this.client.projectId
678
+ },
679
+ {
680
+ responseType: "arraybuffer"
681
+ }
682
+ );
683
+ if (response.status >= 400) {
684
+ this.handleError("fetch session download", response, sessionId);
685
+ }
686
+ return Buffer.from(response.data);
687
+ }
688
+ async archive(sessionId, projectId) {
689
+ const response = await this.client._get(
690
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads/archive`,
691
+ {
692
+ api_key: this.client.apiKey,
693
+ project_id: projectId ?? this.client.projectId
694
+ },
695
+ {
696
+ responseType: "arraybuffer"
697
+ }
698
+ );
699
+ if (response.status >= 400) {
700
+ this.handleError("archive session downloads", response, sessionId);
701
+ }
702
+ return Buffer.from(response.data);
703
+ }
704
+ async delete(sessionId, projectId) {
705
+ const response = await this.client._delete(
706
+ `${this.client.baseUrl}/instance/v1/sessions/${sessionId}/downloads`,
707
+ {
708
+ api_key: this.client.apiKey,
709
+ project_id: projectId ?? this.client.projectId
710
+ }
711
+ );
712
+ if (response.status >= 400) {
713
+ this.handleError("delete session downloads", response, sessionId);
714
+ }
715
+ const result = asRecord3(response.data);
716
+ return new SessionDownloadsDeleteResponse({
717
+ status: getString3(result.status) ?? "",
718
+ deletedCount: getNumber(result.deleted_count) ?? 0
719
+ });
720
+ }
721
+ handleError(action, response, sessionId) {
722
+ const errorData = asRecord3(response.data);
723
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
724
+ if (response.status === 401) {
725
+ throw new AuthenticationError(
726
+ `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
727
+ );
728
+ }
729
+ if (response.status === 404) {
730
+ throw new SessionNotFoundError(`Session downloads not found for ${sessionId}: ${errorMessage}`);
731
+ }
732
+ throw new APIError(`Failed to ${action}: ${errorMessage}`, {
733
+ statusCode: response.status,
734
+ response: response.data
735
+ });
736
+ }
737
+ };
508
738
  var SessionsResource = class {
509
739
  constructor(client) {
510
740
  this.client = client;
741
+ this.downloads = new SessionDownloadsResource(client);
511
742
  }
512
743
  /**
513
744
  * Create a new browser session.
@@ -531,19 +762,25 @@ var SessionsResource = class {
531
762
  } else {
532
763
  getLogger().debug(`Creating session with browser_mode=${payload.browser_mode}`);
533
764
  }
765
+ if (options.extensionIds && options.extensionIds.length > 0) {
766
+ payload.extension_ids = options.extensionIds;
767
+ }
768
+ if (options.proxy) {
769
+ payload.proxy = this.normalizeProxy(options.proxy);
770
+ }
534
771
  const response = await this.client._post(url, payload);
535
772
  if (response.status >= 400) {
536
773
  this.handleCreateError(response);
537
774
  }
538
- const result = asRecord2(response.data);
539
- const sessionId = getString2(result.session_id);
775
+ const result = asRecord3(response.data);
776
+ const sessionId = getString3(result.session_id);
540
777
  if (!sessionId) {
541
778
  throw new APIError("Failed to create session: session_id missing from response", {
542
779
  statusCode: response.status,
543
780
  response: response.data
544
781
  });
545
782
  }
546
- const containerId = getString2(result.container_id) ?? null;
783
+ const containerId = getString3(result.container_id) ?? null;
547
784
  const wsUrl = await this._getWebSocketDebuggerUrl(sessionId);
548
785
  const projectId = options.projectId ?? this.client.projectId;
549
786
  getLogger().info(`Session created successfully: id=${sessionId}, container_id=${containerId}`);
@@ -576,23 +813,22 @@ var SessionsResource = class {
576
813
  if (response.status >= 400) {
577
814
  this.handleListError(response);
578
815
  }
579
- const result = asRecord2(response.data);
816
+ const result = asRecord3(response.data);
580
817
  const sessionsData = Array.isArray(result.sessions) ? result.sessions : [];
581
- const paginationData = asRecord2(result.pagination);
818
+ const paginationData = asRecord3(result.pagination);
582
819
  const sessions = sessionsData.map((item) => {
583
- const session = asRecord2(item);
584
- const sessionId = getString2(session.id) ?? "";
820
+ const session = asRecord3(item);
821
+ const sessionId = getString3(session.id) ?? "";
585
822
  return new SessionInfo({
586
823
  id: sessionId,
587
- status: getString2(session.status) ?? "active",
588
- apiKey: getString2(session.api_key) ?? this.client.apiKey,
589
- projectId: getString2(session.project_id) ?? (options.projectId ?? this.client.projectId),
590
- browserType: getString2(session.browser_type) ?? "normal",
591
- createdAt: getString2(session.created_at) ?? "",
592
- inspectUrl: getString2(session.inspect_url) ?? `${this.client.baseUrl}/inspect?session_id=${sessionId}`,
593
- containerId: getString2(session.container_id) ?? null,
594
- inspectUrlDbg: getString2(session.inspect_url_dbg),
595
- ws: getString2(session.ws) ?? null,
824
+ status: getString3(session.status) ?? "active",
825
+ apiKey: getString3(session.api_key) ?? this.client.apiKey,
826
+ projectId: getString3(session.project_id) ?? (options.projectId ?? this.client.projectId),
827
+ browserType: getString3(session.browser_type) ?? "normal",
828
+ createdAt: getString3(session.created_at) ?? "",
829
+ inspectUrl: getString3(session.inspect_url) ?? `${this.client.baseUrl}/inspect?session_id=${sessionId}`,
830
+ containerId: getString3(session.container_id) ?? null,
831
+ ws: getString3(session.ws) ?? null,
596
832
  client: this.client
597
833
  });
598
834
  });
@@ -639,18 +875,34 @@ var SessionsResource = class {
639
875
  getLogger().error("Error getting WebSocket debugger URL:", response.data);
640
876
  return null;
641
877
  }
642
- const result = asRecord2(response.data);
643
- return getString2(result.webSocketDebuggerUrlTransformed) ?? getString2(result.webSocketDebuggerUrl) ?? null;
878
+ const result = asRecord3(response.data);
879
+ return getString3(result.webSocketDebuggerUrlTransformed) ?? getString3(result.webSocketDebuggerUrl) ?? null;
644
880
  } catch (error) {
645
881
  getLogger().error("Error getting WebSocket debugger URL:", error);
646
882
  return null;
647
883
  }
648
884
  }
885
+ normalizeProxy(proxy) {
886
+ if (!proxy.server) {
887
+ throw new ValidationError("proxy.server is required when proxy is provided");
888
+ }
889
+ const normalizedProxy = {
890
+ type: proxy.type ?? "external",
891
+ server: proxy.server
892
+ };
893
+ if (proxy.username) {
894
+ normalizedProxy.username = proxy.username;
895
+ }
896
+ if (proxy.password) {
897
+ normalizedProxy.password = proxy.password;
898
+ }
899
+ return normalizedProxy;
900
+ }
649
901
  handleCreateError(response) {
650
- const errorData = asRecord2(response.data);
651
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
652
- const errorCode = getString2(errorData.code);
653
- const metadata = asRecord2(errorData.metadata);
902
+ const errorData = asRecord3(response.data);
903
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
904
+ const errorCode = getString3(errorData.code);
905
+ const metadata = asRecord3(errorData.metadata);
654
906
  if (response.status === 401) {
655
907
  throw new AuthenticationError(
656
908
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -664,7 +916,7 @@ var SessionsResource = class {
664
916
  }
665
917
  if (response.status === 409 && errorCode === "context_locked") {
666
918
  throw new ContextLockedError(errorMessage, {
667
- activeSessionId: getString2(metadata.activeSessionId),
919
+ activeSessionId: getString3(metadata.activeSessionId),
668
920
  retryAfter: getNumber(metadata.retryAfter)
669
921
  });
670
922
  }
@@ -674,8 +926,8 @@ var SessionsResource = class {
674
926
  });
675
927
  }
676
928
  handleListError(response) {
677
- const errorData = asRecord2(response.data);
678
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
929
+ const errorData = asRecord3(response.data);
930
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
679
931
  if (response.status === 401) {
680
932
  throw new AuthenticationError(
681
933
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -687,8 +939,8 @@ var SessionsResource = class {
687
939
  });
688
940
  }
689
941
  handleDeleteError(response, sessionId) {
690
- const errorData = asRecord2(response.data);
691
- const errorMessage = getString2(errorData.error) ?? getString2(errorData.message) ?? "Unknown error";
942
+ const errorData = asRecord3(response.data);
943
+ const errorMessage = getString3(errorData.error) ?? getString3(errorData.message) ?? "Unknown error";
692
944
  if (response.status === 401) {
693
945
  throw new AuthenticationError(
694
946
  `Authentication failed: ${errorMessage}. Please check your API key and project ID.`
@@ -728,37 +980,35 @@ var Lexmount = class {
728
980
  }
729
981
  this.httpClient = axios.create({
730
982
  timeout: config2.timeout ?? 6e4,
731
- validateStatus: () => true,
732
- headers: {
733
- "Content-Type": "application/json"
734
- }
983
+ validateStatus: () => true
735
984
  });
736
985
  this.sessions = new SessionsResource(this);
737
986
  this.contexts = new ContextsResource(this);
987
+ this.extensions = new ExtensionsResource(this);
738
988
  }
739
989
  /**
740
990
  * Internal POST request helper with timeout and network error mapping.
741
991
  *
742
992
  * @internal
743
993
  */
744
- async _post(url, data) {
745
- return this.request("POST", url, { data });
994
+ async _post(url, data, config2 = {}) {
995
+ return this.request("POST", url, { ...config2, data });
746
996
  }
747
997
  /**
748
998
  * Internal GET request helper with timeout and network error mapping.
749
999
  *
750
1000
  * @internal
751
1001
  */
752
- async _get(url, params) {
753
- return this.request("GET", url, { params });
1002
+ async _get(url, params, config2 = {}) {
1003
+ return this.request("GET", url, { ...config2, params });
754
1004
  }
755
1005
  /**
756
1006
  * Internal DELETE request helper with timeout and network error mapping.
757
1007
  *
758
1008
  * @internal
759
1009
  */
760
- async _delete(url, data) {
761
- return this.request("DELETE", url, { data });
1010
+ async _delete(url, data, config2 = {}) {
1011
+ return this.request("DELETE", url, { ...config2, data });
762
1012
  }
763
1013
  /**
764
1014
  * Close the client.
@@ -779,10 +1029,17 @@ var Lexmount = class {
779
1029
  const startTime = Date.now();
780
1030
  logger2.debug(`${method} request to ${url}`);
781
1031
  try {
1032
+ const headers = {
1033
+ api_key: this.apiKey,
1034
+ project_id: this.projectId,
1035
+ ...this.getDefaultHeaders(config2.data),
1036
+ ...config2.headers ?? {}
1037
+ };
782
1038
  const response = await this.httpClient.request({
783
1039
  method,
784
1040
  url,
785
- ...config2
1041
+ ...config2,
1042
+ headers
786
1043
  });
787
1044
  const elapsed = Date.now() - startTime;
788
1045
  logger2.debug(`${method} response: status=${response.status}, duration=${elapsed.toFixed(2)}ms`);
@@ -813,10 +1070,21 @@ var Lexmount = class {
813
1070
  logger2.error(`Network error after ${elapsedMs.toFixed(2)}ms:`, axiosError.message);
814
1071
  return new NetworkError(`Network error: ${axiosError.message}`);
815
1072
  }
1073
+ getDefaultHeaders(data) {
1074
+ if (typeof data === "undefined") {
1075
+ return {};
1076
+ }
1077
+ if (typeof FormData !== "undefined" && data instanceof FormData) {
1078
+ return {};
1079
+ }
1080
+ return {
1081
+ "Content-Type": "application/json"
1082
+ };
1083
+ }
816
1084
  };
817
1085
 
818
1086
  // src/index.ts
819
- var VERSION = "0.2.0";
1087
+ var VERSION = "0.2.4";
820
1088
  export {
821
1089
  APIError,
822
1090
  AuthenticationError,
@@ -825,11 +1093,17 @@ export {
825
1093
  ContextLockedError,
826
1094
  ContextNotFoundError,
827
1095
  ContextsResource,
1096
+ ExtensionInfo,
1097
+ ExtensionsResource,
828
1098
  Lexmount,
829
1099
  LexmountError,
830
1100
  LexmountLogger,
831
1101
  NetworkError,
832
1102
  PaginationInfo,
1103
+ SessionDownloadInfo,
1104
+ SessionDownloadsDeleteResponse,
1105
+ SessionDownloadsListResponse,
1106
+ SessionDownloadsResource,
833
1107
  SessionInfo,
834
1108
  SessionListResponse,
835
1109
  SessionNotFoundError,