shoonya-sdk 0.4.9 → 0.5.1

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.
@@ -84,6 +84,7 @@ var Logger = class {
84
84
  logPath = "";
85
85
  maxSize = 0;
86
86
  fileName = "";
87
+ logging = false;
87
88
  /**
88
89
  *
89
90
  * @param logFileName name to prepend the logs file with
@@ -96,6 +97,8 @@ var Logger = class {
96
97
  this.checkPathExistance();
97
98
  }
98
99
  log(msg, logType = "DEBUG") {
100
+ if (!this.logging)
101
+ return;
99
102
  const content = `${logType}:[${(/* @__PURE__ */ new Date()).toISOString()}]:${msg}
100
103
  `;
101
104
  (0, import_node_fs.appendFileSync)(this.logPath, content);
@@ -252,6 +255,7 @@ var RetryManager = class extends import_events.EventEmitter {
252
255
  };
253
256
 
254
257
  // src/shoonya-sdk.ts
258
+ var import_promises = require("timers/promises");
255
259
  var Shoonya = class extends RetryManager {
256
260
  static {
257
261
  __name(this, "Shoonya");
@@ -259,7 +263,6 @@ var Shoonya = class extends RetryManager {
259
263
  accessToken;
260
264
  userId;
261
265
  logger;
262
- logging = false;
263
266
  httpBaseUrl = "https://api.shoonya.com/NorenWClientTP/";
264
267
  wsBaseUrl = "wss://api.shoonya.com/NorenWSTP/";
265
268
  ws;
@@ -286,7 +289,6 @@ var Shoonya = class extends RetryManager {
286
289
  this.userId = "";
287
290
  this.accessToken = "";
288
291
  this.accountId = this.userId;
289
- this.logging = logging;
290
292
  this.reconnectTimeout = { timer: null, timeout: reconnectTimeout };
291
293
  this.heartbeatTimeout = { timer: null, timeout: heartbeatTimeout };
292
294
  if (logging) {
@@ -295,29 +297,65 @@ var Shoonya = class extends RetryManager {
295
297
  1024 * 100
296
298
  //1KB * 100 = 100KB
297
299
  );
300
+ this.logger.logging = logging;
298
301
  }
299
- this.on("resub", (token) => {
300
- this.subscribeUnsafe([token]);
302
+ this.on("resub", async (token) => {
303
+ for (let i = this.scripList.length - 1; i >= 0; i--) {
304
+ const t = this.scripList[i];
305
+ if (t === token) {
306
+ this.unsubscribe([token]);
307
+ this.scripList.splice(i, 1);
308
+ await this.login({
309
+ apiKey: this.apiKey,
310
+ password: this.password,
311
+ twoFa: this.twoFa,
312
+ userId: this.userId
313
+ });
314
+ const msg = {
315
+ t: "c",
316
+ uid: this.userId,
317
+ actid: this.accountId,
318
+ source: "API",
319
+ susertoken: this.accessToken
320
+ };
321
+ this.ws.send(JSON.stringify(msg));
322
+ await (0, import_promises.setTimeout)(100);
323
+ this.subscribe([token]);
324
+ this.logger.log("Resubscribed to" + token);
325
+ break;
326
+ }
327
+ }
301
328
  });
302
329
  }
303
330
  async request(path, body) {
304
331
  const jData = `jData=${JSON.stringify(body.data)}${body.key ? "&jKey=" + body.key : ""}`;
305
332
  try {
306
- const data = await fetch(this.httpBaseUrl + paths[path], {
333
+ const req = await fetch(this.httpBaseUrl + paths[path], {
307
334
  method: "POST",
308
335
  body: jData,
309
- keepalive: true
310
- }).then((res) => {
311
- return res.json();
336
+ keepalive: false
312
337
  });
338
+ let data = await req.json();
339
+ if ("emsg" in data && data.emsg.includes("Session Expired")) {
340
+ await this.login({
341
+ apiKey: this.apiKey,
342
+ password: this.password,
343
+ twoFa: this.twoFa,
344
+ userId: this.userId
345
+ });
346
+ const newJData = `jData=${JSON.stringify(body.data)}${body.key ? "&jKey=" + this.accessToken : ""}`;
347
+ const newReq = await fetch(this.httpBaseUrl + paths[path], {
348
+ method: "POST",
349
+ body: newJData,
350
+ keepalive: false
351
+ });
352
+ data = await newReq.json();
353
+ }
313
354
  return data;
314
355
  } catch (err) {
315
- if (this.logging) {
316
- const errMessage = "Failed to fetch data from api while performing: " + path;
317
- this.logger.log(errMessage, "ERROR");
318
- console.error(errMessage);
319
- }
320
- console.error(err);
356
+ const errMessage = `Error: ${err?.message} in ${path}`;
357
+ this.logger.log(errMessage, "ERROR");
358
+ console.error(errMessage);
321
359
  }
322
360
  }
323
361
  // Rest API
@@ -347,12 +385,10 @@ var Shoonya = class extends RetryManager {
347
385
  this.twoFa = rawCred.twoFa;
348
386
  return req;
349
387
  } catch (err) {
350
- if (this.logging) {
351
- const fallBackMessage = "Attempted to login but it failed";
352
- const errMessage = err?.message || fallBackMessage;
353
- this.logger.log(errMessage, "ERROR");
354
- console.error(errMessage);
355
- }
388
+ const fallBackMessage = "Attempted to login but it failed";
389
+ const errMessage = err?.message || fallBackMessage;
390
+ this.logger.log(errMessage, "ERROR");
391
+ console.error(errMessage);
356
392
  console.error("Login Failed", err);
357
393
  }
358
394
  }
@@ -563,9 +599,10 @@ var Shoonya = class extends RetryManager {
563
599
  const optionType = params.optionType.at(0);
564
600
  const symbol = params.symbol.toUpperCase();
565
601
  let c = 0;
566
- for await (const [expiry, unformattedDate] of this.getNextFormattedDates(
567
- optionExpiry
568
- )) {
602
+ for await (const [
603
+ expiry,
604
+ unformattedDate
605
+ ] of this.getNextFormattedDates()) {
569
606
  const optionToPick = `${symbol}${expiry}${optionType}${strikePrice}`;
570
607
  const optionChain = await this.getOptionChain({
571
608
  count,
@@ -604,12 +641,8 @@ var Shoonya = class extends RetryManager {
604
641
  const newYear = year.slice(2);
605
642
  return `${day}${newMonth}${newYear}`;
606
643
  }
607
- getNextFormattedDates(expiry) {
608
- let multiplier = 1;
609
- if (["next", "more-than-1-day", "more-than-3-day"].includes(expiry))
610
- multiplier = 2;
611
- if (["next-next", "more-than-10-day"].includes(expiry))
612
- multiplier = 3;
644
+ getNextFormattedDates() {
645
+ const multiplier = 3;
613
646
  let currentDate = /* @__PURE__ */ new Date();
614
647
  let dates = [];
615
648
  for (let i = 0; i <= 7 * multiplier; i++) {
@@ -733,11 +766,11 @@ var Shoonya = class extends RetryManager {
733
766
  await this.login(cred);
734
767
  this.connectWS();
735
768
  this.emit("open", "opened ws connection");
736
- this.logging && this.logger.log("Token Refreshed");
769
+ this.logger.log("Token successfully refreshed");
737
770
  } catch (err) {
738
771
  console.error(err);
739
772
  const errMessage = `Token refreshing failed. ERR: ${err.message}`;
740
- this.logging && this.logger.log(errMessage, "ERROR");
773
+ this.logger.log(errMessage, "ERROR");
741
774
  this.getWSState().OPEN && this.ws.close();
742
775
  this.emit("stopped", errMessage);
743
776
  }
@@ -749,7 +782,7 @@ var Shoonya = class extends RetryManager {
749
782
  const result = JSON.parse(e.data.toString());
750
783
  this.lastWsMsgAt = /* @__PURE__ */ new Date();
751
784
  if (result.t === "dk") {
752
- this.logging && this.logger.log(`Subscribed to ${result.ts}. Listening...`);
785
+ this.logger.log(`Subscribed to ${result.ts}. Listening...`);
753
786
  }
754
787
  if (result.lp && result.t === "df") {
755
788
  this.resetTimerForToken(result.tk, result.e);
@@ -762,7 +795,7 @@ var Shoonya = class extends RetryManager {
762
795
  clearTimeout(this.connectTimer);
763
796
  this.connectTimer = setTimeout(() => {
764
797
  this.emit("connect", e);
765
- this.logging && this.logger.log("Connected with Shoonya API! Streaming Data...");
798
+ this.logger.log("Connected with Shoonya API! Streaming Data...");
766
799
  this.subscribeAgain(this.scripList);
767
800
  }, 3e3);
768
801
  return;
@@ -786,13 +819,13 @@ var Shoonya = class extends RetryManager {
786
819
  if (day in [5, 6])
787
820
  return;
788
821
  const err = "API have stopped to respond! there could be a problem with API or market has closed";
789
- this.logging && this.logger.log(err, "WARN");
822
+ this.logger.log(err, "WARN");
790
823
  this.emit("stopped", err);
791
824
  this.getWSState().OPEN && this.ws.close();
792
825
  }, 6e4 * 60 * 18 - 1e4);
793
826
  });
794
827
  this.ws.addEventListener("error", (e) => {
795
- this.logging && this.logger.log("some error in ws");
828
+ this.logger.log("some error in ws");
796
829
  this.emit("error", e);
797
830
  this.getWSState().OPEN && this.ws.close();
798
831
  });
@@ -837,6 +870,7 @@ var Shoonya = class extends RetryManager {
837
870
  for (const val of distinctScrips) {
838
871
  this.scripList.push(val);
839
872
  }
873
+ this.logger.log(JSON.stringify(msg));
840
874
  this.ws && this.ws.send(JSON.stringify(msg));
841
875
  }
842
876
  unsubscribe(scripList) {
@@ -852,6 +886,13 @@ var Shoonya = class extends RetryManager {
852
886
  }
853
887
  }
854
888
  }
889
+ /**
890
+ * Unsubscribe All while removing the tokens from this.scripList
891
+ */
892
+ unsubscribeAllWhileClearing() {
893
+ this.unsubscribe(this.scripList);
894
+ return this.scripList.splice(0);
895
+ }
855
896
  /**
856
897
  * This method will not check if token is already subscribed or not before sending subscribe request
857
898
  *
@@ -891,7 +932,7 @@ var Shoonya = class extends RetryManager {
891
932
  if (this.getWSState().OPEN || this.getWSState().CONNECTING) {
892
933
  clearInterval(this.heartbeatTimeout.timer);
893
934
  this.ws.close();
894
- this.logging && this.logger.log("Websocket Connection with Shoonya API is now closed!");
935
+ this.logger.log("Websocket Connection with Shoonya API is now closed!");
895
936
  this.emit("close");
896
937
  }
897
938
  }
@@ -280,6 +280,7 @@ declare class Logger {
280
280
  logPath: string;
281
281
  maxSize: number;
282
282
  fileName: string;
283
+ logging: boolean;
283
284
  /**
284
285
  *
285
286
  * @param logFileName name to prepend the logs file with
@@ -340,7 +341,6 @@ declare class Shoonya extends RetryManager {
340
341
  accessToken: string;
341
342
  userId: string;
342
343
  logger: Logger;
343
- private logging;
344
344
  private readonly httpBaseUrl;
345
345
  private readonly wsBaseUrl;
346
346
  private ws;
@@ -507,6 +507,10 @@ declare class Shoonya extends RetryManager {
507
507
  */
508
508
  subscribe(scripList: string[]): void;
509
509
  unsubscribe(scripList: string[]): void;
510
+ /**
511
+ * Unsubscribe All while removing the tokens from this.scripList
512
+ */
513
+ unsubscribeAllWhileClearing(): string[];
510
514
  /**
511
515
  * This method will not check if token is already subscribed or not before sending subscribe request
512
516
  *
@@ -280,6 +280,7 @@ declare class Logger {
280
280
  logPath: string;
281
281
  maxSize: number;
282
282
  fileName: string;
283
+ logging: boolean;
283
284
  /**
284
285
  *
285
286
  * @param logFileName name to prepend the logs file with
@@ -340,7 +341,6 @@ declare class Shoonya extends RetryManager {
340
341
  accessToken: string;
341
342
  userId: string;
342
343
  logger: Logger;
343
- private logging;
344
344
  private readonly httpBaseUrl;
345
345
  private readonly wsBaseUrl;
346
346
  private ws;
@@ -507,6 +507,10 @@ declare class Shoonya extends RetryManager {
507
507
  */
508
508
  subscribe(scripList: string[]): void;
509
509
  unsubscribe(scripList: string[]): void;
510
+ /**
511
+ * Unsubscribe All while removing the tokens from this.scripList
512
+ */
513
+ unsubscribeAllWhileClearing(): string[];
510
514
  /**
511
515
  * This method will not check if token is already subscribed or not before sending subscribe request
512
516
  *
@@ -58,6 +58,7 @@ var Logger = class {
58
58
  logPath = "";
59
59
  maxSize = 0;
60
60
  fileName = "";
61
+ logging = false;
61
62
  /**
62
63
  *
63
64
  * @param logFileName name to prepend the logs file with
@@ -70,6 +71,8 @@ var Logger = class {
70
71
  this.checkPathExistance();
71
72
  }
72
73
  log(msg, logType = "DEBUG") {
74
+ if (!this.logging)
75
+ return;
73
76
  const content = `${logType}:[${(/* @__PURE__ */ new Date()).toISOString()}]:${msg}
74
77
  `;
75
78
  appendFileSync(this.logPath, content);
@@ -226,6 +229,7 @@ var RetryManager = class extends EventEmitter {
226
229
  };
227
230
 
228
231
  // src/shoonya-sdk.ts
232
+ import { setTimeout as wait } from "timers/promises";
229
233
  var Shoonya = class extends RetryManager {
230
234
  static {
231
235
  __name(this, "Shoonya");
@@ -233,7 +237,6 @@ var Shoonya = class extends RetryManager {
233
237
  accessToken;
234
238
  userId;
235
239
  logger;
236
- logging = false;
237
240
  httpBaseUrl = "https://api.shoonya.com/NorenWClientTP/";
238
241
  wsBaseUrl = "wss://api.shoonya.com/NorenWSTP/";
239
242
  ws;
@@ -260,7 +263,6 @@ var Shoonya = class extends RetryManager {
260
263
  this.userId = "";
261
264
  this.accessToken = "";
262
265
  this.accountId = this.userId;
263
- this.logging = logging;
264
266
  this.reconnectTimeout = { timer: null, timeout: reconnectTimeout };
265
267
  this.heartbeatTimeout = { timer: null, timeout: heartbeatTimeout };
266
268
  if (logging) {
@@ -269,29 +271,65 @@ var Shoonya = class extends RetryManager {
269
271
  1024 * 100
270
272
  //1KB * 100 = 100KB
271
273
  );
274
+ this.logger.logging = logging;
272
275
  }
273
- this.on("resub", (token) => {
274
- this.subscribeUnsafe([token]);
276
+ this.on("resub", async (token) => {
277
+ for (let i = this.scripList.length - 1; i >= 0; i--) {
278
+ const t = this.scripList[i];
279
+ if (t === token) {
280
+ this.unsubscribe([token]);
281
+ this.scripList.splice(i, 1);
282
+ await this.login({
283
+ apiKey: this.apiKey,
284
+ password: this.password,
285
+ twoFa: this.twoFa,
286
+ userId: this.userId
287
+ });
288
+ const msg = {
289
+ t: "c",
290
+ uid: this.userId,
291
+ actid: this.accountId,
292
+ source: "API",
293
+ susertoken: this.accessToken
294
+ };
295
+ this.ws.send(JSON.stringify(msg));
296
+ await wait(100);
297
+ this.subscribe([token]);
298
+ this.logger.log("Resubscribed to" + token);
299
+ break;
300
+ }
301
+ }
275
302
  });
276
303
  }
277
304
  async request(path, body) {
278
305
  const jData = `jData=${JSON.stringify(body.data)}${body.key ? "&jKey=" + body.key : ""}`;
279
306
  try {
280
- const data = await fetch(this.httpBaseUrl + paths[path], {
307
+ const req = await fetch(this.httpBaseUrl + paths[path], {
281
308
  method: "POST",
282
309
  body: jData,
283
- keepalive: true
284
- }).then((res) => {
285
- return res.json();
310
+ keepalive: false
286
311
  });
312
+ let data = await req.json();
313
+ if ("emsg" in data && data.emsg.includes("Session Expired")) {
314
+ await this.login({
315
+ apiKey: this.apiKey,
316
+ password: this.password,
317
+ twoFa: this.twoFa,
318
+ userId: this.userId
319
+ });
320
+ const newJData = `jData=${JSON.stringify(body.data)}${body.key ? "&jKey=" + this.accessToken : ""}`;
321
+ const newReq = await fetch(this.httpBaseUrl + paths[path], {
322
+ method: "POST",
323
+ body: newJData,
324
+ keepalive: false
325
+ });
326
+ data = await newReq.json();
327
+ }
287
328
  return data;
288
329
  } catch (err) {
289
- if (this.logging) {
290
- const errMessage = "Failed to fetch data from api while performing: " + path;
291
- this.logger.log(errMessage, "ERROR");
292
- console.error(errMessage);
293
- }
294
- console.error(err);
330
+ const errMessage = `Error: ${err?.message} in ${path}`;
331
+ this.logger.log(errMessage, "ERROR");
332
+ console.error(errMessage);
295
333
  }
296
334
  }
297
335
  // Rest API
@@ -321,12 +359,10 @@ var Shoonya = class extends RetryManager {
321
359
  this.twoFa = rawCred.twoFa;
322
360
  return req;
323
361
  } catch (err) {
324
- if (this.logging) {
325
- const fallBackMessage = "Attempted to login but it failed";
326
- const errMessage = err?.message || fallBackMessage;
327
- this.logger.log(errMessage, "ERROR");
328
- console.error(errMessage);
329
- }
362
+ const fallBackMessage = "Attempted to login but it failed";
363
+ const errMessage = err?.message || fallBackMessage;
364
+ this.logger.log(errMessage, "ERROR");
365
+ console.error(errMessage);
330
366
  console.error("Login Failed", err);
331
367
  }
332
368
  }
@@ -537,9 +573,10 @@ var Shoonya = class extends RetryManager {
537
573
  const optionType = params.optionType.at(0);
538
574
  const symbol = params.symbol.toUpperCase();
539
575
  let c = 0;
540
- for await (const [expiry, unformattedDate] of this.getNextFormattedDates(
541
- optionExpiry
542
- )) {
576
+ for await (const [
577
+ expiry,
578
+ unformattedDate
579
+ ] of this.getNextFormattedDates()) {
543
580
  const optionToPick = `${symbol}${expiry}${optionType}${strikePrice}`;
544
581
  const optionChain = await this.getOptionChain({
545
582
  count,
@@ -578,12 +615,8 @@ var Shoonya = class extends RetryManager {
578
615
  const newYear = year.slice(2);
579
616
  return `${day}${newMonth}${newYear}`;
580
617
  }
581
- getNextFormattedDates(expiry) {
582
- let multiplier = 1;
583
- if (["next", "more-than-1-day", "more-than-3-day"].includes(expiry))
584
- multiplier = 2;
585
- if (["next-next", "more-than-10-day"].includes(expiry))
586
- multiplier = 3;
618
+ getNextFormattedDates() {
619
+ const multiplier = 3;
587
620
  let currentDate = /* @__PURE__ */ new Date();
588
621
  let dates = [];
589
622
  for (let i = 0; i <= 7 * multiplier; i++) {
@@ -707,11 +740,11 @@ var Shoonya = class extends RetryManager {
707
740
  await this.login(cred);
708
741
  this.connectWS();
709
742
  this.emit("open", "opened ws connection");
710
- this.logging && this.logger.log("Token Refreshed");
743
+ this.logger.log("Token successfully refreshed");
711
744
  } catch (err) {
712
745
  console.error(err);
713
746
  const errMessage = `Token refreshing failed. ERR: ${err.message}`;
714
- this.logging && this.logger.log(errMessage, "ERROR");
747
+ this.logger.log(errMessage, "ERROR");
715
748
  this.getWSState().OPEN && this.ws.close();
716
749
  this.emit("stopped", errMessage);
717
750
  }
@@ -723,7 +756,7 @@ var Shoonya = class extends RetryManager {
723
756
  const result = JSON.parse(e.data.toString());
724
757
  this.lastWsMsgAt = /* @__PURE__ */ new Date();
725
758
  if (result.t === "dk") {
726
- this.logging && this.logger.log(`Subscribed to ${result.ts}. Listening...`);
759
+ this.logger.log(`Subscribed to ${result.ts}. Listening...`);
727
760
  }
728
761
  if (result.lp && result.t === "df") {
729
762
  this.resetTimerForToken(result.tk, result.e);
@@ -736,7 +769,7 @@ var Shoonya = class extends RetryManager {
736
769
  clearTimeout(this.connectTimer);
737
770
  this.connectTimer = setTimeout(() => {
738
771
  this.emit("connect", e);
739
- this.logging && this.logger.log("Connected with Shoonya API! Streaming Data...");
772
+ this.logger.log("Connected with Shoonya API! Streaming Data...");
740
773
  this.subscribeAgain(this.scripList);
741
774
  }, 3e3);
742
775
  return;
@@ -760,13 +793,13 @@ var Shoonya = class extends RetryManager {
760
793
  if (day in [5, 6])
761
794
  return;
762
795
  const err = "API have stopped to respond! there could be a problem with API or market has closed";
763
- this.logging && this.logger.log(err, "WARN");
796
+ this.logger.log(err, "WARN");
764
797
  this.emit("stopped", err);
765
798
  this.getWSState().OPEN && this.ws.close();
766
799
  }, 6e4 * 60 * 18 - 1e4);
767
800
  });
768
801
  this.ws.addEventListener("error", (e) => {
769
- this.logging && this.logger.log("some error in ws");
802
+ this.logger.log("some error in ws");
770
803
  this.emit("error", e);
771
804
  this.getWSState().OPEN && this.ws.close();
772
805
  });
@@ -811,6 +844,7 @@ var Shoonya = class extends RetryManager {
811
844
  for (const val of distinctScrips) {
812
845
  this.scripList.push(val);
813
846
  }
847
+ this.logger.log(JSON.stringify(msg));
814
848
  this.ws && this.ws.send(JSON.stringify(msg));
815
849
  }
816
850
  unsubscribe(scripList) {
@@ -826,6 +860,13 @@ var Shoonya = class extends RetryManager {
826
860
  }
827
861
  }
828
862
  }
863
+ /**
864
+ * Unsubscribe All while removing the tokens from this.scripList
865
+ */
866
+ unsubscribeAllWhileClearing() {
867
+ this.unsubscribe(this.scripList);
868
+ return this.scripList.splice(0);
869
+ }
829
870
  /**
830
871
  * This method will not check if token is already subscribed or not before sending subscribe request
831
872
  *
@@ -865,7 +906,7 @@ var Shoonya = class extends RetryManager {
865
906
  if (this.getWSState().OPEN || this.getWSState().CONNECTING) {
866
907
  clearInterval(this.heartbeatTimeout.timer);
867
908
  this.ws.close();
868
- this.logging && this.logger.log("Websocket Connection with Shoonya API is now closed!");
909
+ this.logger.log("Websocket Connection with Shoonya API is now closed!");
869
910
  this.emit("close");
870
911
  }
871
912
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shoonya-sdk",
3
- "version": "0.4.9",
3
+ "version": "0.5.1",
4
4
  "description": "Wrapper around Shoonya API",
5
5
  "main": "dist/shoonya-sdk.js",
6
6
  "module": "dist/shoonya-sdk.mjs",