xshell 1.1.8 → 1.1.9
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/antd.sass +43 -0
- package/file.js +7 -2
- package/i18n/dict.json +3 -0
- package/package.json +3 -6
- package/prototype.browser.d.ts +9 -4
- package/prototype.browser.js +37 -8
- package/prototype.d.ts +10 -6
- package/prototype.js +51 -20
- package/server.d.ts +1 -3
- package/server.js +7 -9
- package/patches/@types__byte-size@8.1.2.patch +0 -14
package/antd.sass
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.ant-modal-root
|
|
2
|
+
// 增加 modal 标题下方空白
|
|
3
|
+
.ant-modal-header
|
|
4
|
+
margin-bottom: 18px
|
|
5
|
+
|
|
6
|
+
.ant-modal-mask
|
|
7
|
+
background-color: unset
|
|
8
|
+
|
|
9
|
+
.ant-modal
|
|
10
|
+
.ant-modal-content
|
|
11
|
+
padding: 20px
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@mixin height()
|
|
15
|
+
.ant-table-wrapper
|
|
16
|
+
height: 100%
|
|
17
|
+
|
|
18
|
+
.ant-spin-nested-loading
|
|
19
|
+
height: 100%
|
|
20
|
+
|
|
21
|
+
.ant-spin-container
|
|
22
|
+
height: 100%
|
|
23
|
+
display: flex
|
|
24
|
+
flex-direction: column
|
|
25
|
+
|
|
26
|
+
.ant-table-container
|
|
27
|
+
height: 100%
|
|
28
|
+
display: flex
|
|
29
|
+
flex-direction: column
|
|
30
|
+
|
|
31
|
+
.ant-table-body
|
|
32
|
+
position: relative
|
|
33
|
+
flex: 1
|
|
34
|
+
|
|
35
|
+
table
|
|
36
|
+
position: absolute
|
|
37
|
+
left: 0
|
|
38
|
+
top: 0
|
|
39
|
+
right: 0
|
|
40
|
+
bottom: 0
|
|
41
|
+
|
|
42
|
+
.ant-table
|
|
43
|
+
flex: 1
|
package/file.js
CHANGED
|
@@ -154,7 +154,10 @@ export async function flist(fpd, options = {}) {
|
|
|
154
154
|
return _stats;
|
|
155
155
|
}
|
|
156
156
|
if (deep)
|
|
157
|
-
return (await Promise.all(
|
|
157
|
+
return (await Promise.all(
|
|
158
|
+
// 顶层文件/文件夹
|
|
159
|
+
fps.map(async (fp) => {
|
|
160
|
+
/** 顶层文件夹的大小 */
|
|
158
161
|
let fpd_stats;
|
|
159
162
|
return fp.isdir ?
|
|
160
163
|
[
|
|
@@ -163,7 +166,9 @@ export async function flist(fpd, options = {}) {
|
|
|
163
166
|
if (stats) {
|
|
164
167
|
if (!absolute)
|
|
165
168
|
fp_or_stats.fp = fp + fp_or_stats.fp;
|
|
166
|
-
|
|
169
|
+
// 所有顶层文件夹中的文件(不包括文件夹)大小总和加起来作为文件夹大小
|
|
170
|
+
if (!fp_or_stats.fp.isdir)
|
|
171
|
+
fpd_stats.size += fp_or_stats.size;
|
|
167
172
|
return fp_or_stats;
|
|
168
173
|
}
|
|
169
174
|
else
|
package/i18n/dict.json
CHANGED
|
@@ -382,5 +382,8 @@
|
|
|
382
382
|
},
|
|
383
383
|
"等待 {{duration}} 秒后重试 request (已尝试 {{_count}} 次) …": {
|
|
384
384
|
"en": "Wait {{duration}} seconds before retrying request (tried {{_count}} times) …"
|
|
385
|
+
},
|
|
386
|
+
"fsend 必须传 absolute 选项, sea 选项, 或 fpd_root 文件夹": {
|
|
387
|
+
"en": "fsend must be passed the absolute option, the sea option, or the fpd_root folder"
|
|
385
388
|
}
|
|
386
389
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -66,7 +66,6 @@
|
|
|
66
66
|
"@xterm/xterm": "^5.5.0",
|
|
67
67
|
"ali-oss": "^6.22.0",
|
|
68
68
|
"archiver": "^7.0.1",
|
|
69
|
-
"byte-size": "^9.0.1",
|
|
70
69
|
"chalk": "^5.4.0",
|
|
71
70
|
"chardet": "^2.0.0",
|
|
72
71
|
"cli-table3": "^0.6.5",
|
|
@@ -81,7 +80,7 @@
|
|
|
81
80
|
"gulp-sort": "^2.0.0",
|
|
82
81
|
"hash-string": "^1.0.0",
|
|
83
82
|
"https-proxy-agent": "^7.0.6",
|
|
84
|
-
"i18next": "^24.
|
|
83
|
+
"i18next": "^24.2.0",
|
|
85
84
|
"i18next-scanner": "^4.6.0",
|
|
86
85
|
"koa": "^2.15.3",
|
|
87
86
|
"koa-compress": "^5.1.1",
|
|
@@ -92,7 +91,7 @@
|
|
|
92
91
|
"ora": "^8.1.1",
|
|
93
92
|
"react": "^19.0.0",
|
|
94
93
|
"react-i18next": "^15.2.0",
|
|
95
|
-
"react-object-model": "^1.2.
|
|
94
|
+
"react-object-model": "^1.2.21",
|
|
96
95
|
"resolve-path": "^1.4.0",
|
|
97
96
|
"sass": "^1.83.0",
|
|
98
97
|
"sass-loader": "^16.0.4",
|
|
@@ -117,7 +116,6 @@
|
|
|
117
116
|
"@types/ali-oss": "^6.16.11",
|
|
118
117
|
"@types/archiver": "^6.0.3",
|
|
119
118
|
"@types/babel__traverse": "^7.20.6",
|
|
120
|
-
"@types/byte-size": "^8.1.2",
|
|
121
119
|
"@types/chardet": "^0.8.3",
|
|
122
120
|
"@types/eslint": "^9.6.1",
|
|
123
121
|
"@types/estree": "^1.0.6",
|
|
@@ -137,7 +135,6 @@
|
|
|
137
135
|
},
|
|
138
136
|
"pnpm": {
|
|
139
137
|
"patchedDependencies": {
|
|
140
|
-
"@types/byte-size@8.1.2": "patches/@types__byte-size@8.1.2.patch",
|
|
141
138
|
"koa@2.15.3": "patches/koa@2.15.3.patch"
|
|
142
139
|
}
|
|
143
140
|
}
|
package/prototype.browser.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ declare global {
|
|
|
60
60
|
- pattern_placeholder?: `/\{.*?\}/g`
|
|
61
61
|
*/
|
|
62
62
|
find(this: string, pattern: string, preservations?: string, flags?: string, pattern_placeholder?: RegExp): Record<string, string>;
|
|
63
|
+
/** 查找子串或字符出现的次数 */
|
|
64
|
+
count(this: string, search: string): number;
|
|
63
65
|
/** - type?: `'single'` */
|
|
64
66
|
quote(this: string, type?: keyof typeof quotes | 'psh'): string;
|
|
65
67
|
/** - shape?: `'parenthesis'` */
|
|
@@ -134,8 +136,8 @@ declare global {
|
|
|
134
136
|
to_formal_str(this: Date, ms?: boolean): string;
|
|
135
137
|
}
|
|
136
138
|
interface Number {
|
|
137
|
-
/** 12.4
|
|
138
|
-
to_fsize_str(this: number
|
|
139
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
140
|
+
to_fsize_str(this: number): string;
|
|
139
141
|
to_bin_str(this: number): string;
|
|
140
142
|
/** 转换为 0x???? 这样的十六进制形式
|
|
141
143
|
- length?: 位数自动对齐到 4 的倍数 */
|
|
@@ -146,8 +148,8 @@ declare global {
|
|
|
146
148
|
/** 等价于 .at(-1) */
|
|
147
149
|
last: T;
|
|
148
150
|
indent(this: string[], width?: number, c?: string): string[];
|
|
149
|
-
/** 对数组中所有元素求和 (+),
|
|
150
|
-
sum(this: T[]):
|
|
151
|
+
/** 对数组中所有元素求和 (+), 返回结果,可传入 selector 选择某个属性,或者计算出某个值,用作求和 */
|
|
152
|
+
sum<TReturn = T>(this: T[], selector?: keyof T | KeySelector<T>): TReturn;
|
|
151
153
|
/** 查找数组中最大的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
152
154
|
max(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
153
155
|
/** 查找数组中最小的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
@@ -169,6 +171,8 @@ declare global {
|
|
|
169
171
|
join_lines(append?: boolean): string;
|
|
170
172
|
}
|
|
171
173
|
interface BigInt {
|
|
174
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
175
|
+
to_fsize_str(this: bigint): string;
|
|
172
176
|
toJSON(this: bigint): string;
|
|
173
177
|
}
|
|
174
178
|
interface Error {
|
|
@@ -215,4 +219,5 @@ export declare const brackets: {
|
|
|
215
219
|
};
|
|
216
220
|
export declare function to_json(obj: any, replacer?: any): string;
|
|
217
221
|
export declare function is_codepoint_fullwidth(codepoint: number): boolean;
|
|
222
|
+
export declare function byte_size(bytes: number | bigint): string;
|
|
218
223
|
export {};
|
package/prototype.browser.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/** 在浏览器端修改 prototype,需要更加小心 */
|
|
2
|
-
import byte_size from 'byte-size';
|
|
3
2
|
import EmojiRegex from 'emoji-regex';
|
|
4
3
|
import { t } from "./i18n/instance.js";
|
|
5
4
|
export const emoji_regex = EmojiRegex();
|
|
@@ -224,6 +223,14 @@ Object.defineProperties(String.prototype, {
|
|
|
224
223
|
return Object.fromEntries(Object.entries($placeholders)
|
|
225
224
|
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
226
225
|
},
|
|
226
|
+
count(search) {
|
|
227
|
+
if (!search)
|
|
228
|
+
throw new Error('count 的 search 不能为空');
|
|
229
|
+
let count = 0;
|
|
230
|
+
for (let i = 0; (i = this.indexOf(search, i)) !== -1; i += search.length)
|
|
231
|
+
count++;
|
|
232
|
+
return count;
|
|
233
|
+
},
|
|
227
234
|
quote(type = 'single') {
|
|
228
235
|
if (type === 'psh')
|
|
229
236
|
return `& ${this.quote()}`;
|
|
@@ -418,9 +425,8 @@ function get_time_str(date, hour, ms, splitter) {
|
|
|
418
425
|
}
|
|
419
426
|
// ------------------------------------ Number.prototype
|
|
420
427
|
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
421
|
-
to_fsize_str(
|
|
422
|
-
|
|
423
|
-
return `${value} ${unit.replace('i', '')}`;
|
|
428
|
+
to_fsize_str() {
|
|
429
|
+
return byte_size(this);
|
|
424
430
|
},
|
|
425
431
|
to_bin_str() {
|
|
426
432
|
return `0b${this.toString(2)}`;
|
|
@@ -467,10 +473,17 @@ Object.defineProperties(Array.prototype, {
|
|
|
467
473
|
const indent = character.repeat(width);
|
|
468
474
|
return this.map(line => indent + line);
|
|
469
475
|
},
|
|
470
|
-
sum() {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
476
|
+
sum(selector) {
|
|
477
|
+
if (!this.length)
|
|
478
|
+
return undefined;
|
|
479
|
+
// 快捷路径
|
|
480
|
+
const first = this[0];
|
|
481
|
+
if ((typeof first === 'number' || typeof first === 'bigint') && !selector)
|
|
482
|
+
return this.reduce((acc, x) => acc + x, first);
|
|
483
|
+
if (is_key_type(selector))
|
|
484
|
+
selector = build_selector(selector);
|
|
485
|
+
selector ??= ident;
|
|
486
|
+
return this.reduce((acc, x) => acc + selector(x), selector(first));
|
|
474
487
|
},
|
|
475
488
|
max(selector = ident) {
|
|
476
489
|
if (!this.length)
|
|
@@ -520,6 +533,9 @@ Object.defineProperties(Array.prototype, {
|
|
|
520
533
|
})
|
|
521
534
|
});
|
|
522
535
|
Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
|
|
536
|
+
to_fsize_str() {
|
|
537
|
+
return byte_size(this);
|
|
538
|
+
},
|
|
523
539
|
toJSON() {
|
|
524
540
|
return this.toString();
|
|
525
541
|
}
|
|
@@ -583,4 +599,17 @@ export function is_codepoint_fullwidth(codepoint) {
|
|
|
583
599
|
// cjk unified ideographs extension b .. tertiary ideographic plane
|
|
584
600
|
(0x20000 <= codepoint && codepoint <= 0x3fffd)));
|
|
585
601
|
}
|
|
602
|
+
const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
|
|
603
|
+
const bytes_table = units.map((unit, i) => ({
|
|
604
|
+
start: i === 0 ? 0 : 2 ** (i * 10),
|
|
605
|
+
end: 2 ** ((i + 1) * 10),
|
|
606
|
+
unit
|
|
607
|
+
}));
|
|
608
|
+
export function byte_size(bytes) {
|
|
609
|
+
bytes = Number(bytes);
|
|
610
|
+
const sign = bytes < 0 ? '-' : '';
|
|
611
|
+
bytes = Math.abs(bytes);
|
|
612
|
+
const { unit, start } = bytes_table.find(range => bytes >= range.start && bytes < range.end);
|
|
613
|
+
return `${sign}${start === 0 ? bytes : (bytes / start).toFixed()} ${unit}`;
|
|
614
|
+
}
|
|
586
615
|
//# sourceMappingURL=prototype.browser.js.map
|
package/prototype.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ declare global {
|
|
|
59
59
|
- flags?: `''` 正则匹配选项
|
|
60
60
|
- pattern_placeholder?: `/\{.*?\}/g` */
|
|
61
61
|
find(this: string, pattern: string, preservations?: string, flags?: string, pattern_placeholder?: RegExp): Record<string, string>;
|
|
62
|
+
/** 查找子串或字符出现的次数 */
|
|
63
|
+
count(this: string, search: string): number;
|
|
62
64
|
/** - type?: `'single'` 引号类型 */
|
|
63
65
|
quote(this: string, type?: keyof typeof quotes | 'psh'): string;
|
|
64
66
|
/** - type?: `'single'` 引号类型 */
|
|
@@ -157,8 +159,8 @@ declare global {
|
|
|
157
159
|
to_formal_str(this: Date, ms?: boolean): string;
|
|
158
160
|
}
|
|
159
161
|
interface Number {
|
|
160
|
-
/** 12.4
|
|
161
|
-
to_fsize_str(this: number
|
|
162
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
163
|
+
to_fsize_str(this: number): string;
|
|
162
164
|
to_bin_str(this: number): string;
|
|
163
165
|
/** 转换为 0x???? 这样的十六进制形式
|
|
164
166
|
- length?: 位数自动对齐到 4 的倍数 */
|
|
@@ -171,8 +173,8 @@ declare global {
|
|
|
171
173
|
log(this: string[], limit?: number): void;
|
|
172
174
|
indent(this: string[], width?: number, c?: string): string[];
|
|
173
175
|
indent2to4(this: string[]): string[];
|
|
174
|
-
/** 对数组中所有元素求和 (+),
|
|
175
|
-
sum(this: T[]):
|
|
176
|
+
/** 对数组中所有元素求和 (+), 返回结果,可传入 selector 选择某个属性,或者计算出某个值,用作求和 */
|
|
177
|
+
sum<TReturn = T>(this: T[], selector?: keyof T | KeySelector<T>): TReturn;
|
|
176
178
|
/** 查找数组中最大的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
177
179
|
max(this: T[], selector?: keyof T | KeySelector<T>): T;
|
|
178
180
|
/** 查找数组中最小的元素,可传入 selector 选择某个属性,或者计算出某个值,用作大小比较 */
|
|
@@ -199,6 +201,8 @@ declare global {
|
|
|
199
201
|
join_lines(append?: boolean): string;
|
|
200
202
|
}
|
|
201
203
|
interface BigInt {
|
|
204
|
+
/** 12.4 kb (1 kb = 1024 b) */
|
|
205
|
+
to_fsize_str(this: bigint): string;
|
|
202
206
|
toJSON(this: bigint): string;
|
|
203
207
|
}
|
|
204
208
|
interface Error {
|
|
@@ -212,9 +216,7 @@ interface SliceOptions {
|
|
|
212
216
|
include?: boolean;
|
|
213
217
|
last?: boolean;
|
|
214
218
|
}
|
|
215
|
-
import chalk from 'chalk';
|
|
216
219
|
export declare const emoji_regex: RegExp;
|
|
217
|
-
export { chalk };
|
|
218
220
|
export declare const noop: () => void;
|
|
219
221
|
export declare const ident: <T>(x: T) => T;
|
|
220
222
|
export declare const build_selector: <TObj>(key: keyof TObj) => (obj: TObj) => TObj[keyof TObj];
|
|
@@ -248,3 +250,5 @@ export declare const brackets: {
|
|
|
248
250
|
export declare function to_json(obj: any, replacer?: any): string;
|
|
249
251
|
export declare function to_json_safely(obj: any, replacer?: any): string;
|
|
250
252
|
export declare function is_codepoint_fullwidth(codepoint: number): boolean;
|
|
253
|
+
export declare function byte_size(bytes: number | bigint): string;
|
|
254
|
+
export {};
|
package/prototype.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import util from 'util';
|
|
2
2
|
import EmojiRegex from 'emoji-regex';
|
|
3
|
+
export const emoji_regex = EmojiRegex();
|
|
3
4
|
import strip_ansi from 'strip-ansi';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
5
|
import { to_fp, dirname, basename, extname } from "./path.js";
|
|
6
6
|
import { t } from "./i18n/instance.js";
|
|
7
|
-
chalk.level = 2;
|
|
8
|
-
export const emoji_regex = EmojiRegex();
|
|
9
|
-
export { chalk };
|
|
10
7
|
export const noop = () => { };
|
|
11
8
|
export const ident = (x) => x;
|
|
12
9
|
export const build_selector = (key) => (obj) => obj[key];
|
|
@@ -47,7 +44,6 @@ export const brackets = {
|
|
|
47
44
|
fat: ['【', '】'],
|
|
48
45
|
tortoise_shell: ['〔', '〕'],
|
|
49
46
|
};
|
|
50
|
-
const color_map = Object.fromEntries(['red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_'].map(color => [color, `${color.slice(0, -1)}Bright`]));
|
|
51
47
|
if (!globalThis.my_prototype_defined) {
|
|
52
48
|
// ------------------------------------ String.prototype
|
|
53
49
|
Object.defineProperties(String.prototype, {
|
|
@@ -222,6 +218,15 @@ if (!globalThis.my_prototype_defined) {
|
|
|
222
218
|
return Object.fromEntries(Object.entries($placeholders)
|
|
223
219
|
.map(([name, $i]) => [name, matches[$i] || '']));
|
|
224
220
|
},
|
|
221
|
+
/** 查找子串或字符出现的次数 */
|
|
222
|
+
count(search) {
|
|
223
|
+
if (!search)
|
|
224
|
+
throw new Error('count 的 search 不能为空');
|
|
225
|
+
let count = 0;
|
|
226
|
+
for (let i = 0; (i = this.indexOf(search, i)) !== -1; i += search.length)
|
|
227
|
+
count++;
|
|
228
|
+
return count;
|
|
229
|
+
},
|
|
225
230
|
quote(type = 'single') {
|
|
226
231
|
if (type === 'psh')
|
|
227
232
|
return `& ${this.quote()}`;
|
|
@@ -345,17 +350,21 @@ if (!globalThis.my_prototype_defined) {
|
|
|
345
350
|
.replace(new RegExp('([A-Za-z0-9`\\$%\\^&\\*\\-=\\+\\\\\\|\\/@\u00a1-\u00ff\u2022\u2027\u2150-\u218f])' + cjk, 'g'), '$1 $2');
|
|
346
351
|
}
|
|
347
352
|
}),
|
|
348
|
-
// ------------
|
|
353
|
+
// ------------ colors
|
|
349
354
|
...Object.fromEntries([
|
|
350
355
|
'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'grey',
|
|
351
356
|
'red_', 'green_', 'yellow_', 'blue_', 'magenta_', 'cyan_',
|
|
352
357
|
'underline',
|
|
353
|
-
].map(color =>
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
].map(color => {
|
|
359
|
+
const style = color.endsWith('_') ? `${color.slice(0, -1)}Bright` : color;
|
|
360
|
+
return [color, {
|
|
361
|
+
configurable: true,
|
|
362
|
+
get() {
|
|
363
|
+
// @ts-ignore
|
|
364
|
+
return util.styleText(style, this, { validateStream: false });
|
|
365
|
+
}
|
|
366
|
+
}];
|
|
367
|
+
})),
|
|
359
368
|
// ------------ 文件路径操作
|
|
360
369
|
...to_getter_property_descriptors({
|
|
361
370
|
isdir() {
|
|
@@ -447,9 +456,8 @@ if (!globalThis.my_prototype_defined) {
|
|
|
447
456
|
}
|
|
448
457
|
// ------------------------------------ Number.prototype
|
|
449
458
|
Object.defineProperties(Number.prototype, to_method_property_descriptors({
|
|
450
|
-
to_fsize_str(
|
|
451
|
-
|
|
452
|
-
return `${value} ${unit.replace('i', '')}`;
|
|
459
|
+
to_fsize_str() {
|
|
460
|
+
return byte_size(this);
|
|
453
461
|
},
|
|
454
462
|
to_bin_str() {
|
|
455
463
|
return `0b${this.toString(2)}`;
|
|
@@ -520,10 +528,17 @@ if (!globalThis.my_prototype_defined) {
|
|
|
520
528
|
return this.split_indents()
|
|
521
529
|
.map(line => ' '.repeat(line.indent * 2) + line.text);
|
|
522
530
|
},
|
|
523
|
-
sum() {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
531
|
+
sum(selector) {
|
|
532
|
+
if (!this.length)
|
|
533
|
+
return undefined;
|
|
534
|
+
// 快捷路径
|
|
535
|
+
const first = this[0];
|
|
536
|
+
if ((typeof first === 'number' || typeof first === 'bigint') && !selector)
|
|
537
|
+
return this.reduce((acc, x) => acc + x, first);
|
|
538
|
+
if (is_key_type(selector))
|
|
539
|
+
selector = build_selector(selector);
|
|
540
|
+
selector ??= ident;
|
|
541
|
+
return this.reduce((acc, x) => acc + selector(x), selector(first));
|
|
527
542
|
},
|
|
528
543
|
max(selector = ident) {
|
|
529
544
|
if (!this.length)
|
|
@@ -573,6 +588,9 @@ if (!globalThis.my_prototype_defined) {
|
|
|
573
588
|
})
|
|
574
589
|
});
|
|
575
590
|
Object.defineProperties(BigInt.prototype, to_method_property_descriptors({
|
|
591
|
+
to_fsize_str() {
|
|
592
|
+
return byte_size(this);
|
|
593
|
+
},
|
|
576
594
|
toJSON() {
|
|
577
595
|
return this.toString();
|
|
578
596
|
}
|
|
@@ -643,4 +661,17 @@ export function is_codepoint_fullwidth(codepoint) {
|
|
|
643
661
|
// cjk unified ideographs extension b .. tertiary ideographic plane
|
|
644
662
|
(0x20000 <= codepoint && codepoint <= 0x3fffd)));
|
|
645
663
|
}
|
|
664
|
+
const units = ['b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb'];
|
|
665
|
+
const bytes_table = units.map((unit, i) => ({
|
|
666
|
+
start: i === 0 ? 0 : 2 ** (i * 10),
|
|
667
|
+
end: 2 ** ((i + 1) * 10),
|
|
668
|
+
unit
|
|
669
|
+
}));
|
|
670
|
+
export function byte_size(bytes) {
|
|
671
|
+
bytes = Number(bytes);
|
|
672
|
+
const sign = bytes < 0 ? '-' : '';
|
|
673
|
+
bytes = Math.abs(bytes);
|
|
674
|
+
const { unit, start } = bytes_table.find(range => bytes >= range.start && bytes < range.end);
|
|
675
|
+
return `${sign}${start === 0 ? bytes : (bytes / start).toFixed()} ${unit}`;
|
|
676
|
+
}
|
|
646
677
|
//# sourceMappingURL=prototype.js.map
|
package/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Server as HttpServer, type IncomingHttpHeaders, type IncomingMessa
|
|
|
2
2
|
import { type Http2SecureServer, type IncomingHttpHeaders as IncomingHttp2Headers } from 'http2';
|
|
3
3
|
import type { Duplex } from 'stream';
|
|
4
4
|
import type { WebSocketServer } from 'ws';
|
|
5
|
-
import
|
|
5
|
+
import { default as Koa, type Context, type Next } from 'koa';
|
|
6
6
|
declare module 'koa' {
|
|
7
7
|
interface Request {
|
|
8
8
|
/** 经过 decodeURIComponent 后,在路径重写之前的路径 */
|
|
@@ -13,7 +13,6 @@ declare module 'koa' {
|
|
|
13
13
|
compress: boolean;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
import type { UAParser } from 'ua-parser-js';
|
|
17
16
|
import { Remote, type RequestOptions, type RawResponse } from './net.ts';
|
|
18
17
|
declare module 'http' {
|
|
19
18
|
interface IncomingMessage {
|
|
@@ -34,7 +33,6 @@ export declare class Server {
|
|
|
34
33
|
};
|
|
35
34
|
/** sea 下最后修改时间,用于 http 资源缓存 */
|
|
36
35
|
last_modified_str?: string;
|
|
37
|
-
UAParser: typeof UAParser;
|
|
38
36
|
js_exts: Set<string>;
|
|
39
37
|
empty_body_statuses: Set<number>;
|
|
40
38
|
empty_body_methods: Set<string>;
|
package/server.js
CHANGED
|
@@ -6,6 +6,12 @@ import fs from 'fs';
|
|
|
6
6
|
import { buffer as stream_to_buffer } from 'stream/consumers';
|
|
7
7
|
import util from 'util';
|
|
8
8
|
import node_sea from 'node:sea';
|
|
9
|
+
import { default as Koa } from 'koa';
|
|
10
|
+
import KoaCors from '@koa/cors';
|
|
11
|
+
import KoaCompress from 'koa-compress';
|
|
12
|
+
import { UAParser } from 'ua-parser-js';
|
|
13
|
+
import resolve_safely from 'resolve-path';
|
|
14
|
+
import { contentType as get_content_type } from 'mime-types';
|
|
9
15
|
// --- my libs
|
|
10
16
|
import { t } from "./i18n/instance.js";
|
|
11
17
|
import { request as _request, Remote } from "./net.js";
|
|
@@ -31,7 +37,6 @@ export class Server {
|
|
|
31
37
|
};
|
|
32
38
|
/** sea 下最后修改时间,用于 http 资源缓存 */
|
|
33
39
|
last_modified_str;
|
|
34
|
-
UAParser;
|
|
35
40
|
js_exts = new Set(['.js', '.mjs', '.cjs']);
|
|
36
41
|
empty_body_statuses = new Set([304, 204, 205]);
|
|
37
42
|
empty_body_methods = new Set(['HEAD', 'OPTIONS']);
|
|
@@ -93,14 +98,9 @@ export class Server {
|
|
|
93
98
|
}
|
|
94
99
|
/** start http server and listen */
|
|
95
100
|
async start() {
|
|
96
|
-
const { default: Koa } = await import('koa');
|
|
97
|
-
const { default: KoaCors } = await import('@koa/cors');
|
|
98
|
-
const { default: KoaCompress } = await import('koa-compress');
|
|
99
101
|
if (sea)
|
|
100
102
|
this.last_modified_str = (await fstat(exe_nodejs))
|
|
101
103
|
.mtime.toUTCString();
|
|
102
|
-
const { UAParser } = await import('ua-parser-js');
|
|
103
|
-
this.UAParser = UAParser;
|
|
104
104
|
// --- init koa app
|
|
105
105
|
let app = new Koa();
|
|
106
106
|
app.on('error', this.on_error.bind(this));
|
|
@@ -442,7 +442,7 @@ export class Server {
|
|
|
442
442
|
}
|
|
443
443
|
format_ua(headers) {
|
|
444
444
|
const { rtt, 'device-memory': memory } = headers;
|
|
445
|
-
const { device, os, browser } =
|
|
445
|
+
const { device, os, browser } = UAParser(headers).withClientHints();
|
|
446
446
|
const vendor = device.vendor?.toLowerCase();
|
|
447
447
|
const model = device.model?.toLowerCase();
|
|
448
448
|
const osname = os.name?.toLowerCase();
|
|
@@ -603,7 +603,6 @@ export class Server {
|
|
|
603
603
|
let { response } = ctx;
|
|
604
604
|
if (!absolute && !_sea) {
|
|
605
605
|
fp = fp.strip_if_start(fpd_root).strip_if_start('/');
|
|
606
|
-
const { default: resolve_safely } = await import('resolve-path');
|
|
607
606
|
try {
|
|
608
607
|
fp = resolve_safely(fpd_root, fp).fp;
|
|
609
608
|
}
|
|
@@ -652,7 +651,6 @@ export class Server {
|
|
|
652
651
|
if (download)
|
|
653
652
|
response.set('content-disposition', `attachment; filename="${encodeURIComponent(fp.fname)}"`);
|
|
654
653
|
if (!response.get('content-type')) {
|
|
655
|
-
const { contentType: get_content_type } = await import('mime-types');
|
|
656
654
|
const { fext } = fp;
|
|
657
655
|
response.set('content-type', (this.js_exts.has(fext) ? 'text/javascript; chatset=utf-8' : get_content_type(fext))
|
|
658
656
|
|| 'application/octet-stream');
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# 用来修复 `byte_size()` 函数的 ts 类型报错
|
|
2
|
-
|
|
3
|
-
diff --git a/package.json b/package.json
|
|
4
|
-
index dd8ed66fcb8b1ab93f0a3a015bad95bc31d3b18d..6a3753f42610451163fd7d502a93779fe3dca8db 100644
|
|
5
|
-
--- a/package.json
|
|
6
|
-
+++ b/package.json
|
|
7
|
-
@@ -11,6 +11,7 @@
|
|
8
|
-
"url": "https://github.com/lntel"
|
|
9
|
-
}
|
|
10
|
-
],
|
|
11
|
-
+ "type": "module",
|
|
12
|
-
"main": "",
|
|
13
|
-
"types": "index.d.ts",
|
|
14
|
-
"repository": {
|