laplace-api 5.2.0 → 5.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "laplace-api",
3
- "version": "5.2.0",
3
+ "version": "5.2.1",
4
4
  "description": "Client library for Laplace API for the US stock market and BIST (Istanbul stock market) fundamental financial data.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -40,6 +40,8 @@ export interface News {
40
40
  industries?: NewsIndustry;
41
41
  }
42
42
 
43
+ export type NewsV2 = Omit<News, "relatedTickers">;
44
+
43
45
  export interface NewsPublisher {
44
46
  name: string;
45
47
  logoUrl: string | null;
@@ -122,18 +124,47 @@ export class NewsClient extends Client {
122
124
  });
123
125
  }
124
126
 
127
+ async getNewsV2(
128
+ region: Region,
129
+ locale: Locale,
130
+ newsType?: NewsType,
131
+ page?: number,
132
+ size?: number,
133
+ orderBy?: NewsOrderBy,
134
+ orderByDirection?: SortDirection,
135
+ extraFilters?: string
136
+ ): Promise<PaginatedResponse<NewsV2>> {
137
+ const params = {
138
+ region,
139
+ locale,
140
+ ...(newsType != null && { newsType }),
141
+ ...(page != null && { page }),
142
+ ...(size != null && { size }),
143
+ ...(orderBy != null && { orderBy }),
144
+ ...(orderByDirection != null && { orderByDirection }),
145
+ ...(extraFilters != null && { extraFilters }),
146
+ };
147
+
148
+ return this.sendRequest<PaginatedResponse<NewsV2>>({
149
+ method: "GET",
150
+ url: "/api/v2/news",
151
+ params,
152
+ });
153
+ }
154
+
125
155
  streamNews(
156
+ region: Region,
126
157
  locale: Locale,
127
158
  sectors?: string[],
128
159
  tickers?: string[],
129
160
  categories?: string[],
130
161
  industries?: string[]
131
- ): { events: AsyncIterable<News[]>, cancel: () => void } {
132
- let url = `${this["baseUrl"]}/api/v1/news/stream?locale=${locale}`;
162
+ ): { events: AsyncIterable<NewsV2[]>, cancel: () => void } {
163
+ let url = `${this["baseUrl"]}/api/v1/news/stream?locale=${locale}&region=${region}`;
133
164
  if (sectors?.length) url += `&sectors=${encodeURIComponent(sectors.join(","))}`;
134
165
  if (tickers?.length) url += `&tickers=${encodeURIComponent(tickers.join(","))}`;
135
166
  if (categories?.length) url += `&categories=${encodeURIComponent(categories.join(","))}`;
136
167
  if (industries?.length) url += `&industries=${encodeURIComponent(industries.join(","))}`;
137
- return this.sendSSERequest<News[]>(url);
168
+ return this.sendSSERequest<NewsV2[]>(url);
138
169
  }
139
170
  }
@@ -67,6 +67,11 @@ const mockNewsResponse = {
67
67
  recordCount: 352
68
68
  };
69
69
 
70
+ const mockNewsV2Response = {
71
+ items: mockNewsResponse.items.map(({ relatedTickers, ...rest }) => rest),
72
+ recordCount: mockNewsResponse.recordCount
73
+ };
74
+
70
75
  describe("NewsClient", () => {
71
76
  let client: NewsClient;
72
77
 
@@ -191,9 +196,42 @@ describe("NewsClient", () => {
191
196
  }
192
197
  });
193
198
 
199
+ test("getNewsV2 returns valid paginated data", async () => {
200
+ const resp = await client.getNewsV2(
201
+ Region.Us,
202
+ Locale.Tr,
203
+ NewsType.BRIEFS,
204
+ 0,
205
+ 10,
206
+ NewsOrderBy.TIMESTAMP,
207
+ SortDirection.Desc
208
+ );
209
+
210
+ expect(resp).toBeDefined();
211
+ expect(typeof resp.recordCount).toBe("number");
212
+ expect(resp.recordCount).toBeGreaterThanOrEqual(0);
213
+ expect(Array.isArray(resp.items)).toBe(true);
214
+
215
+ if (resp.items.length > 0) {
216
+ const n = resp.items[0];
217
+
218
+ expect(typeof n.url).toBe("string");
219
+ expect(typeof n.imageUrl).toBe("string");
220
+ expect(typeof n.timestamp).toBe("string");
221
+ expect(typeof n.publisherUrl).toBe("string");
222
+ expect(typeof n.qualityScore).toBe("number");
223
+ expect(typeof n.createdAt).toBe("string");
224
+
225
+ expect((n as any).relatedTickers).toBeUndefined();
226
+
227
+ expect(n.publisher).toBeDefined();
228
+ expect(typeof n.publisher.name).toBe("string");
229
+ }
230
+ });
231
+
194
232
  test("streamNews yields item before timeout or throws gracefully if none arrive", async () => {
195
233
  let newsItemsReceived = 0;
196
- const { events, cancel } = client.streamNews(Locale.Tr);
234
+ const { events, cancel } = client.streamNews(Region.Us, Locale.Tr);
197
235
 
198
236
  const receivePromise = (async () => {
199
237
  for await (const items of events) {
@@ -364,6 +402,76 @@ describe("NewsClient", () => {
364
402
  });
365
403
  });
366
404
 
405
+ describe("getNewsV2", () => {
406
+ test("calls correct endpoint/params and matches raw response", async () => {
407
+ cli.request.mockResolvedValueOnce({ data: mockNewsV2Response });
408
+
409
+ const resp = await client.getNewsV2(
410
+ Region.Tr,
411
+ Locale.Tr,
412
+ NewsType.BRIEFS,
413
+ 1,
414
+ 10,
415
+ NewsOrderBy.TIMESTAMP,
416
+ SortDirection.Desc,
417
+ undefined
418
+ );
419
+
420
+ expect(cli.request).toHaveBeenCalledTimes(1);
421
+ const call = cli.request.mock.calls[0][0];
422
+
423
+ expect(call.method).toBe("GET");
424
+ expect(call.url).toBe("/api/v2/news");
425
+ expect(call.params).toEqual({
426
+ region: Region.Tr,
427
+ locale: Locale.Tr,
428
+ newsType: NewsType.BRIEFS,
429
+ page: 1,
430
+ size: 10,
431
+ orderBy: NewsOrderBy.TIMESTAMP,
432
+ orderByDirection: SortDirection.Desc
433
+ });
434
+
435
+ expect(resp.recordCount).toBe(352);
436
+ expect(resp.items).toHaveLength(1);
437
+
438
+ const n = resp.items[0];
439
+
440
+ expect((n as any).relatedTickers).toBeUndefined();
441
+ expect(n.url).toBe(mockNewsV2Response.items[0].url);
442
+ });
443
+
444
+ test("does not send optional params when undefined", async () => {
445
+ cli.request.mockResolvedValueOnce({ data: mockNewsV2Response });
446
+
447
+ await client.getNewsV2(Region.Tr, Locale.Tr);
448
+
449
+ const call = cli.request.mock.calls[0][0];
450
+ expect(call.params).toEqual({
451
+ region: Region.Tr,
452
+ locale: Locale.Tr
453
+ });
454
+ });
455
+
456
+ test("bubbles up request error", async () => {
457
+ cli.request.mockRejectedValueOnce(new Error("Failed to fetch news v2"));
458
+
459
+ await expect(
460
+ client.getNewsV2(
461
+ Region.Tr,
462
+ Locale.Tr,
463
+ NewsType.REUTERS,
464
+ 0,
465
+ 10,
466
+ NewsOrderBy.TIMESTAMP,
467
+ SortDirection.Desc
468
+ )
469
+ ).rejects.toThrow("Failed to fetch news v2");
470
+
471
+ expect(cli.request).toHaveBeenCalledTimes(1);
472
+ });
473
+ });
474
+
367
475
  describe("streamNews", () => {
368
476
  test("calls correct endpoint/params and correctly yields stream entities", async () => {
369
477
  const eventsList: any[] = [];
@@ -386,7 +494,7 @@ describe("NewsClient", () => {
386
494
  data: mockAsyncIterator
387
495
  });
388
496
 
389
- const { events, cancel } = client.streamNews(Locale.Tr);
497
+ const { events, cancel } = client.streamNews(Region.Us, Locale.Tr);
390
498
 
391
499
  for await (const newsList of events) {
392
500
  eventsList.push(newsList);
@@ -394,7 +502,7 @@ describe("NewsClient", () => {
394
502
 
395
503
  expect(axiosGetSpy).toHaveBeenCalledTimes(1);
396
504
  const callArgs = axiosGetSpy.mock.calls[0];
397
- expect(callArgs[0]).toBe(`${client["baseUrl"]}/api/v1/news/stream?locale=tr`);
505
+ expect(callArgs[0]).toBe(`${client["baseUrl"]}/api/v1/news/stream?locale=tr&region=us`);
398
506
  expect(callArgs[1]?.responseType).toBe('stream');
399
507
 
400
508
  expect(eventsList).toHaveLength(2);
@@ -416,7 +524,7 @@ describe("NewsClient", () => {
416
524
  data: mockAsyncIterator
417
525
  });
418
526
 
419
- const { events, cancel } = client.streamNews(Locale.En, ["tech"], ["AAPL"], ["category"], ["software"]);
527
+ const { events, cancel } = client.streamNews(Region.Us, Locale.En, ["tech"], ["AAPL"], ["category"], ["software"]);
420
528
 
421
529
  for await (const _ of events) {
422
530
  break;
@@ -424,7 +532,7 @@ describe("NewsClient", () => {
424
532
 
425
533
  expect(axiosGetSpy).toHaveBeenCalledTimes(1);
426
534
  const callArgs = axiosGetSpy.mock.calls[0];
427
- expect(callArgs[0]).toBe(`${client["baseUrl"]}/api/v1/news/stream?locale=en&sectors=tech&tickers=AAPL&categories=category&industries=software`);
535
+ expect(callArgs[0]).toBe(`${client["baseUrl"]}/api/v1/news/stream?locale=en&region=us&sectors=tech&tickers=AAPL&categories=category&industries=software`);
428
536
 
429
537
  cancel();
430
538
  axiosGetSpy.mockRestore();