sentisense 0.47.2 → 0.49.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
@@ -318,6 +318,39 @@ client.analyst.estimates("AAPL") // Forward EPS + surpris
318
318
  client.analyst.marketActivity({ lookbackDays: 7 }) // Market-wide analyst actions (PRO).
319
319
  ```
320
320
 
321
+ Coverage answers "who covers this stock and what did they say" in one call, and it is the entry point into the per-analyst surfaces: every named analyst carries the slug that addresses their profile and their calls.
322
+
323
+ ```typescript
324
+ client.analyst.coverage("NVDA", { lookbackDays: 365 }) // Who covers it, by firm. Free: 5 firms.
325
+ client.analyst.profile("gil-luria") // One analyst's firms + coverage book.
326
+ client.analyst.calls("gil-luria", { limit: 25 }) // Their price target notes, newest first.
327
+ ```
328
+
329
+ ```typescript
330
+ const { data: book } = await client.analyst.coverage("NVDA");
331
+
332
+ console.log(`${book.firmCount} firms, ${book.namedAnalystCount} named analysts`);
333
+ console.log(`${book.attributedNoteCount} of ${book.noteCount} notes name someone`);
334
+
335
+ for (const row of book.coverage.slice(0, 5)) {
336
+ if (row.noteCount === 0) {
337
+ // A desk can cover a stock on rating actions alone, with no price target.
338
+ console.log(`${row.firm}: rating only, ${row.firmRating?.rating}`);
339
+ continue;
340
+ }
341
+ const who = row.latestNote?.analyst ?? "unattributed";
342
+ console.log(`${row.firm}: ${row.latestNote?.priceTarget} (${who})`);
343
+
344
+ for (const analyst of row.analysts) {
345
+ if (!analyst.slug) continue;
346
+ const calls = await client.analyst.calls(analyst.slug, { limit: 10 });
347
+ console.log(` ${analyst.name}: ${calls.totalCount} notes on record`);
348
+ }
349
+ }
350
+ ```
351
+
352
+ Two shapes to read rather than assume. A firm can appear with `noteCount: 0`, a `null` `latestNote` and a populated `firmRating`, because coverage means a price target **or** a rating action in the window. And a large, publisher-dependent share of notes name no individual, so an empty `analysts` array alongside a non-zero `noteCount` is normal: read `attributedNoteCount` and `unattributedNoteCount` off the response rather than hardcoding a rate. The response-level counts survive the free truncation, so they describe the whole window even when only 5 rows come back. An unknown slug throws `NotFoundError`, which keeps "published nothing we hold" distinguishable from "does not exist".
353
+
321
354
  ### Earnings
322
355
 
323
356
  The earnings analysis report is the assembled version of a quarter: one object per fiscal period carrying the editorial headline, the KPI cards with year-over-year deltas, the guidance language as management phrased it, and a summary of the earnings call. Pair it with the recent-reporters feed to drive a post-earnings sweep. Both return the preview envelope.
package/dist/cli.cjs CHANGED
@@ -1037,7 +1037,7 @@ var flowsCommand = {
1037
1037
  };
1038
1038
 
1039
1039
  // src/version.ts
1040
- var VERSION = "0.47.1";
1040
+ var VERSION = "0.49.0";
1041
1041
 
1042
1042
  // src/resources/analyst.ts
1043
1043
  var Analyst = class {
@@ -1079,6 +1079,89 @@ var Analyst = class {
1079
1079
  async marketActivity(options) {
1080
1080
  return this.client.get("/api/v1/analyst/activity", options);
1081
1081
  }
1082
+ /**
1083
+ * Get who covers a ticker and what they most recently said, grouped by firm, most
1084
+ * recently active firm first.
1085
+ *
1086
+ * This is the one-call answer to "who covers AMD and what do they say". Each row in
1087
+ * `data.coverage` is a firm, the individual analysts we can name on that firm's desk,
1088
+ * that firm's most recent price target note, and that firm's most recent rating action.
1089
+ *
1090
+ * A PRO key receives every firm. A FREE key receives the 5 most recently active firms
1091
+ * with every response-level count intact, so the counts describe the full window even
1092
+ * when the rows do not.
1093
+ *
1094
+ * Two shapes to read rather than assume. **A firm can cover a stock without publishing
1095
+ * a price target**, because coverage means a note or a rating action in the window: that
1096
+ * row carries `noteCount: 0`, a `null` `latestNote` and a populated `firmRating`, so
1097
+ * read `noteCount` on the row instead of expecting a note. And **not every note names
1098
+ * its analyst**, at a rate that is a property of the publisher and varies enormously by
1099
+ * ticker, so a firm can appear with an empty `analysts` array and a non-zero
1100
+ * `noteCount`, and `latestNote.analyst` can be `null`. Read `attributedNoteCount` and
1101
+ * `unattributedNoteCount` off the response you received rather than hardcoding a rate.
1102
+ *
1103
+ * `firmRating` belongs to the firm, not to a person: rating actions are published at
1104
+ * firm level with no individual attached.
1105
+ *
1106
+ * Each named analyst carries the `slug` that addresses {@link profile} and
1107
+ * {@link calls}, so a coverage response is the natural entry point into a person.
1108
+ */
1109
+ async coverage(ticker, options) {
1110
+ return this.client.get(
1111
+ `/api/v1/analyst/${encodeURIComponent(ticker.toUpperCase())}/coverage`,
1112
+ options
1113
+ );
1114
+ }
1115
+ /**
1116
+ * Get one analyst: the firms they have published under, the window of notes we hold at
1117
+ * each, and the tickers they cover. Throws `NotFoundError` when the slug matches no
1118
+ * analyst.
1119
+ *
1120
+ * A PRO key receives the full book. A FREE key receives the profile with
1121
+ * `data.coverage` truncated to the 5 most recently covered tickers, and the envelope's
1122
+ * `totalCount` reporting how many there are in full.
1123
+ *
1124
+ * `firstSeen` and `lastSeen` are observation windows, not employment dates: they bound
1125
+ * the notes we hold from that analyst at that firm. `mostRecentFirm` says where they
1126
+ * last published, not where they work today. Do not render either as a hire or
1127
+ * departure date.
1128
+ *
1129
+ * This is call history, not a scorecard. There is no accuracy score, hit rate or
1130
+ * ranking here, and nothing in the response should be read as a rating of the person.
1131
+ *
1132
+ * @param slug Analyst slug, lowercased and hyphenated (e.g. `"dan-ives"`). You do not
1133
+ * have to guess one: every named analyst in a {@link coverage} response carries it.
1134
+ */
1135
+ async profile(slug) {
1136
+ return this.client.get(
1137
+ `/api/v1/analyst/people/${encodeURIComponent(slug)}`
1138
+ );
1139
+ }
1140
+ /**
1141
+ * Get one analyst's price target notes, newest first, paged. Throws `NotFoundError`
1142
+ * when the slug matches no analyst, which keeps "this analyst has published nothing we
1143
+ * hold" (an empty page) distinguishable from "this analyst does not exist".
1144
+ *
1145
+ * Ordered by published date descending with the row id as the final tie-break, a total
1146
+ * order, so walking the history with `offset` never drops or repeats a row. That
1147
+ * matters more than it looks: a single roundup article carries several of one analyst's
1148
+ * notes at an identical timestamp.
1149
+ *
1150
+ * A FREE key receives the first 25 rows as a complete response (`isPreview: false`);
1151
+ * asking for a larger `limit` or an `offset` past row 25 returns the free in-allowance
1152
+ * slice with `previewReason: "PRO_REQUIRED"`. A PRO key pages the whole history. The
1153
+ * envelope's `totalCount` is the analyst's whole attributed history rather than the page
1154
+ * size, so `offset + data.length < totalCount` tells you another page is available.
1155
+ *
1156
+ * Dates are day granularity on purpose. Publisher timestamps are not comparable across
1157
+ * sources, so a time of day would advertise precision the data does not have.
1158
+ */
1159
+ async calls(slug, options) {
1160
+ return this.client.get(
1161
+ `/api/v1/analyst/people/${encodeURIComponent(slug)}/calls`,
1162
+ options
1163
+ );
1164
+ }
1082
1165
  };
1083
1166
 
1084
1167
  // src/resources/calendar.ts
package/dist/index.cjs CHANGED
@@ -114,6 +114,89 @@ var Analyst = class {
114
114
  async marketActivity(options) {
115
115
  return this.client.get("/api/v1/analyst/activity", options);
116
116
  }
117
+ /**
118
+ * Get who covers a ticker and what they most recently said, grouped by firm, most
119
+ * recently active firm first.
120
+ *
121
+ * This is the one-call answer to "who covers AMD and what do they say". Each row in
122
+ * `data.coverage` is a firm, the individual analysts we can name on that firm's desk,
123
+ * that firm's most recent price target note, and that firm's most recent rating action.
124
+ *
125
+ * A PRO key receives every firm. A FREE key receives the 5 most recently active firms
126
+ * with every response-level count intact, so the counts describe the full window even
127
+ * when the rows do not.
128
+ *
129
+ * Two shapes to read rather than assume. **A firm can cover a stock without publishing
130
+ * a price target**, because coverage means a note or a rating action in the window: that
131
+ * row carries `noteCount: 0`, a `null` `latestNote` and a populated `firmRating`, so
132
+ * read `noteCount` on the row instead of expecting a note. And **not every note names
133
+ * its analyst**, at a rate that is a property of the publisher and varies enormously by
134
+ * ticker, so a firm can appear with an empty `analysts` array and a non-zero
135
+ * `noteCount`, and `latestNote.analyst` can be `null`. Read `attributedNoteCount` and
136
+ * `unattributedNoteCount` off the response you received rather than hardcoding a rate.
137
+ *
138
+ * `firmRating` belongs to the firm, not to a person: rating actions are published at
139
+ * firm level with no individual attached.
140
+ *
141
+ * Each named analyst carries the `slug` that addresses {@link profile} and
142
+ * {@link calls}, so a coverage response is the natural entry point into a person.
143
+ */
144
+ async coverage(ticker, options) {
145
+ return this.client.get(
146
+ `/api/v1/analyst/${encodeURIComponent(ticker.toUpperCase())}/coverage`,
147
+ options
148
+ );
149
+ }
150
+ /**
151
+ * Get one analyst: the firms they have published under, the window of notes we hold at
152
+ * each, and the tickers they cover. Throws `NotFoundError` when the slug matches no
153
+ * analyst.
154
+ *
155
+ * A PRO key receives the full book. A FREE key receives the profile with
156
+ * `data.coverage` truncated to the 5 most recently covered tickers, and the envelope's
157
+ * `totalCount` reporting how many there are in full.
158
+ *
159
+ * `firstSeen` and `lastSeen` are observation windows, not employment dates: they bound
160
+ * the notes we hold from that analyst at that firm. `mostRecentFirm` says where they
161
+ * last published, not where they work today. Do not render either as a hire or
162
+ * departure date.
163
+ *
164
+ * This is call history, not a scorecard. There is no accuracy score, hit rate or
165
+ * ranking here, and nothing in the response should be read as a rating of the person.
166
+ *
167
+ * @param slug Analyst slug, lowercased and hyphenated (e.g. `"dan-ives"`). You do not
168
+ * have to guess one: every named analyst in a {@link coverage} response carries it.
169
+ */
170
+ async profile(slug) {
171
+ return this.client.get(
172
+ `/api/v1/analyst/people/${encodeURIComponent(slug)}`
173
+ );
174
+ }
175
+ /**
176
+ * Get one analyst's price target notes, newest first, paged. Throws `NotFoundError`
177
+ * when the slug matches no analyst, which keeps "this analyst has published nothing we
178
+ * hold" (an empty page) distinguishable from "this analyst does not exist".
179
+ *
180
+ * Ordered by published date descending with the row id as the final tie-break, a total
181
+ * order, so walking the history with `offset` never drops or repeats a row. That
182
+ * matters more than it looks: a single roundup article carries several of one analyst's
183
+ * notes at an identical timestamp.
184
+ *
185
+ * A FREE key receives the first 25 rows as a complete response (`isPreview: false`);
186
+ * asking for a larger `limit` or an `offset` past row 25 returns the free in-allowance
187
+ * slice with `previewReason: "PRO_REQUIRED"`. A PRO key pages the whole history. The
188
+ * envelope's `totalCount` is the analyst's whole attributed history rather than the page
189
+ * size, so `offset + data.length < totalCount` tells you another page is available.
190
+ *
191
+ * Dates are day granularity on purpose. Publisher timestamps are not comparable across
192
+ * sources, so a time of day would advertise precision the data does not have.
193
+ */
194
+ async calls(slug, options) {
195
+ return this.client.get(
196
+ `/api/v1/analyst/people/${encodeURIComponent(slug)}/calls`,
197
+ options
198
+ );
199
+ }
117
200
  };
118
201
 
119
202
  // src/resources/calendar.ts
@@ -1100,7 +1183,7 @@ var Trackers = class {
1100
1183
  };
1101
1184
 
1102
1185
  // src/version.ts
1103
- var VERSION = "0.47.1";
1186
+ var VERSION = "0.49.0";
1104
1187
 
1105
1188
  // src/client.ts
1106
1189
  var DEFAULT_BASE_URL = "https://app.sentisense.ai";