reportify-sdk 0.1.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 ADDED
@@ -0,0 +1,637 @@
1
+ // src/stock.ts
2
+ var StockModule = class {
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ // ===========================================================================
7
+ // Company Information
8
+ // ===========================================================================
9
+ /**
10
+ * Get company overview including business description, sector, and key metrics
11
+ *
12
+ * @param symbol - Stock symbol (e.g., "US:AAPL", "HK:0700")
13
+ */
14
+ async overview(symbol) {
15
+ return this.client.post("/v1/stock/company-overview", {
16
+ symbol
17
+ });
18
+ }
19
+ /**
20
+ * Get list of major shareholders
21
+ *
22
+ * @param symbol - Stock symbol
23
+ */
24
+ async shareholders(symbol) {
25
+ const response = await this.client.post(
26
+ "/v1/stock/company-shareholders",
27
+ { symbol }
28
+ );
29
+ return Array.isArray(response) ? response : response.shareholders || [];
30
+ }
31
+ // ===========================================================================
32
+ // Financial Statements
33
+ // ===========================================================================
34
+ /**
35
+ * Get income statement data
36
+ *
37
+ * @param symbol - Stock symbol
38
+ * @param options.period - "annual" or "quarterly"
39
+ * @param options.limit - Number of periods to return
40
+ */
41
+ async incomeStatement(symbol, options = {}) {
42
+ const response = await this.client.post(
43
+ "/v1/stock/company-income-statement",
44
+ {
45
+ symbol,
46
+ period: options.period || "annual",
47
+ limit: options.limit || 10
48
+ }
49
+ );
50
+ return this.normalizeArrayResponse(response);
51
+ }
52
+ /**
53
+ * Get balance sheet data
54
+ *
55
+ * @param symbol - Stock symbol
56
+ * @param options.period - "annual" or "quarterly"
57
+ * @param options.limit - Number of periods to return
58
+ */
59
+ async balanceSheet(symbol, options = {}) {
60
+ const response = await this.client.post(
61
+ "/v1/stock/company-balance-sheet",
62
+ {
63
+ symbol,
64
+ period: options.period || "annual",
65
+ limit: options.limit || 10
66
+ }
67
+ );
68
+ return this.normalizeArrayResponse(response);
69
+ }
70
+ /**
71
+ * Get cash flow statement data
72
+ *
73
+ * @param symbol - Stock symbol
74
+ * @param options.period - "annual" or "quarterly"
75
+ * @param options.limit - Number of periods to return
76
+ */
77
+ async cashflowStatement(symbol, options = {}) {
78
+ const response = await this.client.post(
79
+ "/v1/stock/company-cashflow-statement",
80
+ {
81
+ symbol,
82
+ period: options.period || "annual",
83
+ limit: options.limit || 10
84
+ }
85
+ );
86
+ return this.normalizeArrayResponse(response);
87
+ }
88
+ /**
89
+ * Get revenue breakdown by segment, product, or region
90
+ *
91
+ * @param symbol - Stock symbol
92
+ * @param options.breakdownType - Type of breakdown
93
+ */
94
+ async revenueBreakdown(symbol, options = {}) {
95
+ const response = await this.client.post(
96
+ "/v1/stock/company-revenue-breakdown",
97
+ {
98
+ symbol,
99
+ breakdown_type: options.breakdownType || "segment"
100
+ }
101
+ );
102
+ return this.normalizeArrayResponse(response);
103
+ }
104
+ // ===========================================================================
105
+ // Price Data
106
+ // ===========================================================================
107
+ /**
108
+ * Get historical stock prices
109
+ *
110
+ * @param symbol - Stock symbol
111
+ * @param options - Query options
112
+ */
113
+ async prices(symbol, options = {}) {
114
+ const response = await this.client.post(
115
+ "/v1/stock/company-prices",
116
+ {
117
+ symbol,
118
+ start_date: options.startDate,
119
+ end_date: options.endDate,
120
+ limit: options.limit || 100
121
+ }
122
+ );
123
+ return this.normalizeArrayResponse(response);
124
+ }
125
+ /**
126
+ * Get K-line (candlestick) data
127
+ *
128
+ * @param symbol - Stock symbol
129
+ * @param options - Query options
130
+ */
131
+ async kline(symbol, options = {}) {
132
+ const response = await this.client.post(
133
+ "/v1/stock/kline",
134
+ {
135
+ symbol,
136
+ interval: options.interval || "1d",
137
+ adjust: options.adjust || "forward",
138
+ start_date: options.startDate,
139
+ end_date: options.endDate,
140
+ limit: options.limit || 100
141
+ }
142
+ );
143
+ return this.normalizeArrayResponse(response);
144
+ }
145
+ /**
146
+ * Get real-time stock quotes
147
+ *
148
+ * @param symbols - Single symbol or array of symbols
149
+ */
150
+ async quote(symbols) {
151
+ const symbolList = Array.isArray(symbols) ? symbols : [symbols];
152
+ const response = await this.client.post(
153
+ "/v1/stock/quote-realtime",
154
+ { symbols: symbolList }
155
+ );
156
+ return this.normalizeArrayResponse(response);
157
+ }
158
+ /**
159
+ * Get stock index prices
160
+ *
161
+ * @param symbol - Index symbol
162
+ * @param options - Query options
163
+ */
164
+ async indexPrices(symbol, options = {}) {
165
+ const response = await this.client.post(
166
+ "/v1/stock/index-prices",
167
+ {
168
+ symbol,
169
+ start_date: options.startDate,
170
+ end_date: options.endDate,
171
+ limit: options.limit || 100
172
+ }
173
+ );
174
+ return this.normalizeArrayResponse(response);
175
+ }
176
+ // ===========================================================================
177
+ // Screening and Calendar
178
+ // ===========================================================================
179
+ /**
180
+ * Screen stocks based on various criteria
181
+ */
182
+ async screener(options = {}) {
183
+ const response = await this.client.post(
184
+ "/v1/stock/screener",
185
+ {
186
+ market: options.market,
187
+ sector: options.sector,
188
+ min_market_cap: options.minMarketCap,
189
+ max_market_cap: options.maxMarketCap,
190
+ min_pe: options.minPe,
191
+ max_pe: options.maxPe,
192
+ limit: options.limit || 50
193
+ }
194
+ );
195
+ return this.normalizeArrayResponse(response);
196
+ }
197
+ /**
198
+ * Get earnings announcement calendar
199
+ */
200
+ async earningsCalendar(options = {}) {
201
+ const response = await this.client.post(
202
+ "/v1/stock/earnings-calendar",
203
+ {
204
+ area: options.area || "us",
205
+ start_date: options.startDate,
206
+ end_date: options.endDate,
207
+ symbol: options.symbol
208
+ }
209
+ );
210
+ return this.normalizeArrayResponse(response);
211
+ }
212
+ /**
213
+ * Get Hong Kong IPO calendar
214
+ */
215
+ async ipoCalendarHK(status = "Filing") {
216
+ const response = await this.client.post(
217
+ "/v1/stock/ipo-calendar-hk",
218
+ { status }
219
+ );
220
+ return this.normalizeArrayResponse(response);
221
+ }
222
+ // ===========================================================================
223
+ // Helper Methods
224
+ // ===========================================================================
225
+ normalizeArrayResponse(response) {
226
+ if (Array.isArray(response)) {
227
+ return response;
228
+ }
229
+ if ("data" in response) {
230
+ return response.data;
231
+ }
232
+ if ("items" in response) {
233
+ return response.items;
234
+ }
235
+ if ("records" in response) {
236
+ return response.records;
237
+ }
238
+ return [];
239
+ }
240
+ };
241
+
242
+ // src/timeline.ts
243
+ var TimelineModule = class {
244
+ constructor(client) {
245
+ this.client = client;
246
+ }
247
+ /**
248
+ * Get timeline for followed companies
249
+ *
250
+ * Returns recent content related to companies the user is following.
251
+ *
252
+ * @param options.num - Number of items to return (default: 10, max: 100)
253
+ */
254
+ async companies(options = {}) {
255
+ const response = await this.client.post(
256
+ "/v1/tools/timeline/companies",
257
+ { num: options.num || 10 }
258
+ );
259
+ return response.docs || [];
260
+ }
261
+ /**
262
+ * Get timeline for followed topics
263
+ *
264
+ * Returns recent content related to custom topics the user is following.
265
+ *
266
+ * @param options.num - Number of items to return
267
+ */
268
+ async topics(options = {}) {
269
+ const response = await this.client.post(
270
+ "/v1/tools/timeline/topics",
271
+ { num: options.num || 10 }
272
+ );
273
+ return response.docs || [];
274
+ }
275
+ /**
276
+ * Get timeline for followed professional institutes
277
+ *
278
+ * Returns recent content from research institutions, banks, etc.
279
+ *
280
+ * @param options.num - Number of items to return
281
+ */
282
+ async institutes(options = {}) {
283
+ const response = await this.client.post(
284
+ "/v1/tools/timeline/institutes",
285
+ { num: options.num || 10 }
286
+ );
287
+ return response.docs || [];
288
+ }
289
+ /**
290
+ * Get timeline for followed public media
291
+ *
292
+ * Returns recent content from public media accounts.
293
+ *
294
+ * @param options.num - Number of items to return
295
+ */
296
+ async publicMedia(options = {}) {
297
+ const response = await this.client.post(
298
+ "/v1/tools/timeline/public-media",
299
+ { num: options.num || 10 }
300
+ );
301
+ return response.docs || [];
302
+ }
303
+ /**
304
+ * Get timeline for followed social media
305
+ *
306
+ * Returns recent content from social media accounts.
307
+ *
308
+ * @param options.num - Number of items to return
309
+ */
310
+ async socialMedia(options = {}) {
311
+ const response = await this.client.post(
312
+ "/v1/tools/timeline/social-media",
313
+ { num: options.num || 10 }
314
+ );
315
+ return response.docs || [];
316
+ }
317
+ };
318
+
319
+ // src/kb.ts
320
+ var KBModule = class {
321
+ constructor(client) {
322
+ this.client = client;
323
+ }
324
+ /**
325
+ * Search user's knowledge base
326
+ *
327
+ * Performs semantic search across documents the user has uploaded.
328
+ *
329
+ * @param query - Search query string
330
+ * @param options - Search options
331
+ *
332
+ * @example
333
+ * ```typescript
334
+ * const results = await client.kb.search('quarterly revenue', { num: 5 });
335
+ * results.forEach(chunk => console.log(chunk.content));
336
+ * ```
337
+ */
338
+ async search(query, options = {}) {
339
+ const response = await this.client.post(
340
+ "/v1/tools/kb/search",
341
+ {
342
+ query,
343
+ folder_ids: options.folderIds,
344
+ doc_ids: options.docIds,
345
+ start_date: options.startDate,
346
+ end_date: options.endDate,
347
+ num: options.num || 10
348
+ }
349
+ );
350
+ return response.chunks || [];
351
+ }
352
+ };
353
+
354
+ // src/docs.ts
355
+ var DocsModule = class {
356
+ constructor(client) {
357
+ this.client = client;
358
+ }
359
+ /**
360
+ * Get document content and metadata
361
+ *
362
+ * @param docId - Document ID
363
+ */
364
+ async get(docId) {
365
+ return this.client.get(`/v1/docs/${docId}`);
366
+ }
367
+ /**
368
+ * Get document summary
369
+ *
370
+ * @param docId - Document ID
371
+ */
372
+ async summary(docId) {
373
+ return this.client.get(`/v1/docs/${docId}/summary`);
374
+ }
375
+ /**
376
+ * Get raw document content
377
+ *
378
+ * @param docId - Document ID
379
+ */
380
+ async rawContent(docId) {
381
+ return this.client.get(`/v1/docs/${docId}/raw-content`);
382
+ }
383
+ /**
384
+ * List documents with filters
385
+ *
386
+ * @param options - Filter options
387
+ */
388
+ async list(options = {}) {
389
+ const response = await this.client.post("/v1/docs", {
390
+ symbols: options.symbols,
391
+ categories: options.categories,
392
+ start_date: options.startDate,
393
+ end_date: options.endDate,
394
+ page_num: options.page || 1,
395
+ page_size: options.pageSize || 20
396
+ });
397
+ return {
398
+ items: response.docs || [],
399
+ total: response.total || 0,
400
+ page: response.page_num || 1,
401
+ pageSize: response.page_size || 20
402
+ };
403
+ }
404
+ /**
405
+ * Search document chunks semantically
406
+ *
407
+ * @param query - Search query string
408
+ * @param options - Search options
409
+ */
410
+ async searchChunks(query, options = {}) {
411
+ const response = await this.client.post("/v1/search/chunks", {
412
+ query,
413
+ symbols: options.symbols,
414
+ categories: options.categories,
415
+ start_date: options.startDate,
416
+ end_date: options.endDate,
417
+ num: options.num || 10
418
+ });
419
+ return response.chunks || [];
420
+ }
421
+ };
422
+
423
+ // src/types.ts
424
+ var ReportifyError = class extends Error {
425
+ statusCode;
426
+ constructor(message, statusCode) {
427
+ super(message);
428
+ this.name = "ReportifyError";
429
+ this.statusCode = statusCode;
430
+ }
431
+ };
432
+ var AuthenticationError = class extends ReportifyError {
433
+ constructor(message = "Invalid or missing API key") {
434
+ super(message, 401);
435
+ this.name = "AuthenticationError";
436
+ }
437
+ };
438
+ var RateLimitError = class extends ReportifyError {
439
+ constructor(message = "Rate limit exceeded") {
440
+ super(message, 429);
441
+ this.name = "RateLimitError";
442
+ }
443
+ };
444
+ var NotFoundError = class extends ReportifyError {
445
+ constructor(message = "Resource not found") {
446
+ super(message, 404);
447
+ this.name = "NotFoundError";
448
+ }
449
+ };
450
+ var APIError = class extends ReportifyError {
451
+ constructor(message, statusCode) {
452
+ super(message, statusCode);
453
+ this.name = "APIError";
454
+ }
455
+ };
456
+
457
+ // src/client.ts
458
+ var DEFAULT_BASE_URL = "https://api.reportify.cn";
459
+ var DEFAULT_TIMEOUT = 3e4;
460
+ var Reportify = class {
461
+ apiKey;
462
+ baseUrl;
463
+ timeout;
464
+ // Sub-modules
465
+ stock;
466
+ timeline;
467
+ kb;
468
+ docs;
469
+ constructor(config) {
470
+ if (!config.apiKey) {
471
+ throw new AuthenticationError("API key is required");
472
+ }
473
+ this.apiKey = config.apiKey;
474
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
475
+ this.timeout = config.timeout || DEFAULT_TIMEOUT;
476
+ this.stock = new StockModule(this);
477
+ this.timeline = new TimelineModule(this);
478
+ this.kb = new KBModule(this);
479
+ this.docs = new DocsModule(this);
480
+ }
481
+ /**
482
+ * Make an HTTP request to the API
483
+ */
484
+ async request(method, path, options = {}) {
485
+ const url = new URL(path, this.baseUrl);
486
+ if (options.params) {
487
+ Object.entries(options.params).forEach(([key, value]) => {
488
+ if (value !== void 0 && value !== null) {
489
+ url.searchParams.set(key, String(value));
490
+ }
491
+ });
492
+ }
493
+ const controller = new AbortController();
494
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
495
+ try {
496
+ const response = await fetch(url.toString(), {
497
+ method,
498
+ headers: {
499
+ Authorization: `Bearer ${this.apiKey}`,
500
+ "Content-Type": "application/json",
501
+ "User-Agent": "reportify-sdk-js/0.1.0"
502
+ },
503
+ body: options.body ? JSON.stringify(options.body) : void 0,
504
+ signal: controller.signal
505
+ });
506
+ clearTimeout(timeoutId);
507
+ if (response.status === 401) {
508
+ throw new AuthenticationError();
509
+ }
510
+ if (response.status === 429) {
511
+ throw new RateLimitError();
512
+ }
513
+ if (response.status === 404) {
514
+ throw new NotFoundError();
515
+ }
516
+ if (!response.ok) {
517
+ let errorMessage = response.statusText;
518
+ try {
519
+ const errorData = await response.json();
520
+ errorMessage = errorData.detail || errorData.message || errorMessage;
521
+ } catch {
522
+ }
523
+ throw new APIError(errorMessage, response.status);
524
+ }
525
+ return response.json();
526
+ } catch (error) {
527
+ clearTimeout(timeoutId);
528
+ if (error instanceof Error && error.name === "AbortError") {
529
+ throw new APIError("Request timeout", 408);
530
+ }
531
+ throw error;
532
+ }
533
+ }
534
+ /**
535
+ * Make a GET request
536
+ */
537
+ async get(path, params) {
538
+ return this.request("GET", path, { params });
539
+ }
540
+ /**
541
+ * Make a POST request
542
+ */
543
+ async post(path, body) {
544
+ return this.request("POST", path, { body });
545
+ }
546
+ // ===========================================================================
547
+ // Search Methods
548
+ // ===========================================================================
549
+ /**
550
+ * Search documents across all categories
551
+ *
552
+ * @param query - Search query string
553
+ * @param options - Search options
554
+ * @returns List of matching documents
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * const docs = await client.search('Tesla earnings', { num: 10 });
559
+ * docs.forEach(doc => console.log(doc.title));
560
+ * ```
561
+ */
562
+ async search(query, options = {}) {
563
+ const response = await this.post("/v2/search", {
564
+ query,
565
+ num: options.num || 10,
566
+ categories: options.categories,
567
+ symbols: options.symbols,
568
+ start_date: options.startDate,
569
+ end_date: options.endDate
570
+ });
571
+ return response.docs || [];
572
+ }
573
+ /**
574
+ * Search news articles
575
+ */
576
+ async searchNews(query, options = {}) {
577
+ const response = await this.post("/v2/search/news", {
578
+ query,
579
+ num: options.num || 10,
580
+ symbols: options.symbols,
581
+ start_date: options.startDate,
582
+ end_date: options.endDate
583
+ });
584
+ return response.docs || [];
585
+ }
586
+ /**
587
+ * Search research reports
588
+ */
589
+ async searchReports(query, options = {}) {
590
+ const response = await this.post("/v2/search/reports", {
591
+ query,
592
+ num: options.num || 10,
593
+ symbols: options.symbols,
594
+ start_date: options.startDate,
595
+ end_date: options.endDate
596
+ });
597
+ return response.docs || [];
598
+ }
599
+ /**
600
+ * Search company filings
601
+ */
602
+ async searchFilings(query, options = {}) {
603
+ const response = await this.post("/v2/search/filings", {
604
+ query,
605
+ num: options.num || 10,
606
+ symbols: options.symbols,
607
+ start_date: options.startDate,
608
+ end_date: options.endDate
609
+ });
610
+ return response.docs || [];
611
+ }
612
+ /**
613
+ * Search earnings call transcripts
614
+ */
615
+ async searchTranscripts(query, options = {}) {
616
+ const response = await this.post("/v2/search/conference-calls", {
617
+ query,
618
+ num: options.num || 10,
619
+ symbols: options.symbols,
620
+ start_date: options.startDate,
621
+ end_date: options.endDate
622
+ });
623
+ return response.docs || [];
624
+ }
625
+ };
626
+ export {
627
+ APIError,
628
+ AuthenticationError,
629
+ DocsModule,
630
+ KBModule,
631
+ NotFoundError,
632
+ RateLimitError,
633
+ Reportify,
634
+ ReportifyError,
635
+ StockModule,
636
+ TimelineModule
637
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "reportify-sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for Reportify API - Financial data and document search",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
23
+ "lint": "eslint src/",
24
+ "test": "vitest run",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "reportify",
29
+ "finance",
30
+ "stock",
31
+ "api",
32
+ "sdk",
33
+ "financial-data"
34
+ ],
35
+ "author": "Reportify <support@reportify.cn>",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/reportify/reportify-sdk-js"
40
+ },
41
+ "homepage": "https://reportify.cn",
42
+ "bugs": {
43
+ "url": "https://github.com/reportify/reportify-sdk-js/issues"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "dependencies": {},
49
+ "devDependencies": {
50
+ "@types/node": "^20.10.0",
51
+ "tsup": "^8.0.0",
52
+ "typescript": "^5.3.0",
53
+ "vitest": "^1.0.0"
54
+ }
55
+ }