@ganaka/sdk 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -79,7 +79,7 @@ declare const fetchCandles: ({ developerToken, apiDomain, runId, currentTimestam
79
79
  developerToken: string;
80
80
  apiDomain: string;
81
81
  runId: string | null;
82
- currentTimestamp: Date;
82
+ currentTimestamp: string;
83
83
  currentTimezone?: string;
84
84
  }) => (params: default_2.infer<typeof v1_developer_groww_schemas.getGrowwHistoricalCandles.query>) => Promise<default_2.infer<typeof v1_developer_groww_schemas.getGrowwHistoricalCandles.response>["data"]>;
85
85
 
@@ -89,7 +89,7 @@ declare const fetchQuote: ({ developerToken, apiDomain, runId, currentTimestamp,
89
89
  developerToken: string;
90
90
  apiDomain: string;
91
91
  runId: string | null;
92
- currentTimestamp: Date;
92
+ currentTimestamp: string;
93
93
  currentTimezone?: string;
94
94
  }) => (params: default_2.infer<typeof v1_developer_groww_schemas.getGrowwQuote.query>) => Promise<default_2.infer<typeof v1_developer_groww_schemas.getGrowwQuote.response>["data"] | null>;
95
95
 
@@ -99,9 +99,13 @@ declare const fetchQuoteTimeline: ({ developerToken, apiDomain, runId, currentTi
99
99
  developerToken: string;
100
100
  apiDomain: string;
101
101
  runId: string | null;
102
- currentTimestamp: Date;
102
+ currentTimestamp: string;
103
103
  currentTimezone?: string;
104
- }) => (symbol: string, date: Date) => Promise<default_2.infer<typeof v1_developer_groww_schemas.getGrowwQuoteTimeline.response>["data"]["quoteTimeline"]>;
104
+ }) => (symbol: string,
105
+ /**
106
+ * Date in IST string format (YYYY-MM-DD)
107
+ */
108
+ date: string) => Promise<default_2.infer<typeof v1_developer_groww_schemas.getGrowwQuoteTimeline.response>["data"]["quoteTimeline"]>;
105
109
 
106
110
  export declare type FetchQuoteTimelineResponse = Awaited<ReturnType<ReturnType<typeof fetchQuoteTimeline>>>;
107
111
 
@@ -109,7 +113,7 @@ declare const fetchShortlist: ({ developerToken, apiDomain, runId, currentTimest
109
113
  developerToken: string;
110
114
  apiDomain: string;
111
115
  runId: string | null;
112
- currentTimestamp: Date;
116
+ currentTimestamp: string;
113
117
  currentTimezone?: string;
114
118
  }) => (queryParams: default_2.infer<typeof v1_developer_lists_schemas.getLists.query>) => Promise<default_2.infer<typeof v1_developer_lists_schemas.getLists.response>["data"] | null>;
115
119
 
@@ -117,8 +121,10 @@ export declare type FetchShortlistResponse = Awaited<ReturnType<ReturnType<typeo
117
121
 
118
122
  export declare function ganaka<T>({ fn, startTime, endTime, intervalMinutes, deleteRunAfterCompletion, }: {
119
123
  fn: (context: RunContext) => Promise<T>;
120
- startTime: Date;
121
- endTime: Date;
124
+ /** Start time in IST string format (YYYY-MM-DDTHH:mm:ss) */
125
+ startTime: string;
126
+ /** End time in IST string format (YYYY-MM-DDTHH:mm:ss) */
127
+ endTime: string;
122
128
  intervalMinutes: number;
123
129
  /**
124
130
  * Delete run after completion.
@@ -172,8 +178,8 @@ declare const getCandles: {
172
178
  low: z.ZodNumber;
173
179
  close: z.ZodNumber;
174
180
  }, z.core.$strip>>;
175
- start_time: z.ZodString;
176
- end_time: z.ZodString;
181
+ start_time: z.ZodNullable<z.ZodString>;
182
+ end_time: z.ZodNullable<z.ZodString>;
177
183
  interval_in_minutes: z.ZodNumber;
178
184
  }, z.core.$strip>;
179
185
  }, z.core.$strip>;
@@ -752,7 +758,11 @@ export declare interface RunContext {
752
758
  fetchQuote: ReturnType<typeof fetchQuote>;
753
759
  fetchQuoteTimeline: ReturnType<typeof fetchQuoteTimeline>;
754
760
  fetchShortlist: ReturnType<typeof fetchShortlist>;
755
- currentTimestamp: Date;
761
+ /**
762
+ * Current timestamp in IST string format (YYYY-MM-DDTHH:mm:ss)
763
+ * for every loop iteration
764
+ */
765
+ currentTimestamp: string;
756
766
  }
757
767
 
758
768
  declare const signIn: {
package/dist/index.js CHANGED
@@ -4402,8 +4402,8 @@ const p = object({
4402
4402
  close: number$1()
4403
4403
  })
4404
4404
  ),
4405
- start_time: string(),
4406
- end_time: string(),
4405
+ start_time: string().nullable(),
4406
+ end_time: string().nullable(),
4407
4407
  interval_in_minutes: number$1()
4408
4408
  })
4409
4409
  })
@@ -7924,8 +7924,7 @@ const fetchCandles = ({
7924
7924
  headers["X-Run-Id"] = runId;
7925
7925
  }
7926
7926
  if (currentTimestamp) {
7927
- const timestampStr = dayjs.tz(currentTimestamp, currentTimezone).format("YYYY-MM-DDTHH:mm:ss");
7928
- headers["X-Current-Timestamp"] = timestampStr;
7927
+ headers["X-Current-Timestamp"] = currentTimestamp;
7929
7928
  }
7930
7929
  if (currentTimezone) {
7931
7930
  headers["X-Current-Timezone"] = currentTimezone;
@@ -7969,8 +7968,7 @@ const fetchQuote = ({
7969
7968
  headers["X-Run-Id"] = runId;
7970
7969
  }
7971
7970
  if (currentTimestamp) {
7972
- const timestampStr = dayjs.tz(currentTimestamp, currentTimezone).format("YYYY-MM-DDTHH:mm:ss");
7973
- headers["X-Current-Timestamp"] = timestampStr;
7971
+ headers["X-Current-Timestamp"] = currentTimestamp;
7974
7972
  }
7975
7973
  if (currentTimezone) {
7976
7974
  headers["X-Current-Timezone"] = currentTimezone;
@@ -8002,10 +8000,9 @@ const fetchQuoteTimeline = ({
8002
8000
  throw new Error("Developer token not found. Please set DEVELOPER_KEY environment variable.");
8003
8001
  }
8004
8002
  try {
8005
- const dateStr = dayjs.tz(date2, currentTimezone).format("YYYY-MM-DD");
8006
8003
  const validatedParams = _e.getGrowwQuoteTimeline.query.parse({
8007
8004
  symbol,
8008
- date: dateStr
8005
+ date: date2
8009
8006
  });
8010
8007
  const headers = {
8011
8008
  Authorization: `Bearer ${developerToken}`
@@ -8014,8 +8011,7 @@ const fetchQuoteTimeline = ({
8014
8011
  headers["X-Run-Id"] = runId;
8015
8012
  }
8016
8013
  if (currentTimestamp) {
8017
- const timestampStr = dayjs.tz(currentTimestamp, currentTimezone).format("YYYY-MM-DDTHH:mm:ss");
8018
- headers["X-Current-Timestamp"] = timestampStr;
8014
+ headers["X-Current-Timestamp"] = currentTimestamp;
8019
8015
  }
8020
8016
  if (currentTimezone) {
8021
8017
  headers["X-Current-Timezone"] = currentTimezone;
@@ -8059,8 +8055,7 @@ const fetchShortlist = ({
8059
8055
  headers["X-Run-Id"] = runId;
8060
8056
  }
8061
8057
  if (currentTimestamp) {
8062
- const timestampStr = dayjs.tz(currentTimestamp, currentTimezone).format("YYYY-MM-DDTHH:mm:ss");
8063
- headers["X-Current-Timestamp"] = timestampStr;
8058
+ headers["X-Current-Timestamp"] = currentTimestamp;
8064
8059
  }
8065
8060
  if (currentTimezone) {
8066
8061
  headers["X-Current-Timezone"] = currentTimezone;
@@ -8154,7 +8149,7 @@ async function retryWithBackoff(fn, maxRetries = 3, baseDelayMs = 1e3) {
8154
8149
  throw lastError;
8155
8150
  }
8156
8151
  const placeOrder = ({ runId, apiClient }) => async (data) => {
8157
- console.log(data);
8152
+ logger.debug(`data: ${JSON.stringify(data)}`);
8158
8153
  if (runId) {
8159
8154
  try {
8160
8155
  await retryWithBackoff(
@@ -8270,73 +8265,144 @@ class ApiClient {
8270
8265
  }
8271
8266
  }
8272
8267
  }
8273
- function getNextIntervalBoundary(timestamp, intervalMinutes) {
8274
- const date2 = dayjs(timestamp);
8275
- const currentMinute = date2.minute();
8276
- const currentSecond = date2.second();
8277
- const currentMillisecond = date2.millisecond();
8278
- const minutesIntoHour = currentMinute % intervalMinutes;
8279
- if (minutesIntoHour === 0 && currentSecond === 0 && currentMillisecond === 0) {
8280
- return date2.add(intervalMinutes, "minute").toDate();
8281
- }
8282
- const minutesToAdd = intervalMinutes - minutesIntoHour;
8283
- return date2.add(minutesToAdd, "minute").second(0).millisecond(0).toDate();
8284
- }
8268
+ var calendar$1 = { exports: {} };
8269
+ (function(module2, exports$1) {
8270
+ !function(e, t2) {
8271
+ module2.exports = t2();
8272
+ }(commonjsGlobal, function() {
8273
+ return function(e, t2, a) {
8274
+ var n2 = "h:mm A", d2 = { lastDay: "[Yesterday at] " + n2, sameDay: "[Today at] " + n2, nextDay: "[Tomorrow at] " + n2, nextWeek: "dddd [at] " + n2, lastWeek: "[Last] dddd [at] " + n2, sameElse: "MM/DD/YYYY" };
8275
+ t2.prototype.calendar = function(e2, t3) {
8276
+ var n3 = t3 || this.$locale().calendar || d2, o2 = a(e2 || void 0).startOf("d"), s = this.diff(o2, "d", true), i2 = "sameElse", f2 = s < -6 ? i2 : s < -1 ? "lastWeek" : s < 0 ? "lastDay" : s < 1 ? "sameDay" : s < 2 ? "nextDay" : s < 7 ? "nextWeek" : i2, l2 = n3[f2] || d2[f2];
8277
+ return "function" == typeof l2 ? l2.call(this, a()) : this.format(l2);
8278
+ };
8279
+ };
8280
+ });
8281
+ })(calendar$1);
8282
+ var calendarExports = calendar$1.exports;
8283
+ const calendar = /* @__PURE__ */ getDefaultExportFromCjs(calendarExports);
8284
+ var relativeTime$1 = { exports: {} };
8285
+ (function(module2, exports$1) {
8286
+ !function(r2, e) {
8287
+ module2.exports = e();
8288
+ }(commonjsGlobal, function() {
8289
+ return function(r2, e, t2) {
8290
+ r2 = r2 || {};
8291
+ var n2 = e.prototype, o2 = { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" };
8292
+ function i2(r3, e2, t3, o3) {
8293
+ return n2.fromToBase(r3, e2, t3, o3);
8294
+ }
8295
+ t2.en.relativeTime = o2, n2.fromToBase = function(e2, n3, i3, d3, u) {
8296
+ for (var f2, a, s, l2 = i3.$locale().relativeTime || o2, h = r2.thresholds || [{ l: "s", r: 44, d: "second" }, { l: "m", r: 89 }, { l: "mm", r: 44, d: "minute" }, { l: "h", r: 89 }, { l: "hh", r: 21, d: "hour" }, { l: "d", r: 35 }, { l: "dd", r: 25, d: "day" }, { l: "M", r: 45 }, { l: "MM", r: 10, d: "month" }, { l: "y", r: 17 }, { l: "yy", d: "year" }], m2 = h.length, c2 = 0; c2 < m2; c2 += 1) {
8297
+ var y2 = h[c2];
8298
+ y2.d && (f2 = d3 ? t2(e2).diff(i3, y2.d, true) : i3.diff(e2, y2.d, true));
8299
+ var p2 = (r2.rounding || Math.round)(Math.abs(f2));
8300
+ if (s = f2 > 0, p2 <= y2.r || !y2.r) {
8301
+ p2 <= 1 && c2 > 0 && (y2 = h[c2 - 1]);
8302
+ var v2 = l2[y2.l];
8303
+ u && (p2 = u("" + p2)), a = "string" == typeof v2 ? v2.replace("%d", p2) : v2(p2, n3, y2.l, s);
8304
+ break;
8305
+ }
8306
+ }
8307
+ if (n3) return a;
8308
+ var M2 = s ? l2.future : l2.past;
8309
+ return "function" == typeof M2 ? M2(a) : M2.replace("%s", a);
8310
+ }, n2.to = function(r3, e2) {
8311
+ return i2(r3, e2, this, true);
8312
+ }, n2.from = function(r3, e2) {
8313
+ return i2(r3, e2, this);
8314
+ };
8315
+ var d2 = function(r3) {
8316
+ return r3.$u ? t2.utc() : t2();
8317
+ };
8318
+ n2.toNow = function(r3) {
8319
+ return this.to(d2(this), r3);
8320
+ }, n2.fromNow = function(r3) {
8321
+ return this.from(d2(this), r3);
8322
+ };
8323
+ };
8324
+ });
8325
+ })(relativeTime$1);
8326
+ var relativeTimeExports = relativeTime$1.exports;
8327
+ const relativeTime = /* @__PURE__ */ getDefaultExportFromCjs(relativeTimeExports);
8328
+ dayjs.extend(utc);
8329
+ dayjs.extend(timezone);
8330
+ dayjs.extend(calendar);
8331
+ dayjs.extend(relativeTime);
8285
8332
  function sleep(ms) {
8286
8333
  return new Promise((resolve) => setTimeout(resolve, ms));
8287
8334
  }
8288
8335
  async function runMinuteLoop({
8289
- startTime,
8290
- endTime,
8291
- callback,
8292
- intervalMinutes
8336
+ startTimeDayJS,
8337
+ endTimeDayJS,
8338
+ intervalMinutes,
8339
+ callback
8293
8340
  }) {
8294
- const now = /* @__PURE__ */ new Date();
8295
- const isSimulationMode = now < startTime || now > endTime;
8341
+ let currentISTDayJS = dayjs.utc().tz("Asia/Kolkata");
8342
+ logger.debug(`currentIST: ${currentISTDayJS.format("YYYY-MM-DDTHH:mm:ss")}`);
8343
+ logger.debug(`startTime: ${startTimeDayJS.format("YYYY-MM-DDTHH:mm:ss")}`);
8344
+ logger.debug(`endTime: ${endTimeDayJS.format("YYYY-MM-DDTHH:mm:ss")}`);
8345
+ const isSimulationMode = currentISTDayJS.isAfter(endTimeDayJS);
8296
8346
  if (isSimulationMode) {
8297
- console.log("Current time is outside the specified range, simulating loop");
8347
+ logger.info("Current time is after endTime, simulating loop");
8348
+ }
8349
+ if (currentISTDayJS.isBefore(startTimeDayJS)) {
8350
+ const delayUntilStart = startTimeDayJS.diff(currentISTDayJS, "millisecond");
8351
+ logger.info(
8352
+ `Starting loop ${startTimeDayJS.from(currentISTDayJS)} at ${startTimeDayJS.format(
8353
+ "YYYY-MM-DD HH:mm"
8354
+ )}`
8355
+ );
8356
+ await sleep(delayUntilStart);
8357
+ currentISTDayJS = currentISTDayJS.add(delayUntilStart, "millisecond");
8358
+ }
8359
+ if (currentISTDayJS.isAfter(startTimeDayJS) && currentISTDayJS.isBefore(endTimeDayJS)) {
8360
+ startTimeDayJS = currentISTDayJS;
8298
8361
  }
8299
- const startDate = dayjs(startTime);
8300
- const startMinute = startDate.minute();
8362
+ const startMinute = startTimeDayJS.minute();
8301
8363
  const minutesToFirstBoundary = intervalMinutes - startMinute % intervalMinutes;
8302
- const isOnBoundary = startMinute % intervalMinutes === 0 && startDate.second() === 0 && startDate.millisecond() === 0;
8303
- let nextBoundary;
8364
+ const isOnBoundary = startMinute % intervalMinutes === 0 && startTimeDayJS.second() === 0 && startTimeDayJS.millisecond() === 0;
8365
+ let nextBoundaryDayJS;
8304
8366
  if (isOnBoundary) {
8305
- nextBoundary = startTime;
8367
+ nextBoundaryDayJS = startTimeDayJS;
8306
8368
  } else {
8307
- nextBoundary = startDate.add(minutesToFirstBoundary, "minute").second(0).millisecond(0).toDate();
8369
+ nextBoundaryDayJS = startTimeDayJS.add(minutesToFirstBoundary, "minute").second(0).millisecond(0);
8308
8370
  }
8371
+ logger.debug(`nextBoundary: ${nextBoundaryDayJS.format("YYYY-MM-DDTHH:mm:ss")}`);
8309
8372
  if (isSimulationMode) {
8310
- while (nextBoundary <= endTime) {
8373
+ while (nextBoundaryDayJS.isBefore(endTimeDayJS) || nextBoundaryDayJS.isSame(endTimeDayJS)) {
8311
8374
  try {
8312
- await callback(nextBoundary);
8375
+ await callback(nextBoundaryDayJS.format("YYYY-MM-DDTHH:mm:ss"));
8313
8376
  } catch (error) {
8314
8377
  console.error(
8315
- `Error executing callback at ${nextBoundary.toISOString()}:`,
8378
+ `Error executing callback at ${nextBoundaryDayJS.format("YYYY-MM-DDTHH:mm:ss")}:`,
8316
8379
  error
8317
8380
  );
8318
8381
  }
8319
- nextBoundary = dayjs(nextBoundary).add(intervalMinutes, "minute").toDate();
8382
+ nextBoundaryDayJS = nextBoundaryDayJS.add(intervalMinutes, "minute");
8320
8383
  }
8321
8384
  return;
8322
8385
  }
8323
- if (startTime < now && nextBoundary < now) {
8324
- nextBoundary = getNextIntervalBoundary(now, intervalMinutes);
8325
- }
8326
- while (nextBoundary <= endTime) {
8327
- const delay = nextBoundary.getTime() - Date.now();
8386
+ while (nextBoundaryDayJS.isBefore(endTimeDayJS) || nextBoundaryDayJS.isSame(endTimeDayJS)) {
8387
+ const delay = nextBoundaryDayJS.diff(currentISTDayJS, "millisecond");
8328
8388
  if (delay > 0) {
8389
+ logger.info(
8390
+ `Waiting for ${nextBoundaryDayJS.from(
8391
+ currentISTDayJS,
8392
+ true
8393
+ )} to reach next execution time: ${nextBoundaryDayJS.format("YYYY-MM-DD HH:mm:ss")}`
8394
+ );
8329
8395
  await sleep(delay);
8330
8396
  }
8331
8397
  try {
8332
- await callback(nextBoundary);
8398
+ await callback(nextBoundaryDayJS.format("YYYY-MM-DDTHH:mm:ss"));
8333
8399
  } catch (error) {
8334
8400
  console.error(
8335
- `Error executing callback at ${nextBoundary.toISOString()}:`,
8401
+ `Error executing callback at ${nextBoundaryDayJS.format("YYYY-MM-DDTHH:mm:ss")}:`,
8336
8402
  error
8337
8403
  );
8338
8404
  }
8339
- nextBoundary = dayjs(nextBoundary).add(intervalMinutes, "minute").toDate();
8405
+ nextBoundaryDayJS = nextBoundaryDayJS.add(intervalMinutes, "minute");
8340
8406
  }
8341
8407
  }
8342
8408
  dotenv.config();
@@ -8357,10 +8423,15 @@ async function ganaka({
8357
8423
  );
8358
8424
  }
8359
8425
  const apiClient = new ApiClient({ developerToken, apiDomain });
8426
+ const startTimeDayJS = dayjs.tz(startTime, "Asia/Kolkata");
8427
+ const endTimeDayJS = dayjs.tz(endTime, "Asia/Kolkata");
8428
+ if (startTimeDayJS.isAfter(endTimeDayJS)) {
8429
+ throw new Error("Start time cannot be after end time");
8430
+ }
8360
8431
  let runId = null;
8361
8432
  const createRunBody = {
8362
- start_datetime: dayjs.tz(startTime, "Asia/Kolkata").format("YYYY-MM-DDTHH:mm:ss"),
8363
- end_datetime: dayjs.tz(endTime, "Asia/Kolkata").format("YYYY-MM-DDTHH:mm:ss"),
8433
+ start_datetime: startTime,
8434
+ end_datetime: endTime,
8364
8435
  timezone: "Asia/Kolkata"
8365
8436
  };
8366
8437
  try {
@@ -8384,8 +8455,8 @@ async function ganaka({
8384
8455
  }
8385
8456
  try {
8386
8457
  await runMinuteLoop({
8387
- startTime,
8388
- endTime,
8458
+ startTimeDayJS,
8459
+ endTimeDayJS,
8389
8460
  intervalMinutes,
8390
8461
  callback: async (currentTimestamp) => {
8391
8462
  await fn({