xshell 1.0.55 → 1.0.57
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/file.d.ts +10 -8
- package/file.js +24 -13
- package/net.browser.js +1 -1
- package/net.d.ts +2 -1
- package/net.js +3 -3
- package/package.json +17 -17
- package/prototype.browser.d.ts +1 -2
- package/prototype.browser.js +2 -2
- package/prototype.d.ts +0 -1
- package/prototype.js +3 -8
- package/server.d.ts +2 -2
- package/server.js +2 -1
package/file.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export declare function fread_json<T = any>(fp: string, options?: {
|
|
|
51
51
|
print?: boolean;
|
|
52
52
|
}): Promise<T>;
|
|
53
53
|
/** 写入 data 到 fp 路径所指的文件
|
|
54
|
+
会在因不存在父文件夹导致写入失败时,自动创建父文件夹,并再次尝试写入
|
|
55
|
+
最好预先创建父文件夹,减少文件系统操作,提升性能
|
|
54
56
|
- fp: 目标文件完整路径
|
|
55
57
|
- data: 支持下面几种类型
|
|
56
58
|
- string: 写入文本
|
|
@@ -58,12 +60,10 @@ export declare function fread_json<T = any>(fp: string, options?: {
|
|
|
58
60
|
- any: 通过 JSON.stringify 转为文本后写入文件
|
|
59
61
|
- options?:
|
|
60
62
|
- dir?: 文件夹
|
|
61
|
-
- print
|
|
62
|
-
|
|
63
|
-
export declare function fwrite(fp: string | FileHandle, data: string | Uint8Array | any, { dir, print, mkdir, }?: {
|
|
63
|
+
- print?: `true` */
|
|
64
|
+
export declare function fwrite(fp: string | FileHandle, data: string | Uint8Array | any, { dir, print, }?: {
|
|
64
65
|
dir?: string;
|
|
65
66
|
print?: boolean;
|
|
66
|
-
mkdir?: boolean;
|
|
67
67
|
}): Promise<void>;
|
|
68
68
|
export declare function fappend(fp: string, data: string | Uint8Array, { dir, print }?: {
|
|
69
69
|
dir?: string;
|
|
@@ -107,10 +107,11 @@ export declare function ffstat(handle: fsp.FileHandle): Promise<fs.BigIntStats>;
|
|
|
107
107
|
export declare function fdelete(fp: string, { print }?: {
|
|
108
108
|
print?: boolean;
|
|
109
109
|
}): Promise<boolean>;
|
|
110
|
-
/** 复制文件或文件夹
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
110
|
+
/** 复制文件或文件夹
|
|
111
|
+
会在因不存在父文件夹导致复制失败时,自动创建父文件夹,并再次尝试复制
|
|
112
|
+
最好预先创建父文件夹,减少文件系统操作,提升性能
|
|
113
|
+
- fp_src: 源 文件/文件夹 完整路径
|
|
114
|
+
- fp_dst: 目标 文件/文件夹 完整路径
|
|
114
115
|
- options?:
|
|
115
116
|
- print?: `true`
|
|
116
117
|
- overwrite?: `true`
|
|
@@ -122,6 +123,7 @@ export declare function fcopy(fp_src: string, fp_dst: string, { print, overwrite
|
|
|
122
123
|
overwrite?: boolean;
|
|
123
124
|
}): Promise<void>;
|
|
124
125
|
/** 移动文件或文件夹
|
|
126
|
+
相同分区 / 文件系统下使用 rename, 否则 fallback 到复制后删除源文件
|
|
125
127
|
- src: 源 文件/文件夹 完整路径
|
|
126
128
|
- dst: 目标 文件/文件夹 完整路径
|
|
127
129
|
- options?:
|
package/file.js
CHANGED
|
@@ -55,6 +55,8 @@ export async function fread_json(fp, options = {}) {
|
|
|
55
55
|
return JSON.parse(await fread(fp, options));
|
|
56
56
|
}
|
|
57
57
|
/** 写入 data 到 fp 路径所指的文件
|
|
58
|
+
会在因不存在父文件夹导致写入失败时,自动创建父文件夹,并再次尝试写入
|
|
59
|
+
最好预先创建父文件夹,减少文件系统操作,提升性能
|
|
58
60
|
- fp: 目标文件完整路径
|
|
59
61
|
- data: 支持下面几种类型
|
|
60
62
|
- string: 写入文本
|
|
@@ -62,9 +64,8 @@ export async function fread_json(fp, options = {}) {
|
|
|
62
64
|
- any: 通过 JSON.stringify 转为文本后写入文件
|
|
63
65
|
- options?:
|
|
64
66
|
- dir?: 文件夹
|
|
65
|
-
- print
|
|
66
|
-
|
|
67
|
-
export async function fwrite(fp, data, { dir, print = true, mkdir = false, } = {}) {
|
|
67
|
+
- print?: `true` */
|
|
68
|
+
export async function fwrite(fp, data, { dir, print = true, } = {}) {
|
|
68
69
|
const is_handle = typeof fp === 'object' && fp && 'fd' in fp;
|
|
69
70
|
if (is_handle) {
|
|
70
71
|
if (print)
|
|
@@ -85,8 +86,8 @@ export async function fwrite(fp, data, { dir, print = true, mkdir = false, } = {
|
|
|
85
86
|
await fsp.writeFile(fp, data);
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
88
|
-
if (
|
|
89
|
-
await fmkdir(fp.fdir);
|
|
89
|
+
if (error.code === 'ENOENT' && !is_handle) {
|
|
90
|
+
await fmkdir(fp.fdir, { print: false });
|
|
90
91
|
await fsp.writeFile(fp, data);
|
|
91
92
|
}
|
|
92
93
|
else
|
|
@@ -216,10 +217,11 @@ export async function fdelete(fp, { print = true } = {}) {
|
|
|
216
217
|
throw error;
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
|
-
/** 复制文件或文件夹
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
-
|
|
220
|
+
/** 复制文件或文件夹
|
|
221
|
+
会在因不存在父文件夹导致复制失败时,自动创建父文件夹,并再次尝试复制
|
|
222
|
+
最好预先创建父文件夹,减少文件系统操作,提升性能
|
|
223
|
+
- fp_src: 源 文件/文件夹 完整路径
|
|
224
|
+
- fp_dst: 目标 文件/文件夹 完整路径
|
|
223
225
|
- options?:
|
|
224
226
|
- print?: `true`
|
|
225
227
|
- overwrite?: `true`
|
|
@@ -239,12 +241,21 @@ export async function fcopy(fp_src, fp_dst, { print = true, overwrite = true, }
|
|
|
239
241
|
errorOnExist: !overwrite,
|
|
240
242
|
mode: overwrite ? 0 : fs.constants.COPYFILE_EXCL,
|
|
241
243
|
});
|
|
242
|
-
else
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
else
|
|
245
|
+
try {
|
|
246
|
+
await fsp.copyFile(fp_src, fp_dst, overwrite ? 0 : fs.constants.COPYFILE_EXCL);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
if (error.code === 'ENOENT') {
|
|
250
|
+
await fmkdir(fp_dst.fdir, { print });
|
|
251
|
+
await fsp.copyFile(fp_src, fp_dst, overwrite ? 0 : fs.constants.COPYFILE_EXCL);
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
246
256
|
}
|
|
247
257
|
/** 移动文件或文件夹
|
|
258
|
+
相同分区 / 文件系统下使用 rename, 否则 fallback 到复制后删除源文件
|
|
248
259
|
- src: 源 文件/文件夹 完整路径
|
|
249
260
|
- dst: 目标 文件/文件夹 完整路径
|
|
250
261
|
- options?:
|
package/net.browser.js
CHANGED
|
@@ -190,7 +190,7 @@ export async function connect_websocket(url, { protocols, on_message, on_error,
|
|
|
190
190
|
let settled = false;
|
|
191
191
|
websocket.addEventListener('open', event => {
|
|
192
192
|
console.log(websocket.url +
|
|
193
|
-
(websocket.protocol ? websocket.protocol.bracket() : '') +
|
|
193
|
+
(websocket.protocol ? ' ' + websocket.protocol.bracket() : '') +
|
|
194
194
|
t(' 已连接'));
|
|
195
195
|
settled = true;
|
|
196
196
|
resolve(websocket);
|
package/net.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare const cookies: {
|
|
|
25
25
|
init(): Promise<void>;
|
|
26
26
|
get(domain_or_url: string, str?: boolean): Cookie[] | Promise<Cookie[] | string>;
|
|
27
27
|
};
|
|
28
|
-
export { Cookie };
|
|
28
|
+
export type { Cookie };
|
|
29
29
|
export interface BasicAuth {
|
|
30
30
|
type: 'basic';
|
|
31
31
|
username: string;
|
|
@@ -47,6 +47,7 @@ export interface RequestOptions {
|
|
|
47
47
|
timeout?: number;
|
|
48
48
|
auth?: BasicAuth | BearerAuth;
|
|
49
49
|
cookies?: Record<string, string>;
|
|
50
|
+
redirect?: RequestRedirect;
|
|
50
51
|
}
|
|
51
52
|
export interface RequestRawOptions extends RequestOptions {
|
|
52
53
|
raw: true;
|
package/net.js
CHANGED
|
@@ -70,7 +70,7 @@ async function fetch_retry(url, options, timeout, retries = 0, count = 0) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
export async function request(url, { method, queries, headers: _headers, body, type = 'application/json', proxy, encoding, retries, timeout = 5 * 1000, auth, cookies: _cookies, raw = false, } = {}) {
|
|
73
|
+
export async function request(url, { method, queries, headers: _headers, body, type = 'application/json', proxy, encoding, retries, timeout = 5 * 1000, auth, cookies: _cookies, raw = false, redirect = 'follow', } = {}) {
|
|
74
74
|
const { Headers, ProxyAgent, FormData } = await import('undici');
|
|
75
75
|
url = new URL(url);
|
|
76
76
|
if (queries)
|
|
@@ -121,7 +121,7 @@ export async function request(url, { method, queries, headers: _headers, body, t
|
|
|
121
121
|
}
|
|
122
122
|
})(),
|
|
123
123
|
keepalive: true,
|
|
124
|
-
redirect
|
|
124
|
+
redirect,
|
|
125
125
|
maxRedirect: 6,
|
|
126
126
|
credentials: 'include',
|
|
127
127
|
headers,
|
|
@@ -354,7 +354,7 @@ on_message, on_error, on_close }) {
|
|
|
354
354
|
let settled = false;
|
|
355
355
|
websocket.addEventListener('open', event => {
|
|
356
356
|
console.log(websocket.url +
|
|
357
|
-
(websocket.protocol ? websocket.protocol.bracket() : '') +
|
|
357
|
+
(websocket.protocol ? ' ' + websocket.protocol.bracket() : '') +
|
|
358
358
|
t(' 已连接'));
|
|
359
359
|
settled = true;
|
|
360
360
|
resolve(websocket);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"interactive programming"
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=20.
|
|
20
|
-
"vscode": ">=1.
|
|
19
|
+
"node": ">=20.6.0",
|
|
20
|
+
"vscode": ">=1.81.0"
|
|
21
21
|
},
|
|
22
22
|
"author": "ShenHongFei <shen.hongfei@outlook.com> (https://github.com/ShenHongFei)",
|
|
23
23
|
"publisher": "ShenHongFei",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
]
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@babel/core": "^7.22.
|
|
49
|
-
"@babel/parser": "^7.22.
|
|
50
|
-
"@babel/traverse": "^7.22.
|
|
48
|
+
"@babel/core": "^7.22.15",
|
|
49
|
+
"@babel/parser": "^7.22.15",
|
|
50
|
+
"@babel/traverse": "^7.22.15",
|
|
51
51
|
"@koa/cors": "^4.0.0",
|
|
52
52
|
"@types/ws": "^8.5.5",
|
|
53
53
|
"byte-size": "^8.1.1",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"fetch-cookie": "^2.1.0",
|
|
62
62
|
"gulp-sort": "^2.0.0",
|
|
63
63
|
"hash-string": "^1.0.0",
|
|
64
|
-
"i18next": "^23.4.
|
|
65
|
-
"i18next-scanner": "^4.
|
|
64
|
+
"i18next": "^23.4.6",
|
|
65
|
+
"i18next-scanner": "^4.4.0",
|
|
66
66
|
"js-cookie": "^3.0.5",
|
|
67
67
|
"koa": "^2.14.2",
|
|
68
68
|
"koa-compress": "^5.1.1",
|
|
@@ -71,13 +71,13 @@
|
|
|
71
71
|
"mime-types": "^2.1.35",
|
|
72
72
|
"ora": "^7.0.1",
|
|
73
73
|
"react": "^18.2.0",
|
|
74
|
-
"react-i18next": "^13.2.
|
|
74
|
+
"react-i18next": "^13.2.2",
|
|
75
75
|
"resolve-path": "^1.4.0",
|
|
76
76
|
"strip-ansi": "^7.1.0",
|
|
77
77
|
"through2": "^4.0.2",
|
|
78
78
|
"tough-cookie": "^4.1.3",
|
|
79
79
|
"tslib": "^2.6.2",
|
|
80
|
-
"typescript": "^5.
|
|
80
|
+
"typescript": "^5.2.2",
|
|
81
81
|
"ua-parser-js": "2.0.0-alpha.2",
|
|
82
82
|
"undici": "^5.23.0",
|
|
83
83
|
"vinyl": "^3.0.0",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"ws": "^8.13.0"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@babel/types": "^7.22.
|
|
88
|
+
"@babel/types": "^7.22.15",
|
|
89
89
|
"@types/babel__traverse": "^7.20.1",
|
|
90
90
|
"@types/byte-size": "^8.1.0",
|
|
91
91
|
"@types/chardet": "^0.8.1",
|
|
@@ -95,18 +95,18 @@
|
|
|
95
95
|
"@types/koa-compress": "^4.0.3",
|
|
96
96
|
"@types/lodash": "^4.14.197",
|
|
97
97
|
"@types/mime-types": "^2.1.1",
|
|
98
|
-
"@types/node": "^20.5.
|
|
98
|
+
"@types/node": "^20.5.9",
|
|
99
99
|
"@types/react": "^18.2.21",
|
|
100
100
|
"@types/through2": "^2.0.38",
|
|
101
101
|
"@types/tough-cookie": "^4.0.2",
|
|
102
|
-
"@types/ua-parser-js": "^0.7.
|
|
102
|
+
"@types/ua-parser-js": "^0.7.37",
|
|
103
103
|
"@types/vinyl-fs": "^3.0.2",
|
|
104
104
|
"@types/vscode": "^1.81.0",
|
|
105
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
106
|
-
"@typescript-eslint/parser": "^6.
|
|
107
|
-
"eslint": "^8.
|
|
105
|
+
"@typescript-eslint/eslint-plugin": "^6.6.0",
|
|
106
|
+
"@typescript-eslint/parser": "^6.6.0",
|
|
107
|
+
"eslint": "^8.48.0",
|
|
108
108
|
"eslint-plugin-react": "^7.33.2",
|
|
109
|
-
"eslint-plugin-xlint": "^1.0.
|
|
109
|
+
"eslint-plugin-xlint": "^1.0.8"
|
|
110
110
|
},
|
|
111
111
|
"scripts": {
|
|
112
112
|
"start": "node --title=xshell --inspect=0.0.0.0:8420 ./xshell.js",
|
package/prototype.browser.d.ts
CHANGED
|
@@ -10,8 +10,7 @@ declare global {
|
|
|
10
10
|
truncate(this: string, width: number): string;
|
|
11
11
|
/** pad string to `<width>`
|
|
12
12
|
- character?: `' '`
|
|
13
|
-
- position?: `'right'`
|
|
14
|
-
*/
|
|
13
|
+
- position?: `'right'` */
|
|
15
14
|
pad(this: string, width: number, { character, position }?: {
|
|
16
15
|
character?: string;
|
|
17
16
|
position?: 'left' | 'right';
|
package/prototype.browser.js
CHANGED
|
@@ -149,7 +149,7 @@ Object.defineProperties(String.prototype, {
|
|
|
149
149
|
add_part(last_end);
|
|
150
150
|
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
151
151
|
regx_parts = regx_parts.filter(part => part);
|
|
152
|
-
if (regx_parts.
|
|
152
|
+
if (regx_parts[regx_parts.length - 1] === '(.*?)')
|
|
153
153
|
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
154
154
|
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
155
155
|
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
@@ -240,7 +240,7 @@ Object.defineProperties(String.prototype, {
|
|
|
240
240
|
},
|
|
241
241
|
split_lines(delimiter = /\r?\n/) {
|
|
242
242
|
let lines = this.split(delimiter);
|
|
243
|
-
if (lines.
|
|
243
|
+
if (lines[lines.length - 1] === '')
|
|
244
244
|
lines.pop();
|
|
245
245
|
return lines;
|
|
246
246
|
},
|
package/prototype.d.ts
CHANGED
package/prototype.js
CHANGED
|
@@ -147,7 +147,7 @@ if (!globalThis.my_prototype_defined) {
|
|
|
147
147
|
add_part(last_end);
|
|
148
148
|
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
149
149
|
regx_parts = regx_parts.filter(part => part);
|
|
150
|
-
if (regx_parts.
|
|
150
|
+
if (regx_parts.at(-1) === '(.*?)')
|
|
151
151
|
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
152
152
|
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
153
153
|
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
@@ -204,7 +204,7 @@ if (!globalThis.my_prototype_defined) {
|
|
|
204
204
|
add_part(last_end);
|
|
205
205
|
// 最后一个 (.*?) 改为贪心匹配,满足 .{suffix} 的需要
|
|
206
206
|
regx_parts = regx_parts.filter(part => part);
|
|
207
|
-
if (regx_parts
|
|
207
|
+
if (regx_parts.at(-1) === '(.*?)')
|
|
208
208
|
regx_parts[regx_parts.length - 1] = '(.*)';
|
|
209
209
|
const pattern_regx = new RegExp(regx_parts.join(''), flags);
|
|
210
210
|
// --- 根据 pattern_regx 去匹配原有字符串,获取匹配结果,生成 placeholders 词典
|
|
@@ -241,7 +241,7 @@ if (!globalThis.my_prototype_defined) {
|
|
|
241
241
|
},
|
|
242
242
|
split_lines(delimiter = /\r?\n/) {
|
|
243
243
|
let lines = this.split(delimiter);
|
|
244
|
-
if (lines.
|
|
244
|
+
if (lines.at(-1) === '')
|
|
245
245
|
lines.pop();
|
|
246
246
|
return lines;
|
|
247
247
|
},
|
|
@@ -408,11 +408,6 @@ if (!globalThis.my_prototype_defined) {
|
|
|
408
408
|
}));
|
|
409
409
|
// ------------------------------------ Array.prototype
|
|
410
410
|
Object.defineProperties(Array.prototype, {
|
|
411
|
-
...to_getter_property_descriptors({
|
|
412
|
-
last() {
|
|
413
|
-
return this[this.length - 1];
|
|
414
|
-
}
|
|
415
|
-
}),
|
|
416
411
|
// --- 文本处理工具方法
|
|
417
412
|
...to_method_property_descriptors({
|
|
418
413
|
log(limit = 10000) {
|
package/server.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ declare module 'koa' {
|
|
|
16
16
|
compress: boolean;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
import { type Remote, type Headers } from './net.js';
|
|
19
|
+
import { type Remote, type Headers, type RequestOptions } from './net.js';
|
|
20
20
|
declare module 'http' {
|
|
21
21
|
interface IncomingMessage {
|
|
22
22
|
body?: Buffer;
|
|
@@ -66,7 +66,7 @@ export declare class Server {
|
|
|
66
66
|
logger(ctx: Context): void;
|
|
67
67
|
process_ua(ctx: Context): string;
|
|
68
68
|
format_ua(headers: IncomingHttpHeaders | IncomingHttp2Headers): string;
|
|
69
|
-
proxy(ctx: Context, url: string | URL, headers_?: Record<string, string
|
|
69
|
+
proxy(ctx: Context, url: string | URL, headers_?: Record<string, string>, redirect?: RequestOptions['redirect']): Promise<void>;
|
|
70
70
|
static filter_response_headers(headers: Headers): {};
|
|
71
71
|
try_send(ctx: Context, fpd_root: string, fp: string, log_404: boolean): Promise<boolean>;
|
|
72
72
|
/** 将 body 设置为 fp 所指文件的 ReadStream
|
package/server.js
CHANGED
|
@@ -262,7 +262,7 @@ export class Server {
|
|
|
262
262
|
}
|
|
263
263
|
return s;
|
|
264
264
|
}
|
|
265
|
-
async proxy(ctx, url, headers_ = {}) {
|
|
265
|
+
async proxy(ctx, url, headers_ = {}, redirect = 'manual') {
|
|
266
266
|
const { request: { method, headers, query, body, ip } } = ctx;
|
|
267
267
|
let { response } = ctx;
|
|
268
268
|
try {
|
|
@@ -276,6 +276,7 @@ export class Server {
|
|
|
276
276
|
...headers_
|
|
277
277
|
},
|
|
278
278
|
raw: true,
|
|
279
|
+
redirect,
|
|
279
280
|
});
|
|
280
281
|
response.status = response_.status;
|
|
281
282
|
response.set(Server.filter_response_headers(response_.headers));
|