xshell 1.0.69 → 1.0.71

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/apps.d.ts CHANGED
@@ -31,11 +31,13 @@ export declare let oss: {
31
31
  client: OSS;
32
32
  bucket: string;
33
33
  region: string;
34
- root: string;
35
- init({ bucket, region, root, access_id, access_key }: {
34
+ fpd_cdn: string;
35
+ fpd_oss: string;
36
+ init({ bucket, region, fpd_cdn, fpd_oss, access_id, access_key }: {
36
37
  bucket: string;
37
38
  region: string;
38
- root: string;
39
+ fpd_cdn: string;
40
+ fpd_oss: string;
39
41
  access_id: string;
40
42
  access_key: string;
41
43
  }): Promise<void>;
@@ -44,10 +46,12 @@ export declare let oss: {
44
46
  - data: 文件 (Uint8Array) | 本地文件完整路径 (string) | ReadableStream
45
47
  - options?:
46
48
  - private?: `false` 设置为私有,需要通过 URL 签名参数访问
49
+ - cdn?: `false` false 时返回 oss 链接,true 时返回 cdn 链接
47
50
  - print?: `true` 打印消息 */
48
- upload(fp: string, data: Uint8Array | string | Readable, { private: _private, print, }?: {
51
+ upload(fp: string, data: Uint8Array | string | Readable, { private: _private, print, cdn, }?: {
49
52
  private?: boolean;
50
53
  print?: boolean;
54
+ cdn?: boolean;
51
55
  }): Promise<string>;
52
56
  /** 获取经过签名后可访问的 url */
53
57
  get_url(fp: string): Promise<string>;
package/apps.js CHANGED
@@ -41,14 +41,16 @@ export let oss = {
41
41
  client: null,
42
42
  bucket: null,
43
43
  region: null,
44
- root: null,
45
- async init({ bucket, region, root, access_id, access_key }) {
44
+ fpd_cdn: null,
45
+ fpd_oss: null,
46
+ async init({ bucket, region, fpd_cdn, fpd_oss, access_id, access_key }) {
46
47
  if (this.client)
47
48
  return;
48
49
  const OSS = (await import('ali-oss')).default;
49
50
  this.bucket = bucket;
50
51
  this.region = region;
51
- this.root = root;
52
+ this.fpd_cdn = fpd_cdn;
53
+ this.fpd_oss = fpd_oss;
52
54
  this.client = new OSS({
53
55
  accessKeyId: access_id,
54
56
  accessKeySecret: access_key,
@@ -62,9 +64,11 @@ export let oss = {
62
64
  - data: 文件 (Uint8Array) | 本地文件完整路径 (string) | ReadableStream
63
65
  - options?:
64
66
  - private?: `false` 设置为私有,需要通过 URL 签名参数访问
67
+ - cdn?: `false` false 时返回 oss 链接,true 时返回 cdn 链接
65
68
  - print?: `true` 打印消息 */
66
- async upload(fp, data, { private: _private = false, print = true, } = {}) {
69
+ async upload(fp, data, { private: _private = false, print = true, cdn = false, } = {}) {
67
70
  assert(this.client, 'OSS 应该已经初始化了');
71
+ assert(!fp.startsWith('/'), 'fp 不能以 / 开头');
68
72
  assert(!fp.isdir, '不能使用 oss.upload 上传文件夹,请使用 oss.upload_dir');
69
73
  if (typeof data === 'string')
70
74
  assert(data[1] === ':' && path.isAbsolute(data), 'oss.upload 传入 data 参数类型为 string 时,必须为本地文件完整路径');
@@ -77,7 +81,7 @@ export let oss = {
77
81
  url = await this.get_url(fp);
78
82
  }
79
83
  else
80
- url = new URL(this.root + fp).toString();
84
+ url = new URL(`${cdn ? this.fpd_cdn : this.fpd_oss}${fp}`).toString();
81
85
  if (print)
82
86
  console.log(`已上传到 OSS${_private ? ' (私有)' : ''}:`, url);
83
87
  return url;
@@ -86,7 +90,7 @@ export let oss = {
86
90
  async get_url(fp) {
87
91
  assert(this.client, 'OSS 应该已经初始化了');
88
92
  const url = new URL(this.client.signatureUrl(fp, { expires: /* 十年 */ 3600 * 24 * 365 * 10 }));
89
- const url_ = `${this.root}${url.pathname.slice(1)}${url.search}`;
93
+ const url_ = `${this.fpd_cdn}${url.pathname.slice(1)}${url.search}`;
90
94
  return url_;
91
95
  }
92
96
  };
package/git.d.ts CHANGED
@@ -14,12 +14,12 @@ export declare class Git {
14
14
  get_branches(print?: boolean): Promise<string[]>;
15
15
  has_branch(branch: string): Promise<boolean>;
16
16
  /** - last?: `4` */
17
- log({ last, graph, format, }?: {
18
- last?: number;
17
+ log({ n, graph, format, }?: {
18
+ n?: number;
19
19
  graph?: boolean;
20
20
  format?: string;
21
21
  }): Promise<import("./process.js").CallResult<string>>;
22
- get_last_commits(last?: number): Promise<{
22
+ get_last_commits(n?: number): Promise<{
23
23
  time: Date;
24
24
  commiter: string;
25
25
  hash: string;
package/git.js CHANGED
@@ -52,19 +52,19 @@ export class Git {
52
52
  .includes(branch);
53
53
  }
54
54
  /** - last?: `4` */
55
- async log({ last = 4, graph = false, format, } = {}) {
55
+ async log({ n = 4, graph = false, format, } = {}) {
56
56
  if (!graph && !format)
57
57
  // 多行 commit message 会被 join 在一起,用空格隔开
58
58
  format = ['ct', 'cn', 'H', 's'].map(x => `%${x}`).join('%x00');
59
59
  return this.call([
60
60
  'log',
61
61
  ...graph ? ['--graph'] : [],
62
- `-${last}`,
62
+ `-${n}`,
63
63
  ...format ? [`--pretty=format:${format}`] : [],
64
64
  ], { color: !format, print: !format });
65
65
  }
66
- async get_last_commits(last = 100) {
67
- const { stdout } = await this.log({ last });
66
+ async get_last_commits(n = 100) {
67
+ const { stdout } = await this.log({ n });
68
68
  return stdout.split_lines()
69
69
  .map(line => {
70
70
  const [unixtime, commiter, hash, message] = line.split('\x00');
package/net.js CHANGED
@@ -346,7 +346,8 @@ on_message, on_error, on_close }) {
346
346
  const { WebSocket } = await import('ws');
347
347
  let websocket = new WebSocket(url, protocols, {
348
348
  maxPayload: max_payload,
349
- skipUTF8Validation: true
349
+ skipUTF8Validation: true,
350
+ allowSynchronousEvents: true,
350
351
  });
351
352
  // https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
352
353
  websocket.binaryType = 'arraybuffer';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.0.69",
3
+ "version": "1.0.71",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -45,10 +45,10 @@
45
45
  ]
46
46
  },
47
47
  "dependencies": {
48
- "@babel/core": "^7.23.5",
49
- "@babel/parser": "^7.23.5",
50
- "@babel/traverse": "^7.23.5",
51
- "@koa/cors": "^4.0.0",
48
+ "@babel/core": "^7.23.6",
49
+ "@babel/parser": "^7.23.6",
50
+ "@babel/traverse": "^7.23.6",
51
+ "@koa/cors": "^5.0.0",
52
52
  "@types/ws": "^8.5.10",
53
53
  "ali-oss": "^6.18.1",
54
54
  "archiver": "^6.0.1",
@@ -63,7 +63,7 @@
63
63
  "fetch-cookie": "^2.1.0",
64
64
  "gulp-sort": "^2.0.0",
65
65
  "hash-string": "^1.0.0",
66
- "i18next": "^23.7.7",
66
+ "i18next": "^23.7.9",
67
67
  "i18next-scanner": "^4.4.0",
68
68
  "js-cookie": "^3.0.5",
69
69
  "koa": "^2.14.2",
@@ -74,25 +74,25 @@
74
74
  "ora": "^7.0.1",
75
75
  "react": "^18.2.0",
76
76
  "react-i18next": "^13.5.0",
77
- "react-object-model": "^1.2.0",
77
+ "react-object-model": "^1.2.1",
78
78
  "resolve-path": "^1.4.0",
79
79
  "strip-ansi": "^7.1.0",
80
80
  "through2": "^4.0.2",
81
81
  "tough-cookie": "^4.1.3",
82
82
  "tslib": "^2.6.2",
83
- "typescript": "^5.3.2",
83
+ "typescript": "^5.3.3",
84
84
  "ua-parser-js": "2.0.0-alpha.2",
85
- "undici": "^5.28.2",
85
+ "undici": "^6.0.1",
86
86
  "vinyl": "^3.0.0",
87
87
  "vinyl-fs": "^4.0.0",
88
- "ws": "^8.14.2",
88
+ "ws": "^8.15.1",
89
89
  "xterm": "^5.3.0",
90
90
  "xterm-addon-fit": "^0.8.0",
91
91
  "xterm-addon-web-links": "^0.9.0",
92
92
  "xterm-addon-webgl": "^0.16.0"
93
93
  },
94
94
  "devDependencies": {
95
- "@babel/types": "^7.23.5",
95
+ "@babel/types": "^7.23.6",
96
96
  "@types/ali-oss": "^6.16.11",
97
97
  "@types/archiver": "^6.0.2",
98
98
  "@types/babel__traverse": "^7.20.4",
@@ -104,18 +104,18 @@
104
104
  "@types/koa-compress": "^4.0.6",
105
105
  "@types/lodash": "^4.14.202",
106
106
  "@types/mime-types": "^2.1.4",
107
- "@types/node": "^20.10.3",
108
- "@types/react": "^18.2.41",
107
+ "@types/node": "^20.10.4",
108
+ "@types/react": "^18.2.45",
109
109
  "@types/through2": "^2.0.41",
110
110
  "@types/tough-cookie": "^4.0.5",
111
111
  "@types/ua-parser-js": "^0.7.39",
112
112
  "@types/vinyl-fs": "^3.0.5",
113
- "@types/vscode": "^1.84.2",
114
- "@typescript-eslint/eslint-plugin": "^6.13.1",
115
- "@typescript-eslint/parser": "^6.13.1",
113
+ "@types/vscode": "^1.85.0",
114
+ "@typescript-eslint/eslint-plugin": "^6.14.0",
115
+ "@typescript-eslint/parser": "^6.14.0",
116
116
  "eslint": "^8.55.0",
117
117
  "eslint-plugin-react": "^7.33.2",
118
- "eslint-plugin-xlint": "^1.0.10"
118
+ "eslint-plugin-xlint": "^1.0.11"
119
119
  },
120
120
  "scripts": {
121
121
  "start": "node --title=xshell --inspect=0.0.0.0:8420 ./xshell.js",
package/repl.js CHANGED
@@ -31,6 +31,7 @@ export async function start_repl() {
31
31
  let { Server } = await import('./server.js');
32
32
  server = new Server({
33
33
  name: 'repl',
34
+ http: true,
34
35
  http_port: 8421,
35
36
  funcs: {
36
37
  echo({ data: [data] }) {
package/server.d.ts CHANGED
@@ -35,6 +35,10 @@ export declare class Server {
35
35
  js_exts: Set<string>;
36
36
  app: Koa;
37
37
  handler: ReturnType<Koa['callback']>;
38
+ /** 启用 http server */
39
+ http: boolean;
40
+ /** 启用 http2 server */
41
+ http2: boolean;
38
42
  http_port: number;
39
43
  http2_port: number;
40
44
  /** http2 server 证书文件夹路径,设置后才会启用 http2 server */
@@ -55,8 +59,10 @@ export declare class Server {
55
59
  stdout_write: Function;
56
60
  stderr_write: Function;
57
61
  encoder: TextEncoder;
58
- constructor({ name, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, }: {
62
+ constructor({ name, http, http2, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, }: {
59
63
  name: string;
64
+ http?: boolean;
65
+ http2?: boolean;
60
66
  http_port?: number;
61
67
  http2_port?: number;
62
68
  fpd_certs?: string;
package/server.js CHANGED
@@ -26,6 +26,10 @@ export class Server {
26
26
  js_exts = new Set(['.js', '.mjs', '.cjs']);
27
27
  app;
28
28
  handler;
29
+ /** 启用 http server */
30
+ http = false;
31
+ /** 启用 http2 server */
32
+ http2 = false;
29
33
  http_port = 80;
30
34
  http2_port = 443;
31
35
  /** http2 server 证书文件夹路径,设置后才会启用 http2 server */
@@ -44,8 +48,13 @@ export class Server {
44
48
  stdout_write;
45
49
  stderr_write;
46
50
  encoder = new TextEncoder();
47
- constructor({ name, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, }) {
51
+ constructor({ name, http, http2, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, }) {
48
52
  this.name = name;
53
+ if (http)
54
+ this.http = http;
55
+ if (http2)
56
+ this.http2 = http2;
57
+ assert(this.http || this.http2, 'http 和 http2 至少启用一个');
49
58
  if (http_port !== undefined)
50
59
  this.http_port = http_port;
51
60
  if (http2_port !== undefined)
@@ -86,14 +95,18 @@ export class Server {
86
95
  },
87
96
  threshold: 512
88
97
  }));
89
- app.use(KoaCors({ credentials: true }));
98
+ app.use(KoaCors({
99
+ credentials: true,
100
+ origin: (ctx) => ctx.request.get('origin') || '*'
101
+ }));
90
102
  await this.init_app(app);
91
103
  app.use(this._router.bind(this));
92
104
  this.app = app;
93
105
  this.handler = this.app.callback();
94
106
  this.http_server = http_create_server(this.handler);
95
- const { fpd_certs } = this;
96
- if (fpd_certs) {
107
+ const { http, http2 } = this;
108
+ if (http2) {
109
+ const { fpd_certs } = this;
97
110
  let lazy_secure_ctxs = Object.fromEntries(await Promise.all(
98
111
  // fpd_certs 文件夹下面的每个 .key 对应一个证书及域名
99
112
  (await flist(fpd_certs, { print: false, filter: /\.key$/ }))
@@ -121,6 +134,7 @@ export class Server {
121
134
  noServer: true,
122
135
  skipUTF8Validation: true,
123
136
  perMessageDeflate: true,
137
+ allowSynchronousEvents: true,
124
138
  maxPayload: 2 ** 30 // 1 GB
125
139
  });
126
140
  this.websocket_server.on('connection', (ws, request) => {
@@ -192,16 +206,19 @@ export class Server {
192
206
  }
193
207
  }
194
208
  await Promise.all([
195
- new Promise(resolve => {
209
+ http && new Promise(resolve => {
196
210
  this.http_server.listen(this.http_port, resolve);
197
211
  }),
198
- fpd_certs && new Promise(resolve => {
212
+ http2 && new Promise(resolve => {
199
213
  this.http2_server.listen(this.http2_port, resolve);
200
214
  }),
201
215
  ]);
202
216
  console.log(t('{{name}} 启动成功,正在监听 {{ports}} 端口', {
203
217
  name: this.name,
204
- ports: `${this.http_port}${fpd_certs ? `, ${this.http2_port}` : ''}`
218
+ ports: [
219
+ ...http ? [this.http_port] : [],
220
+ ...http2 ? [this.http2_port] : []
221
+ ].join(', ')
205
222
  }));
206
223
  }
207
224
  stop() {
@@ -51,7 +51,7 @@ export declare class Lock<TResource = void> {
51
51
  }
52
52
  export declare function pause(milliseconds?: number): Promise<void>;
53
53
  /** 字符串字典序比较 */
54
- export declare function strcmp(l: string, r: string): 1 | 0 | -1;
54
+ export declare function strcmp(l: string, r: string): 0 | 1 | -1;
55
55
  /** 比较 1.10.02 这种版本号 */
56
56
  export declare function vercmp(l: string, r: string): number;
57
57
  export declare function get<TReturn = any>(obj: any, keypath: string): TReturn;
package/utils.browser.js CHANGED
@@ -181,7 +181,7 @@ export function delta2str(delta) {
181
181
  // [1, 1000) ms
182
182
  if (delta < 1000)
183
183
  return `${delta.toFixed(0)} ms`;
184
- // 1.123 s
184
+ // 1.1 s
185
185
  if (1000 <= delta && delta < 1000 * 60)
186
186
  return `${(delta / 1000).toFixed(1)} s`;
187
187
  // 1 min 12 s [1 min 0s, 60 min)
package/utils.d.ts CHANGED
@@ -22,7 +22,7 @@ export declare function unique<T>(iterable: T[] | Iterable<T>, selector?: string
22
22
  /** 排序对象中 key 的顺序,返回新的对象 */
23
23
  export declare function sort_keys<T>(obj: T): T;
24
24
  /** 字符串字典序比较 */
25
- export declare function strcmp(l: string, r: string): 1 | 0 | -1;
25
+ export declare function strcmp(l: string, r: string): 0 | 1 | -1;
26
26
  /** 比较 1.10.02 这种版本号 */
27
27
  export declare function vercmp(l: string, r: string): number;
28
28
  export declare function get<TReturn = any>(obj: any, keypath: string): TReturn;
package/utils.js CHANGED
@@ -144,7 +144,7 @@ export function delta2str(delta) {
144
144
  // [1, 1000) ms
145
145
  if (delta < 1000)
146
146
  return `${delta.toFixed(0)} ms`;
147
- // 1.123 s
147
+ // 1.1 s
148
148
  if (1000 <= delta && delta < 1000 * 60)
149
149
  return `${(delta / 1000).toFixed(1)} s`;
150
150
  // 1 min 12 s [1 min 0s, 60 min)