@acta-markets/ts-sdk 0.0.18-beta → 0.0.19-beta

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.
@@ -55,7 +55,8 @@ describeIfWsUrl("ws handshake integration (real backend)", () => {
55
55
  });
56
56
  client.on("error", (err) => {
57
57
  if (!welcomeReceived) {
58
- finish(err);
58
+ const msg = err.type === "generic" ? err.data.message : err.type;
59
+ finish(new Error(msg));
59
60
  }
60
61
  });
61
62
  client.on("disconnected", (code, reason) => {
@@ -4,6 +4,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.ActaWsClient = void 0;
5
5
  const flows_1 = require("./flows");
6
6
  const wirePolicy_1 = require("./wirePolicy");
7
+ function toGenericServerError(err) {
8
+ const message = err instanceof Error ? err.message : String(err);
9
+ return { type: "generic", data: { code: "client_error", message } };
10
+ }
7
11
  function formatServerError(error) {
8
12
  if (error.type === "generic") {
9
13
  return `${error.data.code}: ${error.data.message}`;
@@ -160,7 +164,7 @@ class ActaWsClient extends TypedEventEmitter {
160
164
  if (this.ws?.readyState === WS_OPEN) {
161
165
  if (this.welcomeReceived && !this.startAuthSent) {
162
166
  void this.beginAuthHandshake().catch((err) => {
163
- this.emit("error", err);
167
+ this.emit("error", toGenericServerError(err));
164
168
  this.setConnectionState("error");
165
169
  });
166
170
  }
@@ -393,6 +397,7 @@ class ActaWsClient extends TypedEventEmitter {
393
397
  }
394
398
  subscribe(channels, markets) {
395
399
  this.ensureAuthenticated();
400
+ const request_id = this.nextRequestId();
396
401
  for (const c of channels)
397
402
  this.subscribedChannels.add(c);
398
403
  if (markets) {
@@ -402,18 +407,21 @@ class ActaWsClient extends TypedEventEmitter {
402
407
  this.send({
403
408
  type: "Subscribe",
404
409
  data: this.hasMarketScope
405
- ? { channels, markets: Array.from(this.subscribedMarkets) }
406
- : { channels },
410
+ ? { request_id, channels, markets: Array.from(this.subscribedMarkets) }
411
+ : { request_id, channels },
407
412
  });
413
+ return request_id;
408
414
  }
409
415
  unsubscribe(channels) {
410
416
  this.ensureAuthenticated();
417
+ const request_id = this.nextRequestId();
411
418
  for (const c of channels)
412
419
  this.subscribedChannels.delete(c);
413
420
  this.send({
414
421
  type: "Unsubscribe",
415
- data: { channels },
422
+ data: { request_id, channels },
416
423
  });
424
+ return request_id;
417
425
  }
418
426
  ping() {
419
427
  if (this.ws?.readyState === WS_OPEN) {
@@ -468,7 +476,7 @@ class ActaWsClient extends TypedEventEmitter {
468
476
  };
469
477
  ws.onerror = (ev) => {
470
478
  this.log("WebSocket error:", ev);
471
- this.emit("error", new Error("WebSocket error"));
479
+ this.emit("error", toGenericServerError("WebSocket error"));
472
480
  if (this.shouldReconnect) {
473
481
  this.cleanup();
474
482
  this.scheduleReconnect();
@@ -485,7 +493,7 @@ class ActaWsClient extends TypedEventEmitter {
485
493
  this.flushPendingMessages();
486
494
  if (this.authRequested && this.authProvider && !this.startAuthSent) {
487
495
  void this.beginAuthHandshake().catch((err) => {
488
- this.emit("error", err);
496
+ this.emit("error", toGenericServerError(err));
489
497
  this.setConnectionState("error");
490
498
  });
491
499
  }
@@ -711,7 +719,16 @@ class ActaWsClient extends TypedEventEmitter {
711
719
  case "Pong":
712
720
  break;
713
721
  case "Error":
714
- this.emit("error", new Error(formatServerError(message.data)));
722
+ this.emit("error", message.data);
723
+ break;
724
+ case "RequestError":
725
+ this.emit("requestError", message.data);
726
+ break;
727
+ case "SubscribeAck":
728
+ this.emit("subscribeAck", message.data);
729
+ break;
730
+ case "UnsubscribeAck":
731
+ this.emit("unsubscribeAck", message.data);
715
732
  break;
716
733
  }
717
734
  }
@@ -732,7 +749,7 @@ class ActaWsClient extends TypedEventEmitter {
732
749
  async handleAuthRequest(challenge) {
733
750
  this.setConnectionState("authenticating");
734
751
  if (!this.authProvider) {
735
- this.emit("error", new Error("No auth provider configured"));
752
+ this.emit("error", toGenericServerError("No auth provider configured"));
736
753
  return;
737
754
  }
738
755
  try {
@@ -746,7 +763,7 @@ class ActaWsClient extends TypedEventEmitter {
746
763
  });
747
764
  }
748
765
  catch (err) {
749
- this.emit("error", err);
766
+ this.emit("error", toGenericServerError(err));
750
767
  this.setConnectionState("error");
751
768
  }
752
769
  }
@@ -797,9 +814,10 @@ class ActaWsClient extends TypedEventEmitter {
797
814
  this.emit("authenticated", sessionId, expiresAt);
798
815
  if (this.subscribedChannels.size > 0) {
799
816
  const channels = Array.from(this.subscribedChannels);
817
+ const request_id = this.nextRequestId();
800
818
  const data = this.hasMarketScope
801
- ? { channels, markets: Array.from(this.subscribedMarkets) }
802
- : { channels };
819
+ ? { request_id, channels, markets: Array.from(this.subscribedMarkets) }
820
+ : { request_id, channels };
803
821
  this.send({ type: "Subscribe", data });
804
822
  }
805
823
  }
@@ -813,14 +831,14 @@ class ActaWsClient extends TypedEventEmitter {
813
831
  this.lastAuthSessionId = null;
814
832
  this.startAuthSent = false;
815
833
  void this.sendStartAuth().catch((err) => {
816
- this.emit("error", err);
834
+ this.emit("error", toGenericServerError(err));
817
835
  this.setConnectionState("error");
818
836
  });
819
837
  return;
820
838
  }
821
839
  this.setConnectionState("error");
822
840
  const details = message ? `${reason}: ${message}` : reason;
823
- this.emit("error", new Error(`Authentication failed: ${details}`));
841
+ this.emit("error", toGenericServerError(`Authentication failed: ${details}`));
824
842
  }
825
843
  handleSnapshot(snapshot) {
826
844
  this.state.markets.clear();
@@ -959,7 +977,7 @@ class ActaWsClient extends TypedEventEmitter {
959
977
  this.log("Pending queue full, dropping newest message:", message.type);
960
978
  return false;
961
979
  case "throw":
962
- this.emit("error", new Error(`Pending queue overflow (maxPendingMessages=${maxPending}) for message type=${message.type}`));
980
+ this.emit("error", toGenericServerError(`Pending queue overflow (maxPendingMessages=${maxPending}) for message type=${message.type}`));
963
981
  return false;
964
982
  }
965
983
  }
@@ -420,7 +420,11 @@ describe("ActaWsClient", () => {
420
420
  client.getMarkets();
421
421
  client.getTokens();
422
422
  expect(errors).toHaveLength(1);
423
- expect(errors[0].message).toContain("Pending queue overflow");
423
+ const err0 = errors[0];
424
+ expect(err0.type).toBe("generic");
425
+ if (err0.type === "generic") {
426
+ expect(err0.data.message).toContain("Pending queue overflow");
427
+ }
424
428
  ws.triggerMessage(WELCOME_MESSAGE);
425
429
  const flushedTypes = ws.sent
426
430
  .slice(1)
@@ -2,7 +2,7 @@
2
2
  import type { AuthProvider } from "./auth";
3
3
  import type { SignerLike } from "../chain/orders";
4
4
  import type { Address } from "@solana/addresses";
5
- import type { ActiveRfqInfo, ChainEventMessage, EarnSummaryData, TokenMarketsInfoData, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqSkippedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, RequestId, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
5
+ import type { ActiveRfqInfo, ChainEventMessage, EarnSummaryData, TokenMarketsInfoData, GlobalStats, MarketDescriptorInfo, MarketInfo, MyActiveRfqInfo, MyActiveRfqsMessage, OrderStatusMessage, PositionInfo, QuoteAcknowledgedMessage, QuoteBestStatusMessage, QuoteCancelledMessage, QuoteMessage, QuoteRefreshRequestedMessage, QuoteOutbidMessage, QuoteReceivedMessage, QuoteSelectedMessage, QuotesUpdateMessage, RfqBroadcastMessage, RfqClosedMessage, RfqCreatedMessage, RfqSkippedMessage, RfqRequestMessage, RfqAvailableAgainMessage, QuoteExpiredMessage, QuoteFilledMessage, IndicativePricesMessage, IndicativePricesRequestMessage, IndicativePricesResponseMessage, GetIndicativePricesMessage, RequestId, ServerError, ServerMessage, SnapshotMessage, StatsDelta, SubscriptionsMessage, TokenInfo, TradeInfo, UuidString, VersionMismatchMessage, WelcomeMessage, WsChannel } from "./types";
6
6
  export type ConnectionState = "disconnected" | "connecting" | "authenticating" | "authenticated" | "error";
7
7
  export type ClientRole = "taker" | "maker";
8
8
  export type PendingMessagesOverflowPolicy = "drop_oldest" | "drop_newest" | "throw";
@@ -60,7 +60,19 @@ export type ActaWsClientEvents = {
60
60
  authError: (reason: string, message?: string) => void;
61
61
  logoutSuccess: () => void;
62
62
  disconnected: (code: number, reason: string) => void;
63
- error: (error: Error) => void;
63
+ error: (error: ServerError) => void;
64
+ requestError: (data: {
65
+ request_id: RequestId;
66
+ error: ServerError;
67
+ }) => void;
68
+ subscribeAck: (data: {
69
+ request_id: RequestId;
70
+ subscribed: WsChannel[];
71
+ }) => void;
72
+ unsubscribeAck: (data: {
73
+ request_id: RequestId;
74
+ unsubscribed: WsChannel[];
75
+ }) => void;
64
76
  stateChange: (state: ConnectionState) => void;
65
77
  message: (message: ServerMessage) => void;
66
78
  snapshot: (snapshot: SnapshotMessage) => void;
@@ -241,8 +253,8 @@ export declare class ActaWsClient extends TypedEventEmitter<ActaWsClientEvents>
241
253
  makerSigner: SignerLike;
242
254
  }): Promise<void>;
243
255
  cancelQuote(rfqId: string): RequestId;
244
- subscribe(channels: WsChannel[], markets?: string[]): void;
245
- unsubscribe(channels: WsChannel[]): void;
256
+ subscribe(channels: WsChannel[], markets?: string[]): RequestId;
257
+ unsubscribe(channels: WsChannel[]): RequestId;
246
258
  ping(): void;
247
259
  resumeAuth(sessionId: string): void;
248
260
  private doConnect;
@@ -50,7 +50,8 @@ describeIfWsUrl("ws handshake integration (real backend)", () => {
50
50
  });
51
51
  client.on("error", (err) => {
52
52
  if (!welcomeReceived) {
53
- finish(err);
53
+ const msg = err.type === "generic" ? err.data.message : err.type;
54
+ finish(new Error(msg));
54
55
  }
55
56
  });
56
57
  client.on("disconnected", (code, reason) => {
package/dist/ws/client.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /** Acta WebSocket client (rfq-server). */
2
2
  import { buildSignedQuoteMessage, buildAcceptQuoteMessage } from "./flows";
3
3
  import { assertWsU64Safe, validateQuantityBySizeRule } from "./wirePolicy";
4
+ function toGenericServerError(err) {
5
+ const message = err instanceof Error ? err.message : String(err);
6
+ return { type: "generic", data: { code: "client_error", message } };
7
+ }
4
8
  function formatServerError(error) {
5
9
  if (error.type === "generic") {
6
10
  return `${error.data.code}: ${error.data.message}`;
@@ -157,7 +161,7 @@ export class ActaWsClient extends TypedEventEmitter {
157
161
  if (this.ws?.readyState === WS_OPEN) {
158
162
  if (this.welcomeReceived && !this.startAuthSent) {
159
163
  void this.beginAuthHandshake().catch((err) => {
160
- this.emit("error", err);
164
+ this.emit("error", toGenericServerError(err));
161
165
  this.setConnectionState("error");
162
166
  });
163
167
  }
@@ -390,6 +394,7 @@ export class ActaWsClient extends TypedEventEmitter {
390
394
  }
391
395
  subscribe(channels, markets) {
392
396
  this.ensureAuthenticated();
397
+ const request_id = this.nextRequestId();
393
398
  for (const c of channels)
394
399
  this.subscribedChannels.add(c);
395
400
  if (markets) {
@@ -399,18 +404,21 @@ export class ActaWsClient extends TypedEventEmitter {
399
404
  this.send({
400
405
  type: "Subscribe",
401
406
  data: this.hasMarketScope
402
- ? { channels, markets: Array.from(this.subscribedMarkets) }
403
- : { channels },
407
+ ? { request_id, channels, markets: Array.from(this.subscribedMarkets) }
408
+ : { request_id, channels },
404
409
  });
410
+ return request_id;
405
411
  }
406
412
  unsubscribe(channels) {
407
413
  this.ensureAuthenticated();
414
+ const request_id = this.nextRequestId();
408
415
  for (const c of channels)
409
416
  this.subscribedChannels.delete(c);
410
417
  this.send({
411
418
  type: "Unsubscribe",
412
- data: { channels },
419
+ data: { request_id, channels },
413
420
  });
421
+ return request_id;
414
422
  }
415
423
  ping() {
416
424
  if (this.ws?.readyState === WS_OPEN) {
@@ -465,7 +473,7 @@ export class ActaWsClient extends TypedEventEmitter {
465
473
  };
466
474
  ws.onerror = (ev) => {
467
475
  this.log("WebSocket error:", ev);
468
- this.emit("error", new Error("WebSocket error"));
476
+ this.emit("error", toGenericServerError("WebSocket error"));
469
477
  if (this.shouldReconnect) {
470
478
  this.cleanup();
471
479
  this.scheduleReconnect();
@@ -482,7 +490,7 @@ export class ActaWsClient extends TypedEventEmitter {
482
490
  this.flushPendingMessages();
483
491
  if (this.authRequested && this.authProvider && !this.startAuthSent) {
484
492
  void this.beginAuthHandshake().catch((err) => {
485
- this.emit("error", err);
493
+ this.emit("error", toGenericServerError(err));
486
494
  this.setConnectionState("error");
487
495
  });
488
496
  }
@@ -708,7 +716,16 @@ export class ActaWsClient extends TypedEventEmitter {
708
716
  case "Pong":
709
717
  break;
710
718
  case "Error":
711
- this.emit("error", new Error(formatServerError(message.data)));
719
+ this.emit("error", message.data);
720
+ break;
721
+ case "RequestError":
722
+ this.emit("requestError", message.data);
723
+ break;
724
+ case "SubscribeAck":
725
+ this.emit("subscribeAck", message.data);
726
+ break;
727
+ case "UnsubscribeAck":
728
+ this.emit("unsubscribeAck", message.data);
712
729
  break;
713
730
  }
714
731
  }
@@ -729,7 +746,7 @@ export class ActaWsClient extends TypedEventEmitter {
729
746
  async handleAuthRequest(challenge) {
730
747
  this.setConnectionState("authenticating");
731
748
  if (!this.authProvider) {
732
- this.emit("error", new Error("No auth provider configured"));
749
+ this.emit("error", toGenericServerError("No auth provider configured"));
733
750
  return;
734
751
  }
735
752
  try {
@@ -743,7 +760,7 @@ export class ActaWsClient extends TypedEventEmitter {
743
760
  });
744
761
  }
745
762
  catch (err) {
746
- this.emit("error", err);
763
+ this.emit("error", toGenericServerError(err));
747
764
  this.setConnectionState("error");
748
765
  }
749
766
  }
@@ -794,9 +811,10 @@ export class ActaWsClient extends TypedEventEmitter {
794
811
  this.emit("authenticated", sessionId, expiresAt);
795
812
  if (this.subscribedChannels.size > 0) {
796
813
  const channels = Array.from(this.subscribedChannels);
814
+ const request_id = this.nextRequestId();
797
815
  const data = this.hasMarketScope
798
- ? { channels, markets: Array.from(this.subscribedMarkets) }
799
- : { channels };
816
+ ? { request_id, channels, markets: Array.from(this.subscribedMarkets) }
817
+ : { request_id, channels };
800
818
  this.send({ type: "Subscribe", data });
801
819
  }
802
820
  }
@@ -810,14 +828,14 @@ export class ActaWsClient extends TypedEventEmitter {
810
828
  this.lastAuthSessionId = null;
811
829
  this.startAuthSent = false;
812
830
  void this.sendStartAuth().catch((err) => {
813
- this.emit("error", err);
831
+ this.emit("error", toGenericServerError(err));
814
832
  this.setConnectionState("error");
815
833
  });
816
834
  return;
817
835
  }
818
836
  this.setConnectionState("error");
819
837
  const details = message ? `${reason}: ${message}` : reason;
820
- this.emit("error", new Error(`Authentication failed: ${details}`));
838
+ this.emit("error", toGenericServerError(`Authentication failed: ${details}`));
821
839
  }
822
840
  handleSnapshot(snapshot) {
823
841
  this.state.markets.clear();
@@ -956,7 +974,7 @@ export class ActaWsClient extends TypedEventEmitter {
956
974
  this.log("Pending queue full, dropping newest message:", message.type);
957
975
  return false;
958
976
  case "throw":
959
- this.emit("error", new Error(`Pending queue overflow (maxPendingMessages=${maxPending}) for message type=${message.type}`));
977
+ this.emit("error", toGenericServerError(`Pending queue overflow (maxPendingMessages=${maxPending}) for message type=${message.type}`));
960
978
  return false;
961
979
  }
962
980
  }
@@ -418,7 +418,11 @@ describe("ActaWsClient", () => {
418
418
  client.getMarkets();
419
419
  client.getTokens();
420
420
  expect(errors).toHaveLength(1);
421
- expect(errors[0].message).toContain("Pending queue overflow");
421
+ const err0 = errors[0];
422
+ expect(err0.type).toBe("generic");
423
+ if (err0.type === "generic") {
424
+ expect(err0.data.message).toContain("Pending queue overflow");
425
+ }
422
426
  ws.triggerMessage(WELCOME_MESSAGE);
423
427
  const flushedTypes = ws.sent
424
428
  .slice(1)
@@ -171,12 +171,14 @@ export type ClientMessage = {
171
171
  } | {
172
172
  type: "Subscribe";
173
173
  data: {
174
+ request_id: RequestId;
174
175
  channels: WsChannel[];
175
176
  markets?: string[];
176
177
  };
177
178
  } | {
178
179
  type: "Unsubscribe";
179
180
  data: {
181
+ request_id: RequestId;
180
182
  channels: WsChannel[];
181
183
  };
182
184
  };
@@ -483,6 +485,24 @@ export type ServerMessage = {
483
485
  } | {
484
486
  type: "Error";
485
487
  data: ServerError;
488
+ } | {
489
+ type: "RequestError";
490
+ data: {
491
+ request_id: RequestId;
492
+ error: ServerError;
493
+ };
494
+ } | {
495
+ type: "SubscribeAck";
496
+ data: {
497
+ request_id: RequestId;
498
+ subscribed: WsChannel[];
499
+ };
500
+ } | {
501
+ type: "UnsubscribeAck";
502
+ data: {
503
+ request_id: RequestId;
504
+ unsubscribed: WsChannel[];
505
+ };
486
506
  };
487
507
  export type MarketDescriptorInfo = {
488
508
  market: MarketDescriptor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acta-markets/ts-sdk",
3
- "version": "0.0.18-beta",
3
+ "version": "0.0.19-beta",
4
4
  "description": "TypeScript SDK for Acta Protocol",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",