xshell 1.0.53 → 1.0.55

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 CHANGED
@@ -55,7 +55,11 @@ export declare function fread_json<T = any>(fp: string, options?: {
55
55
  - data: 支持下面几种类型
56
56
  - string: 写入文本
57
57
  - Uint8Array, Buffer: 写入二进制 buffer
58
- - any: 通过 JSON.stringify 转为文本后写入文件 */
58
+ - any: 通过 JSON.stringify 转为文本后写入文件
59
+ - options?:
60
+ - dir?: 文件夹
61
+ - print?
62
+ - mkdir: `false` 自动创建 fp 所在的文件夹 */
59
63
  export declare function fwrite(fp: string | FileHandle, data: string | Uint8Array | any, { dir, print, mkdir, }?: {
60
64
  dir?: string;
61
65
  print?: boolean;
@@ -104,6 +108,7 @@ export declare function fdelete(fp: string, { print }?: {
104
108
  print?: boolean;
105
109
  }): Promise<boolean>;
106
110
  /** 复制文件或文件夹 copy file or direcotry
111
+ 会自动创建目标路径所在的文件夹
107
112
  - fp_src: 源 文件/文件夹 完整路径 src file/directory absolute path
108
113
  - fp_dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path
109
114
  - options?:
@@ -116,12 +121,16 @@ export declare function fcopy(fp_src: string, fp_dst: string, { print, overwrite
116
121
  print?: boolean;
117
122
  overwrite?: boolean;
118
123
  }): Promise<void>;
119
- /** 移动文件或文件夹 move file or direcotry
120
- - src: 源 文件/文件夹 完整路径 src file/directory absolute path
121
- - dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path
124
+ /** 移动文件或文件夹
125
+ - src: 源 文件/文件夹 完整路径
126
+ - dst: 目标 文件/文件夹 完整路径
127
+ - options?:
128
+ - print?: `true`
129
+ - overwrite?: `false`
130
+
122
131
  @example
123
132
  fmove('D:/temp/camera/', 'D:/camera/') */
124
- export declare function fmove(src: string, dst: string, { overwrite, print }?: {
133
+ export declare function fmove(fp_src: string, fp_dst: string, { overwrite, print }?: {
125
134
  overwrite?: boolean;
126
135
  print?: boolean;
127
136
  }): Promise<void>;
package/file.js CHANGED
@@ -59,7 +59,11 @@ export async function fread_json(fp, options = {}) {
59
59
  - data: 支持下面几种类型
60
60
  - string: 写入文本
61
61
  - Uint8Array, Buffer: 写入二进制 buffer
62
- - any: 通过 JSON.stringify 转为文本后写入文件 */
62
+ - any: 通过 JSON.stringify 转为文本后写入文件
63
+ - options?:
64
+ - dir?: 文件夹
65
+ - print?
66
+ - mkdir: `false` 自动创建 fp 所在的文件夹 */
63
67
  export async function fwrite(fp, data, { dir, print = true, mkdir = false, } = {}) {
64
68
  const is_handle = typeof fp === 'object' && fp && 'fd' in fp;
65
69
  if (is_handle) {
@@ -81,10 +85,12 @@ export async function fwrite(fp, data, { dir, print = true, mkdir = false, } = {
81
85
  await fsp.writeFile(fp, data);
82
86
  }
83
87
  catch (error) {
84
- if (!mkdir || error.code !== 'ENOENT' || is_handle)
88
+ if (mkdir && error.code === 'ENOENT' && !is_handle) {
89
+ await fmkdir(fp.fdir);
90
+ await fsp.writeFile(fp, data);
91
+ }
92
+ else
85
93
  throw error;
86
- await fmkdir(fp.fdir);
87
- await fsp.writeFile(fp, data);
88
94
  }
89
95
  }
90
96
  export async function fappend(fp, data, { dir, print = true } = {}) {
@@ -211,6 +217,7 @@ export async function fdelete(fp, { print = true } = {}) {
211
217
  }
212
218
  }
213
219
  /** 复制文件或文件夹 copy file or direcotry
220
+ 会自动创建目标路径所在的文件夹
214
221
  - fp_src: 源 文件/文件夹 完整路径 src file/directory absolute path
215
222
  - fp_dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path
216
223
  - options?:
@@ -220,27 +227,56 @@ export async function fdelete(fp, { print = true } = {}) {
220
227
  @example
221
228
  fcopy('D:/temp/camera/', 'D:/camera/') */
222
229
  export async function fcopy(fp_src, fp_dst, { print = true, overwrite = true, } = {}) {
223
- assert(fp_src.isdir === fp_dst.isdir, t('fp_src fp_dst 必须同为文件路径或文件夹路径'));
230
+ const { isdir } = fp_src;
231
+ assert(isdir === fp_dst.isdir, t('fp_src 和 fp_dst 必须同为文件路径或文件夹路径'));
224
232
  assert(path.isAbsolute(fp_src) && path.isAbsolute(fp_dst), t('fp_src 和 fp_dst 必须为完整路径'));
225
233
  if (print)
226
234
  console.log(t('复制'), fp_src, '->', fp_dst);
227
- const { copy } = await import('fs-extra');
228
- await copy(fp_src, fp_dst, { overwrite, errorOnExist: true });
235
+ if (isdir)
236
+ await fsp.cp(fp_src, fp_dst, {
237
+ recursive: true,
238
+ force: overwrite,
239
+ errorOnExist: !overwrite,
240
+ mode: overwrite ? 0 : fs.constants.COPYFILE_EXCL,
241
+ });
242
+ else {
243
+ await fmkdir(fp_dst.fdir, { print: false });
244
+ await fsp.copyFile(fp_src, fp_dst, overwrite ? 0 : fs.constants.COPYFILE_EXCL);
245
+ }
229
246
  }
230
- /** 移动文件或文件夹 move file or direcotry
231
- - src: 源 文件/文件夹 完整路径 src file/directory absolute path
232
- - dst: 目标 文件/文件夹 完整路径 dst file/directory absolute path
247
+ /** 移动文件或文件夹
248
+ - src: 源 文件/文件夹 完整路径
249
+ - dst: 目标 文件/文件夹 完整路径
250
+ - options?:
251
+ - print?: `true`
252
+ - overwrite?: `false`
253
+
233
254
  @example
234
255
  fmove('D:/temp/camera/', 'D:/camera/') */
235
- export async function fmove(src, dst, { overwrite = false, print = true } = {}) {
236
- if (src.isdir !== dst.isdir)
237
- throw new Error(t('srcdst 必须同为文件路径或文件夹路径'));
238
- if (!path.isAbsolute(src) || !path.isAbsolute(dst))
239
- throw new Error(t('src 和 dst 必须为完整路径'));
256
+ export async function fmove(fp_src, fp_dst, { overwrite = false, print = true } = {}) {
257
+ assert(fp_src.isdir === fp_dst.isdir, t('fp_src 和 fp_dst 必须同为文件路径或文件夹路径'));
258
+ assert(path.isAbsolute(fp_src) && path.isAbsolute(fp_dst), t('fp_srcfp_dst 必须为完整路径'));
240
259
  if (print)
241
- console.log(t('移动'), src, '->', dst);
242
- const { move } = await import('fs-extra');
243
- await move(src, dst, { overwrite });
260
+ console.log(t('移动'), fp_src, '->', fp_dst);
261
+ if (!overwrite && fexists(fp_dst))
262
+ throw new Error(`${t('已存在')} ${fp_dst}`);
263
+ await fmkdir(fp_dst.fdir, { print: false });
264
+ async function copy_and_delete() {
265
+ await fcopy(fp_src, fp_dst, { overwrite, print });
266
+ await fdelete(fp_src, { print });
267
+ }
268
+ if (fp_src[0] !== fp_dst[0])
269
+ await copy_and_delete();
270
+ else
271
+ try {
272
+ await fsp.rename(fp_src, fp_dst);
273
+ }
274
+ catch (error) {
275
+ if (error.code === 'EXDEV')
276
+ await copy_and_delete();
277
+ else
278
+ throw error;
279
+ }
244
280
  }
245
281
  /** 重命名文件 rename file
246
282
  - fp: 当前文件名/路径 current filename/path
@@ -259,7 +295,7 @@ export async function frename(fp, fp_, { fpd, print = true, overwrite = true } =
259
295
  if (print)
260
296
  console.log(t('重命名'), fp, '->', fp_);
261
297
  if (!overwrite && fexists(fp_))
262
- throw new Error(t('文件已存在:') + fp_);
298
+ throw new Error(`${t('已存在')} ${fp}`);
263
299
  await fsp.rename(fp, fp_);
264
300
  }
265
301
  /**
package/net.browser.d.ts CHANGED
@@ -63,12 +63,14 @@ export declare function request(url: string | URL, options: RequestOptions): Pro
63
63
  export declare function request_json<T = any>(url: string, options?: RequestOptions): Promise<T>;
64
64
  export declare class WebSocketConnectionError extends Error {
65
65
  name: string;
66
+ url: string;
67
+ protocols?: string[];
66
68
  websocket: WebSocket;
67
69
  event: CloseEvent | /* error 事件时的 event,没有 event.error */ Event;
68
70
  type: 'close' | 'error';
69
71
  code?: number;
70
72
  reason?: string;
71
- constructor(websocket: WebSocket, event: CloseEvent | Event, message?: string);
73
+ constructor(url: string, protocols: string[] | undefined, event: CloseEvent | Event, message?: string);
72
74
  }
73
75
  /** 连接 websocket url, 设置各种事件监听器。在 open 事件后 resolve, 返回 websocket
74
76
  遇到 error 时会创建 WebSocketConnectionError:
@@ -86,7 +88,7 @@ export declare class WebSocketConnectionError extends Error {
86
88
  - on_close?: 和 websocket 的 'close' 事件不相同,只在正常关闭 (close code 为 1000) 时才调用,否则都会调用 on_error
87
89
  https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes */
88
90
  export declare function connect_websocket(url: string | URL, { protocols, on_message, on_error, on_close, }: {
89
- protocols?: string | string[];
91
+ protocols?: string[];
90
92
  on_message(data: ArrayBuffer | string, websocket: WebSocket): any;
91
93
  on_error?(error: WebSocketConnectionError, websocket: WebSocket): any;
92
94
  on_close?(event: CloseEvent, websocket: WebSocket): any;
package/net.browser.js CHANGED
@@ -147,14 +147,18 @@ let decoder = new TextDecoder();
147
147
  let encoder = new TextEncoder();
148
148
  export class WebSocketConnectionError extends Error {
149
149
  name = 'WebSocketConnectionError';
150
+ // 这里不保留 websocket 引用,防止循环引用导致 JSON 序列化失败
151
+ url;
152
+ protocols;
150
153
  websocket;
151
154
  event;
152
155
  type;
153
156
  code;
154
157
  reason;
155
- constructor(websocket, event, message) {
156
- super(`${websocket.url} ${t('连接出错了')}. ${message || ''}`);
157
- this.websocket = websocket;
158
+ constructor(url, protocols, event, message) {
159
+ super(`${url}${protocols ? ' ' + protocols.join(', ').bracket() : ''} ${t('连接出错了')}. ${message || ''}`);
160
+ this.url = url;
161
+ this.protocols = protocols;
158
162
  this.event = event;
159
163
  this.type = event.type;
160
164
  if (this.type === 'close') {
@@ -186,10 +190,7 @@ export async function connect_websocket(url, { protocols, on_message, on_error,
186
190
  let settled = false;
187
191
  websocket.addEventListener('open', event => {
188
192
  console.log(websocket.url +
189
- (protocols ?
190
- ' ' + (typeof protocols === 'string' ? protocols : protocols.join(', ').bracket('square')).bracket()
191
- :
192
- '') +
193
+ (websocket.protocol ? websocket.protocol.bracket() : '') +
193
194
  t(' 已连接'));
194
195
  settled = true;
195
196
  resolve(websocket);
@@ -201,7 +202,7 @@ export async function connect_websocket(url, { protocols, on_message, on_error,
201
202
  else
202
203
  console.log(`${websocket.url} ${t('已正常关闭')}`);
203
204
  else { // 异常关闭,认为发生了错误,进行错误处理
204
- const error = new WebSocketConnectionError(websocket, event, `${t('连接被关闭')}, code: ${event.code}${event.reason ? `, ${t('原因')}: ${event.reason}` : ''}`);
205
+ const error = new WebSocketConnectionError(websocket.url, protocols, event, `${t('连接被关闭')}, code: ${event.code}${event.reason ? `, ${t('原因')}: ${event.reason}` : ''}`);
205
206
  if (settled)
206
207
  if (on_error)
207
208
  on_error(error, websocket);
@@ -214,7 +215,7 @@ export async function connect_websocket(url, { protocols, on_message, on_error,
214
215
  }
215
216
  });
216
217
  websocket.addEventListener('error', event => {
217
- const error = new WebSocketConnectionError(websocket, event);
218
+ const error = new WebSocketConnectionError(websocket.url, protocols, event);
218
219
  // https://blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa
219
220
  // close 的错误信息比较多,这里延后触发 error 事件,放到微任务队列之后的 timers 队列中
220
221
  setTimeout(() => {
package/net.d.ts CHANGED
@@ -107,7 +107,8 @@ export declare function rpc(func: string, args?: any[], { url, async: _async, ig
107
107
  }): Promise<any>;
108
108
  export declare class WebSocketConnectionError extends Error {
109
109
  name: string;
110
- websocket: WebSocket;
110
+ url: string;
111
+ protocols?: string[];
111
112
  event: CloseEvent | ErrorEvent;
112
113
  type: 'close' | 'error';
113
114
  address?: string;
@@ -117,7 +118,7 @@ export declare class WebSocketConnectionError extends Error {
117
118
  /** close 事件时为 close code, error 事件为 error code */
118
119
  code?: string | number;
119
120
  reason?: string;
120
- constructor(websocket: WebSocket, event: CloseEvent | ErrorEvent, message?: string);
121
+ constructor(url: string, protocols: string[] | undefined, event: CloseEvent | ErrorEvent, message?: string);
121
122
  }
122
123
  /** 连接 websocket url, 设置各种事件监听器。在 open 事件后 resolve, 返回 websocket
123
124
  遇到 error 时会创建 WebSocketConnectionError:
@@ -137,7 +138,7 @@ export declare class WebSocketConnectionError extends Error {
137
138
  https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes */
138
139
  export declare function connect_websocket(url: string | URL, { protocols, max_payload, // 8 GB
139
140
  on_message, on_error, on_close }: {
140
- protocols?: string | string[];
141
+ protocols?: string[];
141
142
  max_payload?: number;
142
143
  on_message(data: ArrayBuffer | string, websocket: WebSocket): any;
143
144
  on_error?(error: WebSocketConnectionError, websocket: WebSocket): any;
package/net.js CHANGED
@@ -290,7 +290,9 @@ let decoder = new TextDecoder();
290
290
  let encoder = new TextEncoder();
291
291
  export class WebSocketConnectionError extends Error {
292
292
  name = 'WebSocketConnectionError';
293
- websocket;
293
+ // 这里不保留 websocket 引用,防止循环引用导致 JSON 序列化失败
294
+ url;
295
+ protocols;
294
296
  event;
295
297
  type;
296
298
  address;
@@ -300,9 +302,10 @@ export class WebSocketConnectionError extends Error {
300
302
  /** close 事件时为 close code, error 事件为 error code */
301
303
  code;
302
304
  reason;
303
- constructor(websocket, event, message = '') {
304
- super(`${websocket.url} ${t('连接出错了')}. ${message}`);
305
- this.websocket = websocket;
305
+ constructor(url, protocols, event, message = '') {
306
+ super(`${url}${protocols ? ' ' + protocols.join(', ').bracket() : ''} ${t('连接出错了')}. ${message}`);
307
+ this.url = url;
308
+ this.protocols = protocols;
306
309
  this.event = event;
307
310
  this.type = event.type;
308
311
  if (this.type === 'error') {
@@ -351,10 +354,7 @@ on_message, on_error, on_close }) {
351
354
  let settled = false;
352
355
  websocket.addEventListener('open', event => {
353
356
  console.log(websocket.url +
354
- (protocols ?
355
- ' ' + (typeof protocols === 'string' ? protocols : protocols.join(', ').bracket('square')).bracket()
356
- :
357
- '') +
357
+ (websocket.protocol ? websocket.protocol.bracket() : '') +
358
358
  t(' 已连接'));
359
359
  settled = true;
360
360
  resolve(websocket);
@@ -372,7 +372,7 @@ on_message, on_error, on_close }) {
372
372
  console.log(`${websocket.url} ${t('已正常关闭')}`);
373
373
  else { // 异常关闭,认为发生了错误,进行错误处理
374
374
  assert(settled, t('websocket close 事件时应该已经 settled'));
375
- const error = new WebSocketConnectionError(websocket, event, `${t('连接被关闭')}, code: ${event.code}${event.reason ? `, ${t('原因')}: ${event.reason}` : ''}`);
375
+ const error = new WebSocketConnectionError(websocket.url, protocols, event, `${t('连接被关闭')}, code: ${event.code}${event.reason ? `, ${t('原因')}: ${event.reason}` : ''}`);
376
376
  if (on_error)
377
377
  on_error(error, websocket);
378
378
  else // 既然用户不传 on_error, 就当 unhandled error 抛出来
@@ -381,7 +381,7 @@ on_message, on_error, on_close }) {
381
381
  });
382
382
  });
383
383
  websocket.addEventListener('error', event => {
384
- const error = new WebSocketConnectionError(websocket, event, event.error?.message);
384
+ const error = new WebSocketConnectionError(websocket.url, protocols, event, event.error?.message);
385
385
  if (settled)
386
386
  if (on_error)
387
387
  on_error(error, websocket);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -59,10 +59,9 @@
59
59
  "commander": "^11.0.0",
60
60
  "emoji-regex": "^10.2.1",
61
61
  "fetch-cookie": "^2.1.0",
62
- "fs-extra": "^11.1.1",
63
62
  "gulp-sort": "^2.0.0",
64
63
  "hash-string": "^1.0.0",
65
- "i18next": "^23.4.4",
64
+ "i18next": "^23.4.5",
66
65
  "i18next-scanner": "^4.3.0",
67
66
  "js-cookie": "^3.0.5",
68
67
  "koa": "^2.14.2",
@@ -72,7 +71,7 @@
72
71
  "mime-types": "^2.1.35",
73
72
  "ora": "^7.0.1",
74
73
  "react": "^18.2.0",
75
- "react-i18next": "^13.1.2",
74
+ "react-i18next": "^13.2.0",
76
75
  "resolve-path": "^1.4.0",
77
76
  "strip-ansi": "^7.1.0",
78
77
  "through2": "^4.0.2",
@@ -90,22 +89,21 @@
90
89
  "@types/babel__traverse": "^7.20.1",
91
90
  "@types/byte-size": "^8.1.0",
92
91
  "@types/chardet": "^0.8.1",
93
- "@types/fs-extra": "^11.0.1",
94
92
  "@types/gulp-sort": "2.0.1",
95
93
  "@types/js-cookie": "^3.0.3",
96
94
  "@types/koa": "^2.13.8",
97
95
  "@types/koa-compress": "^4.0.3",
98
96
  "@types/lodash": "^4.14.197",
99
97
  "@types/mime-types": "^2.1.1",
100
- "@types/node": "^20.5.1",
101
- "@types/react": "^18.2.20",
98
+ "@types/node": "^20.5.4",
99
+ "@types/react": "^18.2.21",
102
100
  "@types/through2": "^2.0.38",
103
101
  "@types/tough-cookie": "^4.0.2",
104
102
  "@types/ua-parser-js": "^0.7.36",
105
103
  "@types/vinyl-fs": "^3.0.2",
106
104
  "@types/vscode": "^1.81.0",
107
- "@typescript-eslint/eslint-plugin": "^6.4.0",
108
- "@typescript-eslint/parser": "^6.4.0",
105
+ "@typescript-eslint/eslint-plugin": "^6.4.1",
106
+ "@typescript-eslint/parser": "^6.4.1",
109
107
  "eslint": "^8.47.0",
110
108
  "eslint-plugin-react": "^7.33.2",
111
109
  "eslint-plugin-xlint": "^1.0.7"
package/process.d.ts CHANGED
@@ -40,7 +40,7 @@ interface StartOptions {
40
40
  - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
41
41
  - args: `[]` 参数列表 arguments list
42
42
  - options
43
- - cwd?: `fp_root`
43
+ - cwd?: `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process.
44
44
  - env?: `process.env` 覆盖/添加到 process.env 的环境变量 overwrite/add to process.env
45
45
  - encoding?: `'utf-8'` 子进程输出编码 child output encoding
46
46
  - print?: `true` print 选项,支持设置细项 print option (with details)
package/process.js CHANGED
@@ -8,7 +8,7 @@ export const exe_nodejs = process.execPath.fp;
8
8
  - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
9
9
  - args: `[]` 参数列表 arguments list
10
10
  - options
11
- - cwd?: `fp_root`
11
+ - cwd?: `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process.
12
12
  - env?: `process.env` 覆盖/添加到 process.env 的环境变量 overwrite/add to process.env
13
13
  - encoding?: `'utf-8'` 子进程输出编码 child output encoding
14
14
  - print?: `true` print 选项,支持设置细项 print option (with details)
@@ -184,7 +184,7 @@ export const exe_winterm = `C:/Users/${userInfo().username}/AppData/Local/Micros
184
184
  - args: 调用参数 call parameter
185
185
  - options?: WinTermOptions
186
186
  */
187
- export async function term(exe, args = [], { cwd = process.cwd().fp, print = true, title,
187
+ export async function term(exe, args = [], { cwd = process.cwd().fpd, print = true, title,
188
188
  // env
189
189
  } = {}) {
190
190
  return start(exe_winterm, [
package/server.js CHANGED
@@ -263,7 +263,7 @@ export class Server {
263
263
  return s;
264
264
  }
265
265
  async proxy(ctx, url, headers_ = {}) {
266
- const { request: { method, headers, query, body } } = ctx;
266
+ const { request: { method, headers, query, body, ip } } = ctx;
267
267
  let { response } = ctx;
268
268
  try {
269
269
  const response_ = await _request(url, {
@@ -272,6 +272,7 @@ export class Server {
272
272
  body,
273
273
  headers: {
274
274
  ...headers,
275
+ 'x-forwarded-for': headers['x-forwarded-for'] ? `${headers['x-forwarded-for']}, ${ip}` : ip,
275
276
  ...headers_
276
277
  },
277
278
  raw: true,