sentisense 0.52.0 → 0.54.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/README.md CHANGED
@@ -170,7 +170,22 @@ Most methods resolve to the payload directly, but two families wrap it. The retu
170
170
 
171
171
  **1. Tier-gated endpoints return a preview envelope.** The payload is in `data`, and `isPreview` tells you whether it was truncated for your tier. `totalCount` carries the untruncated size whenever the server knows it: on a truncated response, so you can render "showing N of M", and on a paged endpoint such as `politicians.getActivity`, where it is the full match count on every tier including PRO. A missing `totalCount` means "count `data` yourself", never "zero results".
172
172
 
173
- Affected: `institutional.getFlows` / `getHolders` / `getActivists`, and all five `insights` methods.
173
+ Affected: every method whose declared return type is `PreviewResponse<T>`. A test keeps this table in step with the source, so it is the full list rather than a sample.
174
+
175
+ | Namespace | Methods |
176
+ |-----------|---------|
177
+ | `analyst` | `consensus` `actions` `estimates` `marketActivity` `coverage` `profile` `calls` |
178
+ | `calendar` | `getEarnings` |
179
+ | `earnings` | `getSummaries` `getRecent` |
180
+ | `etfs` | `analystAggregate` `insiderAggregate` `sentimentAggregate` |
181
+ | `insider` | `getActivity` `getTrades` `getClusterBuys` |
182
+ | `insights` | `stock` `stockRange` `market` `latest` `user` |
183
+ | `institutional` | `getFlows` `getHolders` `getActivists` |
184
+ | `options` | `getOverview` |
185
+ | `politicians` | `getActivity` `getFilings` `getMembers` `getMember` |
186
+ | `stocks` | `getSentiment` `getKpis` `getOptionsSummary` `getOptionsHistory` |
187
+
188
+ The envelope itself is always an object, so test the payload rather than the response. Two of these declare a `data` that can be null: `stocks.getOptionsSummary`, for a ticker outside the covered options universe, and `options.getOverview`, before its first nightly build. Everywhere else `data` is an array or an object.
174
189
 
175
190
  ```typescript
176
191
  const flows = await client.institutional.getFlows();
@@ -241,6 +256,27 @@ client.documents.getStories({ limit: 10 })
241
256
  client.documents.getStoryDetail("cluster_abc123")
242
257
  ```
243
258
 
259
+ A story's `cluster` says where it came from and whether it has settled. `storySource` is
260
+ `"ORIGINAL"` for an editorially authored SentiSense Original and `"AI"` for a
261
+ pipeline-generated story, and `isLive` is true while the story is still being revised as
262
+ the event develops. Both are optional: against an API build that predates them they are
263
+ `undefined`, which means "not known" rather than `"AI"` or `false`.
264
+
265
+ `getStoryDetail` returns `unknown`, so narrow it yourself. It carries the same two fields
266
+ plus a `timeline` array of dated updates, newest first and empty when a story has none.
267
+ The `StoryTimelineEntry` type is exported for that array:
268
+
269
+ ```typescript
270
+ import type { StoryTimelineEntry } from "sentisense";
271
+
272
+ const detail = (await client.documents.getStoryDetail("cluster_abc123")) as {
273
+ timeline: StoryTimelineEntry[];
274
+ };
275
+ for (const update of detail.timeline) {
276
+ console.log(new Date(update.publishedAt), update.updateType, update.content);
277
+ }
278
+ ```
279
+
244
280
  ### Institutional flows (13F)
245
281
 
246
282
  ```typescript
@@ -454,11 +490,11 @@ client.stocks.getOptionsHistory("NVDA", { window: "2y" }) // That name's daily
454
490
 
455
491
  The radar carries two separately-ranked boards: `data.rows` for stocks and `data.etfRows` for ETFs. Keep them apart. Every reading behind a row's `interestScore` is a percentile of that ticker's own trailing history, so a ranking built across both boards compares numbers measured against different baselines. The aggregates split the same way, with the `etf`-prefixed fields describing the ETF board alone.
456
492
 
457
- A row whose baseline is still building carries its raw readings with the percentiles and `interestScore` omitted, which means "not enough history yet" rather than "nothing interesting". `getOptionsSummary` reports an uncovered ticker as a `null` payload; `getOptionsHistory` reports it as an empty `series` instead, so check the array rather than null-checking there.
493
+ A row whose baseline is still building carries its raw readings with the percentiles and `interestScore` omitted, which means "not enough history yet" rather than "nothing interesting". `getOptionsSummary` reports an uncovered ticker as a null payload inside the usual envelope, so the check is `result.data === null`: the response object itself is always truthy, and a bare `if (summary === null)` never fires. `getOptionsHistory` reports it as an empty `series` instead, so check the array's length rather than null-checking there.
458
494
 
459
495
  ### SentiSense Rating
460
496
 
461
- Where a stock ranks against the other stocks rated that day, as a score, a letter and a percentile, plus the six dimensions the rank is blended from. It is a relative research signal for informational and educational purposes, not financial, investment or trading advice, and not a recommendation about any security. Every response carries the wording to display alongside a grade in `disclaimer`. [Methodology](https://sentisense.ai/methodology/#sentisense-rating).
497
+ Where a stock ranks against the other stocks rated that day, as a score, a letter and a percentile, plus the seven dimensions the rank is blended from. It is a relative research signal for informational and educational purposes, not financial, investment or trading advice, and not a recommendation about any security. Every response carries the wording to display alongside a grade in `disclaimer`. [Methodology](https://sentisense.ai/methodology/#sentisense-rating).
462
498
 
463
499
  ```typescript
464
500
  const rating = await client.stocks.getRating("AAPL");
@@ -477,7 +513,7 @@ if (rating.rated) {
477
513
 
478
514
  Having no grade is a normal 200, not a 404: ETFs and tickers outside the swept universe answer that way, and `reason` is one of `stale`, `not_rated_today`, `insufficient_dimensions` or `insufficient_coverage_weight`. Only a ticker that resolves to nothing we track rejects with `NotFoundError`.
479
515
 
480
- `dimensions` always holds all six rows in a fixed order, including the ones with no data, which arrive with `present` false and a `null` percentile. Read `present` first and never substitute zero for a missing percentile: zero is the bottom of the cross-section, absence is not a position on it. Only the smart-money dimension carries `subLegs`.
516
+ `dimensions` always holds all seven rows in a fixed order, including the ones with no data, which arrive with `present` false and a `null` percentile. Read `present` first and never substitute zero for a missing percentile: zero is the bottom of the cross-section, absence is not a position on it. Only the smart-money dimension carries `subLegs`.
481
517
 
482
518
  **`score` is not `percentile`.** `percentile` is the rank of the blended signals against the day's rated set. `score = percentile - sum(riskAdjustments.map((a) => a.points))`, floored at 10 when fewer than five dimensions are available, and it is the number `letter` bands (A 90, B 70, C 30, D 10). `bucketLetter` is the band the percentile alone would give, so the two letters differ by exactly what the conditions cost. `riskAdjustments` itemises that cost, `penaltyPoints` totals it, and `riskConditions` names the active ones from the `RiskCondition` union: `thin_coverage`, `weak_dimension`, `unprofitable`, `no_fundamentals`, `high_leverage`, `unseasoned_listing`, `small_market_cap`, `thin_liquidity`, `extended_price`, `insider_selling` and `institutional_outflow`.
483
519
 
package/dist/cli.cjs CHANGED
@@ -1324,7 +1324,7 @@ var flowsCommand = {
1324
1324
  };
1325
1325
 
1326
1326
  // src/version.ts
1327
- var VERSION = "0.52.0";
1327
+ var VERSION = "0.54.0";
1328
1328
 
1329
1329
  // src/resources/analyst.ts
1330
1330
  var Analyst = class {
@@ -1507,7 +1507,14 @@ var Documents = class {
1507
1507
  async getStories(options) {
1508
1508
  return this.client.get("/api/v1/documents/stories", options);
1509
1509
  }
1510
- /** Get full story detail by cluster ID. */
1510
+ /**
1511
+ * Get full story detail by cluster ID.
1512
+ *
1513
+ * Deliberately untyped: narrow it yourself. The response carries `storySource` and
1514
+ * `isLive` alongside the story body, plus a `timeline` array of dated updates,
1515
+ * newest first and empty when the story has none. {@link StoryTimelineEntry} is
1516
+ * exported for that array.
1517
+ */
1511
1518
  async getStoryDetail(clusterId) {
1512
1519
  return this.client.get(`/api/v1/documents/stories/${encodeURIComponent(clusterId)}`);
1513
1520
  }
@@ -3445,6 +3452,7 @@ var optionsCommand = {
3445
3452
  kind: "facts",
3446
3453
  items: fields(
3447
3454
  field("ATM IV", fixed(latest.atmIv, 4)),
3455
+ field("Exp move 1d", fixed(latest.expectedMove1d, 4)),
3448
3456
  field("Skew 25d", signed(latest.skew25d, 4)),
3449
3457
  field("Call vol", humanize(latest.callVol, 1)),
3450
3458
  field("Put vol", humanize(latest.putVol, 1)),
package/dist/index.cjs CHANGED
@@ -255,7 +255,14 @@ var Documents = class {
255
255
  async getStories(options) {
256
256
  return this.client.get("/api/v1/documents/stories", options);
257
257
  }
258
- /** Get full story detail by cluster ID. */
258
+ /**
259
+ * Get full story detail by cluster ID.
260
+ *
261
+ * Deliberately untyped: narrow it yourself. The response carries `storySource` and
262
+ * `isLive` alongside the story body, plus a `timeline` array of dated updates,
263
+ * newest first and empty when the story has none. {@link StoryTimelineEntry} is
264
+ * exported for that array.
265
+ */
259
266
  async getStoryDetail(clusterId) {
260
267
  return this.client.get(`/api/v1/documents/stories/${encodeURIComponent(clusterId)}`);
261
268
  }
@@ -1242,7 +1249,7 @@ var Trackers = class {
1242
1249
  };
1243
1250
 
1244
1251
  // src/version.ts
1245
- var VERSION = "0.52.0";
1252
+ var VERSION = "0.54.0";
1246
1253
 
1247
1254
  // src/client.ts
1248
1255
  var DEFAULT_BASE_URL = "https://app.sentisense.ai";