@discomedia/utils 1.0.54 → 1.0.56

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.cjs CHANGED
@@ -1491,8 +1491,18 @@ class Queue {
1491
1491
  }
1492
1492
 
1493
1493
  function pLimit(concurrency) {
1494
+ let rejectOnClear = false;
1495
+
1496
+ if (typeof concurrency === 'object') {
1497
+ ({concurrency, rejectOnClear = false} = concurrency);
1498
+ }
1499
+
1494
1500
  validateConcurrency(concurrency);
1495
1501
 
1502
+ if (typeof rejectOnClear !== 'boolean') {
1503
+ throw new TypeError('Expected `rejectOnClear` to be a boolean');
1504
+ }
1505
+
1496
1506
  const queue = new Queue();
1497
1507
  let activeCount = 0;
1498
1508
 
@@ -1500,7 +1510,7 @@ function pLimit(concurrency) {
1500
1510
  // Process the next queued function if we're under the concurrency limit
1501
1511
  if (activeCount < concurrency && queue.size > 0) {
1502
1512
  activeCount++;
1503
- queue.dequeue()();
1513
+ queue.dequeue().run();
1504
1514
  }
1505
1515
  };
1506
1516
 
@@ -1527,11 +1537,14 @@ function pLimit(concurrency) {
1527
1537
  next();
1528
1538
  };
1529
1539
 
1530
- const enqueue = (function_, resolve, arguments_) => {
1540
+ const enqueue = (function_, resolve, reject, arguments_) => {
1541
+ const queueItem = {reject};
1542
+
1531
1543
  // Queue the internal resolve function instead of the run function
1532
1544
  // to preserve the asynchronous execution context.
1533
1545
  new Promise(internalResolve => { // eslint-disable-line promise/param-names
1534
- queue.enqueue(internalResolve);
1546
+ queueItem.run = internalResolve;
1547
+ queue.enqueue(queueItem);
1535
1548
  }).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then
1536
1549
 
1537
1550
  // Start processing immediately if we haven't reached the concurrency limit
@@ -1540,8 +1553,8 @@ function pLimit(concurrency) {
1540
1553
  }
1541
1554
  };
1542
1555
 
1543
- const generator = (function_, ...arguments_) => new Promise(resolve => {
1544
- enqueue(function_, resolve, arguments_);
1556
+ const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
1557
+ enqueue(function_, resolve, reject, arguments_);
1545
1558
  });
1546
1559
 
1547
1560
  Object.defineProperties(generator, {
@@ -1553,7 +1566,16 @@ function pLimit(concurrency) {
1553
1566
  },
1554
1567
  clearQueue: {
1555
1568
  value() {
1556
- queue.clear();
1569
+ if (!rejectOnClear) {
1570
+ queue.clear();
1571
+ return;
1572
+ }
1573
+
1574
+ const abortError = AbortSignal.abort().reason;
1575
+
1576
+ while (queue.size > 0) {
1577
+ queue.dequeue().reject(abortError);
1578
+ }
1557
1579
  },
1558
1580
  },
1559
1581
  concurrency: {
@@ -2519,7 +2541,7 @@ const safeJSON = (text) => {
2519
2541
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2520
2542
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2521
2543
 
2522
- const VERSION = '6.15.0'; // x-release-please-version
2544
+ const VERSION = '6.17.0'; // x-release-please-version
2523
2545
 
2524
2546
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2525
2547
  const isRunningInBrowser = () => {
@@ -5812,12 +5834,7 @@ class Assistants extends APIResource {
5812
5834
  /**
5813
5835
  * Create an assistant with a model and instructions.
5814
5836
  *
5815
- * @example
5816
- * ```ts
5817
- * const assistant = await client.beta.assistants.create({
5818
- * model: 'gpt-4o',
5819
- * });
5820
- * ```
5837
+ * @deprecated
5821
5838
  */
5822
5839
  create(body, options) {
5823
5840
  return this._client.post('/assistants', {
@@ -5829,12 +5846,7 @@ class Assistants extends APIResource {
5829
5846
  /**
5830
5847
  * Retrieves an assistant.
5831
5848
  *
5832
- * @example
5833
- * ```ts
5834
- * const assistant = await client.beta.assistants.retrieve(
5835
- * 'assistant_id',
5836
- * );
5837
- * ```
5849
+ * @deprecated
5838
5850
  */
5839
5851
  retrieve(assistantID, options) {
5840
5852
  return this._client.get(path `/assistants/${assistantID}`, {
@@ -5845,12 +5857,7 @@ class Assistants extends APIResource {
5845
5857
  /**
5846
5858
  * Modifies an assistant.
5847
5859
  *
5848
- * @example
5849
- * ```ts
5850
- * const assistant = await client.beta.assistants.update(
5851
- * 'assistant_id',
5852
- * );
5853
- * ```
5860
+ * @deprecated
5854
5861
  */
5855
5862
  update(assistantID, body, options) {
5856
5863
  return this._client.post(path `/assistants/${assistantID}`, {
@@ -5862,13 +5869,7 @@ class Assistants extends APIResource {
5862
5869
  /**
5863
5870
  * Returns a list of assistants.
5864
5871
  *
5865
- * @example
5866
- * ```ts
5867
- * // Automatically fetches more pages as needed.
5868
- * for await (const assistant of client.beta.assistants.list()) {
5869
- * // ...
5870
- * }
5871
- * ```
5872
+ * @deprecated
5872
5873
  */
5873
5874
  list(query = {}, options) {
5874
5875
  return this._client.getAPIList('/assistants', (CursorPage), {
@@ -5880,11 +5881,7 @@ class Assistants extends APIResource {
5880
5881
  /**
5881
5882
  * Delete an assistant.
5882
5883
  *
5883
- * @example
5884
- * ```ts
5885
- * const assistantDeleted =
5886
- * await client.beta.assistants.delete('assistant_id');
5887
- * ```
5884
+ * @deprecated
5888
5885
  */
5889
5886
  delete(assistantID, options) {
5890
5887
  return this._client.delete(path `/assistants/${assistantID}`, {
@@ -7358,8 +7355,8 @@ Evals.Runs = Runs;
7358
7355
  let Files$1 = class Files extends APIResource {
7359
7356
  /**
7360
7357
  * Upload a file that can be used across various endpoints. Individual files can be
7361
- * up to 512 MB, and the size of all files uploaded by one organization can be up
7362
- * to 1 TB.
7358
+ * up to 512 MB, and each project can store up to 2.5 TB of files in total. There
7359
+ * is no organization-wide storage limit.
7363
7360
  *
7364
7361
  * - The Assistants API supports files up to 2 million tokens and of specific file
7365
7362
  * types. See the
@@ -16903,6 +16900,11 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16903
16900
  optionWs = null;
16904
16901
  stockSubscriptions = { trades: [], quotes: [], bars: [] };
16905
16902
  optionSubscriptions = { trades: [], quotes: [], bars: [] };
16903
+ autoReconnect = true;
16904
+ stockReconnectAttempts = 0;
16905
+ optionReconnectAttempts = 0;
16906
+ stockReconnectTimeout = null;
16907
+ optionReconnectTimeout = null;
16906
16908
  setMode(mode = 'production') {
16907
16909
  if (mode === 'sandbox') {
16908
16910
  // sandbox mode
@@ -16931,6 +16933,13 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16931
16933
  return 'production';
16932
16934
  }
16933
16935
  }
16936
+ setAutoReconnect(enabled) {
16937
+ this.autoReconnect = enabled;
16938
+ log(`Auto-reconnect ${enabled ? 'enabled' : 'disabled'}`);
16939
+ }
16940
+ getAutoReconnect() {
16941
+ return this.autoReconnect;
16942
+ }
16934
16943
  constructor() {
16935
16944
  super();
16936
16945
  this.dataURL = 'https://data.alpaca.markets/v2';
@@ -16953,6 +16962,36 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16953
16962
  }
16954
16963
  return AlpacaMarketDataAPI.instance;
16955
16964
  }
16965
+ getReconnectDelay(attempt) {
16966
+ // 0: instant (0ms), 1: 5s, 2: 10s, 3: 15s, 4+: 60s
16967
+ const delays = [0, 5000, 10000, 15000, 60000];
16968
+ return attempt < delays.length ? delays[attempt] : 60000;
16969
+ }
16970
+ scheduleReconnect(streamType) {
16971
+ if (!this.autoReconnect) {
16972
+ log(`Auto-reconnect disabled, not reconnecting ${streamType} stream`);
16973
+ return;
16974
+ }
16975
+ const attempts = streamType === 'stock' ? this.stockReconnectAttempts : this.optionReconnectAttempts;
16976
+ const delay = this.getReconnectDelay(attempts);
16977
+ log(`Scheduling ${streamType} stream reconnect (attempt ${attempts + 1}) in ${delay}ms`);
16978
+ const timeout = setTimeout(() => {
16979
+ log(`Attempting to reconnect ${streamType} stream (attempt ${attempts + 1})`);
16980
+ if (streamType === 'stock') {
16981
+ this.stockReconnectAttempts++;
16982
+ }
16983
+ else {
16984
+ this.optionReconnectAttempts++;
16985
+ }
16986
+ this.connect(streamType);
16987
+ }, delay);
16988
+ if (streamType === 'stock') {
16989
+ this.stockReconnectTimeout = timeout;
16990
+ }
16991
+ else {
16992
+ this.optionReconnectTimeout = timeout;
16993
+ }
16994
+ }
16956
16995
  on(event, listener) {
16957
16996
  return super.on(event, listener);
16958
16997
  }
@@ -16970,6 +17009,21 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16970
17009
  }
16971
17010
  ws.on('open', () => {
16972
17011
  log(`${streamType} stream connected`);
17012
+ // Reset reconnect attempts on successful connection
17013
+ if (streamType === 'stock') {
17014
+ this.stockReconnectAttempts = 0;
17015
+ if (this.stockReconnectTimeout) {
17016
+ clearTimeout(this.stockReconnectTimeout);
17017
+ this.stockReconnectTimeout = null;
17018
+ }
17019
+ }
17020
+ else {
17021
+ this.optionReconnectAttempts = 0;
17022
+ if (this.optionReconnectTimeout) {
17023
+ clearTimeout(this.optionReconnectTimeout);
17024
+ this.optionReconnectTimeout = null;
17025
+ }
17026
+ }
16973
17027
  const authMessage = {
16974
17028
  action: 'auth',
16975
17029
  key: process.env.ALPACA_API_KEY,
@@ -16994,20 +17048,42 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
16994
17048
  }
16995
17049
  }
16996
17050
  });
16997
- ws.on('close', () => {
16998
- log(`${streamType} stream disconnected`, { type: 'warn' });
17051
+ ws.on('close', (code, reason) => {
17052
+ const reasonStr = reason.toString() || 'No reason provided';
17053
+ const codeDesc = this.getCloseCodeDescription(code);
17054
+ log(`${streamType} stream disconnected - Code: ${code} (${codeDesc}), Reason: ${reasonStr}`, { type: 'warn' });
16999
17055
  if (streamType === 'stock') {
17000
17056
  this.stockWs = null;
17001
17057
  }
17002
17058
  else {
17003
17059
  this.optionWs = null;
17004
17060
  }
17005
- // Optional: implement reconnect logic
17061
+ this.scheduleReconnect(streamType);
17006
17062
  });
17007
17063
  ws.on('error', (error) => {
17008
17064
  log(`${streamType} stream error: ${error.message}`, { type: 'error' });
17009
17065
  });
17010
17066
  }
17067
+ getCloseCodeDescription(code) {
17068
+ const codes = {
17069
+ 1000: 'Normal Closure',
17070
+ 1001: 'Going Away',
17071
+ 1002: 'Protocol Error',
17072
+ 1003: 'Unsupported Data',
17073
+ 1005: 'No Status Received',
17074
+ 1006: 'Abnormal Closure',
17075
+ 1007: 'Invalid Frame Payload Data',
17076
+ 1008: 'Policy Violation',
17077
+ 1009: 'Message Too Big',
17078
+ 1010: 'Mandatory Extension',
17079
+ 1011: 'Internal Server Error',
17080
+ 1012: 'Service Restart',
17081
+ 1013: 'Try Again Later',
17082
+ 1014: 'Bad Gateway',
17083
+ 1015: 'TLS Handshake',
17084
+ };
17085
+ return codes[code] || 'Unknown';
17086
+ }
17011
17087
  sendSubscription(streamType) {
17012
17088
  const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
17013
17089
  const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
@@ -17042,11 +17118,21 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
17042
17118
  }
17043
17119
  }
17044
17120
  disconnectStockStream() {
17121
+ if (this.stockReconnectTimeout) {
17122
+ clearTimeout(this.stockReconnectTimeout);
17123
+ this.stockReconnectTimeout = null;
17124
+ }
17125
+ this.stockReconnectAttempts = 0;
17045
17126
  if (this.stockWs) {
17046
17127
  this.stockWs.close();
17047
17128
  }
17048
17129
  }
17049
17130
  disconnectOptionStream() {
17131
+ if (this.optionReconnectTimeout) {
17132
+ clearTimeout(this.optionReconnectTimeout);
17133
+ this.optionReconnectTimeout = null;
17134
+ }
17135
+ this.optionReconnectAttempts = 0;
17050
17136
  if (this.optionWs) {
17051
17137
  this.optionWs.close();
17052
17138
  }
@@ -18447,22 +18533,28 @@ class AlpacaTradingAPI {
18447
18533
  * @param side (string) - the side of the order
18448
18534
  * @param trailPercent100 (number) - the trail percent of the order (scale 100, i.e. 0.5 = 0.5%)
18449
18535
  * @param position_intent (string) - the position intent of the order
18536
+ * @param client_order_id (string) - optional client order id
18537
+ * @returns The created trailing stop order
18450
18538
  */
18451
- async createTrailingStop(symbol, qty, side, trailPercent100, position_intent) {
18539
+ async createTrailingStop(symbol, qty, side, trailPercent100, position_intent, client_order_id) {
18452
18540
  this.log(`Creating trailing stop ${side.toUpperCase()} ${qty} shares for ${symbol} with trail percent ${trailPercent100}%`, {
18453
18541
  symbol,
18454
18542
  });
18543
+ const body = {
18544
+ symbol,
18545
+ qty: Math.abs(qty),
18546
+ side,
18547
+ position_intent,
18548
+ order_class: 'simple',
18549
+ type: 'trailing_stop',
18550
+ trail_percent: trailPercent100, // Already in decimal form (e.g., 4 for 4%)
18551
+ time_in_force: 'gtc',
18552
+ };
18553
+ if (client_order_id !== undefined) {
18554
+ body.client_order_id = client_order_id;
18555
+ }
18455
18556
  try {
18456
- await this.makeRequest(`/orders`, 'POST', {
18457
- symbol,
18458
- qty: Math.abs(qty),
18459
- side,
18460
- position_intent,
18461
- order_class: 'simple',
18462
- type: 'trailing_stop',
18463
- trail_percent: trailPercent100, // Already in decimal form (e.g., 4 for 4%)
18464
- time_in_force: 'gtc',
18465
- });
18557
+ return await this.makeRequest(`/orders`, 'POST', body);
18466
18558
  }
18467
18559
  catch (error) {
18468
18560
  this.log(`Error creating trailing stop: ${error}`, {