@maiyunnet/kebab 9.14.2 → 9.15.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/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "9.14.2";
8
+ export declare const VER = "9.15.0";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  /** --- 框架的 LIB,以 / 结尾 --- */
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '9.14.2';
9
+ export const VER = '9.15.0';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/core.d.ts CHANGED
@@ -127,6 +127,8 @@ export declare function ips(ctr: sCtr.Ctr | http.IncomingHttpHeaders): {
127
127
  export declare const REAL_IP_X = "x-forwarded-for";
128
128
  /** --- 使用的是 Cloudflare --- */
129
129
  export declare const REAL_IP_CF = "cf-connecting-ip";
130
+ /** --- 使用的是 EO --- */
131
+ export declare const REAL_IP_EO = "eo-connecting-ip";
130
132
  /**
131
133
  * --- 获取直连 IP(安全 IP) ---
132
134
  * @param ctr
package/lib/core.js CHANGED
@@ -8,6 +8,7 @@ import * as http2 from 'http2';
8
8
  import * as stream from 'stream';
9
9
  import * as os from 'os';
10
10
  import * as net from 'net';
11
+ import * as crypto from 'crypto';
11
12
  import Ajv from 'ajv';
12
13
  import addFormats from 'ajv-formats';
13
14
  import * as kebab from '#kebab/index.js';
@@ -110,7 +111,7 @@ export function random(length = 8, source = RANDOM_LN, block = '') {
110
111
  }
111
112
  let temp = '';
112
113
  for (let i = 0; i < length; ++i) {
113
- temp += source[rand(0, len - 1)];
114
+ temp += source[crypto.randomInt(len)];
114
115
  }
115
116
  return temp;
116
117
  }
@@ -337,6 +338,8 @@ export function ips(ctr) {
337
338
  export const REAL_IP_X = 'x-forwarded-for';
338
339
  /** --- 使用的是 Cloudflare --- */
339
340
  export const REAL_IP_CF = 'cf-connecting-ip';
341
+ /** --- 使用的是 EO --- */
342
+ export const REAL_IP_EO = 'eo-connecting-ip';
340
343
  /**
341
344
  * --- 规范化 IP 地址 ---
342
345
  * --- 将 IPv4-mapped IPv6(如 ::ffff:127.0.0.1)转换为纯 IPv4,原生 IPv6 保持不变 ---
@@ -1153,24 +1156,36 @@ export function clone(obj) {
1153
1156
  const keys = isArray ? obj.keys() : Object.keys(obj);
1154
1157
  for (const key of keys) {
1155
1158
  const val = obj[key];
1159
+ let clonedValue;
1156
1160
  if (val instanceof Date) {
1157
- newObj[key] = new Date(val.getTime());
1161
+ clonedValue = new Date(val.getTime());
1158
1162
  }
1159
1163
  else if (val instanceof FormData) {
1160
1164
  const fd = new FormData();
1161
1165
  for (const item of val) {
1162
1166
  fd.append(item[0], item[1]);
1163
1167
  }
1164
- newObj[key] = fd;
1168
+ clonedValue = fd;
1165
1169
  }
1166
1170
  else if (val === null) {
1167
- newObj[key] = null;
1171
+ clonedValue = null;
1168
1172
  }
1169
1173
  else if (typeof val === 'object') {
1170
- newObj[key] = clone(val);
1174
+ clonedValue = clone(val);
1171
1175
  }
1172
1176
  else {
1173
- newObj[key] = val;
1177
+ clonedValue = val;
1178
+ }
1179
+ if (!isArray && ((key === '__proto__') || (key === 'prototype') || (key === 'constructor'))) {
1180
+ Object.defineProperty(newObj, key, {
1181
+ 'configurable': true,
1182
+ 'enumerable': true,
1183
+ 'value': clonedValue,
1184
+ 'writable': true,
1185
+ });
1186
+ }
1187
+ else {
1188
+ newObj[key] = clonedValue;
1174
1189
  }
1175
1190
  }
1176
1191
  return newObj;
package/lib/crypto.js CHANGED
@@ -14,7 +14,7 @@ import * as lCore from '#kebab/lib/core.js';
14
14
  * @param options 参数
15
15
  */
16
16
  export function generateKeyPair(type, options = {}) {
17
- return new Promise((resolve) => {
17
+ return new Promise(resolve => {
18
18
  options.modulusLength ??= 2048;
19
19
  if (options.namedCurve !== undefined) {
20
20
  options.namedCurve = options.namedCurve.toUpperCase();
package/lib/fs.js CHANGED
@@ -26,10 +26,9 @@ export async function getContent(path, options) {
26
26
  const encoding = options.encoding;
27
27
  const start = options.start;
28
28
  const end = options.end;
29
- if (start ?? end) {
29
+ if ((start !== undefined) || (end !== undefined)) {
30
30
  return new Promise(function (resolve) {
31
31
  const rs = createReadStream(path, {
32
- 'encoding': encoding,
33
32
  'start': start,
34
33
  'end': end
35
34
  });
package/lib/kv.d.ts CHANGED
@@ -118,6 +118,11 @@ export declare class Kv {
118
118
  * @param key
119
119
  */
120
120
  getJson(key: string): Promise<any | false | null>;
121
+ /**
122
+ * --- 原子获取并删除 JSON 对象 ---
123
+ * @param key 键
124
+ */
125
+ getDelJson(key: string): Promise<any | false | null>;
121
126
  /**
122
127
  * --- 删除已存在的值 ---
123
128
  * @param keys
package/lib/kv.js CHANGED
@@ -37,7 +37,7 @@ export class Kv {
37
37
  if (!conn) {
38
38
  return false;
39
39
  }
40
- return conn.pipeline();
40
+ return conn.createPipelineClient();
41
41
  }
42
42
  /**
43
43
  * --- 设定一个值 ---
@@ -272,6 +272,26 @@ end`;
272
272
  const r = lText.parseJson(v);
273
273
  return r;
274
274
  }
275
+ /**
276
+ * --- 原子获取并删除 JSON 对象 ---
277
+ * @param key 键
278
+ */
279
+ async getDelJson(key) {
280
+ const conn = await this._getConnection();
281
+ if (!conn) {
282
+ return false;
283
+ }
284
+ try {
285
+ const value = await conn.getAndDel(this._etc.pre + key);
286
+ if (value === null) {
287
+ return null;
288
+ }
289
+ return lText.parseJson(value);
290
+ }
291
+ catch {
292
+ return false;
293
+ }
294
+ }
275
295
  /**
276
296
  * --- 删除已存在的值 ---
277
297
  * @param keys
@@ -1,83 +1,4 @@
1
1
  /**
2
- * Project: Kebab, User: JianSuoQiYue
3
- * Date: 2020-04-07 23:45:03
4
- * Last: 2020-04-07 23:45:07, 2022-09-10 01:35:25
2
+ * --- 兼容旧版 net 模块的 FormData 导出,统一复用 undici 实现 ---
5
3
  */
6
- import * as stream from 'stream';
7
- /** --- Item 对象 --- */
8
- export type IItem = {
9
- /** --- key 键 --- */
10
- 'key': string;
11
- 'type': 'string';
12
- /** --- 字符串值 --- */
13
- 'value': string;
14
- 'path': '';
15
- } | {
16
- /** --- key 键 --- */
17
- 'key': string;
18
- 'type': 'file';
19
- /** --- 文件名 --- */
20
- 'value': string;
21
- /** --- 文件路径 --- */
22
- 'path': string;
23
- } | {
24
- /** --- key 键 --- */
25
- 'key': string;
26
- 'type': 'buffer';
27
- /** --- 文件名 --- */
28
- 'value': string;
29
- /** --- Buffer 数据 --- */
30
- 'path': Buffer;
31
- };
32
- export declare class FormData extends stream.Readable {
33
- /** --- read 调用次数 --- */
34
- private _num;
35
- /** --- 要编译的数据 --- */
36
- private readonly _data;
37
- /** --- 分隔符 --- */
38
- private readonly _boundary;
39
- /** --- 正在读取文件吗 --- */
40
- private _fileReading;
41
- /** --- 是否已经结束 --- */
42
- private _close;
43
- /** --- 总字节长度 --- */
44
- private _length;
45
- /** --- 已发送字节长度 --- */
46
- private _sent;
47
- /**
48
- * --- 添加字符串 ---
49
- * @param key 键
50
- * @param val 值
51
- */
52
- putString(key: string, val: string): void;
53
- /**
54
- * --- 添加文件 ---
55
- * @param key 键
56
- * @param path 路径
57
- * @param fname 可选,文件名
58
- */
59
- putFile(key: string, path: string, fname?: string): Promise<boolean>;
60
- /**
61
- * --- 添加 Buffer 数据 ---
62
- * @param key 键
63
- * @param buffer Buffer 数据
64
- * @param fname 文件名
65
- */
66
- putBuffer(key: string, buffer: Buffer, fname: string): void;
67
- /**
68
- * --- 获取 boundary ---
69
- */
70
- getBoundary(): string;
71
- /**
72
- * --- 获取总字节长度 ---
73
- */
74
- getLength(): number;
75
- /**
76
- * --- 获取已发送的字节长度 ---
77
- */
78
- getSent(): number;
79
- /**
80
- * --- 间隔读取(on data 或 pipe 触发)---
81
- */
82
- _read(): void;
83
- }
4
+ export * from '#kebab/lib/undici/formdata.js';
@@ -1,166 +1,4 @@
1
1
  /**
2
- * Project: Kebab, User: JianSuoQiYue
3
- * Date: 2020-04-07 23:45:03
4
- * Last: 2020-04-07 23:45:07, 2022-09-10 01:35:25
2
+ * --- 兼容旧版 net 模块的 FormData 导出,统一复用 undici 实现 ---
5
3
  */
6
- import * as stream from 'stream';
7
- import * as mime from '@litert/mime';
8
- import * as core from '#kebab/lib/core.js';
9
- import * as fs from '#kebab/lib/fs.js';
10
- export class FormData extends stream.Readable {
11
- /** --- read 调用次数 --- */
12
- _num = 0;
13
- /** --- 要编译的数据 --- */
14
- _data = [];
15
- /** --- 分隔符 --- */
16
- _boundary = '----Kebab' + core.random(29, core.RANDOM_LUN);
17
- /** --- 正在读取文件吗 --- */
18
- _fileReading = false;
19
- /** --- 是否已经结束 --- */
20
- _close = false;
21
- /** --- 总字节长度 --- */
22
- _length = 4 + this._boundary.length;
23
- /** --- 已发送字节长度 --- */
24
- _sent = 0;
25
- /**
26
- * --- 添加字符串 ---
27
- * @param key 键
28
- * @param val 值
29
- */
30
- putString(key, val) {
31
- this._data.push({
32
- 'key': key,
33
- 'type': 'string',
34
- 'value': val,
35
- 'path': ''
36
- });
37
- this._length += this._boundary.length + 49 + Buffer.byteLength(key) + Buffer.byteLength(val);
38
- }
39
- /**
40
- * --- 添加文件 ---
41
- * @param key 键
42
- * @param path 路径
43
- * @param fname 可选,文件名
44
- */
45
- async putFile(key, path, fname) {
46
- path = path.replace(/\\/g, '/');
47
- const stat = await fs.stats(path);
48
- if (!stat) {
49
- return false;
50
- }
51
- if (!fname) {
52
- const lio = path.lastIndexOf('/');
53
- fname = lio === -1 ? path : path.slice(lio + 1);
54
- }
55
- this._data.push({
56
- 'key': key,
57
- 'type': 'file',
58
- 'value': fname,
59
- 'path': path
60
- });
61
- this._length += this._boundary.length +
62
- 76 + Buffer.byteLength(key) + Buffer.byteLength(fname) +
63
- mime.getMime(fname).length + stat.size + 2;
64
- return true;
65
- }
66
- /**
67
- * --- 添加 Buffer 数据 ---
68
- * @param key 键
69
- * @param buffer Buffer 数据
70
- * @param fname 文件名
71
- */
72
- putBuffer(key, buffer, fname) {
73
- this._data.push({
74
- 'key': key,
75
- 'type': 'buffer',
76
- 'value': fname,
77
- 'path': buffer
78
- });
79
- this._length += this._boundary.length +
80
- 76 + Buffer.byteLength(key) + Buffer.byteLength(fname) +
81
- mime.getMime(fname).length + buffer.byteLength + 2;
82
- }
83
- /**
84
- * --- 获取 boundary ---
85
- */
86
- getBoundary() {
87
- return this._boundary;
88
- }
89
- /**
90
- * --- 获取总字节长度 ---
91
- */
92
- getLength() {
93
- return this._length;
94
- }
95
- /**
96
- * --- 获取已发送的字节长度 ---
97
- */
98
- getSent() {
99
- return this._sent;
100
- }
101
- /**
102
- * --- 间隔读取(on data 或 pipe 触发)---
103
- */
104
- // eslint-disable-next-line @typescript-eslint/naming-convention
105
- _read() {
106
- if (this._close) {
107
- // --- 结束了 ---
108
- this.push(null);
109
- return;
110
- }
111
- // --- 文件读取中 ---
112
- if (this._fileReading) {
113
- // --- 等待下面 fileReadable 的 on data 或 end 事件 ---
114
- return;
115
- }
116
- // --- 获取当前 item ---
117
- const item = this._data[this._num];
118
- if (!item) {
119
- this._close = true;
120
- const push = `--${this._boundary}--`;
121
- this._sent += Buffer.byteLength(push);
122
- this.push(push);
123
- return;
124
- }
125
- if (item.type === 'buffer') {
126
- // --- Buffer 数据 ---
127
- const push = `--${this._boundary}\r\nContent-Disposition: form-data; name="${item.key}"; filename="${item.value}"\r\nContent-Type: ${mime.getMime(item.value)}\r\n\r\n`;
128
- this._sent += Buffer.byteLength(push);
129
- this.push(push);
130
- this._sent += item.path.byteLength;
131
- this.push(item.path);
132
- const pushEnd = '\r\n';
133
- this._sent += Buffer.byteLength(pushEnd);
134
- this.push(pushEnd);
135
- }
136
- else if (item.type === 'string') {
137
- // --- 字段 ---
138
- const push = `--${this._boundary}\r\nContent-Disposition: form-data; name="${item.key}"\r\n\r\n${item.value}\r\n`;
139
- this._sent += Buffer.byteLength(push);
140
- this.push(push);
141
- }
142
- else {
143
- // --- 文件 ---
144
- const push = `--${this._boundary}\r\nContent-Disposition: form-data; name="${item.key}"; filename="${item.value}"\r\nContent-Type: ${mime.getMime(item.value)}\r\n\r\n`;
145
- this._sent += Buffer.byteLength(push);
146
- this.push(push);
147
- // --- 创建流 ---
148
- this._fileReading = true;
149
- const fileReadable = fs.createReadStream(item.path);
150
- fileReadable.on('data', (chunk) => {
151
- if (!(chunk instanceof Buffer)) {
152
- return;
153
- }
154
- this._sent += chunk.byteLength;
155
- this.push(chunk);
156
- });
157
- fileReadable.on('end', () => {
158
- this._fileReading = false;
159
- const push = '\r\n';
160
- this._sent += Buffer.byteLength(push);
161
- this.push(push);
162
- });
163
- }
164
- ++this._num;
165
- }
166
- }
4
+ export * from '#kebab/lib/undici/formdata.js';
package/lib/net.js CHANGED
@@ -436,7 +436,17 @@ export async function request(u, data, opt = {}) {
436
436
  return res;
437
437
  }
438
438
  // --- 哦,要追踪 ---
439
- headers['referer'] = u;
439
+ const nextUrl = lText.urlResolve(u, req.headers['location']);
440
+ if (lText.isSameOrigin(u, nextUrl)) {
441
+ headers['referer'] = u;
442
+ }
443
+ else {
444
+ // --- 跨域跳转不得携带来源站点凭据 ---
445
+ delete headers['authorization'];
446
+ delete headers['proxy-authorization'];
447
+ delete headers['cookie'];
448
+ delete headers['referer'];
449
+ }
440
450
  let nextMethod = method;
441
451
  let nextData = data;
442
452
  const status = res.headers['http-code'];
@@ -444,7 +454,11 @@ export async function request(u, data, opt = {}) {
444
454
  nextMethod = 'GET';
445
455
  nextData = undefined;
446
456
  }
447
- return request(lText.urlResolve(u, req.headers['location']), nextData, {
457
+ if (nextData instanceof stream.Readable) {
458
+ return res;
459
+ }
460
+ req.getStream().resume();
461
+ return request(nextUrl, nextData, {
448
462
  'method': nextMethod,
449
463
  'type': type,
450
464
  'timeout': timeout,
package/lib/ratelimit.js CHANGED
@@ -8,8 +8,8 @@ import * as lCore from '#kebab/lib/core.js';
8
8
  * @returns 返回结果对象
9
9
  */
10
10
  export async function check(kv, key, opt = {}) {
11
- const window = opt.window ?? 60;
12
- const max = opt.max ?? 60;
11
+ const window = Math.max(Math.floor(opt.window ?? 60), 1);
12
+ const max = Math.max(Math.floor(opt.max ?? 60), 1);
13
13
  const pre = opt.pre ?? 'rl:';
14
14
  const now = lTime.stamp();
15
15
  /** --- 将窗口分为 6 个子段 --- */
@@ -20,7 +20,7 @@ export async function check(kv, key, opt = {}) {
20
20
  const segCount = Math.ceil(window / segSize);
21
21
  /** --- 统计各段请求数总和 --- */
22
22
  let total = 0;
23
- for (let i = 0; i < segCount; ++i) {
23
+ for (let i = 1; i < segCount; ++i) {
24
24
  const segKey = `${pre}${key}:${segId - i}`;
25
25
  const val = await kv.get(segKey);
26
26
  if (val) {
@@ -43,7 +43,7 @@ export async function check(kv, key, opt = {}) {
43
43
  if (count === 1) {
44
44
  await kv.expire(currentSegKey, window + segSize);
45
45
  }
46
- total += 1;
46
+ total += count;
47
47
  const allowed = total <= max;
48
48
  return {
49
49
  'allowed': allowed,
@@ -59,8 +59,8 @@ export async function check(kv, key, opt = {}) {
59
59
  * @param opt 限速选项
60
60
  */
61
61
  export async function checkFixed(kv, key, opt = {}) {
62
- const window = opt.window ?? 60;
63
- const max = opt.max ?? 60;
62
+ const window = Math.max(Math.floor(opt.window ?? 60), 1);
63
+ const max = Math.max(Math.floor(opt.max ?? 60), 1);
64
64
  const pre = opt.pre ?? 'rl:';
65
65
  const now = lTime.stamp();
66
66
  const rkey = pre + key;
package/lib/scan.js CHANGED
@@ -84,8 +84,15 @@ export class Scan {
84
84
  this._sql.delete(this._name).where({
85
85
  'id': data['id']
86
86
  });
87
- const r = lText.parseJson(data['data']);
88
- return r === false ? -3 : r;
87
+ const parsed = lText.parseJson(data['data']);
88
+ if (parsed === false) {
89
+ return -3;
90
+ }
91
+ const deleted = await this._link.execute(this._sql.getSql(), this._sql.getData());
92
+ if (deleted.error || !deleted.packet?.affected) {
93
+ return -3;
94
+ }
95
+ return parsed;
89
96
  }
90
97
  else if (data['time_update'] > 0) {
91
98
  // --- 已被扫描 ---
@@ -109,9 +116,15 @@ export class Scan {
109
116
  }
110
117
  this._timeLeft = ttl;
111
118
  if (data['data'] !== null) {
112
- // --- 已经写入数据了,删除数据库条目并返回写入的数据内容 ---
113
- await this._link.del('scan-' + this._name + '_' + this._token);
114
- return data;
119
+ // --- 原子获取并删除,确保并发轮询时结果只被消费一次 ---
120
+ const consumed = await this._link.getDelJson('scan-' + this._name + '_' + this._token);
121
+ if ((consumed === false) ||
122
+ (consumed === null) ||
123
+ (typeof consumed !== 'object') ||
124
+ (consumed['data'] === null)) {
125
+ return -3;
126
+ }
127
+ return consumed['data'];
115
128
  }
116
129
  else if (data['time_update'] > 0) {
117
130
  // --- 已被扫描 ---
package/lib/session.js CHANGED
@@ -177,6 +177,8 @@ export class Session {
177
177
  'ttl': this._ttl,
178
178
  'domain': opt.domain,
179
179
  'ssl': ssl,
180
+ 'httponly': true,
181
+ 'samesite': 'Lax',
180
182
  });
181
183
  return true;
182
184
  }
package/lib/text.d.ts CHANGED
@@ -19,6 +19,12 @@ export declare function parseHost(host: string): {
19
19
  * @param url
20
20
  */
21
21
  export declare function parseUrl(url: string): kebab.IUrlParse;
22
+ /**
23
+ * --- 判断两个 URL 是否属于同源地址 ---
24
+ * @param from 来源 URL
25
+ * @param to 目标 URL
26
+ */
27
+ export declare function isSameOrigin(from: string, to: string): boolean;
22
28
  /**
23
29
  * --- 将相对路径根据基准路径进行转换 ---
24
30
  * @param from 基准路径
package/lib/text.js CHANGED
@@ -118,6 +118,24 @@ export function parseUrl(url) {
118
118
  rtn['path'] = rtn['pathname'] + (rtn['query'] ? '?' + rtn['query'] : '');
119
119
  return rtn;
120
120
  }
121
+ /**
122
+ * --- 判断两个 URL 是否属于同源地址 ---
123
+ * @param from 来源 URL
124
+ * @param to 目标 URL
125
+ */
126
+ export function isSameOrigin(from, to) {
127
+ const fromUri = parseUrl(from);
128
+ const toUri = parseUrl(to);
129
+ const getPort = (uri) => {
130
+ if (uri.port) {
131
+ return uri.port;
132
+ }
133
+ return uri.protocol === 'https:' ? '443' : '80';
134
+ };
135
+ return ((fromUri.protocol === toUri.protocol) &&
136
+ (fromUri.hostname === toUri.hostname) &&
137
+ (getPort(fromUri) === getPort(toUri)));
138
+ }
121
139
  /** --- 限定结果不能逃逸出基准路径 --- */
122
140
  function urlResolveLimit(from, limit, rtn) {
123
141
  if (!limit) {
@@ -422,15 +440,25 @@ export function queryParse(query) {
422
440
  catch {
423
441
  value = pos === -1 ? '' : i.slice(pos + 1);
424
442
  }
425
- if (arrayKeys[key]) {
443
+ if (Object.hasOwn(arrayKeys, key)) {
426
444
  ret[key].push(value);
427
445
  }
428
- else if (undefined === ret[key]) {
429
- ret[key] = value;
446
+ else if (!Object.hasOwn(ret, key)) {
447
+ Object.defineProperty(ret, key, {
448
+ 'configurable': true,
449
+ 'enumerable': true,
450
+ 'value': value,
451
+ 'writable': true,
452
+ });
430
453
  }
431
454
  else {
432
455
  ret[key] = [ret[key], value];
433
- arrayKeys[key] = true;
456
+ Object.defineProperty(arrayKeys, key, {
457
+ 'configurable': true,
458
+ 'enumerable': true,
459
+ 'value': true,
460
+ 'writable': true,
461
+ });
434
462
  }
435
463
  }
436
464
  return ret;
@@ -444,7 +472,12 @@ export function htmlescape(html) {
444
472
  if (type !== 'string') {
445
473
  return '[' + type + ']';
446
474
  }
447
- return html.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/'/g, '&quot;');
475
+ return html
476
+ .replace(/&/g, '&amp;')
477
+ .replace(/</g, '&lt;')
478
+ .replace(/>/g, '&gt;')
479
+ .replace(/"/g, '&quot;')
480
+ .replace(/'/g, '&#39;');
448
481
  }
449
482
  /** --- CSV 特殊字符转换为实体字符 --- */
450
483
  export function csvescape(str) {
@@ -568,7 +601,7 @@ export function parseJson(str) {
568
601
  }
569
602
  const ints = v.slice(10);
570
603
  const int = parseInt(ints);
571
- if (int <= Number.MAX_SAFE_INTEGER) {
604
+ if ((int >= Number.MIN_SAFE_INTEGER) && (int <= Number.MAX_SAFE_INTEGER)) {
572
605
  return int;
573
606
  }
574
607
  return BigInt(ints);
@@ -70,7 +70,6 @@ export class Response {
70
70
  /**
71
71
  * --- 获取响应读取流对象 ---
72
72
  */
73
- // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
74
73
  getStream() {
75
74
  try {
76
75
  // --- 要解压 ---
@@ -103,7 +102,6 @@ export class Response {
103
102
  /**
104
103
  * --- 获取原生响应读取流对象 ---
105
104
  */
106
- // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
107
105
  getRawStream() {
108
106
  return this._req ? this._req.body : null;
109
107
  }