xshell 1.0.103 → 1.0.105

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/Terminal.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- import 'xterm/css/xterm.css';
2
- import { Terminal as XTermTerminal } from 'xterm';
3
- import { FitAddon } from 'xterm-addon-fit';
1
+ import '@xterm/xterm/css/xterm.css';
2
+ import { Terminal as XTerminal } from '@xterm/xterm';
3
+ import { FitAddon } from '@xterm/addon-fit';
4
4
  import { Model } from 'react-object-model';
5
5
  import type { Remote } from './net.browser.js';
6
6
  export declare function Terminal({ font }: {
7
7
  font: string;
8
8
  }): import("react/jsx-runtime").JSX.Element;
9
9
  declare class TerminalModel extends Model<TerminalModel> {
10
- term: XTermTerminal;
10
+ term: XTerminal;
11
11
  fit_addon: FitAddon;
12
12
  stdio_id: number;
13
13
  fit(): void;
package/Terminal.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import 'xterm/css/xterm.css';
2
+ import '@xterm/xterm/css/xterm.css';
3
3
  import { useEffect, useRef } from 'react';
4
- import { Terminal as XTermTerminal } from 'xterm';
5
- import { FitAddon } from 'xterm-addon-fit';
6
- import { WebglAddon } from 'xterm-addon-webgl';
7
- import { WebLinksAddon } from 'xterm-addon-web-links';
4
+ import { Terminal as XTerminal } from '@xterm/xterm';
5
+ import { FitAddon } from '@xterm/addon-fit';
6
+ import { WebglAddon } from '@xterm/addon-webgl';
7
+ import { WebLinksAddon } from '@xterm/addon-web-links';
8
8
  // 没有 ui
9
9
  // import { SearchAddon } from 'xterm-addon-search'
10
10
  import { Model } from 'react-object-model';
@@ -14,7 +14,7 @@ export function Terminal({ font }) {
14
14
  useEffect(() => {
15
15
  (async () => {
16
16
  await document.fonts.ready;
17
- let term = new XTermTerminal({
17
+ let term = new XTerminal({
18
18
  fontFamily: font,
19
19
  fontSize: 16,
20
20
  cursorStyle: 'bar',
package/git.d.ts CHANGED
@@ -33,22 +33,4 @@ export declare class Git {
33
33
  checkout(branch?: 'main'): Promise<void>;
34
34
  checkout(branch?: string): Promise<void>;
35
35
  _checkout(branch?: string): Promise<void>;
36
- /** 返回是否进行了修改 */
37
- merge(branch: string, fast_forward?: boolean): Promise<boolean>;
38
- /** 记住当前分支名
39
- checkout 到 <目标分支>
40
- merge 当前分支 */
41
- merge_into(target_branch?: string): Promise<void>;
42
- /** 1. fetch 远程修改
43
- 2. checkout `<branch>` 分支
44
- 3. merge `<remote>/<branch>`
45
-
46
- 执行前需要保证工作目录 clean
47
-
48
- - branch?: `'main'` */
49
- update(branch?: 'main'): Promise<void>;
50
- update(branch: string): Promise<void>;
51
- update(branch: string, remote?: string): Promise<void>;
52
- /** - message?: stash description */
53
- stash(message?: string): Promise<import("./process.js").CallResult<string>>;
54
36
  }
package/git.js CHANGED
@@ -1,4 +1,3 @@
1
- import { assert } from './utils.js';
2
1
  import { call } from './process.js';
3
2
  import { fread, fmkdir } from './file.js';
4
3
  export class Git {
@@ -121,56 +120,5 @@ export class Git {
121
120
  throw error;
122
121
  }
123
122
  }
124
- /** 返回是否进行了修改 */
125
- async merge(branch, fast_forward = true) {
126
- console.log(`合并 ${branch} 分支`);
127
- try {
128
- const { stdout, stderr } = await this.call([
129
- 'merge',
130
- branch,
131
- ...fast_forward ? [] : ['--no-ff']
132
- ], { print: false });
133
- const unchanged = stdout === 'Already up to date.\n';
134
- if (unchanged)
135
- console.log('当前分支无需更新');
136
- else
137
- console.log(stdout.trimEnd());
138
- if (stderr)
139
- console.log(stderr);
140
- return !unchanged;
141
- }
142
- catch (error) {
143
- if (error.result) {
144
- const { stdout, stderr } = error.result;
145
- if (stdout)
146
- console.log(stdout);
147
- if (stderr)
148
- console.log(stderr);
149
- }
150
- throw error;
151
- }
152
- }
153
- /** 记住当前分支名
154
- checkout 到 <目标分支>
155
- merge 当前分支 */
156
- async merge_into(target_branch = 'main') {
157
- const branch = await this.get_branch();
158
- assert(branch !== target_branch);
159
- await this.checkout(target_branch);
160
- await this.merge(branch, true);
161
- }
162
- async update(branch = 'main', remote) {
163
- await this.fetch({ remote });
164
- await this.checkout(branch);
165
- await this.merge(`${remote || 'origin'}/${branch}`);
166
- }
167
- /** - message?: stash description */
168
- async stash(message) {
169
- return this.call([
170
- 'stash',
171
- 'push',
172
- ...message ? ['--message', message] : [],
173
- ]);
174
- }
175
123
  }
176
124
  //# sourceMappingURL=git.js.map
package/i18n/README.md CHANGED
@@ -266,7 +266,6 @@ npm i eslint eslint-plugin-i18n --save-dev
266
266
 
267
267
  ## Runtime Dependencies
268
268
  - i18next
269
- - js-cookie
270
269
  - qs
271
270
  - 使用 Trans 组件时
272
271
  - react
package/i18n/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import Cookies from 'js-cookie';
2
1
  import { default as i18next } from 'i18next';
3
2
  import { Dict } from './dict.js';
4
3
  export const LANGUAGES = ['zh', 'en', 'ja', 'ko'];
@@ -35,8 +34,7 @@ export class I18N {
35
34
  const dict = new Dict(_dict);
36
35
  if (!language && is_browser)
37
36
  language = (new URLSearchParams(location.search).get('language') ||
38
- window.language ||
39
- Cookies.get('language'));
37
+ window.language);
40
38
  if (!language)
41
39
  language = Intl.DateTimeFormat().resolvedOptions().locale.slice(0, 2);
42
40
  if (!I18N.LANGUAGE_REGEXP.test(language)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.0.103",
3
+ "version": "1.0.105",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "interactive programming"
17
17
  ],
18
18
  "engines": {
19
- "node": ">=21.3.0",
19
+ "node": ">=22.2.0",
20
20
  "vscode": ">=1.81.0"
21
21
  },
22
22
  "scripts": {
@@ -61,6 +61,10 @@
61
61
  "@typescript-eslint/eslint-plugin": "^7.9.0",
62
62
  "@typescript-eslint/parser": "^7.9.0",
63
63
  "@typescript-eslint/utils": "^7.9.0",
64
+ "@xterm/addon-fit": "^0.10.0",
65
+ "@xterm/addon-web-links": "^0.11.0",
66
+ "@xterm/addon-webgl": "^0.18.0",
67
+ "@xterm/xterm": "^5.5.0",
64
68
  "ali-oss": "^6.20.0",
65
69
  "archiver": "^7.0.1",
66
70
  "byte-size": "^8.1.1",
@@ -79,7 +83,6 @@
79
83
  "https-proxy-agent": "^7.0.4",
80
84
  "i18next": "^23.11.4",
81
85
  "i18next-scanner": "^4.4.0",
82
- "js-cookie": "^3.0.5",
83
86
  "koa": "^2.15.3",
84
87
  "koa-compress": "^5.1.1",
85
88
  "lodash": "^4.17.21",
@@ -99,11 +102,7 @@
99
102
  "undici": "^6.16.1",
100
103
  "vinyl": "^3.0.0",
101
104
  "vinyl-fs": "^4.0.0",
102
- "ws": "^8.17.0",
103
- "xterm": "^5.3.0",
104
- "xterm-addon-fit": "^0.8.0",
105
- "xterm-addon-web-links": "^0.9.0",
106
- "xterm-addon-webgl": "^0.16.0"
105
+ "ws": "^8.17.0"
107
106
  },
108
107
  "devDependencies": {
109
108
  "@babel/types": "^7.24.5",
@@ -115,10 +114,9 @@
115
114
  "@types/eslint": "^8.56.10",
116
115
  "@types/estree": "^1.0.5",
117
116
  "@types/gulp-sort": "^2.0.4",
118
- "@types/js-cookie": "^3.0.6",
119
117
  "@types/koa": "^2.15.0",
120
118
  "@types/koa-compress": "^4.0.6",
121
- "@types/lodash": "^4.17.1",
119
+ "@types/lodash": "^4.17.4",
122
120
  "@types/mime-types": "^2.1.4",
123
121
  "@types/node": "^20.12.12",
124
122
  "@types/react": "^18.3.2",
package/process.js CHANGED
@@ -178,9 +178,7 @@ export async function call(exe, args = [], options = {}) {
178
178
  - throw_code?: `true` code 不为 0 时是否抛出异常 whether to throw Error when code is not 0 */
179
179
  export async function call_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
180
180
  return call(exe_nodejs, [
181
- ...inspect ? [
182
- _break ? `--inspect-brk=localhost:${inspect}` : `--inspect=localhost:${inspect}`
183
- ] : [],
181
+ ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect}`] : [],
184
182
  js,
185
183
  ...args
186
184
  ], options);
package/server.d.ts CHANGED
@@ -33,6 +33,7 @@ export declare class Server {
33
33
  name: string;
34
34
  UAParser: typeof UAParser;
35
35
  js_exts: Set<string>;
36
+ empty_body_statuses: Set<number>;
36
37
  app: Koa;
37
38
  handler: ReturnType<Koa['callback']>;
38
39
  /** 启用 http server */
package/server.js CHANGED
@@ -8,7 +8,7 @@ import util from 'util';
8
8
  // --- my libs
9
9
  import { t } from './i18n/instance.js';
10
10
  import { request as _request, Remote } from './net.js';
11
- import { inspect, output_width, assert, range_to_numbers, encode, filter_keys, filter_values } from './utils.js';
11
+ import { inspect, output_width, assert, range_to_numbers, encode, filter_keys, filter_values, consume_stream } from './utils.js';
12
12
  import { flist, fread, fstat } from './file.js';
13
13
  // ------------ my server
14
14
  export class Server {
@@ -24,6 +24,7 @@ export class Server {
24
24
  name;
25
25
  UAParser;
26
26
  js_exts = new Set(['.js', '.mjs', '.cjs']);
27
+ empty_body_statuses = new Set([304, 204, 205]);
27
28
  app;
28
29
  handler;
29
30
  /** 启用 http server */
@@ -472,7 +473,17 @@ export class Server {
472
473
  response.status = response_.status;
473
474
  response.set(Server.filter_response_headers(response_.headers));
474
475
  if (response_.body)
475
- response.body = path_url.toString().includes('question/create') ? await stream_to_buffer(response_.body) : response_.body;
476
+ // 如果设置了 response.status 304 等状态码,koa/application.js#respond() 方法中会执行
477
+ // ctx.body = null
478
+ // response.res.end()
479
+ // 而 res.end() 会触发 res 流的 finish, 然后由于之前 response.body = response_.body 这条语句
480
+ // 关联了 response_.body 到 res 的 finish 事件,(koa/response.js#set body() 中 onFinish(res, destroy.bind(null, response_.body))
481
+ // 会让 response_.body 这个 UndiciBodyReadable 被提前 finish,而此时
482
+ // 流还没 emit end, 会触发错误 RequestAbortedError [AbortError]: Request aborted
483
+ if (this.empty_body_statuses.has(response_.status))
484
+ consume_stream(response_.body, true);
485
+ else
486
+ response.body = response_.body;
476
487
  }
477
488
  catch (error) {
478
489
  if (error.response?.status !== 404)
package/utils.d.ts CHANGED
@@ -34,7 +34,7 @@ export declare function map_values<TValue, TNewValue>(obj: {
34
34
  };
35
35
  /** 过滤对象中的 keys, 返回新对象 */
36
36
  export declare function filter_keys<TObj>(obj: TObj, filter: (key: string) => any): TObj;
37
- /** 过滤对象中的 valus, 返回新对象 */
37
+ /** 过滤对象中的 values, 返回新对象 */
38
38
  export declare function filter_values<TObj extends Record<string, any>>(obj: TObj, filter?: (value: TObj[string]) => any): TObj;
39
39
  /** 忽略对象中的 keys, 返回新对象 */
40
40
  export declare function omit<TObj>(obj: TObj, omit_keys: string[]): TObj;
@@ -147,7 +147,7 @@ export declare function map_stream<Out, In = Vinyl>(mapper: (obj: In, cb: Functi
147
147
  failures?: boolean;
148
148
  }): Duplex;
149
149
  export declare function stream_to_lines(stream: Readable): AsyncGenerator<string, void, unknown>;
150
- export declare function pipe_with_error(readable: Readable, transform: Transform): Transform;
150
+ export declare function pipe_with_error<TWritable extends Writable>(readable: Readable, writable: TWritable): TWritable;
151
151
  export declare class WritableMemoryStream extends Writable {
152
152
  chunks: Buffer[];
153
153
  pbuffer: Deferred<Buffer>;
@@ -168,6 +168,8 @@ export declare class DecoderStream extends Transform {
168
168
  _transform(chunk: Uint8Array, encoding: BufferEncoding, callback: TransformCallback): void;
169
169
  _flush(callback: TransformCallback): void;
170
170
  }
171
+ /** 消费一个可读流 */
172
+ export declare function consume_stream(stream: Readable, ignore_error?: boolean): Promise<void>;
171
173
  /** 根据 range 生成整数序列 (iterable)
172
174
  - range: 取值为逗号分割的多个可用值或值区间 (不能含有空格),比如:`8321,8322,8300-8310,11000-11999`
173
175
  - reverse?: `false` 在 range 内从后往前生成 */
package/utils.js CHANGED
@@ -80,7 +80,7 @@ export function filter_keys(obj, filter) {
80
80
  return Object.fromEntries(Object.entries(obj)
81
81
  .filter(([key]) => filter(key)));
82
82
  }
83
- /** 过滤对象中的 valus, 返回新对象 */
83
+ /** 过滤对象中的 values, 返回新对象 */
84
84
  export function filter_values(obj, filter = not_empty) {
85
85
  return Object.fromEntries(Object.entries(obj)
86
86
  .filter(([, value]) => filter(value)));
@@ -218,18 +218,13 @@ export async function timeout(milliseconds, action) {
218
218
  // eslint-disable-next-line @typescript-eslint/promise-function-async
219
219
  export function defer(initial) {
220
220
  if (initial === undefined) {
221
- let resolve;
222
- let reject;
223
- let promise = new Promise((_resolve, _reject) => {
224
- resolve = _resolve;
225
- reject = _reject;
226
- });
221
+ let { promise, resolve, reject } = Promise.withResolvers();
227
222
  return Object.assign(promise, { resolve, reject });
228
223
  }
229
224
  else
230
225
  return Object.assign(Promise.resolve(initial), {
231
- resolve() { },
232
- reject() { }
226
+ resolve: noop,
227
+ reject: noop
233
228
  });
234
229
  }
235
230
  /** @example
@@ -476,10 +471,10 @@ export async function* stream_to_lines(stream) {
476
471
  buf = chunk.slice(j);
477
472
  }
478
473
  }
479
- export function pipe_with_error(readable, transform) {
474
+ export function pipe_with_error(readable, writable) {
480
475
  // 不知道 transform 作为 AsyncIterable 使用时, emit error 是否会在 for await (...) 循环中触发错误
481
- readable.once('error', error => { transform.emit('error', error); });
482
- return readable.pipe(transform);
476
+ readable.once('error', error => { writable.emit('error', error); });
477
+ return readable.pipe(writable);
483
478
  }
484
479
  export class WritableMemoryStream extends Writable {
485
480
  chunks = [];
@@ -525,6 +520,17 @@ export class DecoderStream extends Transform {
525
520
  callback();
526
521
  }
527
522
  }
523
+ /** 消费一个可读流 */
524
+ export async function consume_stream(stream, ignore_error = false) {
525
+ try {
526
+ for await (const chunk of stream)
527
+ ;
528
+ }
529
+ catch (error) {
530
+ if (!ignore_error)
531
+ throw error;
532
+ }
533
+ }
528
534
  /** 根据 range 生成整数序列 (iterable)
529
535
  - range: 取值为逗号分割的多个可用值或值区间 (不能含有空格),比如:`8321,8322,8300-8310,11000-11999`
530
536
  - reverse?: `false` 在 range 内从后往前生成 */