xshell 1.3.0 → 1.3.2

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import util from 'util';
1
+ import util from 'node:util';
2
2
  import { call_nodejs, platform, username } from "./process.js";
3
3
  export let npm = {
4
4
  bin: platform == 'win32' ? `C:/Users/${username}/AppData/Roaming/npm/node_modules/pnpm/bin/pnpm.cjs` : '/usr/bin/pnpm',
package/builder.js CHANGED
@@ -1,8 +1,8 @@
1
- import { fileURLToPath } from 'url';
1
+ import { fileURLToPath } from 'node:url';
2
2
  import { not_empty } from "./prototype.js";
3
3
  import { noprint } from "./process.js";
4
4
  import { Lock, filter_values } from "./utils.js";
5
- import { fcopy, fmkdir, fwrite, fread, print_info } from "./file.js";
5
+ import { fcopy, fmkdir, fwrite, fread, print_info, ramdisk } from "./file.js";
6
6
  import { path } from "./path.js";
7
7
  function get_react_js(production, src, map) {
8
8
  return `${src ? import.meta.dirname.fpd : 'vendors/react/'}react.${production ? 'production' : 'development'}.js${map ? '.map' : ''}`;
@@ -472,8 +472,12 @@ export class Bundler {
472
472
  const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer');
473
473
  return [
474
474
  new BundleAnalyzerPlugin({
475
- analyzerPort: 8880,
475
+ analyzerMode: 'static',
476
476
  openAnalyzer: false,
477
+ reportFilename: ramdisk ?
478
+ `T:/t/webpack-analysis/${this.name}.html`
479
+ :
480
+ 'report.html'
477
481
  })
478
482
  ];
479
483
  })() : [],
package/development.js CHANGED
@@ -1,4 +1,4 @@
1
- import process from 'process';
1
+ import process from 'node:process';
2
2
  import { fcopy, fexists, ramdisk } from "./file.js";
3
3
  import { noprint } from "./process.js";
4
4
  /** 监听终端按键 (输入),并调用 key_processor 处理
package/file.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { promises as fsp, default as fs } from 'fs';
1
+ import { promises as fsp, default as fs } from 'node:fs';
2
2
  import type { UnzipFileFilter } from './fflate.ts';
3
3
  export { fsp };
4
4
  export type Encoding = 'utf-8' | 'gb18030' | 'shift-jis' | 'utf-16le';
@@ -208,11 +208,15 @@ export interface FMkdirOptions {
208
208
  export declare function fmkdir(fpd: string, { print }?: FMkdirOptions): Promise<string>;
209
209
  /** 创建软链接
210
210
  - fp_real: 现在真实文件/文件夹的路径
211
- - fp_link: 目标链接文件/文件夹的路径 */
212
- export declare function flink(fp_real: string, fp_link: string, { junction, print, skip_existing }?: {
213
- junction?: boolean;
214
- print?: boolean;
211
+ - fp_link: 目标链接文件/文件夹的路径
212
+ - options?:
213
+ - skip_existing?: `false` 忽略已存在的同名的文件,文件夹
214
+ - print?: `true`
215
+ - junction? */
216
+ export declare function flink(fp_real: string, fp_link: string, { skip_existing, print, junction }?: {
215
217
  skip_existing?: boolean;
218
+ print?: boolean;
219
+ junction?: boolean;
216
220
  }): Promise<void>;
217
221
  export interface ZipOptions {
218
222
  dirname?: string;
package/file.js CHANGED
@@ -1,4 +1,4 @@
1
- import { promises as fsp, default as fs } from 'fs';
1
+ import { promises as fsp, default as fs } from 'node:fs';
2
2
  import { isArrayBuffer, isUint8Array } from 'util/types';
3
3
  import { t } from "./i18n/instance.js";
4
4
  import { noop, to_json } from "./prototype.js";
@@ -456,8 +456,12 @@ export async function fmkdir(fpd, { print = true } = {}) {
456
456
  }
457
457
  /** 创建软链接
458
458
  - fp_real: 现在真实文件/文件夹的路径
459
- - fp_link: 目标链接文件/文件夹的路径 */
460
- export async function flink(fp_real, fp_link, { junction = false, print = true, skip_existing = false } = {}) {
459
+ - fp_link: 目标链接文件/文件夹的路径
460
+ - options?:
461
+ - skip_existing?: `false` 忽略已存在的同名的文件,文件夹
462
+ - print?: `true`
463
+ - junction? */
464
+ export async function flink(fp_real, fp_link, { skip_existing = false, print = true, junction = false } = {}) {
461
465
  check(path.isAbsolute(fp_real) && path.isAbsolute(fp_link), 'fp 必须是绝对路径');
462
466
  const is_fpd_real = fp_real.isdir;
463
467
  const is_fpd_link = fp_link.isdir;
package/net.browser.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t } from "./i18n/instance.js";
2
- import { assert, delay } from "./utils.browser.js";
2
+ import { assert, check, delay } from "./utils.browser.js";
3
3
  import { drop_request_headers } from "./net.common.js";
4
4
  export * from "./net.common.js";
5
5
  async function fetch_retry(url, options, timeout, retries = 0, count = 0) {
@@ -63,33 +63,7 @@ export async function request(url, options = {}) {
63
63
  ...cors ? { mode: 'cors' } : {},
64
64
  headers,
65
65
  // --- body
66
- body: (() => {
67
- if (body === undefined)
68
- return;
69
- switch (type) {
70
- case 'application/json':
71
- return typeof body === 'string' ||
72
- ArrayBuffer.isView(body) ||
73
- body instanceof ArrayBuffer ||
74
- body instanceof Blob ?
75
- body
76
- :
77
- JSON.stringify(body);
78
- case 'application/x-www-form-urlencoded':
79
- return body instanceof URLSearchParams ? body : new URLSearchParams(body);
80
- case 'multipart/form-data':
81
- if (body instanceof FormData)
82
- return body;
83
- else {
84
- let form = new FormData();
85
- for (const key in body) {
86
- let value = body[key];
87
- form.set(key, value);
88
- }
89
- return form;
90
- }
91
- }
92
- })(),
66
+ body: get_request_body(body, type),
93
67
  };
94
68
  let response;
95
69
  try {
@@ -111,14 +85,7 @@ export async function request(url, options = {}) {
111
85
  }
112
86
  if (raw)
113
87
  return response;
114
- const body_ = await (async () => {
115
- if (!response.body)
116
- return encoding === 'binary' ? new ArrayBuffer(0) : '';
117
- if (encoding === 'binary')
118
- return response.arrayBuffer();
119
- else
120
- return response.text();
121
- })();
88
+ const body_ = await get_response_body(response, encoding);
122
89
  return full ? {
123
90
  status: response.status,
124
91
  headers: response.headers,
@@ -127,6 +94,37 @@ export async function request(url, options = {}) {
127
94
  :
128
95
  body_;
129
96
  }
97
+ function get_request_body(body, type) {
98
+ if (body === undefined)
99
+ return;
100
+ if (type === 'application/json') {
101
+ return typeof body === 'string' ||
102
+ ArrayBuffer.isView(body) ||
103
+ body instanceof ArrayBuffer ||
104
+ body instanceof Blob ?
105
+ body
106
+ :
107
+ JSON.stringify(body);
108
+ }
109
+ if (type === 'application/x-www-form-urlencoded')
110
+ return body instanceof URLSearchParams ? body : new URLSearchParams(body);
111
+ check(type === 'multipart/form-data');
112
+ if (body instanceof FormData)
113
+ return body;
114
+ let form = new FormData();
115
+ for (const key in body) {
116
+ let value = body[key];
117
+ form.set(key, value);
118
+ }
119
+ return form;
120
+ }
121
+ async function get_response_body(response, encoding) {
122
+ if (!response.body)
123
+ return encoding === 'binary' ? new ArrayBuffer(0) : '';
124
+ if (encoding === 'binary')
125
+ return response.arrayBuffer();
126
+ return response.text();
127
+ }
130
128
  /** 发起 http 请求并将响应体作为 json 解析 */
131
129
  export async function request_json(url, options) {
132
130
  const body = await request(url, options);
package/net.common.d.ts CHANGED
@@ -100,6 +100,8 @@ export interface RemoteOptions {
100
100
  /** 使用者自定义的在 websocket 连接出错时,或者 handlers 出错时的处理
101
101
  用户设置后会覆盖默认的 print 错误功能 */
102
102
  on_error?(error: WebSocketConnectionError | Error, remote: Remote): void;
103
+ /** 使用者自定义的,在重连之前调用的函数,比如可以修改 url,仅连接发起方有效 */
104
+ on_reconnect?(this: Remote): Promise<void>;
103
105
  }
104
106
  /** 通过创建 remote 对象对 websocket rpc 进行抽象
105
107
  使用 remote.call() 进行一元 rpc
@@ -146,10 +148,11 @@ export declare class Remote {
146
148
  error: WebSocketConnectionError | Error;
147
149
  /** 作为 websocket 连接发起方,传入 url
148
150
  作为 websocket 连接接收方,传入 websocket + name */
149
- constructor({ name, url, websocket, funcs, print, verbose, probe, args, on_error, }?: RemoteOptions);
151
+ constructor({ name, url, websocket, funcs, print, verbose, probe, args, on_error, on_reconnect }?: RemoteOptions);
150
152
  /** 统一处理首次连接和连接后的 websocket 错误 */
151
153
  _on_error: (error: WebSocketConnectionError | Error) => void;
152
- reconnect: () => void;
154
+ on_reconnect?: (this: Remote) => Promise<void>;
155
+ reconnect: () => Promise<void>;
153
156
  _on_message: (data: ArrayBuffer) => void;
154
157
  /** 使用者自定义的在 websocket 连接出错时,或者 handlers 出错时的处理
155
158
  用户设置后会覆盖默认的 print 错误功能 */
package/net.common.js CHANGED
@@ -238,12 +238,14 @@ export class Remote {
238
238
  error;
239
239
  /** 作为 websocket 连接发起方,传入 url
240
240
  作为 websocket 连接接收方,传入 websocket + name */
241
- constructor({ name, url, websocket, funcs, print, verbose, probe, args, on_error, } = {}) {
241
+ constructor({ name, url, websocket, funcs, print, verbose, probe, args, on_error, on_reconnect } = {}) {
242
242
  if (name)
243
243
  this.name = name;
244
244
  if (url) {
245
245
  check(!websocket, '构建 Remote 时 url 和 websocket 只能传其中一个');
246
246
  this.url = url;
247
+ if (on_reconnect)
248
+ this.on_reconnect = on_reconnect;
247
249
  }
248
250
  else { // 连接接收方,一定是 nodejs 环境
249
251
  check(websocket, '构建 Remote 时需传入 url 或者 websocket');
@@ -308,13 +310,16 @@ export class Remote {
308
310
  !this.reconnecting &&
309
311
  this.url &&
310
312
  (this.funcs || this.probe)) {
311
- this.reconnecting = setTimeout(this.reconnect, this.error ? 10_000 : 2_000);
313
+ this.reconnecting = setTimeout(this.reconnect, this.error ? 20_000 : 2_000);
312
314
  this.error = error;
313
315
  }
314
316
  this.on_error(error, this);
315
317
  };
316
- reconnect = () => {
318
+ on_reconnect;
319
+ reconnect = async () => {
317
320
  this.reconnecting = null;
321
+ if (this.on_reconnect)
322
+ await this.on_reconnect();
318
323
  this.try_connect();
319
324
  };
320
325
  _on_message = (data) => {
package/net.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Readable } from 'stream';
1
+ import { type Readable } from 'node:stream';
2
2
  import type { Cookie, CookieJar, MemoryCookieStore } from 'tough-cookie';
3
3
  import type { Encoding } from './file.ts';
4
4
  import { inspect } from './utils.ts';
@@ -48,6 +48,7 @@ export interface RequestOptions {
48
48
  retry: boolean;
49
49
  timeout: boolean;
50
50
  };
51
+ long_connection?: true;
51
52
  }
52
53
  export interface RequestFullOptions extends RequestOptions {
53
54
  full: true;
@@ -96,7 +97,8 @@ export declare class StatusCodeError extends Error {
96
97
  - decode?: `true` 根据 content-encoding: br 等解码压缩后的 response.body
97
98
  - print?:
98
99
  - retry: `true` 是否打印 "等待 1 秒后重试 request" 提示信息
99
- - timeout: `true` 是否打印最后一次超时重试失败时的错误 */
100
+ - timeout: `true` 是否打印最后一次超时重试失败时的错误
101
+ - long_connection?: 用于保持长 tcp 连接,保留 nat 端口映射记录 */
100
102
  export declare function request(url: string | URL): Promise<string>;
101
103
  export declare function request(url: string | URL, options: RequestRawOptions): Promise<RawResponse>;
102
104
  export declare function request(url: string | URL, options: RequestFullOptions & {
package/net.js CHANGED
@@ -1,7 +1,7 @@
1
- import zlib from 'zlib';
2
- import { buffer as stream_to_buffer, text as stream_to_text } from 'stream/consumers';
3
- import { isReadable } from 'stream';
4
- import { inspect, assert, delay, pipe_with_error, map_values, unique, timeout, check, colored } from "./utils.js";
1
+ import zlib from 'node:zlib';
2
+ import { buffer as stream_to_buffer, text as stream_to_text } from 'node:stream/consumers';
3
+ import { isReadable } from 'node:stream';
4
+ import { inspect, assert, delay, pipe_with_error, map_values, unique, timeout, check, colored, encode } from "./utils.js";
5
5
  import { drop_request_headers } from "./net.common.js";
6
6
  export * from "./net.common.js";
7
7
  export var MyProxy;
@@ -24,9 +24,9 @@ export const cookies = {
24
24
  this.jar = new CookieJar(this.store = new MemoryCookieStore());
25
25
  },
26
26
  };
27
- let agents = {};
27
+ let undici;
28
+ let dispatchers = {};
28
29
  async function request_retry(url, options, _timeout, retries = 0, count = 0, print) {
29
- const { default: undici } = await import('undici');
30
30
  try {
31
31
  if (_timeout > 0) {
32
32
  // 设置给 undici 设置 timeout, signal 不一定管用,还是得自己兜底
@@ -65,15 +65,13 @@ export class StatusCodeError extends Error {
65
65
  }
66
66
  }
67
67
  export async function request(url, options = {}) {
68
- let { default: undici, ProxyAgent: UndiciProxyAgent, FormData: UndiciFormData } = await import('undici');
69
- UndiciProxyAgent ??= undici.ProxyAgent;
70
- UndiciFormData ??= undici.FormData;
68
+ undici ??= (await import('undici')).default;
71
69
  const { Cookie } = await import('tough-cookie');
72
70
  await cookies.init();
73
71
  const { queries, headers: _headers, body, type = 'application/json', timeout = 5 * 1000, auth, cookies: _cookies, raw = false, full = false, redirect = 'follow', decode = true, print = {
74
72
  timeout: true,
75
73
  retry: true
76
- } } = options;
74
+ }, long_connection } = options;
77
75
  let { method, retries, encoding, proxy, } = options;
78
76
  url = new URL(url);
79
77
  if (queries)
@@ -126,23 +124,11 @@ export async function request(url, options = {}) {
126
124
  headers[key] = _headers[key];
127
125
  }
128
126
  }
127
+ if (proxy === true)
128
+ proxy = MyProxy.socks5;
129
129
  let undici_options = {
130
130
  ...method ? { method } : {},
131
- dispatcher: await (async () => {
132
- const { default: {
133
- // @ts-ignore
134
- ProxyAgent, Agent, interceptors } } = await import('undici');
135
- if (proxy === true)
136
- proxy = MyProxy.socks5;
137
- return agents[`${proxy || 'direct'}.${redirect}`] ??= (() => {
138
- let dispatcher = proxy ? new ProxyAgent({ uri: proxy }) : new Agent();
139
- if (redirect === 'follow')
140
- dispatcher = dispatcher.compose(
141
- // todo: 强制手动处理重定向,来正确处理 cookie ?
142
- interceptors.redirect({ maxRedirections: 5 }));
143
- return dispatcher;
144
- })();
145
- })(),
131
+ dispatcher: get_dispatcher(proxy, redirect, long_connection),
146
132
  // 下面这些 timeout 都不是总的时间
147
133
  headersTimeout: timeout,
148
134
  // 从收完 headers 开始算
@@ -150,30 +136,7 @@ export async function request(url, options = {}) {
150
136
  // @ts-ignore 没有类型声明,实际可用
151
137
  connectTimeout: timeout,
152
138
  headers,
153
- // --- body
154
- body: (() => {
155
- if (body === undefined)
156
- return;
157
- if (typeof body?.read === 'function' && isReadable(body))
158
- return body;
159
- switch (type) {
160
- case 'application/json': // 可能的类型 string | Record<string, any> | Uint8Array
161
- if (typeof body === 'string')
162
- return body;
163
- if (body instanceof Uint8Array)
164
- return body;
165
- assert(!(body instanceof ArrayBuffer || ArrayBuffer.isView(body)));
166
- return JSON.stringify(body);
167
- case 'application/x-www-form-urlencoded':
168
- return (body instanceof URLSearchParams ? body : new URLSearchParams(body)).toString();
169
- case 'multipart/form-data': {
170
- let form = new UndiciFormData();
171
- for (const key in body)
172
- form.set(key, body[key]);
173
- return form;
174
- }
175
- }
176
- })()
139
+ body: get_request_body(body, type)
177
140
  };
178
141
  let response;
179
142
  try {
@@ -265,25 +228,62 @@ export async function request(url, options = {}) {
265
228
  }
266
229
  if (raw)
267
230
  return response;
268
- const body_ = await (async () => {
269
- if (!response.body)
270
- return encoding === 'binary' ? Buffer.from([]) : '';
271
- if (encoding === 'binary')
272
- return stream_to_buffer(response.body);
273
- encoding ||= /charset=(.*)/.exec(response.headers['content-type'])?.[1] || 'utf-8';
274
- if (/utf-?8/i.test(encoding))
275
- return stream_to_text(response.body);
276
- return new TextDecoder(encoding)
277
- .decode(await stream_to_buffer(response.body));
278
- })();
279
- return full ? {
280
- status: response.status,
281
- headers: response.headers,
282
- body: body_
283
- }
231
+ const body_ = await get_response_body(response.body, encoding, response.headers);
232
+ return full ?
233
+ { status: response.status, headers: response.headers, body: body_ }
284
234
  :
285
235
  body_;
286
236
  }
237
+ function get_dispatcher(proxy, redirect, long_connection) {
238
+ const key = `${proxy || (long_connection ? 'direct.long' : 'direct')}.${redirect}`;
239
+ let dispatcher = dispatchers[key];
240
+ if (dispatcher)
241
+ return dispatcher;
242
+ dispatcher = proxy ?
243
+ // @ts-ignore
244
+ new undici.ProxyAgent({ uri: proxy })
245
+ :
246
+ new undici.Agent({ keepAliveTimeout: long_connection ? 30_000 : undefined });
247
+ if (redirect === 'follow')
248
+ dispatcher = dispatcher.compose(
249
+ // todo: 强制手动处理重定向,来正确处理 cookie ?
250
+ undici.interceptors.redirect({ maxRedirections: 5 }));
251
+ return dispatchers[key] = dispatcher;
252
+ }
253
+ function get_request_body(body, type) {
254
+ if (body === undefined)
255
+ return undefined;
256
+ if (typeof body?.read === 'function' && isReadable(body))
257
+ return body;
258
+ if (type === 'application/json') {
259
+ // 可能的类型 string | Record<string, any> | Uint8Array
260
+ if (typeof body === 'string')
261
+ return encode(body);
262
+ if (body instanceof Uint8Array)
263
+ return body;
264
+ check(!(body instanceof ArrayBuffer || ArrayBuffer.isView(body)));
265
+ return JSON.stringify(body);
266
+ }
267
+ if (type === 'application/x-www-form-urlencoded')
268
+ return encode((body instanceof URLSearchParams ? body : new URLSearchParams(body)).toString());
269
+ check(type === 'multipart/form-data');
270
+ // undici.FormData 会和 globalThis.FormData 不一致,禁止传入 FormData 类型
271
+ let form = new undici.FormData();
272
+ for (const key in body)
273
+ form.set(key, body[key]);
274
+ return form;
275
+ }
276
+ async function get_response_body(body, encoding, headers) {
277
+ if (!body)
278
+ return encoding === 'binary' ? Buffer.from([]) : '';
279
+ if (encoding === 'binary')
280
+ return stream_to_buffer(body);
281
+ encoding ||= /charset=(.*)/.exec(headers['content-type'])?.[1] || 'utf-8';
282
+ if (/utf-?8/i.test(encoding))
283
+ return stream_to_text(body);
284
+ return new TextDecoder(encoding)
285
+ .decode(await stream_to_buffer(body));
286
+ }
287
287
  /** 发起 http 请求并将响应体作为 json 解析 */
288
288
  export async function request_json(url, options) {
289
289
  const body = await request(url, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -64,7 +64,7 @@
64
64
  "commander": "^14.0.2",
65
65
  "css-loader": "^7.1.2",
66
66
  "emoji-regex": "^10.6.0",
67
- "eslint": "^9.38.0",
67
+ "eslint": "^9.39.0",
68
68
  "eslint-plugin-import": "^2.32.0",
69
69
  "eslint-plugin-react": "^7.37.5",
70
70
  "https-proxy-agent": "^7.0.6",
@@ -76,9 +76,9 @@
76
76
  "mime-types": "^3.0.1",
77
77
  "p-map": "^7.0.3",
78
78
  "react": "^19.2.0",
79
- "react-i18next": "^16.2.1",
79
+ "react-i18next": "^16.2.3",
80
80
  "resolve-path": "^1.4.0",
81
- "sass": "^1.93.2",
81
+ "sass": "^1.93.3",
82
82
  "sass-loader": "^16.0.6",
83
83
  "source-map-loader": "^5.0.0",
84
84
  "strip-ansi": "^7.1.2",
package/path.d.ts CHANGED
@@ -54,7 +54,7 @@ export declare function extname(path: string): string;
54
54
  /** `/` */
55
55
  export declare const sep = "/";
56
56
  /** The platform-specific file delimiter. ';' or ':'. */
57
- export declare const delimiter: ";" | ":";
57
+ export declare const delimiter: ":" | ";";
58
58
  /** Returns an object from a path string - the opposite of format().
59
59
  @param path path to evaluate.
60
60
  @throws {TypeError} if `path` is not a string. */
@@ -81,7 +81,7 @@ export declare let path: {
81
81
  basename: typeof basename;
82
82
  extname: typeof extname;
83
83
  sep: string;
84
- delimiter: ";" | ":";
84
+ delimiter: ":" | ";";
85
85
  parse: typeof parse;
86
86
  format: typeof format;
87
87
  toNamespacedPath: typeof toNamespacedPath;
@@ -1,4 +1,4 @@
1
- import type { TimerOptions } from 'timers';
1
+ import type { TimerOptions } from 'node:timers';
2
2
  import type { HttpsProxyAgent } from 'https-proxy-agent';
3
3
  export declare let platform: Platform;
4
4
  export declare function set_platform(_platform: Platform): void;
package/process.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { InspectOptions } from 'util';
2
- import { type ChildProcess } from 'child_process';
1
+ import type { InspectOptions } from 'node:util';
2
+ import { type ChildProcess } from 'node:child_process';
3
3
  import './prototype.ts';
4
4
  import { type Encoding } from './file.ts';
5
5
  import type { MyProxy } from './net.ts';
package/process.js CHANGED
@@ -1,5 +1,5 @@
1
- import { spawn } from 'child_process';
2
- import os from 'os';
1
+ import { spawn } from 'node:child_process';
2
+ import os from 'node:os';
3
3
  import node_sea from 'node:sea';
4
4
  import "./prototype.js";
5
5
  import { fopen } from "./file.js";
package/prototype.js CHANGED
@@ -1,4 +1,4 @@
1
- import util from 'util';
1
+ import util from 'node:util';
2
2
  import { platform } from "./platform.js";
3
3
  import { to_method_property_descriptors } from "./prototype.common.js";
4
4
  export * from "./prototype.common.js";
package/repl.js CHANGED
@@ -6,8 +6,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- import repl from 'repl';
10
- import process from 'process';
9
+ import repl from 'node:repl';
10
+ import process from 'node:process';
11
11
  import { fileURLToPath } from 'url';
12
12
  import { path } from "./path.js";
13
13
  import { t } from "./i18n/instance.js";
package/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { type Server as HttpServer, type IncomingHttpHeaders, type IncomingMessage } from 'http';
2
- import { type Http2SecureServer, type IncomingHttpHeaders as IncomingHttp2Headers } from 'http2';
3
- import type { Duplex } from 'stream';
1
+ import { type Server as HttpServer, type IncomingHttpHeaders, type IncomingMessage } from 'node:http';
2
+ import { type Http2SecureServer, type IncomingHttpHeaders as IncomingHttp2Headers } from 'node:http2';
3
+ import type { Duplex } from 'node:stream';
4
4
  import type { WebSocketServer } from 'ws';
5
5
  import { default as Koa, type Context, type Next } from 'koa';
6
6
  import { Remote, type RequestOptions, type RawResponse, type MessageHandler } from './net.ts';
package/server.js CHANGED
@@ -1,9 +1,9 @@
1
- import { createServer as http_create_server, } from 'http';
2
- import { createSecureServer as http2_create_server } from 'http2';
3
- import { createSecureContext } from 'tls';
4
- import zlib from 'zlib';
5
- import fs from 'fs';
6
- import { buffer as stream_to_buffer } from 'stream/consumers';
1
+ import { createServer as http_create_server, } from 'node:http';
2
+ import { createSecureServer as http2_create_server } from 'node:http2';
3
+ import { createSecureContext } from 'node:tls';
4
+ import zlib from 'node:zlib';
5
+ import fs from 'node:fs';
6
+ import { buffer as stream_to_buffer } from 'node:stream/consumers';
7
7
  import node_sea from 'node:sea';
8
8
  import { default as Koa } from 'koa';
9
9
  import KoaCors from '@koa/cors';
package/utils.common.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TimerOptions } from 'timers';
1
+ import type { TimerOptions } from 'node:timers';
2
2
  import { type Mapper } from './prototype.common.ts';
3
3
  export declare function delay(milliseconds: number, options?: TimerOptions): Promise<void>;
4
4
  export declare function assert<T>(assertion: T, message?: string): T;
@@ -124,6 +124,13 @@ export interface Deferred<TValue> extends Promise<TValue> {
124
124
  - initial?: `undefined` 传入非 undefined 值(包括 null)时直接设置为 resolved 状态
125
125
  注: 下面的方法不能标记为 aysnc function, 否则会对返回值再做一层 Promise.resolve() 导致 reject, resolve 属性丢失 */
126
126
  export declare function defer<TValue>(initial?: TValue): Deferred<TValue>;
127
+ export interface Deferred2<TValue> extends Promise<TValue> {
128
+ resolve(value: TValue | PromiseLike<TValue>): void;
129
+ reject(reason?: Error): void;
130
+ get settled(): boolean;
131
+ }
132
+ /** 有 settled 状态的 defer */
133
+ export declare function defer2<TValue>(initial?: TValue): Deferred2<TValue>;
127
134
  export interface LockedAction<TResource, TResult> {
128
135
  (resource: TResource): TResult | Promise<TResult>;
129
136
  }
@@ -166,3 +173,13 @@ export declare function tomorrow(date?: Date | string | number): Date;
166
173
  export declare function to_csv_field(str: string): string;
167
174
  /** 设置 error.message 同时更新 error.stack */
168
175
  export declare function set_error_message(error: Error, message: string): Error;
176
+ /** 比较两个数组中的元素完全相同,数组元素用引用比较 */
177
+ export declare function array_equals(a: any[], b: any[]): boolean;
178
+ export declare function nowstr(with_date?: boolean): string;
179
+ interface MyTimeout {
180
+ clear(): void;
181
+ ref: NodeJS.Timeout | number;
182
+ }
183
+ /** 面向对象的 timeout, callback 在后的 timeout */
184
+ export declare function set_timeout(delay: number, callback: VoidFunction): MyTimeout;
185
+ export {};
package/utils.common.js CHANGED
@@ -396,6 +396,33 @@ export function defer(initial) {
396
396
  reject: noop
397
397
  });
398
398
  }
399
+ /** 有 settled 状态的 defer */
400
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
401
+ export function defer2(initial) {
402
+ if (initial === undefined) {
403
+ let settled = false;
404
+ let { promise, resolve, reject } = Promise.withResolvers();
405
+ return Object.assign(promise, {
406
+ resolve(value) {
407
+ settled = true;
408
+ resolve(value);
409
+ },
410
+ reject(error) {
411
+ settled = true;
412
+ reject(error);
413
+ },
414
+ get settled() {
415
+ return settled;
416
+ }
417
+ });
418
+ }
419
+ else
420
+ return Object.assign(Promise.resolve(initial), {
421
+ resolve: noop,
422
+ reject: noop,
423
+ settled: true
424
+ });
425
+ }
399
426
  /** @example
400
427
  let lock = new Lock(redis)
401
428
 
@@ -537,4 +564,29 @@ export function set_error_message(error, message) {
537
564
  error.stack.slice_from('\n', { optional: true });
538
565
  return error;
539
566
  }
567
+ /** 比较两个数组中的元素完全相同,数组元素用引用比较 */
568
+ export function array_equals(a, b) {
569
+ if (!a && !b)
570
+ return true;
571
+ if (a && !b || !a && b)
572
+ return false;
573
+ return a.every((x, i) => x === b[i]);
574
+ }
575
+ export function nowstr(with_date = false) {
576
+ const date = new Date();
577
+ return with_date ? date.to_str() : date.to_time_str();
578
+ }
579
+ /** 面向对象的 timeout, callback 在后的 timeout */
580
+ export function set_timeout(delay, callback) {
581
+ let ret = {
582
+ ref: setTimeout(callback, delay),
583
+ clear() {
584
+ if (!ret.ref)
585
+ return;
586
+ clearTimeout(ret.ref);
587
+ ret.ref = null;
588
+ }
589
+ };
590
+ return ret;
591
+ }
540
592
  //# sourceMappingURL=utils.common.js.map
package/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Writable, Transform, type Readable, type Duplex, type TransformCallback } from 'stream';
2
- import util from 'util';
1
+ import { Writable, Transform, type Readable, type Duplex, type TransformCallback } from 'node:stream';
2
+ import util from 'node:util';
3
3
  import './prototype.ts';
4
4
  import './platform.ts';
5
5
  export * from './utils.common.ts';
package/utils.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Stream, Writable, Transform } from 'stream';
2
- import util from 'util';
3
- import ncrypto from 'crypto';
1
+ import { Stream, Writable, Transform } from 'node:stream';
2
+ import util from 'node:util';
3
+ import ncrypto from 'node:crypto';
4
4
  import "./prototype.js";
5
5
  import "./platform.js";
6
6
  import { assert, decode, defer, delay } from "./utils.common.js";