daxiapi-cli 1.2.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function (program) {
7
+ const sectorCmd = program.command('sector');
8
+
9
+ sectorCmd
10
+ .command('heatmap')
11
+ .description('获取A股板块热力图数据(同花顺分类),支持按强度(cs)、涨跌幅(zdf)等多个维度排序,可查询1-30天数据。返回板块强度热力图、涨跌幅热力图、箱体突破板块统计、强度与均线交叉板块等信息。可用于板块轮动分析、强势板块识别和热点追踪。')
12
+ .option('--order <field>', '排序字段', 'cs')
13
+ .option('--limit <num>', '数量限制', 5)
14
+ .action(async options => {
15
+ try {
16
+ const token = config.getToken();
17
+ if (!token) {
18
+ const error = new Error('未配置 API Token');
19
+ error.response = {status: 401};
20
+ throw error;
21
+ }
22
+
23
+ const data = await api.getSectorData(token, options.order, options.limit);
24
+ output(data);
25
+ } catch (error) {
26
+ handleError(error);
27
+ process.exit(1);
28
+ }
29
+ });
30
+
31
+ sectorCmd
32
+ .command('bk')
33
+ .description('获取A股行业板块数据(同花顺分类),包括行业名称、今日涨幅、5日涨幅、20日涨幅、CS强度、CS均线、强度指标(QD)等核心数据。数据按今日涨幅降序排列,可用于板块轮动分析、强势板块识别和行业配置参考。')
34
+ .action(async () => {
35
+ try {
36
+ const token = config.getToken();
37
+ if (!token) {
38
+ const error = new Error('未配置 API Token');
39
+ error.response = {status: 401};
40
+ throw error;
41
+ }
42
+
43
+ const data = await api.getBkData(token);
44
+ output(data);
45
+ } catch (error) {
46
+ handleError(error);
47
+ process.exit(1);
48
+ }
49
+ });
50
+
51
+ sectorCmd
52
+ .command('stocks')
53
+ .description('获取A股指定板块内股票排名,支持BK0428、0428、881155等多种板块代码格式。支持按强度(cs)、涨跌幅(zdf)、市值(sm)、成交额(cg)、换手率(cr)、SCTR排名等多种维度排序。返回板块内前20只股票的详细数据,可用于板块内强势股筛选和个股分析。')
54
+ .requiredOption('--code <bkCode>', '板块代码')
55
+ .option('--order <field>', '排序字段', 'cs')
56
+ .action(async options => {
57
+ try {
58
+ const token = config.getToken();
59
+ if (!token) {
60
+ const error = new Error('未配置 API Token');
61
+ error.response = {status: 401};
62
+ throw error;
63
+ }
64
+
65
+ const data = await api.getSectorRankStock(token, options.code, options.order);
66
+ output(data);
67
+ } catch (error) {
68
+ handleError(error);
69
+ process.exit(1);
70
+ }
71
+ });
72
+
73
+ sectorCmd
74
+ .command('top')
75
+ .description('获取A股热门股票数据,筛选当日涨幅>7%且IBS>50的强势股,按板块分组展示每个板块内强度排名前10的股票。返回股票名称、代码、涨幅、5/10/20日涨跌幅、所属板块、概念等信息,可用于短线热点追踪和强势股挖掘。')
76
+ .action(async () => {
77
+ try {
78
+ const token = config.getToken();
79
+ if (!token) {
80
+ const error = new Error('未配置 API Token');
81
+ error.response = {status: 401};
82
+ throw error;
83
+ }
84
+
85
+ const data = await api.getTopStocks(token);
86
+ output(data);
87
+ } catch (error) {
88
+ handleError(error);
89
+ process.exit(1);
90
+ }
91
+ });
92
+
93
+ sectorCmd
94
+ .command('gn')
95
+ .description('获取A股热门概念板块列表,支持同花顺(ths)和东方财富(dfcf)两个数据源。按板块内涨幅7%以上股票个数降序排序,返回前20个概念板块的名称、今日涨幅、7%+股票数、5/10/20日涨幅、强度指标(QD)、CS强度等信息。可用于概念板块热度分析和热点追踪。')
96
+ .option('--type <type>', '数据源类型 (dfcf|ths)', 'ths')
97
+ .action(async options => {
98
+ try {
99
+ const token = config.getToken();
100
+ if (!token) {
101
+ const error = new Error('未配置 API Token');
102
+ error.response = {status: 401};
103
+ throw error;
104
+ }
105
+
106
+ if (!['dfcf', 'ths'].includes(options.type)) {
107
+ throw createParameterError(
108
+ '参数无效',
109
+ ["参数 'type' 必须是 dfcf 或 ths"],
110
+ ['daxiapi sector gn --type ths', 'daxiapi sector gn --type dfcf']
111
+ );
112
+ }
113
+
114
+ const data = await api.getGnHot(token, options.type);
115
+ output(data);
116
+ } catch (error) {
117
+ handleError(error);
118
+ process.exit(1);
119
+ }
120
+ });
121
+ };
@@ -0,0 +1,80 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function(program) {
7
+ const stockCmd = program.command('stock');
8
+
9
+ stockCmd
10
+ .command('info')
11
+ .description('根据股票代码获取A股详细信息,支持多个代码用逗号分隔(最多20只),支持6位数字代码和116.xxx格式。返回股票名称、代码、涨跌幅、CS强度、SCTR排名、所属板块、概念、市值、成交额等详细数据。可用于个股分析和多只股票对比。')
12
+ .argument('<codes...>', '股票代码(支持多个)')
13
+ .action(async (codes) => {
14
+ try {
15
+ const token = config.getToken();
16
+ if (!token) {
17
+ const error = new Error('未配置 API Token');
18
+ error.response = {status: 401};
19
+ throw error;
20
+ }
21
+
22
+ if (!codes || codes.length === 0) {
23
+ throw createParameterError(
24
+ '参数无效',
25
+ ["参数 'codes' 不能为空"],
26
+ [
27
+ 'daxiapi stock info 000001',
28
+ 'daxiapi stock info 000001 600031 300750'
29
+ ]
30
+ );
31
+ }
32
+
33
+ const data = await api.getStockData(token, codes);
34
+ output(data);
35
+ } catch (error) {
36
+ handleError(error);
37
+ process.exit(1);
38
+ }
39
+ });
40
+
41
+ stockCmd
42
+ .command('gn <gnId>')
43
+ .description('根据概念板块ID获取该概念下的所有股票数据,支持同花顺(881155)和东方财富(BK0428)两种格式的板块ID。自动根据ID格式选择数据源,返回股票名称、代码、涨跌幅、CS强度、SCTR排名等详细信息,最多返回300只股票。可用于概念板块成分股分析和板块内股票筛选。')
44
+ .option('--type <type>', '数据源类型 (dfcf|ths)', 'ths')
45
+ .action(async (gnId, options) => {
46
+ try {
47
+ const token = config.getToken();
48
+ if (!token) {
49
+ const error = new Error('未配置 API Token');
50
+ error.response = {status: 401};
51
+ throw error;
52
+ }
53
+
54
+ if (!gnId) {
55
+ throw createParameterError(
56
+ '参数无效',
57
+ ["参数 'gnId' 不能为空"],
58
+ ['daxiapi stock gn GN1234']
59
+ );
60
+ }
61
+
62
+ if (!['dfcf', 'ths'].includes(options.type)) {
63
+ throw createParameterError(
64
+ '参数无效',
65
+ ["参数 'type' 必须是 dfcf 或 ths"],
66
+ [
67
+ 'daxiapi stock gn GN1234 --type ths',
68
+ 'daxiapi stock gn GN1234 --type dfcf'
69
+ ]
70
+ );
71
+ }
72
+
73
+ const data = await api.getGainianStock(token, gnId, options.type);
74
+ output(data);
75
+ } catch (error) {
76
+ handleError(error);
77
+ process.exit(1);
78
+ }
79
+ });
80
+ };
@@ -0,0 +1,39 @@
1
+ const config = require('../lib/config');
2
+ const api = require('../lib/api');
3
+ const {handleError, createParameterError} = require('../lib/error');
4
+ const {output} = require('../lib/output');
5
+
6
+ module.exports = function(program) {
7
+ program
8
+ .command('zdt')
9
+ .description('获取A股涨跌停股票池数据,支持查询涨停(zt)、跌停(dt)、炸板(zb)三类股票。返回股票代码、名称、涨停统计、所属行业、概念、CS强度、SCTR排名等信息,并提供市场整体涨跌停统计。可用于短线热点追踪和市场情绪分析。')
10
+ .option('--type <type>', '类型 (zt|dt|zb)', 'zt')
11
+ .action(async (options) => {
12
+ try {
13
+ const token = config.getToken();
14
+ if (!token) {
15
+ const error = new Error('未配置 API Token');
16
+ error.response = {status: 401};
17
+ throw error;
18
+ }
19
+
20
+ if (!['zt', 'dt', 'zb'].includes(options.type)) {
21
+ throw createParameterError(
22
+ '参数无效',
23
+ ["参数 'type' 必须是 zt、dt 或 zb"],
24
+ [
25
+ 'daxiapi zdt --type zt',
26
+ 'daxiapi zdt --type dt',
27
+ 'daxiapi zdt --type zb'
28
+ ]
29
+ );
30
+ }
31
+
32
+ const data = await api.getZdtPool(token, options.type);
33
+ output(data);
34
+ } catch (error) {
35
+ handleError(error);
36
+ process.exit(1);
37
+ }
38
+ });
39
+ };
package/lib/api.js CHANGED
@@ -1,286 +1,128 @@
1
1
  const axios = require('axios');
2
2
  const config = require('./config');
3
3
 
4
- const BASE_URL = config.getBaseUrl() || 'https://daxiapi.com';
4
+ const BASE_URL = config.get('baseUrl') || 'https://daxiapi.com';
5
5
 
6
- /**
7
- * 获取市场类型前缀
8
- */
9
- function getMarketPrefix(code) {
10
- if (code.startsWith('688') || code.startsWith('689')) {
11
- return 'sh';
12
- }
13
- if (code.startsWith('60')) {
14
- return 'sh';
15
- }
16
- return 'sz';
17
- }
18
-
19
- /**
20
- * 创建请求实例
21
- */
22
6
  function createClient(token) {
23
7
  return axios.create({
24
8
  baseURL: `${BASE_URL}/coze`,
25
9
  headers: {
26
- 'X-API-Token': token,
10
+ 'Authorization': `Bearer ${token}`,
27
11
  'Content-Type': 'application/json'
28
12
  },
29
13
  timeout: 30000
30
14
  });
31
15
  }
32
16
 
33
- /**
34
- * GET 请求
35
- */
36
17
  async function get(client, path) {
37
18
  const {data} = await client.get(path);
38
19
  if (data.errCode !== 0) {
39
- throw new Error(data.errMsg || `API Error: ${data.errCode}`);
20
+ const error = new Error(data.errMsg || `API Error: ${data.errCode}`);
21
+ error.response = {status: data.errCode};
22
+ throw error;
40
23
  }
41
24
  return data.data;
42
25
  }
43
26
 
44
- /**
45
- * POST 请求
46
- */
47
27
  async function post(client, path, body = {}) {
48
28
  const {data} = await client.post(path, body);
49
29
  if (data.errCode !== 0) {
50
- throw new Error(data.errMsg || `API Error: ${data.errCode}`);
30
+ const error = new Error(data.errMsg || `API Error: ${data.errCode}`);
31
+ error.response = {status: data.errCode};
32
+ throw error;
51
33
  }
52
34
  return data.data;
53
35
  }
54
36
 
55
- // ==================== API 方法 ====================
56
-
57
- /**
58
- * 获取指数K线
59
- */
60
- async function getIndexK(token) {
61
- const client = createClient(token);
62
- return get(client, '/get_index_k');
63
- }
64
-
65
- /**
66
- * 获取市场数据
67
- */
68
37
  async function getMarketData(token) {
69
38
  const client = createClient(token);
70
- return get(client, '/get_market_data');
39
+ return get(client, '/get_index_data');
71
40
  }
72
41
 
73
- /**
74
- * 获取市场温度
75
- */
76
- async function getMarketDegree(token) {
42
+ async function getMarketTemp(token) {
77
43
  const client = createClient(token);
78
- return get(client, '/get_market_degree');
44
+ return get(client, '/get_market_temp');
79
45
  }
80
46
 
81
- /**
82
- * 获取市场风格
83
- */
84
47
  async function getMarketStyle(token) {
85
48
  const client = createClient(token);
86
49
  return get(client, '/get_market_style');
87
50
  }
88
51
 
89
- /**
90
- * 获取指数估值
91
- */
92
52
  async function getMarketValueData(token) {
93
53
  const client = createClient(token);
94
54
  return get(client, '/get_market_value_data');
95
55
  }
96
56
 
97
- /**
98
- * 获取收盘新闻
99
- */
100
- async function getMarketNews(token) {
57
+ async function getBkData(token) {
101
58
  const client = createClient(token);
102
- return get(client, '/get_market_end_news');
59
+ return get(client, '/get_bk_data');
103
60
  }
104
61
 
105
- /**
106
- * 获取板块热力图
107
- */
108
- async function getSectorData(token, orderBy = 'cs', lmt = 5) {
62
+ async function getSectorData(token, orderBy = 'cs', limit = 5) {
109
63
  const client = createClient(token);
110
- return post(client, '/get_sector_data', {orderBy, lmt});
64
+ return post(client, '/get_sector_data', {orderBy, lmt: limit});
111
65
  }
112
66
 
113
- /**
114
- * 获取板块内个股排名
115
- */
116
67
  async function getSectorRankStock(token, sectorCode, orderBy = 'cs') {
117
68
  const client = createClient(token);
118
69
  return post(client, '/get_sector_rank_stock', {sectorCode, orderBy});
119
70
  }
120
71
 
121
- /**
122
- * 获取概念内个股
123
- */
124
- async function getGainianStock(token, gnId) {
72
+ async function getTopStocks(token) {
125
73
  const client = createClient(token);
126
- return post(client, '/get_gainian_stock', {gnId});
74
+ return post(client, '/get_top_stocks', {});
75
+ }
76
+
77
+ async function getGnHot(token, type = 'ths') {
78
+ const client = createClient(token);
79
+ return post(client, '/get_gn_hot', {type});
127
80
  }
128
81
 
129
- /**
130
- * 获取个股数据
131
- */
132
82
  async function getStockData(token, codes) {
133
83
  const client = createClient(token);
134
84
  return post(client, '/get_stock_data', {code: codes});
135
85
  }
136
86
 
137
- /**
138
- * 搜索股票/行业
139
- */
140
- async function queryStock(token, keyword, type = 'stock') {
87
+ async function getGainianStock(token, gnId, type = 'ths') {
141
88
  const client = createClient(token);
142
- return post(client, '/query_stock_data', {q: keyword, type});
89
+ return post(client, '/get_gainian_stock', {gnId, type});
143
90
  }
144
91
 
145
- /**
146
- * 获取概念板块数据
147
- */
148
- async function getGnTable(token) {
92
+ async function getKline(token, code) {
149
93
  const client = createClient(token);
150
- return post(client, '/get_gn_table');
94
+ return post(client, '/get_kline', {code});
151
95
  }
152
96
 
153
- // ==================== K线数据(多数据源) ====================
154
-
155
- /**
156
- * 获取K线数据(首选腾讯,备选东方财富)
157
- * @param {string} code - 股票代码
158
- * @param {number} limit - 数据条数,默认300
159
- * @param {string} type - K线类型: day(日线), week(周线), month(月线)
160
- * @returns {Promise<Object>} K线数据
161
- */
162
- async function getKline(code, limit = 300, type = 'day') {
163
- // 首选腾讯
164
- try {
165
- const data = await getKlineFromQQ(code, limit, type);
166
- return {source: 'qq', ...data};
167
- } catch (err) {
168
- console.log('腾讯数据源失败,切换到东方财富...');
169
- }
170
-
171
- // 备选东方财富
172
- try {
173
- const data = await getKlineFromEastmoney(code, limit, type);
174
- return {source: 'eastmoney', ...data};
175
- } catch (err) {
176
- throw new Error('所有数据源均失败,请稍后重试');
177
- }
97
+ async function getZdtPool(token, type = 'zt') {
98
+ const client = createClient(token);
99
+ return post(client, '/get_zdt_pool', {type});
178
100
  }
179
101
 
180
- /**
181
- * 腾讯财经K线数据
182
- * @param {string} code - 股票代码
183
- * @param {number} limit - 数据条数
184
- * @param {string} type - K线类型
185
- */
186
- async function getKlineFromQQ(code, limit = 500, type = 'day') {
187
- const market = getMarketPrefix(code);
188
- const fullCode = `${market}${code}`;
189
-
190
- // 腾讯接口限制最大2000条
191
- if (limit > 2000) {
192
- limit = 2000;
193
- }
194
-
195
- const url = `https://proxy.finance.qq.com/ifzqgtimg/appstock/app/newfqkline/get?_var=&param=${fullCode},${type},,,${limit},qfq&r=0.${Date.now()}`;
196
-
197
- const {data} = await axios.get(url, {timeout: 10000});
198
-
199
- if (!data.data || !data.data[fullCode]) {
200
- throw new Error('腾讯数据源返回异常');
201
- }
202
-
203
- const klineData = data.data[fullCode].qfqday || data.data[fullCode].day;
204
- if (!klineData || klineData.length === 0) {
205
- throw new Error('无K线数据');
206
- }
207
-
208
- const klines = klineData.map(([date, open, close, high, low, volume, , , amount]) => ({
209
- date,
210
- open: parseFloat(open),
211
- close: parseFloat(close),
212
- high: parseFloat(high),
213
- low: parseFloat(low),
214
- volume: parseFloat(volume),
215
- amount: parseFloat(amount)
216
- }));
217
-
218
- return {
219
- code,
220
- name: data.data[fullCode].qt?.[fullCode]?.[1] || code,
221
- klines,
222
- count: klines.length
223
- };
102
+ async function getSecId(token, code) {
103
+ const client = createClient(token);
104
+ return post(client, '/get_sec_id', {code});
224
105
  }
225
106
 
226
- /**
227
- * 东方财富K线数据
228
- * @param {string} code - 股票代码
229
- * @param {number} limit - 数据条数
230
- * @param {string} type - K线类型: day=101, week=102, month=103
231
- */
232
- async function getKlineFromEastmoney(code, limit = 300, type = 'day') {
233
- // K线类型映射
234
- const kltMap = {day: '101', week: '102', month: '103'};
235
- const klt = kltMap[type] || '101';
236
-
237
- // 市场代码
238
- const secid = code.startsWith('6') ? `1.${code}` : `0.${code}`;
239
-
240
- const url = `https://push2his.eastmoney.com/api/qt/stock/kline/get?fields1=f1,f2,f3,f4,f5,f6&fields2=f51,f52,f53,f54,f55,f56,f57,f58,f61&ut=7eea3edcaed734bea9cbfc24409ed989&end=29991010&klt=${klt}&secid=${secid}&fqt=1&lmt=${limit}`;
241
-
242
- const {data} = await axios.get(url, {timeout: 10000});
243
-
244
- if (!data.data || !data.data.klines) {
245
- throw new Error('东方财富数据源返回异常');
246
- }
247
-
248
- const klines = data.data.klines.map(line => {
249
- const [date, open, close, high, low, volume, amount, , turnover] = line.split(',');
250
- return {
251
- date,
252
- open: parseFloat(open),
253
- close: parseFloat(close),
254
- high: parseFloat(high),
255
- low: parseFloat(low),
256
- volume: parseFloat(volume),
257
- amount: parseFloat(amount),
258
- turnover: parseFloat(turnover) || 0
259
- };
260
- });
261
-
262
- return {
263
- code,
264
- name: data.data.name || code,
265
- klines,
266
- count: klines.length
267
- };
107
+ async function queryStockData(token, q, type = 'stock') {
108
+ const client = createClient(token);
109
+ return post(client, '/query_stock_data', {q, type});
268
110
  }
269
111
 
270
112
  module.exports = {
271
- getIndexK,
272
113
  getMarketData,
273
- getMarketDegree,
114
+ getMarketTemp,
274
115
  getMarketStyle,
275
116
  getMarketValueData,
276
- getMarketNews,
117
+ getBkData,
277
118
  getSectorData,
278
119
  getSectorRankStock,
279
- getGainianStock,
120
+ getTopStocks,
121
+ getGnHot,
280
122
  getStockData,
281
- queryStock,
282
- getGnTable,
123
+ getGainianStock,
283
124
  getKline,
284
- getKlineFromQQ,
285
- getKlineFromEastmoney
125
+ getZdtPool,
126
+ getSecId,
127
+ queryStockData
286
128
  };
package/lib/config.js CHANGED
@@ -17,30 +17,18 @@ const config = new Conf({
17
17
  schema
18
18
  });
19
19
 
20
- /**
21
- * 获取Token(优先环境变量)
22
- */
23
20
  function getToken() {
24
21
  return process.env.DAXIAPI_TOKEN || config.get('token');
25
22
  }
26
23
 
27
- /**
28
- * 获取配置项
29
- */
30
24
  function get(key) {
31
25
  return config.get(key);
32
26
  }
33
27
 
34
- /**
35
- * 设置配置项
36
- */
37
28
  function set(key, value) {
38
29
  config.set(key, value);
39
30
  }
40
31
 
41
- /**
42
- * 获取所有配置
43
- */
44
32
  function getAll() {
45
33
  return {
46
34
  token: getToken() ? '******' + getToken().slice(-4) : undefined,
@@ -48,9 +36,6 @@ function getAll() {
48
36
  };
49
37
  }
50
38
 
51
- /**
52
- * 删除配置项
53
- */
54
39
  function del(key) {
55
40
  config.delete(key);
56
41
  }
package/lib/error.js ADDED
@@ -0,0 +1,80 @@
1
+ const chalk = require('chalk');
2
+
3
+ const errorMessages = {
4
+ 401: {
5
+ title: 'API Token 无效或已过期',
6
+ solutions: [
7
+ '检查 Token 是否正确配置:\n daxiapi config set token YOUR_TOKEN',
8
+ '或设置环境变量:\n export DAXIAPI_TOKEN=YOUR_TOKEN',
9
+ 'Token 可在 daxiapi.com 用户中心获取'
10
+ ]
11
+ },
12
+ 403: {
13
+ title: '无访问权限',
14
+ solutions: [
15
+ '检查您的账户是否有访问该接口的权限',
16
+ '联系管理员开通相关权限',
17
+ '访问 daxiapi.com 了解权限说明'
18
+ ]
19
+ },
20
+ 429: {
21
+ title: '请求频率超限',
22
+ solutions: [
23
+ '请稍后重试',
24
+ '检查您的请求频率是否过高',
25
+ '升级账户获取更高配额'
26
+ ]
27
+ },
28
+ 500: {
29
+ title: '服务器内部错误',
30
+ solutions: [
31
+ '请稍后重试',
32
+ '如果问题持续,请联系技术支持',
33
+ '访问 daxiapi.com 查看服务状态'
34
+ ]
35
+ }
36
+ };
37
+
38
+ function handleError(error) {
39
+ console.log(chalk.red.bold('\n❌ 错误:'), error.message || error.title);
40
+
41
+ const statusCode = error.response?.status || error.statusCode;
42
+ const errorInfo = errorMessages[statusCode];
43
+
44
+ if (errorInfo) {
45
+ console.log(chalk.bold('\n解决方法:'));
46
+ errorInfo.solutions.forEach((solution, index) => {
47
+ console.log(` ${index + 1}. ${solution}`);
48
+ });
49
+ } else if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {
50
+ console.log(chalk.bold('\n解决方法:'));
51
+ console.log(' 1. 检查网络连接是否正常');
52
+ console.log(' 2. 检查 API 地址是否正确:\n daxiapi config set baseUrl https://daxiapi.com');
53
+ console.log(' 3. 如果使用代理,请检查代理配置');
54
+ } else if (error.details) {
55
+ console.log(chalk.bold('\n详细信息:'));
56
+ error.details.forEach(detail => {
57
+ console.log(` - ${detail}`);
58
+ });
59
+ if (error.examples) {
60
+ console.log(chalk.bold('\n使用示例:'));
61
+ error.examples.forEach(example => {
62
+ console.log(` ${example}`);
63
+ });
64
+ }
65
+ }
66
+
67
+ console.log('');
68
+ }
69
+
70
+ function createParameterError(message, details, examples) {
71
+ const error = new Error(message);
72
+ error.details = details;
73
+ error.examples = examples;
74
+ return error;
75
+ }
76
+
77
+ module.exports = {
78
+ handleError,
79
+ createParameterError
80
+ };