fi-pool-server 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/README.md +26 -0
- package/dist/db/index.d.ts +18 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +58 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +11 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +42 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1101 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +149 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/services/analysis.d.ts +62 -0
- package/dist/services/analysis.d.ts.map +1 -0
- package/dist/services/analysis.js +74 -0
- package/dist/services/analysis.js.map +1 -0
- package/dist/services/daily-info.d.ts +150 -0
- package/dist/services/daily-info.d.ts.map +1 -0
- package/dist/services/daily-info.js +293 -0
- package/dist/services/daily-info.js.map +1 -0
- package/dist/services/embedding.d.ts +89 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +227 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/llm.d.ts +64 -0
- package/dist/services/llm.d.ts.map +1 -0
- package/dist/services/llm.js +109 -0
- package/dist/services/llm.js.map +1 -0
- package/dist/services/pipeline.d.ts +161 -0
- package/dist/services/pipeline.d.ts.map +1 -0
- package/dist/services/pipeline.js +844 -0
- package/dist/services/pipeline.js.map +1 -0
- package/dist/services/pool.d.ts +142 -0
- package/dist/services/pool.d.ts.map +1 -0
- package/dist/services/pool.js +208 -0
- package/dist/services/pool.js.map +1 -0
- package/dist/services/sentiment.d.ts +31 -0
- package/dist/services/sentiment.d.ts.map +1 -0
- package/dist/services/sentiment.js +76 -0
- package/dist/services/sentiment.js.map +1 -0
- package/dist/services/session.d.ts +117 -0
- package/dist/services/session.d.ts.map +1 -0
- package/dist/services/session.js +176 -0
- package/dist/services/session.js.map +1 -0
- package/dist/services/stock.d.ts +82 -0
- package/dist/services/stock.d.ts.map +1 -0
- package/dist/services/stock.js +99 -0
- package/dist/services/stock.js.map +1 -0
- package/dist/services/word-count.d.ts +61 -0
- package/dist/services/word-count.d.ts.map +1 -0
- package/dist/services/word-count.js +120 -0
- package/dist/services/word-count.js.map +1 -0
- package/dist/tools/auxiliary.d.ts +93 -0
- package/dist/tools/auxiliary.d.ts.map +1 -0
- package/dist/tools/auxiliary.js +204 -0
- package/dist/tools/auxiliary.js.map +1 -0
- package/dist/tools/command.d.ts +193 -0
- package/dist/tools/command.d.ts.map +1 -0
- package/dist/tools/command.js +263 -0
- package/dist/tools/command.js.map +1 -0
- package/dist/tools/execute.d.ts +109 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +112 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/manager.d.ts +150 -0
- package/dist/tools/manager.d.ts.map +1 -0
- package/dist/tools/manager.js +200 -0
- package/dist/tools/manager.js.map +1 -0
- package/dist/tools/query.d.ts +163 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +190 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/utils/http-client.d.ts +87 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/http-client.js +211 -0
- package/dist/utils/http-client.js.map +1 -0
- package/dist/utils/indicators.d.ts +194 -0
- package/dist/utils/indicators.d.ts.map +1 -0
- package/dist/utils/indicators.js +395 -0
- package/dist/utils/indicators.js.map +1 -0
- package/dist/utils/signals.d.ts +65 -0
- package/dist/utils/signals.d.ts.map +1 -0
- package/dist/utils/signals.js +171 -0
- package/dist/utils/signals.js.map +1 -0
- package/drizzle/0000_equal_marvel_apes.sql +124 -0
- package/drizzle/meta/0000_snapshot.json +858 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +58 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 查询类工具(Query)
|
|
3
|
+
*
|
|
4
|
+
* 封装面向用户的数据查询操作,直接返回数据而不包装在 data 中。
|
|
5
|
+
*
|
|
6
|
+
* @module tools/query
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 列出所有股池,附带每个股池中的股票数量。
|
|
10
|
+
*
|
|
11
|
+
* @returns 股池列表,每个元素包含 pool 全部字段和 stockCount
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const pools = await listPools();
|
|
15
|
+
* pools.forEach(p => console.log(p.name, p.stockCount));
|
|
16
|
+
*/
|
|
17
|
+
export declare function listPools(): Promise<{
|
|
18
|
+
id: number;
|
|
19
|
+
name: string;
|
|
20
|
+
desc: string;
|
|
21
|
+
poolAnalysis: string;
|
|
22
|
+
poolSignal: number;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
stockCount: number;
|
|
26
|
+
}[]>;
|
|
27
|
+
/**
|
|
28
|
+
* 查询指定股池中的所有股票详情。
|
|
29
|
+
*
|
|
30
|
+
* 返回包含股票代码、名称、当前价格以及加入时间的列表。
|
|
31
|
+
*
|
|
32
|
+
* @param poolId - 股池 ID
|
|
33
|
+
* @returns 股池中的股票列表
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const stocks = await getPoolStocks(1);
|
|
37
|
+
* stocks.forEach(s => console.log(s.code, s.name));
|
|
38
|
+
*/
|
|
39
|
+
export declare function getPoolStocks(poolId: number): Promise<{
|
|
40
|
+
code: string;
|
|
41
|
+
name: string;
|
|
42
|
+
currentPrice: number;
|
|
43
|
+
addedAt: string;
|
|
44
|
+
}[]>;
|
|
45
|
+
/**
|
|
46
|
+
* 查询股票基本信息。
|
|
47
|
+
*
|
|
48
|
+
* @param code - 六位股票代码(如 '600519')
|
|
49
|
+
* @returns 股票对象,未找到时返回 null
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const info = await getStockInfo('600519');
|
|
53
|
+
* if (info) console.log(info.name, info.currentPrice);
|
|
54
|
+
*/
|
|
55
|
+
export declare function getStockInfo(code: string): Promise<{
|
|
56
|
+
name: string;
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
code: string;
|
|
59
|
+
currentPrice: number;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* 查询指定股票的日行情数据。
|
|
63
|
+
*
|
|
64
|
+
* 可选的日期范围过滤。
|
|
65
|
+
*
|
|
66
|
+
* @param code - 股票代码
|
|
67
|
+
* @param startDate - 可选起始日期 'yyyy-MM-dd'(含),不指定则不限制起始
|
|
68
|
+
* @param endDate - 可选结束日期 'yyyy-MM-dd'(含),不指定则不限制结束
|
|
69
|
+
* @returns 日行情数据数组(按日期升序)
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const data = await getDailyInfo('600519', '2024-05-01', '2024-06-01');
|
|
73
|
+
*/
|
|
74
|
+
export declare function getDailyInfo(code: string, startDate?: string, endDate?: string): Promise<{
|
|
75
|
+
date: string;
|
|
76
|
+
id: number;
|
|
77
|
+
code: string;
|
|
78
|
+
open: number;
|
|
79
|
+
high: number;
|
|
80
|
+
low: number;
|
|
81
|
+
close: number;
|
|
82
|
+
volume: number;
|
|
83
|
+
}[]>;
|
|
84
|
+
/**
|
|
85
|
+
* 查询指定股票指定日期的客观分析报告。
|
|
86
|
+
*
|
|
87
|
+
* @param code - 股票代码
|
|
88
|
+
* @param date - 报告日期 'yyyy-MM-dd'
|
|
89
|
+
* @param mode - 输出模式:
|
|
90
|
+
* - 'overview':仅返回 id, code, date, summary 等摘要字段
|
|
91
|
+
* - 'full'(默认):返回完整报告字段(含 indicators, signals 等)
|
|
92
|
+
* @returns 分析报告对象,未找到时返回 null
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const report = await getAnalysisReport('600519', '2024-06-01', 'overview');
|
|
96
|
+
*/
|
|
97
|
+
export declare function getAnalysisReport(code: string, date: string, mode?: 'overview' | 'full'): Promise<{
|
|
98
|
+
date: string;
|
|
99
|
+
id: number;
|
|
100
|
+
createdAt: string;
|
|
101
|
+
code: string;
|
|
102
|
+
summary: string;
|
|
103
|
+
indicators: string;
|
|
104
|
+
signals: string;
|
|
105
|
+
} | {
|
|
106
|
+
id: number;
|
|
107
|
+
code: string;
|
|
108
|
+
date: string;
|
|
109
|
+
summary: string;
|
|
110
|
+
createdAt: string;
|
|
111
|
+
} | null>;
|
|
112
|
+
/**
|
|
113
|
+
* 查询指定股票指定日期的最终报告。
|
|
114
|
+
*
|
|
115
|
+
* @param code - 股票代码
|
|
116
|
+
* @param date - 报告日期 'yyyy-MM-dd'
|
|
117
|
+
* @param mode - 输出模式:
|
|
118
|
+
* - 'overview':仅返回 id, code, date, summary, pipelineId 等摘要字段
|
|
119
|
+
* - 'full'(默认):返回完整报告字段(含 fullReport, roleSummary 等)
|
|
120
|
+
* @returns 最终报告对象,未找到时返回 null
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* const report = await getFinalReport('600519', '2024-06-01', 'full');
|
|
124
|
+
*/
|
|
125
|
+
export declare function getFinalReport(code: string, date: string, mode?: 'overview' | 'full'): Promise<{
|
|
126
|
+
date: string;
|
|
127
|
+
id: number;
|
|
128
|
+
createdAt: string;
|
|
129
|
+
code: string;
|
|
130
|
+
summary: string;
|
|
131
|
+
fullReport: string;
|
|
132
|
+
roleSummary: string;
|
|
133
|
+
pipelineId: string;
|
|
134
|
+
} | {
|
|
135
|
+
id: number;
|
|
136
|
+
code: string;
|
|
137
|
+
date: string;
|
|
138
|
+
summary: string;
|
|
139
|
+
pipelineId: string;
|
|
140
|
+
createdAt: string;
|
|
141
|
+
} | null>;
|
|
142
|
+
/**
|
|
143
|
+
* 查看系统运行状态。
|
|
144
|
+
*
|
|
145
|
+
* 收集版本号、数据库大小、股票/股池数量、最新数据时间、
|
|
146
|
+
* LLM 连接状态及服务运行时长等信息。
|
|
147
|
+
*
|
|
148
|
+
* @returns 系统状态对象
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* const status = await getSystemStatus();
|
|
152
|
+
* console.log(status.version, status.llmConnected);
|
|
153
|
+
*/
|
|
154
|
+
export declare function getSystemStatus(): Promise<{
|
|
155
|
+
version: string;
|
|
156
|
+
dbSize: string;
|
|
157
|
+
stocksTracked: number;
|
|
158
|
+
poolsCount: number;
|
|
159
|
+
lastDataUpdate: string;
|
|
160
|
+
llmConnected: boolean;
|
|
161
|
+
uptime: number;
|
|
162
|
+
}>;
|
|
163
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH;;;;;;;;GAQG;AACH,wBAAsB,SAAS;;;;;;;;;KAE9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM;;;;;KAEjD;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM;;;;;GAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;;;;;;;;;KAEpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAU,GAAG,MAAe;;;;;;;;;;;;;;UA0BrG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,UAAU,GAAG,MAAe;;;;;;;;;;;;;;;;UA2BlG;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe;;;;;;;;GAyCpC"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 查询类工具(Query)
|
|
3
|
+
*
|
|
4
|
+
* 封装面向用户的数据查询操作,直接返回数据而不包装在 data 中。
|
|
5
|
+
*
|
|
6
|
+
* @module tools/query
|
|
7
|
+
*/
|
|
8
|
+
import * as poolService from '../services/pool.js';
|
|
9
|
+
import * as stockService from '../services/stock.js';
|
|
10
|
+
import * as dailyInfoService from '../services/daily-info.js';
|
|
11
|
+
import * as llmService from '../services/llm.js';
|
|
12
|
+
import { getDatabase, getDbPath } from '../db/index.js';
|
|
13
|
+
import { dailyAnalysisReport, finalReport, stock, pool } from '../db/schema.js';
|
|
14
|
+
import { eq, and, sql } from 'drizzle-orm';
|
|
15
|
+
import { VERSION } from '../index.js';
|
|
16
|
+
import { existsSync, statSync } from 'fs';
|
|
17
|
+
import { resolve } from 'path';
|
|
18
|
+
/**
|
|
19
|
+
* 列出所有股池,附带每个股池中的股票数量。
|
|
20
|
+
*
|
|
21
|
+
* @returns 股池列表,每个元素包含 pool 全部字段和 stockCount
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const pools = await listPools();
|
|
25
|
+
* pools.forEach(p => console.log(p.name, p.stockCount));
|
|
26
|
+
*/
|
|
27
|
+
export async function listPools() {
|
|
28
|
+
return poolService.listPools();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 查询指定股池中的所有股票详情。
|
|
32
|
+
*
|
|
33
|
+
* 返回包含股票代码、名称、当前价格以及加入时间的列表。
|
|
34
|
+
*
|
|
35
|
+
* @param poolId - 股池 ID
|
|
36
|
+
* @returns 股池中的股票列表
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const stocks = await getPoolStocks(1);
|
|
40
|
+
* stocks.forEach(s => console.log(s.code, s.name));
|
|
41
|
+
*/
|
|
42
|
+
export async function getPoolStocks(poolId) {
|
|
43
|
+
return poolService.getPoolStocks(poolId);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 查询股票基本信息。
|
|
47
|
+
*
|
|
48
|
+
* @param code - 六位股票代码(如 '600519')
|
|
49
|
+
* @returns 股票对象,未找到时返回 null
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const info = await getStockInfo('600519');
|
|
53
|
+
* if (info) console.log(info.name, info.currentPrice);
|
|
54
|
+
*/
|
|
55
|
+
export async function getStockInfo(code) {
|
|
56
|
+
return stockService.getStockByCode(code);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 查询指定股票的日行情数据。
|
|
60
|
+
*
|
|
61
|
+
* 可选的日期范围过滤。
|
|
62
|
+
*
|
|
63
|
+
* @param code - 股票代码
|
|
64
|
+
* @param startDate - 可选起始日期 'yyyy-MM-dd'(含),不指定则不限制起始
|
|
65
|
+
* @param endDate - 可选结束日期 'yyyy-MM-dd'(含),不指定则不限制结束
|
|
66
|
+
* @returns 日行情数据数组(按日期升序)
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* const data = await getDailyInfo('600519', '2024-05-01', '2024-06-01');
|
|
70
|
+
*/
|
|
71
|
+
export async function getDailyInfo(code, startDate, endDate) {
|
|
72
|
+
return dailyInfoService.getDailyInfo(code, startDate, endDate);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 查询指定股票指定日期的客观分析报告。
|
|
76
|
+
*
|
|
77
|
+
* @param code - 股票代码
|
|
78
|
+
* @param date - 报告日期 'yyyy-MM-dd'
|
|
79
|
+
* @param mode - 输出模式:
|
|
80
|
+
* - 'overview':仅返回 id, code, date, summary 等摘要字段
|
|
81
|
+
* - 'full'(默认):返回完整报告字段(含 indicators, signals 等)
|
|
82
|
+
* @returns 分析报告对象,未找到时返回 null
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const report = await getAnalysisReport('600519', '2024-06-01', 'overview');
|
|
86
|
+
*/
|
|
87
|
+
export async function getAnalysisReport(code, date, mode = 'full') {
|
|
88
|
+
const db = getDatabase();
|
|
89
|
+
const row = db
|
|
90
|
+
.select()
|
|
91
|
+
.from(dailyAnalysisReport)
|
|
92
|
+
.where(and(eq(dailyAnalysisReport.code, code), eq(dailyAnalysisReport.date, date)))
|
|
93
|
+
.get();
|
|
94
|
+
if (!row)
|
|
95
|
+
return null;
|
|
96
|
+
if (mode === 'overview') {
|
|
97
|
+
return {
|
|
98
|
+
id: row.id,
|
|
99
|
+
code: row.code,
|
|
100
|
+
date: row.date,
|
|
101
|
+
summary: row.summary,
|
|
102
|
+
createdAt: row.createdAt,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return row;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 查询指定股票指定日期的最终报告。
|
|
109
|
+
*
|
|
110
|
+
* @param code - 股票代码
|
|
111
|
+
* @param date - 报告日期 'yyyy-MM-dd'
|
|
112
|
+
* @param mode - 输出模式:
|
|
113
|
+
* - 'overview':仅返回 id, code, date, summary, pipelineId 等摘要字段
|
|
114
|
+
* - 'full'(默认):返回完整报告字段(含 fullReport, roleSummary 等)
|
|
115
|
+
* @returns 最终报告对象,未找到时返回 null
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* const report = await getFinalReport('600519', '2024-06-01', 'full');
|
|
119
|
+
*/
|
|
120
|
+
export async function getFinalReport(code, date, mode = 'full') {
|
|
121
|
+
const db = getDatabase();
|
|
122
|
+
const row = db
|
|
123
|
+
.select()
|
|
124
|
+
.from(finalReport)
|
|
125
|
+
.where(and(eq(finalReport.code, code), eq(finalReport.date, date)))
|
|
126
|
+
.get();
|
|
127
|
+
if (!row)
|
|
128
|
+
return null;
|
|
129
|
+
if (mode === 'overview') {
|
|
130
|
+
return {
|
|
131
|
+
id: row.id,
|
|
132
|
+
code: row.code,
|
|
133
|
+
date: row.date,
|
|
134
|
+
summary: row.summary,
|
|
135
|
+
pipelineId: row.pipelineId,
|
|
136
|
+
createdAt: row.createdAt,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return row;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 查看系统运行状态。
|
|
143
|
+
*
|
|
144
|
+
* 收集版本号、数据库大小、股票/股池数量、最新数据时间、
|
|
145
|
+
* LLM 连接状态及服务运行时长等信息。
|
|
146
|
+
*
|
|
147
|
+
* @returns 系统状态对象
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* const status = await getSystemStatus();
|
|
151
|
+
* console.log(status.version, status.llmConnected);
|
|
152
|
+
*/
|
|
153
|
+
export async function getSystemStatus() {
|
|
154
|
+
const db = getDatabase();
|
|
155
|
+
// 统计股票数量
|
|
156
|
+
const stockCount = db.select({ count: sql `count(*)` }).from(stock).get()?.count ?? 0;
|
|
157
|
+
// 统计股池数量
|
|
158
|
+
const poolCount = db.select({ count: sql `count(*)` }).from(pool).get()?.count ?? 0;
|
|
159
|
+
// 获取最新行情更新时间
|
|
160
|
+
const latestDaily = db
|
|
161
|
+
.select({ maxDate: sql `max(${dailyAnalysisReport.date})` })
|
|
162
|
+
.from(dailyAnalysisReport)
|
|
163
|
+
.get();
|
|
164
|
+
// 数据库文件大小
|
|
165
|
+
let dbSize = '未知';
|
|
166
|
+
try {
|
|
167
|
+
const dbPath = resolve(getDbPath());
|
|
168
|
+
if (existsSync(dbPath)) {
|
|
169
|
+
const bytes = statSync(dbPath).size;
|
|
170
|
+
dbSize = bytes < 1024 * 1024
|
|
171
|
+
? `${(bytes / 1024).toFixed(1)} KB`
|
|
172
|
+
: `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// 忽略文件大小错误
|
|
177
|
+
}
|
|
178
|
+
// 检查 LLM 连接
|
|
179
|
+
const llmConnected = await llmService.checkConnection().catch(() => false);
|
|
180
|
+
return {
|
|
181
|
+
version: VERSION,
|
|
182
|
+
dbSize,
|
|
183
|
+
stocksTracked: stockCount,
|
|
184
|
+
poolsCount: poolCount,
|
|
185
|
+
lastDataUpdate: latestDaily?.maxDate || '无数据',
|
|
186
|
+
llmConnected,
|
|
187
|
+
uptime: Math.floor(process.uptime()),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP 客户端工具模块
|
|
3
|
+
*
|
|
4
|
+
* 基于 Node.js 内置 fetch(Node 22+),提供带超时控制、
|
|
5
|
+
* 错误处理和重试机制的 HTTP 请求封装。
|
|
6
|
+
*
|
|
7
|
+
* @module http-client
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* HTTP 请求错误
|
|
11
|
+
*
|
|
12
|
+
* 当服务端返回非 2xx 状态码时抛出,包含状态码、状态文本和响应体。
|
|
13
|
+
*/
|
|
14
|
+
export declare class HttpError extends Error {
|
|
15
|
+
/** HTTP 状态码 */
|
|
16
|
+
readonly status: number;
|
|
17
|
+
/** HTTP 状态文本 */
|
|
18
|
+
readonly statusText: string;
|
|
19
|
+
/** 响应体文本 */
|
|
20
|
+
readonly body: string;
|
|
21
|
+
constructor(status: number, statusText: string, body: string);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 发起 HTTP 请求并解析响应为 JSON
|
|
25
|
+
*
|
|
26
|
+
* @typeParam T - 期望的 JSON 数据类型
|
|
27
|
+
* @param url - 请求 URL
|
|
28
|
+
* @param options - 可选的 fetch 选项(method、headers、body 等)
|
|
29
|
+
* @param signal - 可选的 AbortSignal,用于外部控制中止
|
|
30
|
+
* @param timeout - 超时毫秒数,默认 15s
|
|
31
|
+
* @returns 解析后的 JSON 数据
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const data = await fetchJson<{ code: string; price: number }>(
|
|
36
|
+
* 'https://api.example.com/stock/600519'
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @throws {HttpError} 当响应状态码非 2xx 时
|
|
41
|
+
* @throws {AbortError} 当请求超时或被中止时
|
|
42
|
+
* @throws {SyntaxError} 当响应体不是合法 JSON 时
|
|
43
|
+
*/
|
|
44
|
+
export declare function fetchJson<T>(url: string, options?: RequestInit, signal?: AbortSignal, timeout?: number): Promise<T>;
|
|
45
|
+
/**
|
|
46
|
+
* 发起 HTTP 请求并获取原始文本
|
|
47
|
+
*
|
|
48
|
+
* @param url - 请求 URL
|
|
49
|
+
* @param options - 可选的 fetch 选项(method、headers、body 等)
|
|
50
|
+
* @param signal - 可选的 AbortSignal,用于外部控制中止
|
|
51
|
+
* @param timeout - 超时毫秒数,默认 15s
|
|
52
|
+
* @returns 响应文本
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const html = await fetchText('https://example.com');
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @throws {HttpError} 当响应状态码非 2xx 时
|
|
60
|
+
* @throws {AbortError} 当请求超时或被中止时
|
|
61
|
+
*/
|
|
62
|
+
export declare function fetchText(url: string, options?: RequestInit, signal?: AbortSignal, timeout?: number): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* 带退避重试机制的异步函数执行器
|
|
65
|
+
*
|
|
66
|
+
* 对传入的异步函数进行重试,仅在遇到可重试错误
|
|
67
|
+
*(网络异常或服务端 5xx 状态码)时触发。
|
|
68
|
+
* 重试间隔恒定(非指数退避),适用于高频数据轮询场景。
|
|
69
|
+
*
|
|
70
|
+
* @param fn - 要执行的异步函数(通常是 fetch 调用)
|
|
71
|
+
* @param retries - 最大重试次数,默认 2(共执行 1 + retries = 3 次)
|
|
72
|
+
* @param delay - 每次重试前的等待时间(毫秒),默认 1000
|
|
73
|
+
* @returns 函数执行结果
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const data = await fetchWithRetry(
|
|
78
|
+
* () => fetchJson<StockData>('https://api.example.com/stock'),
|
|
79
|
+
* 3, // 最多重试 3 次
|
|
80
|
+
* 500 // 间隔 500ms
|
|
81
|
+
* );
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @throws 最后一次尝试抛出的原始错误(非可重试错误直接透传)
|
|
85
|
+
*/
|
|
86
|
+
export declare function fetchWithRetry<T>(fn: () => Promise<T>, retries?: number, delay?: number): Promise<T>;
|
|
87
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/utils/http-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,eAAe;IACf,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,gBAAgB;IAChB,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC,YAAY;IACZ,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO7D;AAgED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CASzH;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3H;AA2BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,MAAwB,EACjC,KAAK,GAAE,MAA+B,GACrC,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP 客户端工具模块
|
|
3
|
+
*
|
|
4
|
+
* 基于 Node.js 内置 fetch(Node 22+),提供带超时控制、
|
|
5
|
+
* 错误处理和重试机制的 HTTP 请求封装。
|
|
6
|
+
*
|
|
7
|
+
* @module http-client
|
|
8
|
+
*/
|
|
9
|
+
// ─── 常量 ─────────────────────────────────────────────────────
|
|
10
|
+
/** 默认请求超时时间(毫秒) */
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
12
|
+
/** 默认最大重试次数 */
|
|
13
|
+
const DEFAULT_RETRIES = 2;
|
|
14
|
+
/** 默认重试间隔(毫秒) */
|
|
15
|
+
const DEFAULT_RETRY_DELAY_MS = 1_000;
|
|
16
|
+
// ─── 错误类型 ─────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* HTTP 请求错误
|
|
19
|
+
*
|
|
20
|
+
* 当服务端返回非 2xx 状态码时抛出,包含状态码、状态文本和响应体。
|
|
21
|
+
*/
|
|
22
|
+
export class HttpError extends Error {
|
|
23
|
+
/** HTTP 状态码 */
|
|
24
|
+
status;
|
|
25
|
+
/** HTTP 状态文本 */
|
|
26
|
+
statusText;
|
|
27
|
+
/** 响应体文本 */
|
|
28
|
+
body;
|
|
29
|
+
constructor(status, statusText, body) {
|
|
30
|
+
super(`HTTP ${status} ${statusText}`);
|
|
31
|
+
this.name = 'HttpError';
|
|
32
|
+
this.status = status;
|
|
33
|
+
this.statusText = statusText;
|
|
34
|
+
this.body = body;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ─── 底层请求函数 ─────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* 核心请求函数:发起 HTTP 请求并返回 Response
|
|
40
|
+
*
|
|
41
|
+
* 内置超时控制,超时时抛出 AbortError。
|
|
42
|
+
*
|
|
43
|
+
* @param url - 请求 URL
|
|
44
|
+
* @param options - fetch 选项(method、headers、body 等)
|
|
45
|
+
* @param signal - 外部 AbortSignal(可与内部超时同时生效)
|
|
46
|
+
* @param timeout - 超时毫秒数,默认 DEFAULT_TIMEOUT_MS
|
|
47
|
+
* @returns Response 对象
|
|
48
|
+
* @throws {HttpError} 当响应状态码非 2xx 时
|
|
49
|
+
* @throws {AbortError} 当请求超时或被外部中止时
|
|
50
|
+
*/
|
|
51
|
+
async function request(url, options, signal, timeout) {
|
|
52
|
+
const effectiveTimeout = timeout ?? DEFAULT_TIMEOUT_MS;
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
|
|
55
|
+
try {
|
|
56
|
+
const combinedSignal = signal
|
|
57
|
+
? combineAbortSignals(signal, controller.signal)
|
|
58
|
+
: controller.signal;
|
|
59
|
+
const fetchOptions = {
|
|
60
|
+
...options,
|
|
61
|
+
signal: combinedSignal,
|
|
62
|
+
};
|
|
63
|
+
const response = await fetch(url, fetchOptions);
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const body = await response.text();
|
|
66
|
+
throw new HttpError(response.status, response.statusText, body);
|
|
67
|
+
}
|
|
68
|
+
return response;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
clearTimeout(timeoutId);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 合并两个 AbortSignal,任一 signal 中止则合并后的 signal 中止
|
|
76
|
+
*/
|
|
77
|
+
function combineAbortSignals(...signals) {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
for (const sig of signals) {
|
|
80
|
+
if (sig.aborted) {
|
|
81
|
+
controller.abort(sig.reason);
|
|
82
|
+
return controller.signal;
|
|
83
|
+
}
|
|
84
|
+
sig.addEventListener('abort', () => controller.abort(sig.reason), { once: true });
|
|
85
|
+
}
|
|
86
|
+
return controller.signal;
|
|
87
|
+
}
|
|
88
|
+
// ─── 公开函数 ─────────────────────────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* 发起 HTTP 请求并解析响应为 JSON
|
|
91
|
+
*
|
|
92
|
+
* @typeParam T - 期望的 JSON 数据类型
|
|
93
|
+
* @param url - 请求 URL
|
|
94
|
+
* @param options - 可选的 fetch 选项(method、headers、body 等)
|
|
95
|
+
* @param signal - 可选的 AbortSignal,用于外部控制中止
|
|
96
|
+
* @param timeout - 超时毫秒数,默认 15s
|
|
97
|
+
* @returns 解析后的 JSON 数据
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const data = await fetchJson<{ code: string; price: number }>(
|
|
102
|
+
* 'https://api.example.com/stock/600519'
|
|
103
|
+
* );
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @throws {HttpError} 当响应状态码非 2xx 时
|
|
107
|
+
* @throws {AbortError} 当请求超时或被中止时
|
|
108
|
+
* @throws {SyntaxError} 当响应体不是合法 JSON 时
|
|
109
|
+
*/
|
|
110
|
+
export async function fetchJson(url, options, signal, timeout) {
|
|
111
|
+
const response = await request(url, options, signal, timeout);
|
|
112
|
+
const text = await response.text();
|
|
113
|
+
if (text.length === 0) {
|
|
114
|
+
throw new SyntaxError('响应体为空,无法解析为 JSON');
|
|
115
|
+
}
|
|
116
|
+
return JSON.parse(text);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 发起 HTTP 请求并获取原始文本
|
|
120
|
+
*
|
|
121
|
+
* @param url - 请求 URL
|
|
122
|
+
* @param options - 可选的 fetch 选项(method、headers、body 等)
|
|
123
|
+
* @param signal - 可选的 AbortSignal,用于外部控制中止
|
|
124
|
+
* @param timeout - 超时毫秒数,默认 15s
|
|
125
|
+
* @returns 响应文本
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const html = await fetchText('https://example.com');
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* @throws {HttpError} 当响应状态码非 2xx 时
|
|
133
|
+
* @throws {AbortError} 当请求超时或被中止时
|
|
134
|
+
*/
|
|
135
|
+
export async function fetchText(url, options, signal, timeout) {
|
|
136
|
+
const response = await request(url, options, signal, timeout);
|
|
137
|
+
return response.text();
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 判断一个错误是否应该触发重试
|
|
141
|
+
*
|
|
142
|
+
* 重试条件:
|
|
143
|
+
* - 网络错误(TypeError)
|
|
144
|
+
* - 服务端错误(HTTP 5xx)
|
|
145
|
+
*
|
|
146
|
+
* @param error - 捕获的异常
|
|
147
|
+
* @returns 是否应重试
|
|
148
|
+
*/
|
|
149
|
+
function isRetryableError(error) {
|
|
150
|
+
if (error instanceof TypeError) {
|
|
151
|
+
// TypeError 通常表示网络层面错误(DNS 解析失败、连接重置等)
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
if (error instanceof HttpError) {
|
|
155
|
+
// 5xx 服务端错误可以重试
|
|
156
|
+
return error.status >= 500 && error.status < 600;
|
|
157
|
+
}
|
|
158
|
+
// 非 HttpError 或 TypeError 的错误(如 JSON 解析错误)不重试
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 带退避重试机制的异步函数执行器
|
|
163
|
+
*
|
|
164
|
+
* 对传入的异步函数进行重试,仅在遇到可重试错误
|
|
165
|
+
*(网络异常或服务端 5xx 状态码)时触发。
|
|
166
|
+
* 重试间隔恒定(非指数退避),适用于高频数据轮询场景。
|
|
167
|
+
*
|
|
168
|
+
* @param fn - 要执行的异步函数(通常是 fetch 调用)
|
|
169
|
+
* @param retries - 最大重试次数,默认 2(共执行 1 + retries = 3 次)
|
|
170
|
+
* @param delay - 每次重试前的等待时间(毫秒),默认 1000
|
|
171
|
+
* @returns 函数执行结果
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* const data = await fetchWithRetry(
|
|
176
|
+
* () => fetchJson<StockData>('https://api.example.com/stock'),
|
|
177
|
+
* 3, // 最多重试 3 次
|
|
178
|
+
* 500 // 间隔 500ms
|
|
179
|
+
* );
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @throws 最后一次尝试抛出的原始错误(非可重试错误直接透传)
|
|
183
|
+
*/
|
|
184
|
+
export async function fetchWithRetry(fn, retries = DEFAULT_RETRIES, delay = DEFAULT_RETRY_DELAY_MS) {
|
|
185
|
+
let lastError;
|
|
186
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
187
|
+
try {
|
|
188
|
+
return await fn();
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
lastError = error;
|
|
192
|
+
if (attempt < retries && isRetryableError(error)) {
|
|
193
|
+
await sleep(delay);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// 非可重试错误或已达最大重试次数,直接抛出
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// TypeScript 控制流无法推断此处不可达,显式抛出
|
|
201
|
+
throw lastError;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 延迟函数
|
|
205
|
+
*
|
|
206
|
+
* @param ms - 等待毫秒数
|
|
207
|
+
*/
|
|
208
|
+
function sleep(ms) {
|
|
209
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/utils/http-client.ts"],"names":[],"mappings":"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"}
|