autoscholar-cli 1.0.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.
@@ -0,0 +1,307 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.searchOpenAlex = searchOpenAlex;
7
+ exports.searchArxiv = searchArxiv;
8
+ exports.searchCrossRef = searchCrossRef;
9
+ exports.searchGoogleScholar = searchGoogleScholar;
10
+ exports.multiSourceSearch = multiSourceSearch;
11
+ exports.getOpenAlexReferences = getOpenAlexReferences;
12
+ const axios_1 = __importDefault(require("axios"));
13
+ const xml2js_1 = require("xml2js");
14
+ async function searchOpenAlex(query, limit = 25) {
15
+ try {
16
+ const response = await axios_1.default.get('https://api.openalex.org/works', {
17
+ params: {
18
+ search: query,
19
+ per_page: Math.min(limit, 50),
20
+ mailto: 'autoscholar@research.ai',
21
+ },
22
+ timeout: 20000,
23
+ });
24
+ return (response.data.results || []).map((w) => {
25
+ const authors = (w.authorships || []).map((a) => a.author?.display_name || 'Unknown');
26
+ const year = w.publication_year || null;
27
+ const title = w.title || 'Untitled';
28
+ const citeKey = buildCiteKey(authors[0] || 'unknown', year);
29
+ let abstract = '';
30
+ if (w.abstract_inverted_index) {
31
+ const entries = Object.entries(w.abstract_inverted_index);
32
+ const words = [];
33
+ for (const [word, positions] of entries) {
34
+ for (const pos of positions) {
35
+ words.push([pos, word]);
36
+ }
37
+ }
38
+ words.sort((a, b) => a[0] - b[0]);
39
+ abstract = words.map((w) => w[1]).join(' ');
40
+ }
41
+ return {
42
+ title,
43
+ authors,
44
+ year,
45
+ abstract,
46
+ doi: w.doi?.replace('https://doi.org/', '') || null,
47
+ arxivId: null,
48
+ venue: w.primary_location?.source?.display_name || '',
49
+ citationCount: w.cited_by_count || 0,
50
+ pdfUrl: w.open_access?.oa_url || null,
51
+ source: 'openalex',
52
+ bibtex: buildBibtex({ title, authors, year, doi: w.doi?.replace('https://doi.org/', ''), venue: w.primary_location?.source?.display_name || '', citeKey }),
53
+ citeKey,
54
+ };
55
+ });
56
+ }
57
+ catch (err) {
58
+ return [];
59
+ }
60
+ }
61
+ async function searchArxiv(query, limit = 15, category) {
62
+ try {
63
+ let searchQuery = query;
64
+ if (category) {
65
+ searchQuery = `cat:${category} AND all:${query}`;
66
+ }
67
+ const response = await axios_1.default.get('http://export.arxiv.org/api/query', {
68
+ params: {
69
+ search_query: `all:${searchQuery}`,
70
+ max_results: Math.min(limit, 30),
71
+ sortBy: 'relevance',
72
+ },
73
+ timeout: 20000,
74
+ });
75
+ return new Promise((resolve) => {
76
+ (0, xml2js_1.parseString)(response.data, (err, result) => {
77
+ if (err || !result?.feed?.entry) {
78
+ resolve([]);
79
+ return;
80
+ }
81
+ const papers = result.feed.entry.map((e) => {
82
+ const title = (e.title?.[0] || 'Untitled').replace(/\n/g, ' ').trim();
83
+ const authors = (e.author || []).map((a) => a.name?.[0] || 'Unknown');
84
+ const published = e.published?.[0] || '';
85
+ const year = published ? new Date(published).getFullYear() : null;
86
+ const arxivId = (e.id?.[0] || '').replace('http://arxiv.org/abs/', '');
87
+ const abstract = (e.summary?.[0] || '').trim();
88
+ const citeKey = buildCiteKey(authors[0] || 'unknown', year);
89
+ const pdfLink = (e.link || []).find((l) => l.$.title === 'pdf');
90
+ const pdfUrl = pdfLink?.$.href || null;
91
+ return {
92
+ title,
93
+ authors,
94
+ year,
95
+ abstract,
96
+ doi: null,
97
+ arxivId,
98
+ venue: 'arXiv',
99
+ citationCount: 0,
100
+ pdfUrl,
101
+ source: 'arxiv',
102
+ bibtex: buildBibtex({ title, authors, year, doi: null, venue: 'arXiv', citeKey, arxivId }),
103
+ citeKey,
104
+ };
105
+ });
106
+ resolve(papers);
107
+ });
108
+ });
109
+ }
110
+ catch {
111
+ return [];
112
+ }
113
+ }
114
+ async function searchCrossRef(query, limit = 15) {
115
+ try {
116
+ const response = await axios_1.default.get('https://api.crossref.org/works', {
117
+ params: {
118
+ query,
119
+ rows: Math.min(limit, 30),
120
+ mailto: 'autoscholar@research.ai',
121
+ },
122
+ timeout: 20000,
123
+ });
124
+ return (response.data.message?.items || []).map((item) => {
125
+ const title = (item.title || ['Untitled'])[0];
126
+ const authors = (item.author || []).map((a) => `${a.given || ''} ${a.family || ''}`.trim());
127
+ const year = item.published?.['date-parts']?.[0]?.[0] || null;
128
+ const doi = item.DOI || null;
129
+ const venue = item['container-title']?.[0] || '';
130
+ const citeKey = buildCiteKey(authors[0] || 'unknown', year);
131
+ return {
132
+ title,
133
+ authors,
134
+ year,
135
+ abstract: item.abstract || '',
136
+ doi,
137
+ arxivId: null,
138
+ venue,
139
+ citationCount: item['is-referenced-by-count'] || 0,
140
+ pdfUrl: item.link?.[0]?.URL || null,
141
+ source: 'crossref',
142
+ bibtex: buildBibtex({ title, authors, year, doi, venue, citeKey }),
143
+ citeKey,
144
+ };
145
+ });
146
+ }
147
+ catch {
148
+ return [];
149
+ }
150
+ }
151
+ async function searchGoogleScholar(query, apiKey, limit = 10) {
152
+ try {
153
+ const response = await axios_1.default.get('https://serpapi.com/search', {
154
+ params: {
155
+ engine: 'google_scholar',
156
+ q: query,
157
+ num: Math.min(limit, 20),
158
+ api_key: apiKey,
159
+ },
160
+ timeout: 20000,
161
+ });
162
+ return (response.data.organic_results || []).map((r) => {
163
+ const title = r.title || 'Untitled';
164
+ const authors = r.publication_info?.authors?.map((a) => a.name) || ['Unknown'];
165
+ const yearMatch = r.publication_info?.summary?.match(/(\d{4})/);
166
+ const year = yearMatch ? parseInt(yearMatch[1]) : null;
167
+ const citeKey = buildCiteKey(authors[0] || 'unknown', year);
168
+ return {
169
+ title,
170
+ authors,
171
+ year,
172
+ abstract: r.snippet || '',
173
+ doi: null,
174
+ arxivId: null,
175
+ venue: r.publication_info?.summary || '',
176
+ citationCount: r.inline_links?.cited_by?.total || 0,
177
+ pdfUrl: r.resources?.[0]?.link || null,
178
+ source: 'google_scholar',
179
+ bibtex: buildBibtex({ title, authors, year, doi: null, venue: '', citeKey }),
180
+ citeKey,
181
+ };
182
+ });
183
+ }
184
+ catch {
185
+ return [];
186
+ }
187
+ }
188
+ async function multiSourceSearch(query, options) {
189
+ const limit = options?.limit || 25;
190
+ const sources = options?.sources || ['openalex', 'arxiv', 'crossref'];
191
+ const sourcesUsed = [];
192
+ const sourcesFailed = [];
193
+ let allPapers = [];
194
+ const searches = [];
195
+ if (sources.includes('openalex')) {
196
+ searches.push(searchOpenAlex(query, limit)
197
+ .then((p) => { sourcesUsed.push('openalex'); return p; })
198
+ .catch(() => { sourcesFailed.push('openalex'); return []; }));
199
+ }
200
+ if (sources.includes('arxiv')) {
201
+ searches.push(searchArxiv(query, limit, options?.arxivCategory)
202
+ .then((p) => { sourcesUsed.push('arxiv'); return p; })
203
+ .catch(() => { sourcesFailed.push('arxiv'); return []; }));
204
+ }
205
+ if (sources.includes('crossref')) {
206
+ searches.push(searchCrossRef(query, limit)
207
+ .then((p) => { sourcesUsed.push('crossref'); return p; })
208
+ .catch(() => { sourcesFailed.push('crossref'); return []; }));
209
+ }
210
+ if (sources.includes('google_scholar') && options?.serpApiKey) {
211
+ searches.push(searchGoogleScholar(query, options.serpApiKey, limit)
212
+ .then((p) => { sourcesUsed.push('google_scholar'); return p; })
213
+ .catch(() => { sourcesFailed.push('google_scholar'); return []; }));
214
+ }
215
+ const results = await Promise.all(searches);
216
+ for (const papers of results) {
217
+ allPapers.push(...papers);
218
+ }
219
+ const seen = new Set();
220
+ const deduped = [];
221
+ for (const p of allPapers) {
222
+ const key = p.doi || p.title.toLowerCase().substring(0, 60);
223
+ if (!seen.has(key)) {
224
+ seen.add(key);
225
+ deduped.push(p);
226
+ }
227
+ }
228
+ const usedKeys = new Set();
229
+ for (const p of deduped) {
230
+ let key = p.citeKey;
231
+ let suffix = 'a';
232
+ while (usedKeys.has(key)) {
233
+ key = `${p.citeKey}${suffix}`;
234
+ suffix = String.fromCharCode(suffix.charCodeAt(0) + 1);
235
+ }
236
+ usedKeys.add(key);
237
+ p.citeKey = key;
238
+ p.bibtex = buildBibtex({
239
+ title: p.title,
240
+ authors: p.authors,
241
+ year: p.year,
242
+ doi: p.doi,
243
+ venue: p.venue,
244
+ citeKey: key,
245
+ arxivId: p.arxivId,
246
+ });
247
+ }
248
+ deduped.sort((a, b) => b.citationCount - a.citationCount);
249
+ const bibtexBlock = deduped.map((p) => p.bibtex).join('\n\n');
250
+ return { papers: deduped, bibtexBlock, sourcesUsed, sourcesFailed };
251
+ }
252
+ async function getOpenAlexReferences(doi, limit = 15) {
253
+ try {
254
+ const response = await axios_1.default.get('https://api.openalex.org/works', {
255
+ params: {
256
+ filter: `cites:https://doi.org/${doi}`,
257
+ per_page: limit,
258
+ mailto: 'autoscholar@research.ai',
259
+ },
260
+ timeout: 15000,
261
+ });
262
+ return (response.data.results || []).slice(0, limit).map((w) => {
263
+ const authors = (w.authorships || []).map((a) => a.author?.display_name || 'Unknown');
264
+ const year = w.publication_year || null;
265
+ const title = w.title || 'Untitled';
266
+ const citeKey = buildCiteKey(authors[0] || 'unknown', year);
267
+ return {
268
+ title,
269
+ authors,
270
+ year,
271
+ abstract: '',
272
+ doi: w.doi?.replace('https://doi.org/', '') || null,
273
+ arxivId: null,
274
+ venue: w.primary_location?.source?.display_name || '',
275
+ citationCount: w.cited_by_count || 0,
276
+ pdfUrl: null,
277
+ source: 'openalex',
278
+ bibtex: buildBibtex({ title, authors, year, doi: w.doi?.replace('https://doi.org/', ''), venue: '', citeKey }),
279
+ citeKey,
280
+ };
281
+ });
282
+ }
283
+ catch {
284
+ return [];
285
+ }
286
+ }
287
+ function buildCiteKey(firstAuthor, year) {
288
+ const lastName = firstAuthor.split(' ').pop()?.toLowerCase().replace(/[^a-z]/g, '') || 'unknown';
289
+ return `${lastName}${year || 'nd'}`;
290
+ }
291
+ function buildBibtex(p) {
292
+ const type = p.arxivId ? 'misc' : 'article';
293
+ const authorStr = p.authors.join(' and ');
294
+ let bib = `@${type}{${p.citeKey},\n`;
295
+ bib += ` author = {${authorStr}},\n`;
296
+ bib += ` title = {${p.title}},\n`;
297
+ if (p.venue)
298
+ bib += ` journal = {${p.venue}},\n`;
299
+ if (p.year)
300
+ bib += ` year = {${p.year}},\n`;
301
+ if (p.doi)
302
+ bib += ` doi = {${p.doi}},\n`;
303
+ if (p.arxivId)
304
+ bib += ` eprint = {${p.arxivId}},\n archivePrefix = {arXiv},\n`;
305
+ bib += `}`;
306
+ return bib;
307
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EODHDClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const EODHD_BASE = 'https://eodhd.com/api';
9
+ class EODHDClient {
10
+ constructor(apiKey) {
11
+ this.apiKey = apiKey;
12
+ }
13
+ normalizeTicker(ticker) {
14
+ if (!ticker.includes('.')) {
15
+ return `${ticker}.US`;
16
+ }
17
+ return ticker;
18
+ }
19
+ async getEOD(ticker, fromDate, toDate, period = 'd') {
20
+ const normalized = this.normalizeTicker(ticker);
21
+ const params = {
22
+ api_token: this.apiKey,
23
+ fmt: 'json',
24
+ period,
25
+ };
26
+ if (fromDate)
27
+ params.from = fromDate;
28
+ if (toDate)
29
+ params.to = toDate;
30
+ const response = await axios_1.default.get(`${EODHD_BASE}/eod/${normalized}`, {
31
+ params,
32
+ timeout: 30000,
33
+ });
34
+ return response.data;
35
+ }
36
+ async getIntraday(ticker, interval = '5m', fromDate, toDate) {
37
+ const normalized = this.normalizeTicker(ticker);
38
+ const params = {
39
+ api_token: this.apiKey,
40
+ fmt: 'json',
41
+ interval,
42
+ };
43
+ if (fromDate)
44
+ params.from = this.toUnixTimestamp(fromDate);
45
+ if (toDate)
46
+ params.to = this.toUnixTimestamp(toDate);
47
+ const response = await axios_1.default.get(`${EODHD_BASE}/intraday/${normalized}`, {
48
+ params,
49
+ timeout: 30000,
50
+ });
51
+ return response.data;
52
+ }
53
+ async getOptions(ticker) {
54
+ const normalized = this.normalizeTicker(ticker);
55
+ const response = await axios_1.default.get(`${EODHD_BASE}/options/${normalized}`, {
56
+ params: {
57
+ api_token: this.apiKey,
58
+ fmt: 'json',
59
+ },
60
+ timeout: 30000,
61
+ });
62
+ return response.data;
63
+ }
64
+ async getLiveQuote(ticker) {
65
+ const normalized = this.normalizeTicker(ticker);
66
+ const response = await axios_1.default.get(`${EODHD_BASE}/real-time/${normalized}`, {
67
+ params: {
68
+ api_token: this.apiKey,
69
+ fmt: 'json',
70
+ },
71
+ timeout: 10000,
72
+ });
73
+ return response.data;
74
+ }
75
+ async getExchangeList() {
76
+ const response = await axios_1.default.get(`${EODHD_BASE}/exchanges-list`, {
77
+ params: {
78
+ api_token: this.apiKey,
79
+ fmt: 'json',
80
+ },
81
+ timeout: 10000,
82
+ });
83
+ return response.data;
84
+ }
85
+ toUnixTimestamp(dateStr) {
86
+ const d = new Date(dateStr);
87
+ return Math.floor(d.getTime() / 1000);
88
+ }
89
+ }
90
+ exports.EODHDClient = EODHDClient;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FirecrawlClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const FIRECRAWL_BASE = 'https://api.firecrawl.dev/v1';
9
+ class FirecrawlClient {
10
+ constructor(apiKey) {
11
+ this.apiKey = apiKey;
12
+ }
13
+ get headers() {
14
+ return {
15
+ 'Content-Type': 'application/json',
16
+ Authorization: `Bearer ${this.apiKey}`,
17
+ };
18
+ }
19
+ async scrape(url, options) {
20
+ const response = await axios_1.default.post(`${FIRECRAWL_BASE}/scrape`, {
21
+ url,
22
+ formats: options?.formats || ['markdown'],
23
+ onlyMainContent: options?.onlyMainContent ?? true,
24
+ waitFor: options?.waitFor || 0,
25
+ timeout: options?.timeout || 30000,
26
+ }, { headers: this.headers, timeout: 90000 });
27
+ return {
28
+ url: response.data.data?.url || url,
29
+ markdown: response.data.data?.markdown || '',
30
+ metadata: response.data.data?.metadata || {},
31
+ };
32
+ }
33
+ async search(query, limit = 10) {
34
+ const response = await axios_1.default.post(`${FIRECRAWL_BASE}/search`, {
35
+ query,
36
+ limit,
37
+ scrapeOptions: { formats: ['markdown'] },
38
+ }, { headers: this.headers, timeout: 30000 });
39
+ return (response.data.data || []).map((r) => ({
40
+ url: r.url || '',
41
+ title: r.metadata?.title || r.title || '',
42
+ description: r.metadata?.description || r.description || '',
43
+ markdown: r.markdown || '',
44
+ }));
45
+ }
46
+ async crawl(url, options) {
47
+ const response = await axios_1.default.post(`${FIRECRAWL_BASE}/crawl`, {
48
+ url,
49
+ limit: options?.limit || 10,
50
+ maxDepth: options?.maxDepth || 2,
51
+ includePaths: options?.includePaths,
52
+ excludePaths: options?.excludePaths,
53
+ scrapeOptions: { formats: ['markdown'] },
54
+ }, { headers: this.headers, timeout: 30000 });
55
+ const jobId = response.data.id;
56
+ if (!jobId)
57
+ return { id: '', status: 'failed', data: [] };
58
+ return this.pollJob('crawl', jobId);
59
+ }
60
+ async extract(urls, prompt, schema) {
61
+ const response = await axios_1.default.post(`${FIRECRAWL_BASE}/extract`, {
62
+ urls,
63
+ prompt,
64
+ schema,
65
+ }, { headers: this.headers, timeout: 60000 });
66
+ return response.data;
67
+ }
68
+ async mapSite(url) {
69
+ const response = await axios_1.default.post(`${FIRECRAWL_BASE}/map`, { url }, { headers: this.headers, timeout: 30000 });
70
+ return response.data.links || [];
71
+ }
72
+ async pollJob(type, jobId, maxWaitMs = 120000) {
73
+ const start = Date.now();
74
+ while (Date.now() - start < maxWaitMs) {
75
+ await new Promise((r) => setTimeout(r, 3000));
76
+ try {
77
+ const resp = await axios_1.default.get(`${FIRECRAWL_BASE}/${type}/${jobId}`, {
78
+ headers: this.headers,
79
+ timeout: 10000,
80
+ });
81
+ if (resp.data.status === 'completed') {
82
+ return resp.data;
83
+ }
84
+ if (resp.data.status === 'failed' || resp.data.status === 'cancelled') {
85
+ return { id: jobId, status: resp.data.status, data: [] };
86
+ }
87
+ }
88
+ catch {
89
+ }
90
+ }
91
+ return { id: jobId, status: 'timeout', data: [] };
92
+ }
93
+ }
94
+ exports.FirecrawlClient = FirecrawlClient;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FMPClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const FMP_STABLE_URL = 'https://financialmodelingprep.com/stable';
9
+ class FMPClient {
10
+ constructor(apiKey) {
11
+ this.apiKey = apiKey;
12
+ }
13
+ async request(endpoint, params = {}) {
14
+ const response = await axios_1.default.get(`${FMP_STABLE_URL}/${endpoint}`, {
15
+ params: { ...params, apikey: this.apiKey },
16
+ timeout: 60000,
17
+ });
18
+ return response.data;
19
+ }
20
+ async getQuote(symbol) {
21
+ return this.request('quote', { symbol });
22
+ }
23
+ async getCompanyProfile(symbol) {
24
+ return this.request('profile', { symbol });
25
+ }
26
+ async getIncomeStatement(symbol, period = 'annual', limit = 10) {
27
+ return this.request('income-statement', { symbol, period, limit });
28
+ }
29
+ async getBalanceSheet(symbol, period = 'annual', limit = 10) {
30
+ return this.request('balance-sheet-statement', { symbol, period, limit });
31
+ }
32
+ async getCashFlow(symbol, period = 'annual', limit = 10) {
33
+ return this.request('cash-flow-statement', { symbol, period, limit });
34
+ }
35
+ async getKeyMetrics(symbol, period = 'annual', limit = 10) {
36
+ return this.request('key-metrics', { symbol, period, limit });
37
+ }
38
+ async getFinancialRatios(symbol, period = 'annual', limit = 10) {
39
+ return this.request('ratios', { symbol, period, limit });
40
+ }
41
+ async getHistoricalPrices(symbol, fromDate, toDate) {
42
+ const params = { symbol };
43
+ if (fromDate)
44
+ params.from = fromDate;
45
+ if (toDate)
46
+ params.to = toDate;
47
+ return this.request('historical-price-eod/full', params);
48
+ }
49
+ async getStockList() {
50
+ return this.request('stock-list');
51
+ }
52
+ async getMarketGainers() {
53
+ return this.request('stock-market/gainers');
54
+ }
55
+ async getMarketLosers() {
56
+ return this.request('stock-market/losers');
57
+ }
58
+ async getRSI(symbol, period = 'daily', timePeriod = 14) {
59
+ return this.request('technical-indicator/rsi', { symbol, period, timePeriod });
60
+ }
61
+ async getMACD(symbol, period = 'daily') {
62
+ return this.request('technical-indicator/macd', { symbol, period });
63
+ }
64
+ async getEMA(symbol, period = 'daily', timePeriod = 20) {
65
+ return this.request('technical-indicator/ema', { symbol, period, timePeriod });
66
+ }
67
+ async getSMA(symbol, period = 'daily', timePeriod = 20) {
68
+ return this.request('technical-indicator/sma', { symbol, period, timePeriod });
69
+ }
70
+ async getSECFilings(symbol, type, limit = 10) {
71
+ const params = { symbol, limit };
72
+ if (type)
73
+ params.type = type;
74
+ return this.request('sec-filings', params);
75
+ }
76
+ async getEconomicCalendar(from, to) {
77
+ const params = {};
78
+ if (from)
79
+ params.from = from;
80
+ if (to)
81
+ params.to = to;
82
+ return this.request('economic-calendar', params);
83
+ }
84
+ async getTreasuryRates() {
85
+ return this.request('treasury');
86
+ }
87
+ async search(query, limit = 10) {
88
+ return this.request('search', { query, limit });
89
+ }
90
+ async getStockNews(symbol, limit = 50) {
91
+ return this.request('stock-news', { tickers: symbol, limit });
92
+ }
93
+ async getESGScore(symbol) {
94
+ return this.request('esg-environmental-social-governance-data', { symbol });
95
+ }
96
+ async getInsiderTrading(symbol, limit = 100) {
97
+ return this.request('insider-trading', { symbol, limit });
98
+ }
99
+ async getInstitutionalHolders(symbol) {
100
+ return this.request('institutional-holder', { symbol });
101
+ }
102
+ async getForexQuote(pair) {
103
+ return this.request('quote', { symbol: pair });
104
+ }
105
+ async getCommodityPrices() {
106
+ return this.request('commodities-list');
107
+ }
108
+ async getDCF(symbol) {
109
+ return this.request('discounted-cash-flow', { symbol });
110
+ }
111
+ async getEnterpriseValue(symbol, period = 'annual', limit = 10) {
112
+ return this.request('enterprise-values', { symbol, period, limit });
113
+ }
114
+ }
115
+ exports.FMPClient = FMPClient;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FREDClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const FRED_BASE = 'https://api.stlouisfed.org/fred';
9
+ class FREDClient {
10
+ constructor(apiKey) {
11
+ this.apiKey = apiKey;
12
+ }
13
+ async request(endpoint, params = {}) {
14
+ const response = await axios_1.default.get(`${FRED_BASE}/${endpoint}`, {
15
+ params: {
16
+ ...params,
17
+ api_key: this.apiKey,
18
+ file_type: 'json',
19
+ },
20
+ timeout: 30000,
21
+ });
22
+ return response.data;
23
+ }
24
+ async getSeries(seriesId) {
25
+ const data = await this.request('series', { series_id: seriesId });
26
+ return data.seriess[0];
27
+ }
28
+ async getObservations(seriesId, options) {
29
+ const params = { series_id: seriesId };
30
+ if (options?.observationStart)
31
+ params.observation_start = options.observationStart;
32
+ if (options?.observationEnd)
33
+ params.observation_end = options.observationEnd;
34
+ if (options?.units)
35
+ params.units = options.units;
36
+ if (options?.frequency)
37
+ params.frequency = options.frequency;
38
+ if (options?.aggregationMethod)
39
+ params.aggregation_method = options.aggregationMethod;
40
+ const data = await this.request('series/observations', params);
41
+ return data.observations;
42
+ }
43
+ async searchSeries(searchText, limit = 20) {
44
+ const data = await this.request('series/search', {
45
+ search_text: searchText,
46
+ limit,
47
+ });
48
+ return data.seriess || [];
49
+ }
50
+ async getCategory(categoryId) {
51
+ return this.request('category', { category_id: categoryId });
52
+ }
53
+ async getCategorySeries(categoryId, limit = 20) {
54
+ const data = await this.request('category/series', {
55
+ category_id: categoryId,
56
+ limit,
57
+ });
58
+ return data.seriess || [];
59
+ }
60
+ async getRelatedTags(seriesId) {
61
+ return this.request('series/tags', { series_id: seriesId });
62
+ }
63
+ async getGDP(start, end) {
64
+ return this.getObservations('GDP', { observationStart: start, observationEnd: end });
65
+ }
66
+ async getCPI(start, end) {
67
+ return this.getObservations('CPIAUCSL', { observationStart: start, observationEnd: end });
68
+ }
69
+ async getUnemploymentRate(start, end) {
70
+ return this.getObservations('UNRATE', { observationStart: start, observationEnd: end });
71
+ }
72
+ async getFedFundsRate(start, end) {
73
+ return this.getObservations('FEDFUNDS', { observationStart: start, observationEnd: end });
74
+ }
75
+ async getVIX(start, end) {
76
+ return this.getObservations('VIXCLS', { observationStart: start, observationEnd: end });
77
+ }
78
+ async getSP500(start, end) {
79
+ return this.getObservations('SP500', { observationStart: start, observationEnd: end });
80
+ }
81
+ }
82
+ exports.FREDClient = FREDClient;