pmxtjs 2.34.2 → 2.35.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.
Files changed (37) hide show
  1. package/dist/esm/generated/src/apis/DefaultApi.d.ts +35 -1
  2. package/dist/esm/generated/src/apis/DefaultApi.js +55 -1
  3. package/dist/esm/generated/src/models/FetchEventsPaginated200Response.d.ts +46 -0
  4. package/dist/esm/generated/src/models/FetchEventsPaginated200Response.js +47 -0
  5. package/dist/esm/generated/src/models/PaginatedEventsResult.d.ts +45 -0
  6. package/dist/esm/generated/src/models/PaginatedEventsResult.js +50 -0
  7. package/dist/esm/generated/src/models/index.d.ts +2 -0
  8. package/dist/esm/generated/src/models/index.js +2 -0
  9. package/dist/esm/pmxt/client.d.ts +24 -1
  10. package/dist/esm/pmxt/client.js +418 -88
  11. package/dist/esm/pmxt/models.d.ts +11 -0
  12. package/dist/esm/pmxt/server-manager.js +16 -2
  13. package/dist/generated/src/apis/DefaultApi.d.ts +35 -1
  14. package/dist/generated/src/apis/DefaultApi.js +56 -2
  15. package/dist/generated/src/models/FetchEventsPaginated200Response.d.ts +46 -0
  16. package/dist/generated/src/models/FetchEventsPaginated200Response.js +54 -0
  17. package/dist/generated/src/models/PaginatedEventsResult.d.ts +45 -0
  18. package/dist/generated/src/models/PaginatedEventsResult.js +57 -0
  19. package/dist/generated/src/models/index.d.ts +2 -0
  20. package/dist/generated/src/models/index.js +2 -0
  21. package/dist/pmxt/client.d.ts +24 -1
  22. package/dist/pmxt/client.js +418 -88
  23. package/dist/pmxt/models.d.ts +11 -0
  24. package/dist/pmxt/server-manager.js +16 -2
  25. package/generated/.openapi-generator/FILES +4 -0
  26. package/generated/docs/DefaultApi.md +77 -0
  27. package/generated/docs/FetchEventsPaginated200Response.md +38 -0
  28. package/generated/docs/PaginatedEventsResult.md +39 -0
  29. package/generated/package.json +1 -1
  30. package/generated/src/apis/DefaultApi.ts +79 -0
  31. package/generated/src/models/FetchEventsPaginated200Response.ts +96 -0
  32. package/generated/src/models/PaginatedEventsResult.ts +91 -0
  33. package/generated/src/models/index.ts +2 -0
  34. package/package.json +2 -2
  35. package/pmxt/client.ts +394 -88
  36. package/pmxt/models.ts +14 -0
  37. package/pmxt/server-manager.ts +15 -2
package/pmxt/client.ts CHANGED
@@ -29,6 +29,7 @@ import {
29
29
  OrderBook,
30
30
  OrderLevel,
31
31
  PaginatedMarketsResult,
32
+ PaginatedEventsResult,
32
33
  Position,
33
34
  PriceCandle,
34
35
  SubscribedAddressSnapshot,
@@ -453,6 +454,54 @@ export abstract class Exchange {
453
454
  return headers;
454
455
  }
455
456
 
457
+ /**
458
+ * Resolve the current sidecar base URL.
459
+ *
460
+ * For hosted mode the configured basePath is returned as-is.
461
+ * For local mode the port is re-read from the lock file on every
462
+ * call so we pick up sidecar restarts that land on a different port.
463
+ */
464
+ private resolveBaseUrl(): string {
465
+ if (this.isHosted) return this.config.basePath;
466
+ const port = this.serverManager.getRunningPort();
467
+ return `http://localhost:${port}`;
468
+ }
469
+
470
+ /**
471
+ * Execute a fetch with retry on connection failures.
472
+ *
473
+ * Only retries on connection-level errors (ECONNREFUSED, ECONNRESET) —
474
+ * never on HTTP responses (4xx, 5xx). On first connection failure,
475
+ * attempts to restart the sidecar.
476
+ */
477
+ private async fetchWithRetry(
478
+ input: RequestInfo | URL,
479
+ init?: RequestInit,
480
+ ): Promise<Response> {
481
+ const delays = [200, 500, 1000];
482
+ let lastError: unknown;
483
+
484
+ for (let attempt = 0; attempt <= delays.length; attempt++) {
485
+ try {
486
+ return await fetch(input, init);
487
+ } catch (error) {
488
+ lastError = error;
489
+ if (attempt >= delays.length) break;
490
+
491
+ // Connection failed — try to restart the sidecar on first failure
492
+ if (attempt === 0 && !this.isHosted) {
493
+ try {
494
+ await this.serverManager.ensureServerRunning();
495
+ } catch {
496
+ // Restart failed — continue retrying anyway
497
+ }
498
+ }
499
+ await new Promise(resolve => setTimeout(resolve, delays[attempt]));
500
+ }
501
+ }
502
+ throw lastError;
503
+ }
504
+
456
505
  // Low-Level API Access
457
506
 
458
507
  /**
@@ -473,14 +522,14 @@ export abstract class Exchange {
473
522
  async callApi(operationId: string, params?: Record<string, any>): Promise<any> {
474
523
  await this.initPromise;
475
524
  try {
476
- const url = `${this.config.basePath}/api/${this.exchangeName}/callApi`;
525
+ const url = `${this.resolveBaseUrl()}/api/${this.exchangeName}/callApi`;
477
526
 
478
527
  const requestBody: any = {
479
528
  args: [operationId, params],
480
529
  credentials: this.getCredentials()
481
530
  };
482
531
 
483
- const response = await fetch(url, {
532
+ const response = await this.fetchWithRetry(url, {
484
533
  method: 'POST',
485
534
  headers: {
486
535
  'Content-Type': 'application/json',
@@ -529,13 +578,14 @@ export abstract class Exchange {
529
578
  query: Record<string, unknown>,
530
579
  args: unknown[],
531
580
  ): Promise<any> {
532
- const baseUrl = `${this.config.basePath}/api/${this.exchangeName}/${methodName}`;
581
+ const resolvedBase = this.resolveBaseUrl();
582
+ const baseUrl = `${resolvedBase}/api/${this.exchangeName}/${methodName}`;
533
583
  const hasCredentials = this.getCredentials() !== undefined;
534
584
 
535
585
  if (!hasCredentials && !this._getReadsUnsupported && !queryHasNestedObject(query)) {
536
586
  const qs = buildSidecarQueryString(query);
537
587
  const getUrl = qs ? `${baseUrl}?${qs}` : baseUrl;
538
- const response = await fetch(getUrl, {
588
+ const response = await this.fetchWithRetry(getUrl, {
539
589
  method: 'GET',
540
590
  headers: this.getAuthHeaders(),
541
591
  });
@@ -559,7 +609,7 @@ export abstract class Exchange {
559
609
  }
560
610
 
561
611
  // POST fallback — identical to the original per-method template.
562
- const response = await fetch(baseUrl, {
612
+ const response = await this.fetchWithRetry(baseUrl, {
563
613
  method: 'POST',
564
614
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
565
615
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
@@ -581,14 +631,17 @@ export abstract class Exchange {
581
631
  try {
582
632
  const args: any[] = [];
583
633
  args.push(reload);
584
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/loadMarkets`, {
634
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/loadMarkets`, {
585
635
  method: 'POST',
586
636
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
587
637
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
588
638
  });
589
639
  if (!response.ok) {
590
- const error = await response.json().catch(() => ({}));
591
- throw new Error(error.error?.message || response.statusText);
640
+ const body = await response.json().catch(() => ({}));
641
+ if (body.error && typeof body.error === "object") {
642
+ throw fromServerError(body.error);
643
+ }
644
+ throw new PmxtError(body.error?.message || response.statusText);
592
645
  }
593
646
  const json = await response.json();
594
647
  const data = this.handleResponse(json);
@@ -598,7 +651,8 @@ export abstract class Exchange {
598
651
  }
599
652
  return result;
600
653
  } catch (error) {
601
- throw new Error(`Failed to loadMarkets: ${error}`);
654
+ if (error instanceof PmxtError) throw error;
655
+ throw new PmxtError(`Failed to loadMarkets: ${error}`);
602
656
  }
603
657
  }
604
658
 
@@ -607,20 +661,24 @@ export abstract class Exchange {
607
661
  try {
608
662
  const args: any[] = [];
609
663
  if (params !== undefined) args.push(params);
610
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchMarkets`, {
664
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMarkets`, {
611
665
  method: 'POST',
612
666
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
613
667
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
614
668
  });
615
669
  if (!response.ok) {
616
- const error = await response.json().catch(() => ({}));
617
- throw new Error(error.error?.message || response.statusText);
670
+ const body = await response.json().catch(() => ({}));
671
+ if (body.error && typeof body.error === "object") {
672
+ throw fromServerError(body.error);
673
+ }
674
+ throw new PmxtError(body.error?.message || response.statusText);
618
675
  }
619
676
  const json = await response.json();
620
677
  const data = this.handleResponse(json);
621
678
  return data.map(convertMarket);
622
679
  } catch (error) {
623
- throw new Error(`Failed to fetchMarkets: ${error}`);
680
+ if (error instanceof PmxtError) throw error;
681
+ throw new PmxtError(`Failed to fetchMarkets: ${error}`);
624
682
  }
625
683
  }
626
684
 
@@ -629,14 +687,17 @@ export abstract class Exchange {
629
687
  try {
630
688
  const args: any[] = [];
631
689
  if (params !== undefined) args.push(params);
632
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchMarketsPaginated`, {
690
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMarketsPaginated`, {
633
691
  method: 'POST',
634
692
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
635
693
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
636
694
  });
637
695
  if (!response.ok) {
638
- const error = await response.json().catch(() => ({}));
639
- throw new Error(error.error?.message || response.statusText);
696
+ const body = await response.json().catch(() => ({}));
697
+ if (body.error && typeof body.error === "object") {
698
+ throw fromServerError(body.error);
699
+ }
700
+ throw new PmxtError(body.error?.message || response.statusText);
640
701
  }
641
702
  const json = await response.json();
642
703
  const data = this.handleResponse(json);
@@ -646,7 +707,8 @@ export abstract class Exchange {
646
707
  nextCursor: data.nextCursor,
647
708
  };
648
709
  } catch (error) {
649
- throw new Error(`Failed to fetchMarketsPaginated: ${error}`);
710
+ if (error instanceof PmxtError) throw error;
711
+ throw new PmxtError(`Failed to fetchMarketsPaginated: ${error}`);
650
712
  }
651
713
  }
652
714
 
@@ -655,20 +717,54 @@ export abstract class Exchange {
655
717
  try {
656
718
  const args: any[] = [];
657
719
  if (params !== undefined) args.push(params);
658
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchEvents`, {
720
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchEvents`, {
659
721
  method: 'POST',
660
722
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
661
723
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
662
724
  });
663
725
  if (!response.ok) {
664
- const error = await response.json().catch(() => ({}));
665
- throw new Error(error.error?.message || response.statusText);
726
+ const body = await response.json().catch(() => ({}));
727
+ if (body.error && typeof body.error === "object") {
728
+ throw fromServerError(body.error);
729
+ }
730
+ throw new PmxtError(body.error?.message || response.statusText);
666
731
  }
667
732
  const json = await response.json();
668
733
  const data = this.handleResponse(json);
669
734
  return data.map(convertEvent);
670
735
  } catch (error) {
671
- throw new Error(`Failed to fetchEvents: ${error}`);
736
+ if (error instanceof PmxtError) throw error;
737
+ throw new PmxtError(`Failed to fetchEvents: ${error}`);
738
+ }
739
+ }
740
+
741
+ async fetchEventsPaginated(params?: any): Promise<PaginatedEventsResult> {
742
+ await this.initPromise;
743
+ try {
744
+ const args: any[] = [];
745
+ if (params !== undefined) args.push(params);
746
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchEventsPaginated`, {
747
+ method: 'POST',
748
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
749
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
750
+ });
751
+ if (!response.ok) {
752
+ const body = await response.json().catch(() => ({}));
753
+ if (body.error && typeof body.error === "object") {
754
+ throw fromServerError(body.error);
755
+ }
756
+ throw new PmxtError(body.error?.message || response.statusText);
757
+ }
758
+ const json = await response.json();
759
+ const data = this.handleResponse(json);
760
+ return {
761
+ data: (data.data || []).map(convertEvent),
762
+ total: data.total,
763
+ nextCursor: data.nextCursor,
764
+ };
765
+ } catch (error) {
766
+ if (error instanceof PmxtError) throw error;
767
+ throw new PmxtError(`Failed to fetchEventsPaginated: ${error}`);
672
768
  }
673
769
  }
674
770
 
@@ -677,20 +773,24 @@ export abstract class Exchange {
677
773
  try {
678
774
  const args: any[] = [];
679
775
  if (params !== undefined) args.push(params);
680
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchMarket`, {
776
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMarket`, {
681
777
  method: 'POST',
682
778
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
683
779
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
684
780
  });
685
781
  if (!response.ok) {
686
- const error = await response.json().catch(() => ({}));
687
- throw new Error(error.error?.message || response.statusText);
782
+ const body = await response.json().catch(() => ({}));
783
+ if (body.error && typeof body.error === "object") {
784
+ throw fromServerError(body.error);
785
+ }
786
+ throw new PmxtError(body.error?.message || response.statusText);
688
787
  }
689
788
  const json = await response.json();
690
789
  const data = this.handleResponse(json);
691
790
  return convertMarket(data);
692
791
  } catch (error) {
693
- throw new Error(`Failed to fetchMarket: ${error}`);
792
+ if (error instanceof PmxtError) throw error;
793
+ throw new PmxtError(`Failed to fetchMarket: ${error}`);
694
794
  }
695
795
  }
696
796
 
@@ -699,20 +799,24 @@ export abstract class Exchange {
699
799
  try {
700
800
  const args: any[] = [];
701
801
  if (params !== undefined) args.push(params);
702
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchEvent`, {
802
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchEvent`, {
703
803
  method: 'POST',
704
804
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
705
805
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
706
806
  });
707
807
  if (!response.ok) {
708
- const error = await response.json().catch(() => ({}));
709
- throw new Error(error.error?.message || response.statusText);
808
+ const body = await response.json().catch(() => ({}));
809
+ if (body.error && typeof body.error === "object") {
810
+ throw fromServerError(body.error);
811
+ }
812
+ throw new PmxtError(body.error?.message || response.statusText);
710
813
  }
711
814
  const json = await response.json();
712
815
  const data = this.handleResponse(json);
713
816
  return convertEvent(data);
714
817
  } catch (error) {
715
- throw new Error(`Failed to fetchEvent: ${error}`);
818
+ if (error instanceof PmxtError) throw error;
819
+ throw new PmxtError(`Failed to fetchEvent: ${error}`);
716
820
  }
717
821
  }
718
822
 
@@ -721,20 +825,24 @@ export abstract class Exchange {
721
825
  try {
722
826
  const args: any[] = [];
723
827
  args.push(id);
724
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchOrderBook`, {
828
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchOrderBook`, {
725
829
  method: 'POST',
726
830
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
727
831
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
728
832
  });
729
833
  if (!response.ok) {
730
- const error = await response.json().catch(() => ({}));
731
- throw new Error(error.error?.message || response.statusText);
834
+ const body = await response.json().catch(() => ({}));
835
+ if (body.error && typeof body.error === "object") {
836
+ throw fromServerError(body.error);
837
+ }
838
+ throw new PmxtError(body.error?.message || response.statusText);
732
839
  }
733
840
  const json = await response.json();
734
841
  const data = this.handleResponse(json);
735
842
  return convertOrderBook(data);
736
843
  } catch (error) {
737
- throw new Error(`Failed to fetchOrderBook: ${error}`);
844
+ if (error instanceof PmxtError) throw error;
845
+ throw new PmxtError(`Failed to fetchOrderBook: ${error}`);
738
846
  }
739
847
  }
740
848
 
@@ -743,20 +851,24 @@ export abstract class Exchange {
743
851
  try {
744
852
  const args: any[] = [];
745
853
  args.push(built);
746
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/submitOrder`, {
854
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/submitOrder`, {
747
855
  method: 'POST',
748
856
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
749
857
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
750
858
  });
751
859
  if (!response.ok) {
752
- const error = await response.json().catch(() => ({}));
753
- throw new Error(error.error?.message || response.statusText);
860
+ const body = await response.json().catch(() => ({}));
861
+ if (body.error && typeof body.error === "object") {
862
+ throw fromServerError(body.error);
863
+ }
864
+ throw new PmxtError(body.error?.message || response.statusText);
754
865
  }
755
866
  const json = await response.json();
756
867
  const data = this.handleResponse(json);
757
868
  return convertOrder(data);
758
869
  } catch (error) {
759
- throw new Error(`Failed to submitOrder: ${error}`);
870
+ if (error instanceof PmxtError) throw error;
871
+ throw new PmxtError(`Failed to submitOrder: ${error}`);
760
872
  }
761
873
  }
762
874
 
@@ -765,20 +877,24 @@ export abstract class Exchange {
765
877
  try {
766
878
  const args: any[] = [];
767
879
  args.push(orderId);
768
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/cancelOrder`, {
880
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/cancelOrder`, {
769
881
  method: 'POST',
770
882
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
771
883
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
772
884
  });
773
885
  if (!response.ok) {
774
- const error = await response.json().catch(() => ({}));
775
- throw new Error(error.error?.message || response.statusText);
886
+ const body = await response.json().catch(() => ({}));
887
+ if (body.error && typeof body.error === "object") {
888
+ throw fromServerError(body.error);
889
+ }
890
+ throw new PmxtError(body.error?.message || response.statusText);
776
891
  }
777
892
  const json = await response.json();
778
893
  const data = this.handleResponse(json);
779
894
  return convertOrder(data);
780
895
  } catch (error) {
781
- throw new Error(`Failed to cancelOrder: ${error}`);
896
+ if (error instanceof PmxtError) throw error;
897
+ throw new PmxtError(`Failed to cancelOrder: ${error}`);
782
898
  }
783
899
  }
784
900
 
@@ -787,20 +903,24 @@ export abstract class Exchange {
787
903
  try {
788
904
  const args: any[] = [];
789
905
  args.push(orderId);
790
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchOrder`, {
906
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchOrder`, {
791
907
  method: 'POST',
792
908
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
793
909
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
794
910
  });
795
911
  if (!response.ok) {
796
- const error = await response.json().catch(() => ({}));
797
- throw new Error(error.error?.message || response.statusText);
912
+ const body = await response.json().catch(() => ({}));
913
+ if (body.error && typeof body.error === "object") {
914
+ throw fromServerError(body.error);
915
+ }
916
+ throw new PmxtError(body.error?.message || response.statusText);
798
917
  }
799
918
  const json = await response.json();
800
919
  const data = this.handleResponse(json);
801
920
  return convertOrder(data);
802
921
  } catch (error) {
803
- throw new Error(`Failed to fetchOrder: ${error}`);
922
+ if (error instanceof PmxtError) throw error;
923
+ throw new PmxtError(`Failed to fetchOrder: ${error}`);
804
924
  }
805
925
  }
806
926
 
@@ -809,20 +929,24 @@ export abstract class Exchange {
809
929
  try {
810
930
  const args: any[] = [];
811
931
  if (marketId !== undefined) args.push(marketId);
812
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchOpenOrders`, {
932
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchOpenOrders`, {
813
933
  method: 'POST',
814
934
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
815
935
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
816
936
  });
817
937
  if (!response.ok) {
818
- const error = await response.json().catch(() => ({}));
819
- throw new Error(error.error?.message || response.statusText);
938
+ const body = await response.json().catch(() => ({}));
939
+ if (body.error && typeof body.error === "object") {
940
+ throw fromServerError(body.error);
941
+ }
942
+ throw new PmxtError(body.error?.message || response.statusText);
820
943
  }
821
944
  const json = await response.json();
822
945
  const data = this.handleResponse(json);
823
946
  return data.map(convertOrder);
824
947
  } catch (error) {
825
- throw new Error(`Failed to fetchOpenOrders: ${error}`);
948
+ if (error instanceof PmxtError) throw error;
949
+ throw new PmxtError(`Failed to fetchOpenOrders: ${error}`);
826
950
  }
827
951
  }
828
952
 
@@ -831,20 +955,24 @@ export abstract class Exchange {
831
955
  try {
832
956
  const args: any[] = [];
833
957
  if (params !== undefined) args.push(params);
834
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchMyTrades`, {
958
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMyTrades`, {
835
959
  method: 'POST',
836
960
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
837
961
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
838
962
  });
839
963
  if (!response.ok) {
840
- const error = await response.json().catch(() => ({}));
841
- throw new Error(error.error?.message || response.statusText);
964
+ const body = await response.json().catch(() => ({}));
965
+ if (body.error && typeof body.error === "object") {
966
+ throw fromServerError(body.error);
967
+ }
968
+ throw new PmxtError(body.error?.message || response.statusText);
842
969
  }
843
970
  const json = await response.json();
844
971
  const data = this.handleResponse(json);
845
972
  return data.map(convertUserTrade);
846
973
  } catch (error) {
847
- throw new Error(`Failed to fetchMyTrades: ${error}`);
974
+ if (error instanceof PmxtError) throw error;
975
+ throw new PmxtError(`Failed to fetchMyTrades: ${error}`);
848
976
  }
849
977
  }
850
978
 
@@ -853,20 +981,24 @@ export abstract class Exchange {
853
981
  try {
854
982
  const args: any[] = [];
855
983
  if (params !== undefined) args.push(params);
856
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchClosedOrders`, {
984
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchClosedOrders`, {
857
985
  method: 'POST',
858
986
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
859
987
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
860
988
  });
861
989
  if (!response.ok) {
862
- const error = await response.json().catch(() => ({}));
863
- throw new Error(error.error?.message || response.statusText);
990
+ const body = await response.json().catch(() => ({}));
991
+ if (body.error && typeof body.error === "object") {
992
+ throw fromServerError(body.error);
993
+ }
994
+ throw new PmxtError(body.error?.message || response.statusText);
864
995
  }
865
996
  const json = await response.json();
866
997
  const data = this.handleResponse(json);
867
998
  return data.map(convertOrder);
868
999
  } catch (error) {
869
- throw new Error(`Failed to fetchClosedOrders: ${error}`);
1000
+ if (error instanceof PmxtError) throw error;
1001
+ throw new PmxtError(`Failed to fetchClosedOrders: ${error}`);
870
1002
  }
871
1003
  }
872
1004
 
@@ -875,20 +1007,24 @@ export abstract class Exchange {
875
1007
  try {
876
1008
  const args: any[] = [];
877
1009
  if (params !== undefined) args.push(params);
878
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchAllOrders`, {
1010
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchAllOrders`, {
879
1011
  method: 'POST',
880
1012
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
881
1013
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
882
1014
  });
883
1015
  if (!response.ok) {
884
- const error = await response.json().catch(() => ({}));
885
- throw new Error(error.error?.message || response.statusText);
1016
+ const body = await response.json().catch(() => ({}));
1017
+ if (body.error && typeof body.error === "object") {
1018
+ throw fromServerError(body.error);
1019
+ }
1020
+ throw new PmxtError(body.error?.message || response.statusText);
886
1021
  }
887
1022
  const json = await response.json();
888
1023
  const data = this.handleResponse(json);
889
1024
  return data.map(convertOrder);
890
1025
  } catch (error) {
891
- throw new Error(`Failed to fetchAllOrders: ${error}`);
1026
+ if (error instanceof PmxtError) throw error;
1027
+ throw new PmxtError(`Failed to fetchAllOrders: ${error}`);
892
1028
  }
893
1029
  }
894
1030
 
@@ -897,20 +1033,24 @@ export abstract class Exchange {
897
1033
  try {
898
1034
  const args: any[] = [];
899
1035
  if (address !== undefined) args.push(address);
900
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchPositions`, {
1036
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchPositions`, {
901
1037
  method: 'POST',
902
1038
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
903
1039
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
904
1040
  });
905
1041
  if (!response.ok) {
906
- const error = await response.json().catch(() => ({}));
907
- throw new Error(error.error?.message || response.statusText);
1042
+ const body = await response.json().catch(() => ({}));
1043
+ if (body.error && typeof body.error === "object") {
1044
+ throw fromServerError(body.error);
1045
+ }
1046
+ throw new PmxtError(body.error?.message || response.statusText);
908
1047
  }
909
1048
  const json = await response.json();
910
1049
  const data = this.handleResponse(json);
911
1050
  return data.map(convertPosition);
912
1051
  } catch (error) {
913
- throw new Error(`Failed to fetchPositions: ${error}`);
1052
+ if (error instanceof PmxtError) throw error;
1053
+ throw new PmxtError(`Failed to fetchPositions: ${error}`);
914
1054
  }
915
1055
  }
916
1056
 
@@ -919,20 +1059,24 @@ export abstract class Exchange {
919
1059
  try {
920
1060
  const args: any[] = [];
921
1061
  if (address !== undefined) args.push(address);
922
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/fetchBalance`, {
1062
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchBalance`, {
923
1063
  method: 'POST',
924
1064
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
925
1065
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
926
1066
  });
927
1067
  if (!response.ok) {
928
- const error = await response.json().catch(() => ({}));
929
- throw new Error(error.error?.message || response.statusText);
1068
+ const body = await response.json().catch(() => ({}));
1069
+ if (body.error && typeof body.error === "object") {
1070
+ throw fromServerError(body.error);
1071
+ }
1072
+ throw new PmxtError(body.error?.message || response.statusText);
930
1073
  }
931
1074
  const json = await response.json();
932
1075
  const data = this.handleResponse(json);
933
1076
  return data.map(convertBalance);
934
1077
  } catch (error) {
935
- throw new Error(`Failed to fetchBalance: ${error}`);
1078
+ if (error instanceof PmxtError) throw error;
1079
+ throw new PmxtError(`Failed to fetchBalance: ${error}`);
936
1080
  }
937
1081
  }
938
1082
 
@@ -941,19 +1085,23 @@ export abstract class Exchange {
941
1085
  try {
942
1086
  const args: any[] = [];
943
1087
  args.push(id);
944
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/unwatchOrderBook`, {
1088
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/unwatchOrderBook`, {
945
1089
  method: 'POST',
946
1090
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
947
1091
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
948
1092
  });
949
1093
  if (!response.ok) {
950
- const error = await response.json().catch(() => ({}));
951
- throw new Error(error.error?.message || response.statusText);
1094
+ const body = await response.json().catch(() => ({}));
1095
+ if (body.error && typeof body.error === "object") {
1096
+ throw fromServerError(body.error);
1097
+ }
1098
+ throw new PmxtError(body.error?.message || response.statusText);
952
1099
  }
953
1100
  const json = await response.json();
954
1101
  this.handleResponse(json);
955
1102
  } catch (error) {
956
- throw new Error(`Failed to unwatchOrderBook: ${error}`);
1103
+ if (error instanceof PmxtError) throw error;
1104
+ throw new PmxtError(`Failed to unwatchOrderBook: ${error}`);
957
1105
  }
958
1106
  }
959
1107
 
@@ -962,19 +1110,23 @@ export abstract class Exchange {
962
1110
  try {
963
1111
  const args: any[] = [];
964
1112
  args.push(address);
965
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/unwatchAddress`, {
1113
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/unwatchAddress`, {
966
1114
  method: 'POST',
967
1115
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
968
1116
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
969
1117
  });
970
1118
  if (!response.ok) {
971
- const error = await response.json().catch(() => ({}));
972
- throw new Error(error.error?.message || response.statusText);
1119
+ const body = await response.json().catch(() => ({}));
1120
+ if (body.error && typeof body.error === "object") {
1121
+ throw fromServerError(body.error);
1122
+ }
1123
+ throw new PmxtError(body.error?.message || response.statusText);
973
1124
  }
974
1125
  const json = await response.json();
975
1126
  this.handleResponse(json);
976
1127
  } catch (error) {
977
- throw new Error(`Failed to unwatchAddress: ${error}`);
1128
+ if (error instanceof PmxtError) throw error;
1129
+ throw new PmxtError(`Failed to unwatchAddress: ${error}`);
978
1130
  }
979
1131
  }
980
1132
 
@@ -982,19 +1134,173 @@ export abstract class Exchange {
982
1134
  await this.initPromise;
983
1135
  try {
984
1136
  const args: any[] = [];
985
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/close`, {
1137
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/close`, {
986
1138
  method: 'POST',
987
1139
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
988
1140
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
989
1141
  });
990
1142
  if (!response.ok) {
991
- const error = await response.json().catch(() => ({}));
992
- throw new Error(error.error?.message || response.statusText);
1143
+ const body = await response.json().catch(() => ({}));
1144
+ if (body.error && typeof body.error === "object") {
1145
+ throw fromServerError(body.error);
1146
+ }
1147
+ throw new PmxtError(body.error?.message || response.statusText);
993
1148
  }
994
1149
  const json = await response.json();
995
1150
  this.handleResponse(json);
996
1151
  } catch (error) {
997
- throw new Error(`Failed to close: ${error}`);
1152
+ if (error instanceof PmxtError) throw error;
1153
+ throw new PmxtError(`Failed to close: ${error}`);
1154
+ }
1155
+ }
1156
+
1157
+ async fetchMarketMatches(params: any): Promise<any[]> {
1158
+ await this.initPromise;
1159
+ try {
1160
+ const args: any[] = [];
1161
+ args.push(params);
1162
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMarketMatches`, {
1163
+ method: 'POST',
1164
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1165
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1166
+ });
1167
+ if (!response.ok) {
1168
+ const body = await response.json().catch(() => ({}));
1169
+ if (body.error && typeof body.error === "object") {
1170
+ throw fromServerError(body.error);
1171
+ }
1172
+ throw new PmxtError(body.error?.message || response.statusText);
1173
+ }
1174
+ const json = await response.json();
1175
+ return this.handleResponse(json);
1176
+ } catch (error) {
1177
+ if (error instanceof PmxtError) throw error;
1178
+ throw new PmxtError(`Failed to fetchMarketMatches: ${error}`);
1179
+ }
1180
+ }
1181
+
1182
+ async fetchMatches(params: any): Promise<any[]> {
1183
+ await this.initPromise;
1184
+ try {
1185
+ const args: any[] = [];
1186
+ args.push(params);
1187
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchMatches`, {
1188
+ method: 'POST',
1189
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1190
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1191
+ });
1192
+ if (!response.ok) {
1193
+ const body = await response.json().catch(() => ({}));
1194
+ if (body.error && typeof body.error === "object") {
1195
+ throw fromServerError(body.error);
1196
+ }
1197
+ throw new PmxtError(body.error?.message || response.statusText);
1198
+ }
1199
+ const json = await response.json();
1200
+ return this.handleResponse(json);
1201
+ } catch (error) {
1202
+ if (error instanceof PmxtError) throw error;
1203
+ throw new PmxtError(`Failed to fetchMatches: ${error}`);
1204
+ }
1205
+ }
1206
+
1207
+ async fetchEventMatches(params: any): Promise<any[]> {
1208
+ await this.initPromise;
1209
+ try {
1210
+ const args: any[] = [];
1211
+ args.push(params);
1212
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchEventMatches`, {
1213
+ method: 'POST',
1214
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1215
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1216
+ });
1217
+ if (!response.ok) {
1218
+ const body = await response.json().catch(() => ({}));
1219
+ if (body.error && typeof body.error === "object") {
1220
+ throw fromServerError(body.error);
1221
+ }
1222
+ throw new PmxtError(body.error?.message || response.statusText);
1223
+ }
1224
+ const json = await response.json();
1225
+ return this.handleResponse(json);
1226
+ } catch (error) {
1227
+ if (error instanceof PmxtError) throw error;
1228
+ throw new PmxtError(`Failed to fetchEventMatches: ${error}`);
1229
+ }
1230
+ }
1231
+
1232
+ async compareMarketPrices(params: any): Promise<any[]> {
1233
+ await this.initPromise;
1234
+ try {
1235
+ const args: any[] = [];
1236
+ args.push(params);
1237
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/compareMarketPrices`, {
1238
+ method: 'POST',
1239
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1240
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1241
+ });
1242
+ if (!response.ok) {
1243
+ const body = await response.json().catch(() => ({}));
1244
+ if (body.error && typeof body.error === "object") {
1245
+ throw fromServerError(body.error);
1246
+ }
1247
+ throw new PmxtError(body.error?.message || response.statusText);
1248
+ }
1249
+ const json = await response.json();
1250
+ return this.handleResponse(json);
1251
+ } catch (error) {
1252
+ if (error instanceof PmxtError) throw error;
1253
+ throw new PmxtError(`Failed to compareMarketPrices: ${error}`);
1254
+ }
1255
+ }
1256
+
1257
+ async fetchHedges(params: any): Promise<any[]> {
1258
+ await this.initPromise;
1259
+ try {
1260
+ const args: any[] = [];
1261
+ args.push(params);
1262
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchHedges`, {
1263
+ method: 'POST',
1264
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1265
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1266
+ });
1267
+ if (!response.ok) {
1268
+ const body = await response.json().catch(() => ({}));
1269
+ if (body.error && typeof body.error === "object") {
1270
+ throw fromServerError(body.error);
1271
+ }
1272
+ throw new PmxtError(body.error?.message || response.statusText);
1273
+ }
1274
+ const json = await response.json();
1275
+ return this.handleResponse(json);
1276
+ } catch (error) {
1277
+ if (error instanceof PmxtError) throw error;
1278
+ throw new PmxtError(`Failed to fetchHedges: ${error}`);
1279
+ }
1280
+ }
1281
+
1282
+ async fetchArbitrage(params?: any): Promise<any[]> {
1283
+ await this.initPromise;
1284
+ try {
1285
+ const args: any[] = [];
1286
+ if (params !== undefined) args.push(params);
1287
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/fetchArbitrage`, {
1288
+ method: 'POST',
1289
+ headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1290
+ body: JSON.stringify({ args, credentials: this.getCredentials() }),
1291
+ });
1292
+ if (!response.ok) {
1293
+ const body = await response.json().catch(() => ({}));
1294
+ if (body.error && typeof body.error === "object") {
1295
+ throw fromServerError(body.error);
1296
+ }
1297
+ throw new PmxtError(body.error?.message || response.statusText);
1298
+ }
1299
+ const json = await response.json();
1300
+ return this.handleResponse(json);
1301
+ } catch (error) {
1302
+ if (error instanceof PmxtError) throw error;
1303
+ throw new PmxtError(`Failed to fetchArbitrage: ${error}`);
998
1304
  }
999
1305
  }
1000
1306
 
@@ -1109,7 +1415,7 @@ export abstract class Exchange {
1109
1415
  args.push(limit);
1110
1416
  }
1111
1417
 
1112
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/watchOrderBook`, {
1418
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/watchOrderBook`, {
1113
1419
  method: 'POST',
1114
1420
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1115
1421
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
@@ -1173,7 +1479,7 @@ export abstract class Exchange {
1173
1479
  args.push(limit);
1174
1480
  }
1175
1481
 
1176
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/watchTrades`, {
1482
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/watchTrades`, {
1177
1483
  method: 'POST',
1178
1484
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1179
1485
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
@@ -1225,7 +1531,7 @@ export abstract class Exchange {
1225
1531
  if (types !== undefined) {
1226
1532
  args.push(types);
1227
1533
  }
1228
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/watchAddress`, {
1534
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/watchAddress`, {
1229
1535
  method: 'POST',
1230
1536
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1231
1537
  body: JSON.stringify({ args, credentials: this.getCredentials() }),
@@ -1320,7 +1626,7 @@ export abstract class Exchange {
1320
1626
  paramsDict.fee = params.fee;
1321
1627
  }
1322
1628
 
1323
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/buildOrder`, {
1629
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/buildOrder`, {
1324
1630
  method: 'POST',
1325
1631
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1326
1632
  body: JSON.stringify({ args: [paramsDict], credentials: this.getCredentials() }),
@@ -1396,7 +1702,7 @@ export abstract class Exchange {
1396
1702
  paramsDict.fee = params.fee;
1397
1703
  }
1398
1704
 
1399
- const response = await fetch(`${this.config.basePath}/api/${this.exchangeName}/createOrder`, {
1705
+ const response = await this.fetchWithRetry(`${this.resolveBaseUrl()}/api/${this.exchangeName}/createOrder`, {
1400
1706
  method: 'POST',
1401
1707
  headers: { 'Content-Type': 'application/json', ...this.getAuthHeaders() },
1402
1708
  body: JSON.stringify({ args: [paramsDict], credentials: this.getCredentials() }),
@@ -1455,9 +1761,9 @@ export abstract class Exchange {
1455
1761
  body.credentials = credentials;
1456
1762
  }
1457
1763
 
1458
- const url = `${this.config.basePath}/api/${this.exchangeName}/getExecutionPriceDetailed`;
1764
+ const url = `${this.resolveBaseUrl()}/api/${this.exchangeName}/getExecutionPriceDetailed`;
1459
1765
 
1460
- const response = await fetch(url, {
1766
+ const response = await this.fetchWithRetry(url, {
1461
1767
  method: 'POST',
1462
1768
  headers: {
1463
1769
  'Content-Type': 'application/json',