sentisense 0.53.0 → 0.55.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.
package/dist/index.mjs CHANGED
@@ -33,6 +33,13 @@ var RateLimitError = class extends SentiSenseError {
33
33
  this.retryAfter = retryAfter;
34
34
  }
35
35
  };
36
+ var TemporarilyUnavailableError = class extends SentiSenseError {
37
+ constructor(message, retryAfter, code) {
38
+ super(message, 503, code);
39
+ this.name = "TemporarilyUnavailableError";
40
+ this.retryAfter = retryAfter;
41
+ }
42
+ };
36
43
  var APIError = class extends SentiSenseError {
37
44
  constructor(message, status, code) {
38
45
  super(message, status, code);
@@ -54,6 +61,38 @@ var Analyst = class {
54
61
  `/api/v1/analyst/${encodeURIComponent(ticker.toUpperCase())}/consensus`
55
62
  );
56
63
  }
64
+ /**
65
+ * Get daily consensus observations, ordered by `snapshotDate` ascending.
66
+ * Each row describes the target fields as observed on that date. When
67
+ * `countsObserved` is `false`, the vendor panel did not come back that day and the
68
+ * distribution counts are carried forward.
69
+ *
70
+ * A PRO key receives the requested window. A FREE key receives the last 30 days;
71
+ * `targetMedian`, `recommendationMean`, and the five distribution fields are `null`.
72
+ * The envelope's `totalCount` still sizes the full requested window.
73
+ */
74
+ async consensusHistory(ticker, options) {
75
+ return this.client.get(
76
+ `/api/v1/analyst/${encodeURIComponent(ticker.toUpperCase())}/consensus/history`,
77
+ options
78
+ );
79
+ }
80
+ /**
81
+ * Get factual call history as recorded when a stock moved 20% or more over five
82
+ * sessions, newest move first by `moveEndDate`.
83
+ *
84
+ * PRO receives full moves and calls. FREE receives the newest move with up to five
85
+ * calls and all move-level counts intact. The envelope's `totalCount` counts all
86
+ * available moves before the limit. A known stock with no qualifying move returns
87
+ * an empty `moves` array. Each call includes `analystName`: it is `null`, never
88
+ * absent, when the publisher named nobody.
89
+ */
90
+ async calledIt(ticker, options) {
91
+ return this.client.get(
92
+ `/api/v1/analyst/${encodeURIComponent(ticker.toUpperCase())}/called-it`,
93
+ options
94
+ );
95
+ }
57
96
  /**
58
97
  * Get recent analyst upgrade/downgrade actions for a ticker, newest first.
59
98
  * Free users receive the 3 most recent.
@@ -286,6 +325,52 @@ var Earnings = class {
286
325
  async getRecent(options) {
287
326
  return this.client.get("/api/v1/earnings/recent", options);
288
327
  }
328
+ /**
329
+ * Measured price reactions to a ticker's last earnings reports, newest first.
330
+ *
331
+ * Use this after {@link getRecent} when you need one company's realized
332
+ * post-report history. `client.calendar.getEarnings()` is the forward-looking
333
+ * schedule instead. This endpoint returns its payload directly, without a
334
+ * preview envelope, and every API key receives the full series.
335
+ *
336
+ * `timing` is always present on each row and can be `null` when the reacting
337
+ * session was inferred rather than observed.
338
+ */
339
+ async getReactions(ticker) {
340
+ return this.client.get(
341
+ `/api/v1/stocks/${encodeURIComponent(ticker.toUpperCase())}/earnings/reactions`
342
+ );
343
+ }
344
+ /**
345
+ * Market-wide earnings outcomes and realized reaction statistics.
346
+ *
347
+ * Use this for aggregate beat, miss, inline, and post-report move rates.
348
+ * {@link getRecent} returns individual recent reports, while
349
+ * `client.calendar.getEarnings()` covers upcoming dates. The response uses
350
+ * the preview envelope, but every API key receives the full body and
351
+ * `isPreview` is always `false`.
352
+ *
353
+ * `baseline` and `deviation` are omitted for long-span windows, and rates can
354
+ * be `null` when their denominator is zero.
355
+ */
356
+ async getStatistics(options) {
357
+ return this.client.get("/api/v1/earnings/statistics", options);
358
+ }
359
+ /**
360
+ * Important recently reported and upcoming earnings in one ranking.
361
+ *
362
+ * Use this to prioritize a cross-ticker sweep. Follow reported rows with
363
+ * {@link getReactions} for realized history; use {@link getRecent} for an
364
+ * unranked recent feed or `client.calendar.getEarnings()` for the broader
365
+ * forward schedule.
366
+ *
367
+ * A PRO key receives the full ranking. A FREE key receives the first three
368
+ * rows in each section with `totalInWindow` left intact. Optional row fields
369
+ * are omitted when null, so check them before use.
370
+ */
371
+ async getRanked(options) {
372
+ return this.client.get("/api/v1/earnings/ranked", options);
373
+ }
289
374
  };
290
375
 
291
376
  // src/resources/entityMetrics.ts
@@ -1014,7 +1099,7 @@ var Stocks = class {
1014
1099
  * the full series. Returns 404 for tickers that do not yet have curated coverage.
1015
1100
  *
1016
1101
  * Coverage today: near-complete for the S&P 500 plus extended universe
1017
- * (~500 tickers). Use `listKpiCoverage()` to enumerate.
1102
+ * (900+ tickers). Use `listKpiCoverage()` to enumerate.
1018
1103
  */
1019
1104
  async getKpis(ticker) {
1020
1105
  return this.client.get(
@@ -1215,7 +1300,7 @@ var Trackers = class {
1215
1300
  };
1216
1301
 
1217
1302
  // src/version.ts
1218
- var VERSION = "0.53.0";
1303
+ var VERSION = "0.55.0";
1219
1304
 
1220
1305
  // src/client.ts
1221
1306
  var DEFAULT_BASE_URL = "https://app.sentisense.ai";
@@ -1314,12 +1399,23 @@ var SentiSense = class {
1314
1399
  if (!response.ok) {
1315
1400
  const isRetryable = response.status === 429 || response.status >= 500;
1316
1401
  if (isRetryable && attempt < this.maxRetries) {
1317
- if (response.status === 429) {
1318
- delayMs = retryAfterSeconds(
1402
+ if (response.status === 429 || response.status === 503) {
1403
+ const requestedS = retryAfterSeconds(
1319
1404
  response.headers.get("Retry-After"),
1320
1405
  RATE_LIMIT_FALLBACK_WAIT_S,
1321
- MAX_RATE_LIMIT_WAIT_S
1322
- ) * 1e3;
1406
+ Number.POSITIVE_INFINITY
1407
+ );
1408
+ if (requestedS > MAX_RATE_LIMIT_WAIT_S) {
1409
+ try {
1410
+ await response.body?.cancel();
1411
+ } catch {
1412
+ }
1413
+ throw new TemporarilyUnavailableError(
1414
+ `Server asked for a ${Math.round(requestedS)}s wait, longer than this client's ${MAX_RATE_LIMIT_WAIT_S}s budget`,
1415
+ requestedS
1416
+ );
1417
+ }
1418
+ delayMs = requestedS * 1e3;
1323
1419
  } else {
1324
1420
  delayMs = Math.min(BASE_DELAY_MS * Math.pow(2, attempt), MAX_DELAY_MS) + Math.random() * 1e3;
1325
1421
  }
@@ -1429,6 +1525,7 @@ export {
1429
1525
  RateLimitError,
1430
1526
  SentiSense,
1431
1527
  SentiSenseError,
1528
+ TemporarilyUnavailableError,
1432
1529
  VERSION,
1433
1530
  SentiSense as default
1434
1531
  };