@openfeed/sdk-js 1.1.5 → 1.2.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.
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
+
5
+ ### [1.1.5](https://github.com/openfeed-org/sdk-js/compare/1.1.4...1.1.5) (2023-12-22)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * new approach for listening to alias changes ([69f2d7d](https://github.com/openfeed-org/sdk-js/commit/69f2d7d6e5b64d7abeb6c6cda052c6e7f512aef3))
@@ -0,0 +1,10 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
+
5
+ ### [1.1.6](https://github.com/openfeed-org/sdk-js/compare/1.1.5...1.1.6) (2024-02-27)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * enhance unsubscription flow to prevent duplicate race condition ([863a4fe](https://github.com/openfeed-org/sdk-js/commit/863a4fe5e2ff27613b70a9f1638df211fd796acc))
package/CHANGELOG.md CHANGED
@@ -2,9 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ### [1.1.5](https://github.com/openfeed-org/sdk-js/compare/1.1.4...1.1.5) (2023-12-22)
5
+ ## [1.2.0](https://github.com/openfeed-org/sdk-js/compare/1.1.6...1.2.0) (2024-03-25)
6
+
7
+
8
+ ### Features
9
+
10
+ * update proto and generate ts files ([cee34a2](https://github.com/openfeed-org/sdk-js/commit/cee34a2f35a5e35ab6c28f9d65dbe71800727819))
6
11
 
7
12
 
8
13
  ### Bug Fixes
9
14
 
10
- * new approach for listening to alias changes ([69f2d7d](https://github.com/openfeed-org/sdk-js/commit/69f2d7d6e5b64d7abeb6c6cda052c6e7f512aef3))
15
+ * enhance alias change handling to prevent loss of subscriptions ([3714a15](https://github.com/openfeed-org/sdk-js/commit/3714a15f57e1da81876d2c18828823df452b524d))
@@ -124,7 +124,7 @@ export declare enum ActionType {
124
124
  * message types
125
125
  */
126
126
  export interface OpenfeedMessage {
127
- /** / Nanoecond unix epoch at time of message transmission (UTC) */
127
+ /** / Nano second unix epoch at time of message transmission (UTC) */
128
128
  sendingTime: Long;
129
129
  /**
130
130
  * / The total number of markets available on this channel
@@ -991,6 +991,7 @@ export interface InstrumentAction {
991
991
  tradeDate: number;
992
992
  action: ActionType;
993
993
  message: string;
994
+ oldAlias: string;
994
995
  instrument: InstrumentDefinition | undefined;
995
996
  newInstrument: InstrumentDefinition | undefined;
996
997
  }
@@ -21,6 +21,7 @@ export declare enum Result {
21
21
  INSUFFICIENT_PRIVILEGES = 125,
22
22
  AUTHENTICATION_REQUIRED = 126,
23
23
  GENERIC_FAILURE = 127,
24
+ INVALID_USERNAME = 128,
24
25
  UNRECOGNIZED = -1
25
26
  }
26
27
  export declare enum SubscriptionType {
@@ -49,6 +50,7 @@ export interface OpenfeedGatewayRequest {
49
50
  instrumentRequest?: InstrumentRequest | undefined;
50
51
  instrumentReferenceRequest?: InstrumentReferenceRequest | undefined;
51
52
  exchangeRequest?: ExchangeRequest | undefined;
53
+ listSubscriptionsRequest?: ListSubscriptionsRequest | undefined;
52
54
  }
53
55
  /** / Openfeed Server Response */
54
56
  export interface OpenfeedGatewayMessage {
@@ -66,6 +68,7 @@ export interface OpenfeedGatewayMessage {
66
68
  ohlc?: Ohlc | undefined;
67
69
  exchangeResponse?: ExchangeResponse | undefined;
68
70
  instrumentAction?: InstrumentAction | undefined;
71
+ listSubscriptionsResponse?: ListSubscriptionsResponse | undefined;
69
72
  }
70
73
  /**
71
74
  * //////////////////
@@ -213,6 +216,34 @@ export interface SubscriptionResponse {
213
216
  unsubscribe: boolean;
214
217
  snapshotIntervalSeconds: number;
215
218
  }
219
+ /** / List Subscriptions for a user */
220
+ export interface ListSubscriptionsRequest {
221
+ correlationId: Long;
222
+ token: string;
223
+ username: string;
224
+ }
225
+ export interface ListSubscriptionsResponse {
226
+ correlationId: Long;
227
+ status: Status | undefined;
228
+ username: string;
229
+ sessions: ListSubscriptionsResponse_Session[];
230
+ }
231
+ export interface ListSubscriptionsResponse_Session {
232
+ /** / Nano second unix epoch */
233
+ loginTime: Long;
234
+ token: string;
235
+ clientVersion: string;
236
+ marketSubscriptions: ListSubscriptionsResponse_Subscription[];
237
+ exchangeSubscriptions: ListSubscriptionsResponse_Subscription[];
238
+ }
239
+ export interface ListSubscriptionsResponse_Subscription {
240
+ subscriptionId: string;
241
+ symbolId: string;
242
+ marketId: Long;
243
+ symbols: string[];
244
+ exchange: string;
245
+ root: string;
246
+ }
216
247
  export declare const OpenfeedGatewayRequestEncode: {
217
248
  encode(message: OpenfeedGatewayRequest, writer?: _m0.Writer): _m0.Writer;
218
249
  }, OpenfeedGatewayRequestDecode: {
@@ -303,3 +334,23 @@ export declare const SubscriptionResponseEncode: {
303
334
  }, SubscriptionResponseDecode: {
304
335
  decode(input: _m0.Reader | Uint8Array, length?: number): SubscriptionResponse;
305
336
  };
337
+ export declare const ListSubscriptionsRequestEncode: {
338
+ encode(message: ListSubscriptionsRequest, writer?: _m0.Writer): _m0.Writer;
339
+ }, ListSubscriptionsRequestDecode: {
340
+ decode(input: _m0.Reader | Uint8Array, length?: number): ListSubscriptionsRequest;
341
+ };
342
+ export declare const ListSubscriptionsResponseEncode: {
343
+ encode(message: ListSubscriptionsResponse, writer?: _m0.Writer): _m0.Writer;
344
+ }, ListSubscriptionsResponseDecode: {
345
+ decode(input: _m0.Reader | Uint8Array, length?: number): ListSubscriptionsResponse;
346
+ };
347
+ export declare const ListSubscriptionsResponse_SessionEncode: {
348
+ encode(message: ListSubscriptionsResponse_Session, writer?: _m0.Writer): _m0.Writer;
349
+ }, ListSubscriptionsResponse_SessionDecode: {
350
+ decode(input: _m0.Reader | Uint8Array, length?: number): ListSubscriptionsResponse_Session;
351
+ };
352
+ export declare const ListSubscriptionsResponse_SubscriptionEncode: {
353
+ encode(message: ListSubscriptionsResponse_Subscription, writer?: _m0.Writer): _m0.Writer;
354
+ }, ListSubscriptionsResponse_SubscriptionDecode: {
355
+ decode(input: _m0.Reader | Uint8Array, length?: number): ListSubscriptionsResponse_Subscription;
356
+ };
@@ -1 +1 @@
1
- export declare const version = "1.1.5";
1
+ export declare const version = "1.2.0";
package/dist/index.js CHANGED
@@ -7054,6 +7054,7 @@ function createBaseInstrumentAction() {
7054
7054
  tradeDate: 0,
7055
7055
  action: 0,
7056
7056
  message: "",
7057
+ oldAlias: "",
7057
7058
  instrument: void 0,
7058
7059
  newInstrument: void 0
7059
7060
  };
@@ -7090,6 +7091,12 @@ const InstrumentActionDecode = {
7090
7091
  }
7091
7092
  message.message = reader2.string();
7092
7093
  continue;
7094
+ case 5:
7095
+ if (tag !== 42) {
7096
+ break;
7097
+ }
7098
+ message.oldAlias = reader2.string();
7099
+ continue;
7093
7100
  case 10:
7094
7101
  if (tag !== 82) {
7095
7102
  break;
@@ -7190,6 +7197,7 @@ var Result = /* @__PURE__ */ ((Result2) => {
7190
7197
  Result2[Result2["INSUFFICIENT_PRIVILEGES"] = 125] = "INSUFFICIENT_PRIVILEGES";
7191
7198
  Result2[Result2["AUTHENTICATION_REQUIRED"] = 126] = "AUTHENTICATION_REQUIRED";
7192
7199
  Result2[Result2["GENERIC_FAILURE"] = 127] = "GENERIC_FAILURE";
7200
+ Result2[Result2["INVALID_USERNAME"] = 128] = "INVALID_USERNAME";
7193
7201
  Result2[Result2["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
7194
7202
  return Result2;
7195
7203
  })(Result || {});
@@ -7232,6 +7240,9 @@ const OpenfeedGatewayRequestEncode = {
7232
7240
  if (message.exchangeRequest !== void 0) {
7233
7241
  ExchangeRequestEncode.encode(message.exchangeRequest, writer2.uint32(50).fork()).ldelim();
7234
7242
  }
7243
+ if (message.listSubscriptionsRequest !== void 0) {
7244
+ ListSubscriptionsRequestEncode.encode(message.listSubscriptionsRequest, writer2.uint32(58).fork()).ldelim();
7245
+ }
7235
7246
  return writer2;
7236
7247
  }
7237
7248
  };
@@ -7250,7 +7261,8 @@ function createBaseOpenfeedGatewayMessage() {
7250
7261
  volumeAtPrice: void 0,
7251
7262
  ohlc: void 0,
7252
7263
  exchangeResponse: void 0,
7253
- instrumentAction: void 0
7264
+ instrumentAction: void 0,
7265
+ listSubscriptionsResponse: void 0
7254
7266
  };
7255
7267
  }
7256
7268
  const OpenfeedGatewayMessageDecode = {
@@ -7345,6 +7357,12 @@ const OpenfeedGatewayMessageDecode = {
7345
7357
  }
7346
7358
  message.instrumentAction = InstrumentActionDecode.decode(reader2, reader2.uint32());
7347
7359
  continue;
7360
+ case 15:
7361
+ if (tag !== 122) {
7362
+ break;
7363
+ }
7364
+ message.listSubscriptionsResponse = ListSubscriptionsResponseDecode.decode(reader2, reader2.uint32());
7365
+ continue;
7348
7366
  }
7349
7367
  if ((tag & 7) === 4 || tag === 0) {
7350
7368
  break;
@@ -7993,6 +8011,170 @@ const SubscriptionResponseDecode = {
7993
8011
  return message;
7994
8012
  }
7995
8013
  };
8014
+ const ListSubscriptionsRequestEncode = {
8015
+ encode(message, writer2 = _m0.Writer.create()) {
8016
+ if (!message.correlationId.isZero()) {
8017
+ writer2.uint32(8).sint64(message.correlationId);
8018
+ }
8019
+ if (message.token !== "") {
8020
+ writer2.uint32(18).string(message.token);
8021
+ }
8022
+ if (message.username !== "") {
8023
+ writer2.uint32(26).string(message.username);
8024
+ }
8025
+ return writer2;
8026
+ }
8027
+ };
8028
+ function createBaseListSubscriptionsResponse() {
8029
+ return { correlationId: Long.ZERO, status: void 0, username: "", sessions: [] };
8030
+ }
8031
+ const ListSubscriptionsResponseDecode = {
8032
+ decode(input, length) {
8033
+ const reader2 = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
8034
+ let end2 = length === void 0 ? reader2.len : reader2.pos + length;
8035
+ const message = createBaseListSubscriptionsResponse();
8036
+ while (reader2.pos < end2) {
8037
+ const tag = reader2.uint32();
8038
+ switch (tag >>> 3) {
8039
+ case 1:
8040
+ if (tag !== 8) {
8041
+ break;
8042
+ }
8043
+ message.correlationId = reader2.sint64();
8044
+ continue;
8045
+ case 2:
8046
+ if (tag !== 18) {
8047
+ break;
8048
+ }
8049
+ message.status = StatusDecode.decode(reader2, reader2.uint32());
8050
+ continue;
8051
+ case 3:
8052
+ if (tag !== 26) {
8053
+ break;
8054
+ }
8055
+ message.username = reader2.string();
8056
+ continue;
8057
+ case 10:
8058
+ if (tag !== 82) {
8059
+ break;
8060
+ }
8061
+ message.sessions.push(ListSubscriptionsResponse_SessionDecode.decode(reader2, reader2.uint32()));
8062
+ continue;
8063
+ }
8064
+ if ((tag & 7) === 4 || tag === 0) {
8065
+ break;
8066
+ }
8067
+ reader2.skipType(tag & 7);
8068
+ }
8069
+ return message;
8070
+ }
8071
+ };
8072
+ function createBaseListSubscriptionsResponse_Session() {
8073
+ return { loginTime: Long.ZERO, token: "", clientVersion: "", marketSubscriptions: [], exchangeSubscriptions: [] };
8074
+ }
8075
+ const ListSubscriptionsResponse_SessionDecode = {
8076
+ decode(input, length) {
8077
+ const reader2 = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
8078
+ let end2 = length === void 0 ? reader2.len : reader2.pos + length;
8079
+ const message = createBaseListSubscriptionsResponse_Session();
8080
+ while (reader2.pos < end2) {
8081
+ const tag = reader2.uint32();
8082
+ switch (tag >>> 3) {
8083
+ case 1:
8084
+ if (tag !== 8) {
8085
+ break;
8086
+ }
8087
+ message.loginTime = reader2.sint64();
8088
+ continue;
8089
+ case 2:
8090
+ if (tag !== 18) {
8091
+ break;
8092
+ }
8093
+ message.token = reader2.string();
8094
+ continue;
8095
+ case 3:
8096
+ if (tag !== 26) {
8097
+ break;
8098
+ }
8099
+ message.clientVersion = reader2.string();
8100
+ continue;
8101
+ case 10:
8102
+ if (tag !== 82) {
8103
+ break;
8104
+ }
8105
+ message.marketSubscriptions.push(ListSubscriptionsResponse_SubscriptionDecode.decode(reader2, reader2.uint32()));
8106
+ continue;
8107
+ case 11:
8108
+ if (tag !== 90) {
8109
+ break;
8110
+ }
8111
+ message.exchangeSubscriptions.push(ListSubscriptionsResponse_SubscriptionDecode.decode(reader2, reader2.uint32()));
8112
+ continue;
8113
+ }
8114
+ if ((tag & 7) === 4 || tag === 0) {
8115
+ break;
8116
+ }
8117
+ reader2.skipType(tag & 7);
8118
+ }
8119
+ return message;
8120
+ }
8121
+ };
8122
+ function createBaseListSubscriptionsResponse_Subscription() {
8123
+ return { subscriptionId: "", symbolId: "", marketId: Long.ZERO, symbols: [], exchange: "", root: "" };
8124
+ }
8125
+ const ListSubscriptionsResponse_SubscriptionDecode = {
8126
+ decode(input, length) {
8127
+ const reader2 = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
8128
+ let end2 = length === void 0 ? reader2.len : reader2.pos + length;
8129
+ const message = createBaseListSubscriptionsResponse_Subscription();
8130
+ while (reader2.pos < end2) {
8131
+ const tag = reader2.uint32();
8132
+ switch (tag >>> 3) {
8133
+ case 1:
8134
+ if (tag !== 10) {
8135
+ break;
8136
+ }
8137
+ message.subscriptionId = reader2.string();
8138
+ continue;
8139
+ case 2:
8140
+ if (tag !== 18) {
8141
+ break;
8142
+ }
8143
+ message.symbolId = reader2.string();
8144
+ continue;
8145
+ case 3:
8146
+ if (tag !== 24) {
8147
+ break;
8148
+ }
8149
+ message.marketId = reader2.sint64();
8150
+ continue;
8151
+ case 4:
8152
+ if (tag !== 34) {
8153
+ break;
8154
+ }
8155
+ message.symbols.push(reader2.string());
8156
+ continue;
8157
+ case 10:
8158
+ if (tag !== 82) {
8159
+ break;
8160
+ }
8161
+ message.exchange = reader2.string();
8162
+ continue;
8163
+ case 11:
8164
+ if (tag !== 90) {
8165
+ break;
8166
+ }
8167
+ message.root = reader2.string();
8168
+ continue;
8169
+ }
8170
+ if ((tag & 7) === 4 || tag === 0) {
8171
+ break;
8172
+ }
8173
+ reader2.skipType(tag & 7);
8174
+ }
8175
+ return message;
8176
+ }
8177
+ };
7996
8178
  if (_m0.util.Long !== Long) {
7997
8179
  _m0.util.Long = Long;
7998
8180
  _m0.configure();
@@ -8031,7 +8213,7 @@ class ResolutionSource {
8031
8213
  return this.onError;
8032
8214
  }
8033
8215
  }
8034
- const version = "1.1.5";
8216
+ const version = "1.2.0";
8035
8217
  const send = (socket, message) => {
8036
8218
  socket.send(OpenfeedGatewayRequestEncode.encode(toT(message)).finish());
8037
8219
  };
@@ -8073,7 +8255,7 @@ class ConnectionDisposedError extends Error {
8073
8255
  }
8074
8256
  class OpenFeedConnection {
8075
8257
  constructor(connectionToken, socket, listeners, logger) {
8076
- __publicField(this, "subscriptions", /* @__PURE__ */ new Map());
8258
+ __publicField(this, "subscriptionRequests", /* @__PURE__ */ new Map());
8077
8259
  __publicField(this, "exchangeRequests", /* @__PURE__ */ new Map());
8078
8260
  __publicField(this, "instrumentRequests", /* @__PURE__ */ new Map());
8079
8261
  __publicField(this, "definitionsInFlight", /* @__PURE__ */ new Map());
@@ -8157,6 +8339,16 @@ class OpenFeedConnection {
8157
8339
  request.resolve(message.exchangeResponse);
8158
8340
  continue;
8159
8341
  }
8342
+ if (message.subscriptionResponse) {
8343
+ const { correlationId, unsubscribe } = message.subscriptionResponse;
8344
+ if (!unsubscribe) {
8345
+ const request = this.subscriptionRequests.get(correlationId.toString());
8346
+ if (!request)
8347
+ throw new Error(`Subscription response ID ${correlationId} not found`);
8348
+ const [, sub] = request;
8349
+ sub.resolve();
8350
+ }
8351
+ }
8160
8352
  this.listeners.onMessage(message);
8161
8353
  }
8162
8354
  } catch (error) {
@@ -8229,7 +8421,8 @@ class OpenFeedConnection {
8229
8421
  requests: requests.map((r) => toT(r)),
8230
8422
  unsubscribe: false
8231
8423
  };
8232
- this.subscriptions.set(correlationId.toString(), subscriptionRequest);
8424
+ const source = new ResolutionSource();
8425
+ this.subscriptionRequests.set(correlationId.toString(), [subscriptionRequest, source]);
8233
8426
  send(this.socket, { subscriptionRequest });
8234
8427
  return correlationId;
8235
8428
  });
@@ -8237,13 +8430,12 @@ class OpenFeedConnection {
8237
8430
  if (this.whenDisconnectedSource.completed) {
8238
8431
  throw new ConnectionDisposedError("This connection was closed");
8239
8432
  }
8240
- const subscription = this.subscriptions.get(subscriptionId.toString());
8433
+ const subscription = this.subscriptionRequests.get(subscriptionId.toString());
8241
8434
  if (!subscription) {
8242
8435
  throw new Error(`Subscription ID ${subscriptionId} does not exist.`);
8243
8436
  }
8244
- const subscriptionRequest = { ...subscription, unsubscribe: true };
8245
- send(this.socket, { subscriptionRequest });
8246
- this.subscriptions.delete(subscriptionId.toString());
8437
+ const [originalRequest, sub] = subscription;
8438
+ this.fireUnsubscribeWhenReady(originalRequest, sub);
8247
8439
  });
8248
8440
  __publicField(this, "getExchanges", async () => {
8249
8441
  var _a;
@@ -8342,6 +8534,18 @@ class OpenFeedConnection {
8342
8534
  this.socket.close(1e3, error.message);
8343
8535
  this.whenDisconnectedSource.reject(error);
8344
8536
  }
8537
+ // We are keeping this fire and forget, because our problems
8538
+ // would be caused by disconnection, and reconnect will clean up the rest
8539
+ async fireUnsubscribeWhenReady(originalRequest, sub) {
8540
+ try {
8541
+ await sub.whenCompleted;
8542
+ const subscriptionRequest = { ...originalRequest, unsubscribe: true };
8543
+ send(this.socket, { subscriptionRequest });
8544
+ } catch (e) {
8545
+ } finally {
8546
+ this.subscriptionRequests.delete(originalRequest.correlationId.toString());
8547
+ }
8548
+ }
8345
8549
  }
8346
8550
  class OpenFeedClient {
8347
8551
  constructor(url, username, password, listeners, logger, clientId) {
@@ -8607,14 +8811,25 @@ class OpenFeedListeners {
8607
8811
  return res ?? [void 0, void 0];
8608
8812
  };
8609
8813
  if (message.subscriptionResponse) {
8610
- if (message.subscriptionResponse != null && message.subscriptionResponse.marketId !== Long.ZERO) {
8611
- [def, symbols] = getInstrumentDefinition(message.subscriptionResponse.marketId);
8612
- if (!symbols) {
8613
- symbols = [message.subscriptionResponse.symbol];
8614
- } else if (!symbols.includes(message.subscriptionResponse.symbol)) {
8615
- symbols = [...symbols, message.subscriptionResponse.symbol];
8616
- }
8617
- this.instrumentByMarketId.set(message.subscriptionResponse.marketId.toString(), [def, symbols]);
8814
+ const { marketId, symbol, unsubscribe } = message.subscriptionResponse;
8815
+ if (marketId !== Long.ZERO) {
8816
+ [def, symbols] = getInstrumentDefinition(marketId);
8817
+ if (!unsubscribe) {
8818
+ if (!symbols) {
8819
+ symbols = [symbol];
8820
+ } else if (!symbols.includes(symbol)) {
8821
+ symbols = [...symbols, symbol];
8822
+ }
8823
+ } else {
8824
+ if (symbols) {
8825
+ symbols = symbols.filter((s) => s !== symbol);
8826
+ }
8827
+ if (!symbols) {
8828
+ this.instrumentByMarketId.delete(marketId.toString());
8829
+ }
8830
+ this.instrumentBySymbol.delete(symbol);
8831
+ }
8832
+ this.instrumentByMarketId.set(marketId.toString(), [def, symbols]);
8618
8833
  }
8619
8834
  } else if (message.instrumentDefinition) {
8620
8835
  [def, symbols] = getInstrumentDefinition(message.instrumentDefinition.marketId);
@@ -8625,13 +8840,27 @@ class OpenFeedListeners {
8625
8840
  } else if (message.instrumentAction) {
8626
8841
  const { marketId } = ((_a = message.instrumentAction) == null ? void 0 : _a.instrument) ?? {};
8627
8842
  if (message.instrumentAction.action === ActionType.ALIAS_CHANGED && marketId) {
8843
+ const { oldAlias } = message.instrumentAction;
8844
+ const [root, num] = oldAlias.split("*");
8845
+ const newAliasNum = oldAlias.endsWith("*0") ? 0 : Number.parseInt(num, 10) + 1;
8846
+ const newAlias = `${root}*${newAliasNum}`;
8628
8847
  [def, symbols] = getInstrumentDefinition(marketId);
8629
- const newSymbols = (symbols == null ? void 0 : symbols.filter((s) => !s.includes("*"))) ?? [];
8848
+ const newSymbols = (symbols == null ? void 0 : symbols.filter((s) => s !== oldAlias)) ?? [];
8630
8849
  if (!newSymbols.length) {
8631
8850
  this.instrumentByMarketId.delete(marketId.toString());
8632
8851
  } else {
8633
8852
  this.instrumentByMarketId.set(marketId.toString(), [def, newSymbols]);
8634
8853
  }
8854
+ const { marketId: newMarketId } = message.instrumentAction.newInstrument ?? {};
8855
+ if (newMarketId) {
8856
+ const [newDef, newSym] = getInstrumentDefinition(newMarketId);
8857
+ const newSymbolsFiltered = (newAlias === oldAlias ? newSym : newSym == null ? void 0 : newSym.filter((s) => s !== newAlias)) ?? [];
8858
+ if (!newSymbolsFiltered.length) {
8859
+ this.instrumentByMarketId.delete(newMarketId.toString());
8860
+ } else {
8861
+ this.instrumentByMarketId.set(newMarketId.toString(), [newDef, newSymbolsFiltered]);
8862
+ }
8863
+ }
8635
8864
  }
8636
8865
  if (message.instrumentAction.action === ActionType.EXCHANGE_MOVE && marketId) {
8637
8866
  [def, symbols] = getInstrumentDefinition(marketId);
package/dist/node.js CHANGED
@@ -10672,6 +10672,7 @@ function createBaseInstrumentAction() {
10672
10672
  tradeDate: 0,
10673
10673
  action: 0,
10674
10674
  message: "",
10675
+ oldAlias: "",
10675
10676
  instrument: void 0,
10676
10677
  newInstrument: void 0
10677
10678
  };
@@ -10708,6 +10709,12 @@ var InstrumentActionDecode = {
10708
10709
  }
10709
10710
  message.message = reader.string();
10710
10711
  continue;
10712
+ case 5:
10713
+ if (tag !== 42) {
10714
+ break;
10715
+ }
10716
+ message.oldAlias = reader.string();
10717
+ continue;
10711
10718
  case 10:
10712
10719
  if (tag !== 82) {
10713
10720
  break;
@@ -10810,6 +10817,7 @@ var Result = /* @__PURE__ */ ((Result2) => {
10810
10817
  Result2[Result2["INSUFFICIENT_PRIVILEGES"] = 125] = "INSUFFICIENT_PRIVILEGES";
10811
10818
  Result2[Result2["AUTHENTICATION_REQUIRED"] = 126] = "AUTHENTICATION_REQUIRED";
10812
10819
  Result2[Result2["GENERIC_FAILURE"] = 127] = "GENERIC_FAILURE";
10820
+ Result2[Result2["INVALID_USERNAME"] = 128] = "INVALID_USERNAME";
10813
10821
  Result2[Result2["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
10814
10822
  return Result2;
10815
10823
  })(Result || {});
@@ -10852,6 +10860,9 @@ var OpenfeedGatewayRequestEncode = {
10852
10860
  if (message.exchangeRequest !== void 0) {
10853
10861
  ExchangeRequestEncode.encode(message.exchangeRequest, writer.uint32(50).fork()).ldelim();
10854
10862
  }
10863
+ if (message.listSubscriptionsRequest !== void 0) {
10864
+ ListSubscriptionsRequestEncode.encode(message.listSubscriptionsRequest, writer.uint32(58).fork()).ldelim();
10865
+ }
10855
10866
  return writer;
10856
10867
  }
10857
10868
  };
@@ -10870,7 +10881,8 @@ function createBaseOpenfeedGatewayMessage() {
10870
10881
  volumeAtPrice: void 0,
10871
10882
  ohlc: void 0,
10872
10883
  exchangeResponse: void 0,
10873
- instrumentAction: void 0
10884
+ instrumentAction: void 0,
10885
+ listSubscriptionsResponse: void 0
10874
10886
  };
10875
10887
  }
10876
10888
  var OpenfeedGatewayMessageDecode = {
@@ -10965,6 +10977,12 @@ var OpenfeedGatewayMessageDecode = {
10965
10977
  }
10966
10978
  message.instrumentAction = InstrumentActionDecode.decode(reader, reader.uint32());
10967
10979
  continue;
10980
+ case 15:
10981
+ if (tag !== 122) {
10982
+ break;
10983
+ }
10984
+ message.listSubscriptionsResponse = ListSubscriptionsResponseDecode.decode(reader, reader.uint32());
10985
+ continue;
10968
10986
  }
10969
10987
  if ((tag & 7) === 4 || tag === 0) {
10970
10988
  break;
@@ -11613,6 +11631,170 @@ var SubscriptionResponseDecode = {
11613
11631
  return message;
11614
11632
  }
11615
11633
  };
11634
+ var ListSubscriptionsRequestEncode = {
11635
+ encode(message, writer = import_minimal3.default.Writer.create()) {
11636
+ if (!message.correlationId.isZero()) {
11637
+ writer.uint32(8).sint64(message.correlationId);
11638
+ }
11639
+ if (message.token !== "") {
11640
+ writer.uint32(18).string(message.token);
11641
+ }
11642
+ if (message.username !== "") {
11643
+ writer.uint32(26).string(message.username);
11644
+ }
11645
+ return writer;
11646
+ }
11647
+ };
11648
+ function createBaseListSubscriptionsResponse() {
11649
+ return { correlationId: long_default.ZERO, status: void 0, username: "", sessions: [] };
11650
+ }
11651
+ var ListSubscriptionsResponseDecode = {
11652
+ decode(input, length) {
11653
+ const reader = input instanceof import_minimal3.default.Reader ? input : import_minimal3.default.Reader.create(input);
11654
+ let end = length === void 0 ? reader.len : reader.pos + length;
11655
+ const message = createBaseListSubscriptionsResponse();
11656
+ while (reader.pos < end) {
11657
+ const tag = reader.uint32();
11658
+ switch (tag >>> 3) {
11659
+ case 1:
11660
+ if (tag !== 8) {
11661
+ break;
11662
+ }
11663
+ message.correlationId = reader.sint64();
11664
+ continue;
11665
+ case 2:
11666
+ if (tag !== 18) {
11667
+ break;
11668
+ }
11669
+ message.status = StatusDecode.decode(reader, reader.uint32());
11670
+ continue;
11671
+ case 3:
11672
+ if (tag !== 26) {
11673
+ break;
11674
+ }
11675
+ message.username = reader.string();
11676
+ continue;
11677
+ case 10:
11678
+ if (tag !== 82) {
11679
+ break;
11680
+ }
11681
+ message.sessions.push(ListSubscriptionsResponse_SessionDecode.decode(reader, reader.uint32()));
11682
+ continue;
11683
+ }
11684
+ if ((tag & 7) === 4 || tag === 0) {
11685
+ break;
11686
+ }
11687
+ reader.skipType(tag & 7);
11688
+ }
11689
+ return message;
11690
+ }
11691
+ };
11692
+ function createBaseListSubscriptionsResponse_Session() {
11693
+ return { loginTime: long_default.ZERO, token: "", clientVersion: "", marketSubscriptions: [], exchangeSubscriptions: [] };
11694
+ }
11695
+ var ListSubscriptionsResponse_SessionDecode = {
11696
+ decode(input, length) {
11697
+ const reader = input instanceof import_minimal3.default.Reader ? input : import_minimal3.default.Reader.create(input);
11698
+ let end = length === void 0 ? reader.len : reader.pos + length;
11699
+ const message = createBaseListSubscriptionsResponse_Session();
11700
+ while (reader.pos < end) {
11701
+ const tag = reader.uint32();
11702
+ switch (tag >>> 3) {
11703
+ case 1:
11704
+ if (tag !== 8) {
11705
+ break;
11706
+ }
11707
+ message.loginTime = reader.sint64();
11708
+ continue;
11709
+ case 2:
11710
+ if (tag !== 18) {
11711
+ break;
11712
+ }
11713
+ message.token = reader.string();
11714
+ continue;
11715
+ case 3:
11716
+ if (tag !== 26) {
11717
+ break;
11718
+ }
11719
+ message.clientVersion = reader.string();
11720
+ continue;
11721
+ case 10:
11722
+ if (tag !== 82) {
11723
+ break;
11724
+ }
11725
+ message.marketSubscriptions.push(ListSubscriptionsResponse_SubscriptionDecode.decode(reader, reader.uint32()));
11726
+ continue;
11727
+ case 11:
11728
+ if (tag !== 90) {
11729
+ break;
11730
+ }
11731
+ message.exchangeSubscriptions.push(ListSubscriptionsResponse_SubscriptionDecode.decode(reader, reader.uint32()));
11732
+ continue;
11733
+ }
11734
+ if ((tag & 7) === 4 || tag === 0) {
11735
+ break;
11736
+ }
11737
+ reader.skipType(tag & 7);
11738
+ }
11739
+ return message;
11740
+ }
11741
+ };
11742
+ function createBaseListSubscriptionsResponse_Subscription() {
11743
+ return { subscriptionId: "", symbolId: "", marketId: long_default.ZERO, symbols: [], exchange: "", root: "" };
11744
+ }
11745
+ var ListSubscriptionsResponse_SubscriptionDecode = {
11746
+ decode(input, length) {
11747
+ const reader = input instanceof import_minimal3.default.Reader ? input : import_minimal3.default.Reader.create(input);
11748
+ let end = length === void 0 ? reader.len : reader.pos + length;
11749
+ const message = createBaseListSubscriptionsResponse_Subscription();
11750
+ while (reader.pos < end) {
11751
+ const tag = reader.uint32();
11752
+ switch (tag >>> 3) {
11753
+ case 1:
11754
+ if (tag !== 10) {
11755
+ break;
11756
+ }
11757
+ message.subscriptionId = reader.string();
11758
+ continue;
11759
+ case 2:
11760
+ if (tag !== 18) {
11761
+ break;
11762
+ }
11763
+ message.symbolId = reader.string();
11764
+ continue;
11765
+ case 3:
11766
+ if (tag !== 24) {
11767
+ break;
11768
+ }
11769
+ message.marketId = reader.sint64();
11770
+ continue;
11771
+ case 4:
11772
+ if (tag !== 34) {
11773
+ break;
11774
+ }
11775
+ message.symbols.push(reader.string());
11776
+ continue;
11777
+ case 10:
11778
+ if (tag !== 82) {
11779
+ break;
11780
+ }
11781
+ message.exchange = reader.string();
11782
+ continue;
11783
+ case 11:
11784
+ if (tag !== 90) {
11785
+ break;
11786
+ }
11787
+ message.root = reader.string();
11788
+ continue;
11789
+ }
11790
+ if ((tag & 7) === 4 || tag === 0) {
11791
+ break;
11792
+ }
11793
+ reader.skipType(tag & 7);
11794
+ }
11795
+ return message;
11796
+ }
11797
+ };
11616
11798
  if (import_minimal3.default.util.Long !== long_default) {
11617
11799
  import_minimal3.default.util.Long = long_default;
11618
11800
  import_minimal3.default.configure();
@@ -11655,7 +11837,7 @@ var ResolutionSource = class {
11655
11837
  };
11656
11838
 
11657
11839
  // generated/version.ts
11658
- var version = "1.1.5";
11840
+ var version = "1.2.0";
11659
11841
 
11660
11842
  // src/connection/connection.ts
11661
11843
  var send = (socket, message) => {
@@ -11707,7 +11889,7 @@ var OpenFeedConnection = class {
11707
11889
  this.socket.onclose = this.onClose;
11708
11890
  this.runConnectionWatchLoop();
11709
11891
  }
11710
- subscriptions = /* @__PURE__ */ new Map();
11892
+ subscriptionRequests = /* @__PURE__ */ new Map();
11711
11893
  exchangeRequests = /* @__PURE__ */ new Map();
11712
11894
  instrumentRequests = /* @__PURE__ */ new Map();
11713
11895
  definitionsInFlight = /* @__PURE__ */ new Map();
@@ -11791,6 +11973,16 @@ var OpenFeedConnection = class {
11791
11973
  request.resolve(message.exchangeResponse);
11792
11974
  continue;
11793
11975
  }
11976
+ if (message.subscriptionResponse) {
11977
+ const { correlationId, unsubscribe } = message.subscriptionResponse;
11978
+ if (!unsubscribe) {
11979
+ const request = this.subscriptionRequests.get(correlationId.toString());
11980
+ if (!request)
11981
+ throw new Error(`Subscription response ID ${correlationId} not found`);
11982
+ const [, sub] = request;
11983
+ sub.resolve();
11984
+ }
11985
+ }
11794
11986
  this.listeners.onMessage(message);
11795
11987
  }
11796
11988
  } catch (error) {
@@ -11881,7 +12073,8 @@ var OpenFeedConnection = class {
11881
12073
  requests: requests.map((r) => toT(r)),
11882
12074
  unsubscribe: false
11883
12075
  };
11884
- this.subscriptions.set(correlationId.toString(), subscriptionRequest);
12076
+ const source = new ResolutionSource();
12077
+ this.subscriptionRequests.set(correlationId.toString(), [subscriptionRequest, source]);
11885
12078
  send(this.socket, { subscriptionRequest });
11886
12079
  return correlationId;
11887
12080
  };
@@ -11889,14 +12082,25 @@ var OpenFeedConnection = class {
11889
12082
  if (this.whenDisconnectedSource.completed) {
11890
12083
  throw new ConnectionDisposedError("This connection was closed");
11891
12084
  }
11892
- const subscription = this.subscriptions.get(subscriptionId.toString());
12085
+ const subscription = this.subscriptionRequests.get(subscriptionId.toString());
11893
12086
  if (!subscription) {
11894
12087
  throw new Error(`Subscription ID ${subscriptionId} does not exist.`);
11895
12088
  }
11896
- const subscriptionRequest = { ...subscription, unsubscribe: true };
11897
- send(this.socket, { subscriptionRequest });
11898
- this.subscriptions.delete(subscriptionId.toString());
12089
+ const [originalRequest, sub] = subscription;
12090
+ this.fireUnsubscribeWhenReady(originalRequest, sub);
11899
12091
  };
12092
+ // We are keeping this fire and forget, because our problems
12093
+ // would be caused by disconnection, and reconnect will clean up the rest
12094
+ async fireUnsubscribeWhenReady(originalRequest, sub) {
12095
+ try {
12096
+ await sub.whenCompleted;
12097
+ const subscriptionRequest = { ...originalRequest, unsubscribe: true };
12098
+ send(this.socket, { subscriptionRequest });
12099
+ } catch (e) {
12100
+ } finally {
12101
+ this.subscriptionRequests.delete(originalRequest.correlationId.toString());
12102
+ }
12103
+ }
11900
12104
  getExchanges = async () => {
11901
12105
  var _a;
11902
12106
  if (this.whenDisconnectedSource.completed) {
@@ -12236,14 +12440,25 @@ var OpenFeedListeners = class {
12236
12440
  return res ?? [void 0, void 0];
12237
12441
  };
12238
12442
  if (message.subscriptionResponse) {
12239
- if (message.subscriptionResponse != null && message.subscriptionResponse.marketId !== long_default.ZERO) {
12240
- [def, symbols] = getInstrumentDefinition(message.subscriptionResponse.marketId);
12241
- if (!symbols) {
12242
- symbols = [message.subscriptionResponse.symbol];
12243
- } else if (!symbols.includes(message.subscriptionResponse.symbol)) {
12244
- symbols = [...symbols, message.subscriptionResponse.symbol];
12443
+ const { marketId, symbol, unsubscribe } = message.subscriptionResponse;
12444
+ if (marketId !== long_default.ZERO) {
12445
+ [def, symbols] = getInstrumentDefinition(marketId);
12446
+ if (!unsubscribe) {
12447
+ if (!symbols) {
12448
+ symbols = [symbol];
12449
+ } else if (!symbols.includes(symbol)) {
12450
+ symbols = [...symbols, symbol];
12451
+ }
12452
+ } else {
12453
+ if (symbols) {
12454
+ symbols = symbols.filter((s) => s !== symbol);
12455
+ }
12456
+ if (!symbols) {
12457
+ this.instrumentByMarketId.delete(marketId.toString());
12458
+ }
12459
+ this.instrumentBySymbol.delete(symbol);
12245
12460
  }
12246
- this.instrumentByMarketId.set(message.subscriptionResponse.marketId.toString(), [def, symbols]);
12461
+ this.instrumentByMarketId.set(marketId.toString(), [def, symbols]);
12247
12462
  }
12248
12463
  } else if (message.instrumentDefinition) {
12249
12464
  [def, symbols] = getInstrumentDefinition(message.instrumentDefinition.marketId);
@@ -12254,13 +12469,27 @@ var OpenFeedListeners = class {
12254
12469
  } else if (message.instrumentAction) {
12255
12470
  const { marketId } = ((_a = message.instrumentAction) == null ? void 0 : _a.instrument) ?? {};
12256
12471
  if (message.instrumentAction.action === 4 /* ALIAS_CHANGED */ && marketId) {
12472
+ const { oldAlias } = message.instrumentAction;
12473
+ const [root, num] = oldAlias.split("*");
12474
+ const newAliasNum = oldAlias.endsWith("*0") ? 0 : Number.parseInt(num, 10) + 1;
12475
+ const newAlias = `${root}*${newAliasNum}`;
12257
12476
  [def, symbols] = getInstrumentDefinition(marketId);
12258
- const newSymbols = (symbols == null ? void 0 : symbols.filter((s) => !s.includes("*"))) ?? [];
12477
+ const newSymbols = (symbols == null ? void 0 : symbols.filter((s) => s !== oldAlias)) ?? [];
12259
12478
  if (!newSymbols.length) {
12260
12479
  this.instrumentByMarketId.delete(marketId.toString());
12261
12480
  } else {
12262
12481
  this.instrumentByMarketId.set(marketId.toString(), [def, newSymbols]);
12263
12482
  }
12483
+ const { marketId: newMarketId } = message.instrumentAction.newInstrument ?? {};
12484
+ if (newMarketId) {
12485
+ const [newDef, newSym] = getInstrumentDefinition(newMarketId);
12486
+ const newSymbolsFiltered = (newAlias === oldAlias ? newSym : newSym == null ? void 0 : newSym.filter((s) => s !== newAlias)) ?? [];
12487
+ if (!newSymbolsFiltered.length) {
12488
+ this.instrumentByMarketId.delete(newMarketId.toString());
12489
+ } else {
12490
+ this.instrumentByMarketId.set(newMarketId.toString(), [newDef, newSymbolsFiltered]);
12491
+ }
12492
+ }
12264
12493
  }
12265
12494
  if (message.instrumentAction.action === 3 /* EXCHANGE_MOVE */ && marketId) {
12266
12495
  [def, symbols] = getInstrumentDefinition(marketId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfeed/sdk-js",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "JavaScript SDK for Barchart OpenFeed",
5
5
  "main": "dist/node.js",
6
6
  "browser": "dist/index.js",