laplace-api 4.4.0 → 4.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "laplace-api",
3
- "version": "4.4.0",
3
+ "version": "4.6.0",
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": {
@@ -1,3 +1,5 @@
1
+ import { OrderbookLiveData } from "./live-price";
2
+
1
3
  interface RawBISTStockLiveData {
2
4
  _id: number;
3
5
  symbol: string;
@@ -33,16 +35,19 @@ export enum LivePriceFeed {
33
35
  LiveUs = "live_price_us",
34
36
  DelayedBist = "delayed_price_tr",
35
37
  DelayedUs = "delayed_price_us",
36
- // DepthBist = "depth_tr",
38
+ DepthBist = "depth_tr",
37
39
  }
38
40
 
39
41
  type StockLiveDataType<T extends LivePriceFeed> = T extends
40
42
  | LivePriceFeed.LiveBist
41
43
  | LivePriceFeed.DelayedBist
42
- ? // | LivePriceFeed.DepthBist
43
- BISTStockLiveData
44
+ ? BISTStockLiveData
45
+ : T extends LivePriceFeed.DepthBist
46
+ ? OrderbookLiveData
44
47
  : USStockLiveData;
45
48
 
49
+ type LastDataKey = `${string}:${LivePriceFeed}`;
50
+
46
51
  export enum LogLevel {
47
52
  Info = "info",
48
53
  Warn = "warn",
@@ -94,14 +99,17 @@ export class LivePriceWebSocketClient {
94
99
  number,
95
100
  {
96
101
  symbols: string[];
97
- handler: (data: BISTStockLiveData | USStockLiveData) => void;
102
+ handler: (data: BISTStockLiveData | USStockLiveData | OrderbookLiveData) => void;
98
103
  feed: LivePriceFeed;
99
104
  }
100
105
  >();
101
106
  private symbolLastData = new Map<
102
- string,
103
- BISTStockLiveData | USStockLiveData
107
+ LastDataKey,
108
+ BISTStockLiveData | USStockLiveData | OrderbookLiveData
104
109
  >();
110
+ private getLastDataKey(symbol: string, feed: LivePriceFeed): LastDataKey {
111
+ return `${symbol}:${feed}`;
112
+ }
105
113
  private reconnectAttempts = 0;
106
114
  private reconnectTimeout: NodeJS.Timeout | null = null;
107
115
  private isClosed: boolean = false;
@@ -276,13 +284,11 @@ export class LivePriceWebSocketClient {
276
284
  WebSocketErrorType.MESSAGE_PARSE_ERROR
277
285
  );
278
286
  }
279
- let priceData: BISTStockLiveData | USStockLiveData;
287
+ let priceData: BISTStockLiveData | USStockLiveData | OrderbookLiveData;
280
288
 
281
289
  if (
282
290
  feed === LivePriceFeed.DelayedBist ||
283
291
  feed === LivePriceFeed.LiveBist
284
- // ||
285
- // feed === LivePriceFeed.DepthBist
286
292
  ) {
287
293
  const message = messageData as RawBISTStockLiveData;
288
294
  priceData = {
@@ -293,6 +299,13 @@ export class LivePriceWebSocketClient {
293
299
  timestamp: message?.d,
294
300
  percentChange: message?.c,
295
301
  } as BISTStockLiveData;
302
+ } else if (feed === LivePriceFeed.DepthBist) {
303
+ const message = messageData as OrderbookLiveData;
304
+ priceData = {
305
+ updated: message.updated,
306
+ deleted: message.deleted,
307
+ symbol: message?.symbol,
308
+ } as OrderbookLiveData;
296
309
  } else {
297
310
  const message = messageData as RawUSStockLiveData;
298
311
  priceData = {
@@ -302,7 +315,8 @@ export class LivePriceWebSocketClient {
302
315
  } as USStockLiveData;
303
316
  }
304
317
  if (priceData.symbol) {
305
- this.symbolLastData.set(priceData.symbol, priceData);
318
+ const lastDataKey = this.getLastDataKey(priceData.symbol, feed);
319
+ this.symbolLastData.set(lastDataKey, priceData);
306
320
  const handlers = this.getHandlersForSymbol(
307
321
  priceData.symbol,
308
322
  feed
@@ -409,7 +423,7 @@ export class LivePriceWebSocketClient {
409
423
  const subscriptionId = this.subscriptionCounter++;
410
424
  let symbolsToAdd: string[] = [];
411
425
 
412
- const typedHandler = (data: BISTStockLiveData | USStockLiveData) => {
426
+ const typedHandler = (data: BISTStockLiveData | USStockLiveData | OrderbookLiveData) => {
413
427
  handler(data as StockLiveDataType<F>);
414
428
  };
415
429
 
@@ -424,8 +438,13 @@ export class LivePriceWebSocketClient {
424
438
  if (symbolHandlers.length === 1) {
425
439
  symbolsToAdd.push(symbol);
426
440
  } else if (symbolHandlers.length > 1) {
427
- const lastData: BISTStockLiveData | USStockLiveData | undefined =
428
- this.symbolLastData.get(symbol);
441
+ const lastDataKey = this.getLastDataKey(symbol, feed);
442
+ const lastData:
443
+ | BISTStockLiveData
444
+ | USStockLiveData
445
+ | OrderbookLiveData
446
+ | undefined = this.symbolLastData.get(lastDataKey);
447
+
429
448
  if (lastData) {
430
449
  typedHandler(lastData);
431
450
  }
@@ -445,7 +464,7 @@ export class LivePriceWebSocketClient {
445
464
  private getHandlersForSymbol(
446
465
  symbol: string,
447
466
  feed: LivePriceFeed
448
- ): ((data: BISTStockLiveData | USStockLiveData) => void)[] {
467
+ ): ((data: BISTStockLiveData | USStockLiveData | OrderbookLiveData) => void)[] {
449
468
  return Array.from(this.subscriptions.values())
450
469
  .filter((s) => s.symbols.includes(symbol) && s.feed === feed)
451
470
  .map((s) => s.handler);
@@ -479,6 +498,11 @@ export class LivePriceWebSocketClient {
479
498
  feed: feed,
480
499
  })
481
500
  );
501
+
502
+ for (const symbol of symbols) {
503
+ const key = this.getLastDataKey(symbol, feed);
504
+ this.symbolLastData.delete(key);
505
+ }
482
506
  }
483
507
 
484
508
  private async addSymbols(symbols: string[], feed: LivePriceFeed) {
@@ -0,0 +1,137 @@
1
+ import {Client} from "./client";
2
+ import {Locale, Region} from "./collections";
3
+ import {PaginatedResponse} from "./capital_increase";
4
+ import {SortDirection} from "./broker";
5
+
6
+ export interface NewsHighlights {
7
+ consumer: string[];
8
+ energyAndUtilities: string[];
9
+ finance: string[];
10
+ healthcare: string[];
11
+ industrialsAndMaterials: string[];
12
+ tech: string[];
13
+ other: string[];
14
+ }
15
+
16
+ export enum NewsType {
17
+ BRIEFS = "briefs",
18
+ BLOOMBERG = "bloomberg",
19
+ FDA = "fda",
20
+ REUTERS = "reuters",
21
+ }
22
+
23
+ export enum NewsOrderBy {
24
+ TIMESTAMP = "timestamp",
25
+ }
26
+
27
+ export interface News {
28
+ url: string;
29
+ imageUrl: string;
30
+ timestamp: string;
31
+ publisherUrl: string;
32
+ publisher: NewsPublisher;
33
+ relatedTickers: NewsTicker[];
34
+ qualityScore: number;
35
+ createdAt: string;
36
+ tickers?: NewsTicker[];
37
+ categories?: NewsCategories;
38
+ sectors?: NewsSector;
39
+ content?: NewsContent;
40
+ industries?: NewsIndustry;
41
+ }
42
+
43
+ export interface NewsPublisher {
44
+ name: string;
45
+ logoUrl?: string;
46
+ }
47
+
48
+ export interface NewsTicker {
49
+ id: string;
50
+ name: string;
51
+ symbol?: string;
52
+ }
53
+
54
+ export interface NewsCategories {
55
+ name: string;
56
+ newsCount: number;
57
+ categoryType?: string;
58
+ meanType?: number;
59
+ }
60
+
61
+ export interface NewsSector {
62
+ name: string;
63
+ newsCount: number;
64
+ categoryType?: string;
65
+ meanType?: number;
66
+ }
67
+
68
+ export interface NewsContent {
69
+ title: string;
70
+ description: string;
71
+ content: string[];
72
+ summary: string[];
73
+ investorInsight: string;
74
+ }
75
+
76
+ export interface NewsIndustry {
77
+ name: string;
78
+ meanType: number;
79
+ }
80
+
81
+ export class NewsClient extends Client {
82
+ async getHighlights(region: Region, locale: Locale): Promise<NewsHighlights> {
83
+ const url = new URL(
84
+ `${this["baseUrl"]}/api/v1/news/highlights`,
85
+ );
86
+ url.searchParams.append("region", region);
87
+ url.searchParams.append("locale", locale);
88
+
89
+ return this.sendRequest<NewsHighlights>({
90
+ method: "GET",
91
+ url: url.toString(),
92
+ })
93
+ }
94
+
95
+ async getNews(
96
+ region: Region,
97
+ locale: Locale,
98
+ newsType: NewsType,
99
+ page: number | null,
100
+ size: number | null,
101
+ orderBy: NewsOrderBy | null,
102
+ orderByDirection: SortDirection | null,
103
+ extraFilters: string | null,
104
+ ): Promise<PaginatedResponse<News>> {
105
+ const url = new URL(
106
+ `${this["baseUrl"]}/api/v1/news`,
107
+ );
108
+ url.searchParams.append("region", region);
109
+ url.searchParams.append("locale", locale);
110
+ url.searchParams.append("newsType", newsType);
111
+
112
+ if (page) {
113
+ url.searchParams.append("page", page.toString());
114
+ }
115
+
116
+ if (size) {
117
+ url.searchParams.append("size", size.toString());
118
+ }
119
+
120
+ if (orderBy) {
121
+ url.searchParams.append("orderBy", orderBy);
122
+ }
123
+
124
+ if (orderByDirection) {
125
+ url.searchParams.append("orderByDirection", orderByDirection);
126
+ }
127
+
128
+ if (extraFilters) {
129
+ url.searchParams.append("extraFilters", extraFilters);
130
+ }
131
+
132
+ return this.sendRequest<PaginatedResponse<News>>({
133
+ method: "GET",
134
+ url: url.toString(),
135
+ });
136
+ }
137
+ }
@@ -298,12 +298,14 @@ export class StockClient extends Client {
298
298
  if (request.resolution) params.resolution = request.resolution;
299
299
  if (request.indicators) params.indicators = request.indicators;
300
300
  if (request.chartType != null) params.chartType = request.chartType;
301
-
302
- return this.sendRequest<Blob>({
303
- method: 'GET',
304
- url: '/api/v1/stock/chart',
301
+
302
+ const data = await this.sendRequest<ArrayBuffer>({
303
+ method: "GET",
304
+ url: "/api/v1/stock/chart",
305
305
  params,
306
- responseType: 'blob',
306
+ responseType: "arraybuffer",
307
307
  });
308
+
309
+ return new Blob([data], { type: "image/png" });
308
310
  }
309
311
  }
@@ -0,0 +1,204 @@
1
+ import { Logger } from "winston";
2
+ import { LaplaceConfiguration } from "../utilities/configuration";
3
+ import {
4
+ NewsClient,
5
+ NewsHighlights,
6
+ News,
7
+ NewsType,
8
+ NewsOrderBy,
9
+ } from "../client/news";
10
+ import "./client_test_suite";
11
+ import { Region, Locale } from "../client/collections";
12
+ import { SortDirection } from "../client/broker";
13
+ import { PaginatedResponse } from "../client/capital_increase";
14
+
15
+ const mockNewsHighlightsResponse: NewsHighlights = {
16
+ consumer: ["news1", "news2"],
17
+ energyAndUtilities: ["news3"],
18
+ finance: ["news4", "news5"],
19
+ healthcare: ["news6"],
20
+ industrialsAndMaterials: ["news7"],
21
+ tech: ["news8"],
22
+ other: ["news9"]
23
+ };
24
+
25
+ const mockNewsResponse: News[] = [
26
+ {
27
+ url: "https://example.com/news1",
28
+ imageUrl: "https://example.com/image1.jpg",
29
+ timestamp: "2024-03-14T10:00:00Z",
30
+ publisherUrl: "https://example.com",
31
+ publisher: {
32
+ name: "Example Publisher",
33
+ logoUrl: "https://example.com/logo.png"
34
+ },
35
+ relatedTickers: [
36
+ {
37
+ id: "1",
38
+ name: "Ticker 1",
39
+ symbol: "TCK1"
40
+ }
41
+ ],
42
+ qualityScore: 85,
43
+ createdAt: "2024-03-14T09:00:00Z"
44
+ },
45
+ {
46
+ url: "https://example.com/news2",
47
+ imageUrl: "https://example.com/image2.jpg",
48
+ timestamp: "2024-03-14T11:00:00Z",
49
+ publisherUrl: "https://example.com",
50
+ publisher: {
51
+ name: "Example Publisher 2"
52
+ },
53
+ relatedTickers: [],
54
+ qualityScore: 90,
55
+ createdAt: "2024-03-14T10:00:00Z"
56
+ }
57
+ ];
58
+
59
+ const mockPaginatedNewsResponse: PaginatedResponse<News> = {
60
+ recordCount: 2,
61
+ items: mockNewsResponse
62
+ };
63
+
64
+ describe("News Client", () => {
65
+ let client: NewsClient;
66
+
67
+ beforeAll(() => {
68
+ const config = (global as any).testSuite.config as LaplaceConfiguration;
69
+ const logger: Logger = {
70
+ info: jest.fn(),
71
+ error: jest.fn(),
72
+ warn: jest.fn(),
73
+ debug: jest.fn(),
74
+ } as unknown as Logger;
75
+
76
+ client = new NewsClient(config, logger);
77
+ });
78
+
79
+ describe("Integration Tests", () => {
80
+ describe("getHighlights", () => {
81
+ test("should return news highlights for region and locale", async () => {
82
+ const resp = await client.getHighlights(Region.Tr, Locale.Tr);
83
+
84
+ expect(resp).toBeDefined();
85
+ expect(Array.isArray(resp.consumer)).toBe(true);
86
+ expect(Array.isArray(resp.energyAndUtilities)).toBe(true);
87
+ expect(Array.isArray(resp.finance)).toBe(true);
88
+ expect(Array.isArray(resp.healthcare)).toBe(true);
89
+ expect(Array.isArray(resp.industrialsAndMaterials)).toBe(true);
90
+ expect(Array.isArray(resp.tech)).toBe(true);
91
+ expect(Array.isArray(resp.other)).toBe(true);
92
+ });
93
+ });
94
+
95
+ describe("getNews", () => {
96
+ test("should return paginated news list", async () => {
97
+ const resp = await client.getNews(
98
+ Region.Tr,
99
+ Locale.Tr,
100
+ NewsType.BRIEFS,
101
+ 1,
102
+ 10,
103
+ NewsOrderBy.TIMESTAMP,
104
+ SortDirection.Desc,
105
+ null
106
+ );
107
+
108
+ expect(resp).toBeDefined();
109
+ expect(typeof resp.recordCount).toBe("number");
110
+ expect(Array.isArray(resp.items)).toBe(true);
111
+
112
+ if (resp.items.length > 0) {
113
+ const firstNews = resp.items[0];
114
+ expect(typeof firstNews.url).toBe("string");
115
+ expect(typeof firstNews.timestamp).toBe("string");
116
+ expect(typeof firstNews.publisher).toBe("object");
117
+ expect(Array.isArray(firstNews.relatedTickers)).toBe(true);
118
+ }
119
+ });
120
+ });
121
+ });
122
+
123
+ describe("Mock Tests", () => {
124
+ beforeEach(() => {
125
+ jest.clearAllMocks();
126
+ });
127
+
128
+ describe("getHighlights", () => {
129
+ test("should return news highlights with mock data", async () => {
130
+ jest.spyOn(client, 'getHighlights').mockResolvedValue(mockNewsHighlightsResponse);
131
+
132
+ const resp = await client.getHighlights(Region.Tr, Locale.Tr);
133
+
134
+ expect(resp).toBeDefined();
135
+ expect(resp.consumer).toHaveLength(2);
136
+ expect(resp.energyAndUtilities).toHaveLength(1);
137
+ expect(resp.finance).toHaveLength(2);
138
+ expect(resp.tech).toHaveLength(1);
139
+
140
+ expect(client.getHighlights).toHaveBeenCalledWith(Region.Tr, Locale.Tr);
141
+ });
142
+
143
+ test("should handle API errors for highlights", async () => {
144
+ jest.spyOn(client, 'getHighlights').mockRejectedValue(new Error("Failed to fetch highlights"));
145
+
146
+ await expect(client.getHighlights(Region.Tr, Locale.Tr))
147
+ .rejects.toThrow("Failed to fetch highlights");
148
+ });
149
+ });
150
+
151
+ describe("getNews", () => {
152
+ test("should return paginated news with mock data", async () => {
153
+ jest.spyOn(client, 'getNews').mockResolvedValue(mockPaginatedNewsResponse);
154
+
155
+ const resp = await client.getNews(
156
+ Region.Tr,
157
+ Locale.Tr,
158
+ NewsType.BRIEFS,
159
+ 1,
160
+ 10,
161
+ NewsOrderBy.TIMESTAMP,
162
+ SortDirection.Desc,
163
+ null
164
+ );
165
+
166
+ expect(resp.items).toHaveLength(2);
167
+ expect(resp.recordCount).toBe(2);
168
+
169
+ const firstNews = resp.items[0];
170
+ expect(firstNews.url).toBe("https://example.com/news1");
171
+ expect(firstNews.publisher.name).toBe("Example Publisher");
172
+ expect(firstNews.relatedTickers).toHaveLength(1);
173
+ expect(firstNews.qualityScore).toBe(85);
174
+
175
+ expect(client.getNews).toHaveBeenCalledWith(
176
+ Region.Tr,
177
+ Locale.Tr,
178
+ NewsType.BRIEFS,
179
+ 1,
180
+ 10,
181
+ NewsOrderBy.TIMESTAMP,
182
+ SortDirection.Desc,
183
+ null
184
+ );
185
+ });
186
+
187
+ test("should handle API errors for news", async () => {
188
+ jest.spyOn(client, 'getNews').mockRejectedValue(new Error("Failed to fetch news"));
189
+
190
+ await expect(client.getNews(
191
+ Region.Tr,
192
+ Locale.Tr,
193
+ NewsType.BRIEFS,
194
+ 1,
195
+ 10,
196
+ NewsOrderBy.TIMESTAMP,
197
+ SortDirection.Desc,
198
+ null
199
+ )).rejects.toThrow("Failed to fetch news");
200
+ });
201
+ });
202
+ });
203
+ });
204
+
@@ -125,14 +125,14 @@ const mockTickRulesResponse = {
125
125
 
126
126
  const mockEarningsTranscriptList: EarningsTranscriptListItem[] = [
127
127
  {
128
- symbol: "TUPRS",
128
+ symbol: "AAPL",
129
129
  year: 2024,
130
130
  quarter: 1,
131
131
  date: "2024-05-15",
132
- fiscal_year: 2024
132
+ fiscal_year: 2024,
133
133
  },
134
134
  {
135
- symbol: "TUPRS",
135
+ symbol: "AAPL",
136
136
  year: 2023,
137
137
  quarter: 4,
138
138
  date: "2024-02-20",
@@ -141,7 +141,7 @@ const mockEarningsTranscriptList: EarningsTranscriptListItem[] = [
141
141
  ];
142
142
 
143
143
  const mockEarningsTranscriptDetail: EarningsTranscriptWithSummary = {
144
- symbol: "TUPRS",
144
+ symbol: "AAPL",
145
145
  year: 2024,
146
146
  quarter: 1,
147
147
  date: "2024-05-15",
@@ -153,14 +153,14 @@ const mockEarningsTranscriptDetail: EarningsTranscriptWithSummary = {
153
153
  const mockMarketStates: MarketState[] = [
154
154
  {
155
155
  id: 1,
156
- marketSymbol: "XIST",
156
+ marketSymbol: "BIST",
157
157
  state: "OPEN",
158
158
  lastTimestamp: "2024-03-14T10:00:00Z",
159
159
  stockSymbol: "TUPRS"
160
160
  },
161
161
  {
162
162
  id: 2,
163
- marketSymbol: "XIST",
163
+ marketSymbol: "BIST",
164
164
  state: "CLOSED",
165
165
  lastTimestamp: "2024-03-14T18:00:00Z",
166
166
  stockSymbol: "GARAN"
@@ -174,7 +174,7 @@ const mockPaginatedMarketStates: PaginatedResponse<MarketState> = {
174
174
 
175
175
  const mockSingleMarketState: MarketState = {
176
176
  id: 1,
177
- marketSymbol: "XIST",
177
+ marketSymbol: "BIST",
178
178
  state: "OPEN",
179
179
  lastTimestamp: "2024-03-14T10:00:00Z",
180
180
  stockSymbol: "TUPRS"
@@ -389,7 +389,7 @@ describe("Stocks Client", () => {
389
389
 
390
390
  describe("getEarningsTranscripts", () => {
391
391
  test("should return earnings transcript list", async () => {
392
- const resp = await client.getEarningsTranscripts("TUPRS", Region.Tr);
392
+ const resp = await client.getEarningsTranscripts("AAPL", Region.Us);
393
393
 
394
394
  expect(Array.isArray(resp)).toBe(true);
395
395
 
@@ -406,7 +406,7 @@ describe("Stocks Client", () => {
406
406
 
407
407
  describe("getEarningsTranscript", () => {
408
408
  test("should return earnings transcript detail", async () => {
409
- const resp = await client.getEarningsTranscript("TUPRS", 2023, 4);
409
+ const resp = await client.getEarningsTranscript("AAPL", 2023, 4);
410
410
 
411
411
  expect(resp).toBeDefined();
412
412
  expect(typeof resp.symbol).toBe("string");
@@ -476,7 +476,7 @@ describe("Stocks Client", () => {
476
476
 
477
477
  describe("getState", () => {
478
478
  test("should return single market state", async () => {
479
- const resp = await client.getState("XIST");
479
+ const resp = await client.getState("BIST");
480
480
 
481
481
  expect(resp).toBeDefined();
482
482
  expect(typeof resp.id).toBe("number");
@@ -495,11 +495,10 @@ describe("Stocks Client", () => {
495
495
  symbol: "TUPRS",
496
496
  region: Region.Tr,
497
497
  });
498
-
499
498
  expect(resp).toBeDefined();
500
499
  expect(resp).toBeInstanceOf(Blob);
501
500
  expect(resp.size).toBeGreaterThan(0);
502
- });
501
+ }, 10000);
503
502
  });
504
503
  });
505
504
 
@@ -693,12 +692,12 @@ describe("Stocks Client", () => {
693
692
  test("should return earnings transcript list with mock data", async () => {
694
693
  jest.spyOn(client, 'getEarningsTranscripts').mockResolvedValue(mockEarningsTranscriptList);
695
694
 
696
- const resp = await client.getEarningsTranscripts("TUPRS", Region.Tr);
695
+ const resp = await client.getEarningsTranscripts("AAPL", Region.Us);
697
696
 
698
697
  expect(resp).toHaveLength(2);
699
698
 
700
699
  const firstTranscript = resp[0];
701
- expect(firstTranscript.symbol).toBe("TUPRS");
700
+ expect(firstTranscript.symbol).toBe("AAPL");
702
701
  expect(firstTranscript.year).toBe(2024);
703
702
  expect(firstTranscript.quarter).toBe(1);
704
703
  expect(firstTranscript.date).toBe("2024-05-15");
@@ -708,14 +707,18 @@ describe("Stocks Client", () => {
708
707
  expect(secondTranscript.year).toBe(2023);
709
708
  expect(secondTranscript.quarter).toBe(4);
710
709
 
711
- expect(client.getEarningsTranscripts).toHaveBeenCalledWith("TUPRS", Region.Tr);
710
+ expect(client.getEarningsTranscripts).toHaveBeenCalledWith(
711
+ "AAPL",
712
+ Region.Us
713
+ );
712
714
  });
713
715
 
714
716
  test("should handle API errors for earnings transcripts", async () => {
715
717
  jest.spyOn(client, 'getEarningsTranscripts').mockRejectedValue(new Error("Transcripts not found"));
716
718
 
717
- await expect(client.getEarningsTranscripts("INVALID", Region.Tr))
718
- .rejects.toThrow("Transcripts not found");
719
+ await expect(
720
+ client.getEarningsTranscripts("INVALID", Region.Us)
721
+ ).rejects.toThrow("Transcripts not found");
719
722
  });
720
723
  });
721
724
 
@@ -723,9 +726,9 @@ describe("Stocks Client", () => {
723
726
  test("should return earnings transcript detail with mock data", async () => {
724
727
  jest.spyOn(client, 'getEarningsTranscript').mockResolvedValue(mockEarningsTranscriptDetail);
725
728
 
726
- const resp = await client.getEarningsTranscript("TUPRS", 2024, 1);
729
+ const resp = await client.getEarningsTranscript("AAPL", 2024, 1);
727
730
 
728
- expect(resp.symbol).toBe("TUPRS");
731
+ expect(resp.symbol).toBe("AAPL");
729
732
  expect(resp.year).toBe(2024);
730
733
  expect(resp.quarter).toBe(1);
731
734
  expect(resp.date).toBe("2024-05-15");
@@ -733,14 +736,19 @@ describe("Stocks Client", () => {
733
736
  expect(resp.summary).toBe("Strong Q1 performance with 15% revenue growth");
734
737
  expect(resp.has_summary).toBe(true);
735
738
 
736
- expect(client.getEarningsTranscript).toHaveBeenCalledWith("TUPRS", 2024, 1);
739
+ expect(client.getEarningsTranscript).toHaveBeenCalledWith(
740
+ "AAPL",
741
+ 2024,
742
+ 1
743
+ );
737
744
  });
738
745
 
739
746
  test("should handle API errors for earnings transcript detail", async () => {
740
747
  jest.spyOn(client, 'getEarningsTranscript').mockRejectedValue(new Error("Transcript not found"));
741
748
 
742
- await expect(client.getEarningsTranscript("TUPRS", 2020, 1))
743
- .rejects.toThrow("Transcript not found");
749
+ await expect(
750
+ client.getEarningsTranscript("AAPL", 2020, 1)
751
+ ).rejects.toThrow("Transcript not found");
744
752
  });
745
753
  });
746
754
 
@@ -755,7 +763,7 @@ describe("Stocks Client", () => {
755
763
 
756
764
  const firstState = resp.items[0];
757
765
  expect(firstState.id).toBe(1);
758
- expect(firstState.marketSymbol).toBe("XIST");
766
+ expect(firstState.marketSymbol).toBe("BIST");
759
767
  expect(firstState.state).toBe("OPEN");
760
768
  expect(firstState.stockSymbol).toBe("TUPRS");
761
769
 
@@ -777,7 +785,7 @@ describe("Stocks Client", () => {
777
785
  const resp = await client.getStockState("TUPRS");
778
786
 
779
787
  expect(resp.id).toBe(1);
780
- expect(resp.marketSymbol).toBe("XIST");
788
+ expect(resp.marketSymbol).toBe("BIST");
781
789
  expect(resp.state).toBe("OPEN");
782
790
  expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
783
791
  expect(resp.stockSymbol).toBe("TUPRS");
@@ -821,14 +829,14 @@ describe("Stocks Client", () => {
821
829
  test("should return single market state with mock data", async () => {
822
830
  jest.spyOn(client, 'getState').mockResolvedValue(mockSingleMarketState);
823
831
 
824
- const resp = await client.getState("XIST");
832
+ const resp = await client.getState("BIST");
825
833
 
826
834
  expect(resp.id).toBe(1);
827
- expect(resp.marketSymbol).toBe("XIST");
835
+ expect(resp.marketSymbol).toBe("BIST");
828
836
  expect(resp.state).toBe("OPEN");
829
837
  expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
830
838
 
831
- expect(client.getState).toHaveBeenCalledWith("XIST");
839
+ expect(client.getState).toHaveBeenCalledWith("BIST");
832
840
  });
833
841
 
834
842
  test("should handle API errors for single state", async () => {