mytglib 2.0.0 → 2.0.1

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.
Files changed (3) hide show
  1. package/README.md +66 -17
  2. package/dist/index.js +1 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -102,8 +102,10 @@ try {
102
102
  }
103
103
  ```
104
104
 
105
- iOS 默认使用 `ios.CURRENT_VERSION` 数组中的最新版本。需要覆盖时,必须同时传入
106
- `appVersion` 与 `overrideLayer`,两者会作为同一版本配置应用:
105
+ iOS 默认使用 `ios.CURRENT_VERSION` 的最后一项。覆盖版本时仍需同时传入 `appVersion` 与
106
+ `overrideLayer`,以兼容现有调用方;`appVersion` 会原样用于 Telegram `initConnection.appVersion`,
107
+ `overrideLayer` 不会传给底层客户端。Node.js 的协议 layer 始终由 `@mtcute/node` 当前 codec 的
108
+ `tl.LAYER` 决定,当前为 layer 229。
107
109
 
108
110
  ```js
109
111
  const iosCore = new CoreClient({
@@ -112,14 +114,15 @@ const iosCore = new CoreClient({
112
114
  proxy: { type: "http", host: "127.0.0.1", port: 8080 },
113
115
  sessionDirPath: resolve("telegram-sessions"),
114
116
  langCode: "en",
115
- appVersion: "13.0 (35000) ",
116
- overrideLayer: 229,
117
+ appVersion: "12.8.1 (33181) ",
118
+ overrideLayer: 227,
117
119
  deviceTokenResolver: async () => ({ token: "AQIDBA==" }),
118
120
  });
119
121
  ```
120
122
 
121
- 覆盖值仅适用于 iOS;`appVersion` 必须是非空字符串,`overrideLayer` 必须是正数 int32。
122
- 如果传入的 `appVersion` 已存在于内置数组,其 layer 必须与数组中的官方配对一致。
123
+ 覆盖值仅适用于 iOS;`appVersion` 必须是非空字符串,`overrideLayer` 必须是正数 int32。Rust fork
124
+ 同样只把 `app_version` 用于 `initConnection`,协议 layer 始终使用编译期 `tl::LAYER`。Node.js 和 Rust
125
+ 新写入的 `override_layer` Metadata 均记录当前真实 codec layer(当前为 229),不记录历史选择值。
123
126
  `langCode` 同样只支持 iOS,并且必须来自公开的 `iosLangPackLanguages`;省略时继续根据
124
127
  手机号自动选择。手工覆盖只改变 Telegram `langCode`,`systemLangCode` 仍按手机号地区推断。
125
128
 
@@ -137,7 +140,7 @@ const response = await core.sendCode({
137
140
  });
138
141
  ```
139
142
 
140
- 传入的五个能力字段必须是 boolean;Android 的 `allowAppHash` 以及 iOS 的 APNs `token`、`appSandbox` 仍由平台配置自动生成,不属于可覆盖字段。根据 [mtcute 0.31.0 `sendCode` API](https://ref.mtcute.dev/funcs/_mtcute_core.highlevel_methods.sendCode.html),future auth tokens 的参数类型是 `Uint8Array[]`;本库直接构造 raw `codeSettings`,因此对应的 `logoutTokens` 使用原生 JavaScript 数组,并在请求对象中固定保留空数组 `[]`,而不是 TL JSON 包装对象或字符串数组。mtcute 0.31.0 只会序列化非空的 `logoutTokens`,因此空数组不会设置可选 TL vector flag。
143
+ 传入的五个能力字段必须是 boolean;Android 的 `allowAppHash` 以及 iOS 的 APNs `token`、`appSandbox` 仍由平台配置自动生成,不属于可覆盖字段。根据 [mtcute 0.32.0 `sendCode` API](https://ref.mtcute.dev/funcs/_mtcute_core.highlevel_methods.sendCode.html),future auth tokens 的参数类型是 `Uint8Array[]`;本库直接构造 raw `codeSettings`,因此对应的 `logoutTokens` 使用原生 JavaScript 数组,并在请求对象中固定保留空数组 `[]`,而不是 TL JSON 包装对象或字符串数组。mtcute 0.32.0 只会序列化非空的 `logoutTokens`,因此空数组不会设置可选 TL vector flag。
141
144
 
142
145
  `deviceTokenResolver` 和 `recaptchaMobileTokenResolver` 必须返回包含非空字符串 `token` 字段的对象,对象可保留求解服务返回的 `errorMessage`、`message` 等附加字段。无有效 token 时会抛出 `TypeError`,其 `cause` 是 resolver 返回的完整结果;reCAPTCHA token 最长为 16,384 个字符。
143
146
 
@@ -163,7 +166,7 @@ const updates = await core.submitCredentials({
163
166
 
164
167
  `timeout`、`maxRetryCount` 和 `abortSignal` 是所有 mytglib 登录 RPC 的统一调用参数。`timeout` 默认为 `30000`,必须是正安全整数毫秒;`maxRetryCount` 默认为 `0`,必须是非负安全整数;`abortSignal` 默认为 `undefined`,传入时必须是 `AbortSignal`。客户端创建后会通过原始 `TelegramClient.withParams()` 生成 `core.client`,登录流程和通过 `core.client.call()` 发出的请求都会使用这些参数。密码更新的最终 `account.updatePasswordSettings` 会把 `maxRetryCount` 强制为 `0`,避免 internal/flood retry middleware 重放;前置的只读 `account.getPassword` 仍使用客户端配置。它们只作用于 RPC,不处理 `connect()` 超时,也不会取消正在进行的 `connect()`。
165
168
 
166
- `sessionDirPath` 是必传的会话主目录。路径已存在时必须是目录;路径不存在时会在初始化过程中递归创建。`init()` 会按照 `<主目录>/<+手机号>/<+手机号>.session` 创建 SQLite 会话文件,然后依次解析设备 token 并连接客户端。连接成功后可通过 `core.sessionFilePath` 直接取得当前客户端使用的 SQLite 文件路径;连接前该属性为 `null`。登录相关公共异步方法均返回原始 Telegram TL 响应。`core.rawClient` 保存原始 `TelegramClient`,只负责 `connect()`、`notifyLoggedIn()` 和 `destroy()`;`core.client` 保存 `withParams()` 返回的 RPC Proxy。`core.destroy()` 始终销毁 `rawClient`,不会在 `@mtcute/node` 0.31.0 的包装对象上调用 `destroy()`,从而避免私有字段错误。无论成功或失败,都应在 `finally` 中调用 `core.destroy()`,永久关闭连接、定时器和存储资源。销毁成功后两个客户端引用都会恢复为 `null`,SQLite 文件路径仍保留在 `core.sessionFilePath` 上。
169
+ `sessionDirPath` 是必传的会话主目录。路径已存在时必须是目录;路径不存在时会在初始化过程中递归创建。`init()` 会按照 `<主目录>/<+手机号>/<+手机号>.session` 创建 SQLite 会话文件,然后依次解析设备 token 并连接客户端。连接成功后可通过 `core.sessionFilePath` 直接取得当前客户端使用的 SQLite 文件路径;连接前该属性为 `null`。登录相关公共异步方法均返回原始 Telegram TL 响应。`core.rawClient` 保存原始 `TelegramClient`,只负责 `connect()`、`notifyLoggedIn()` 和 `destroy()`;`core.client` 保存 `withParams()` 返回的 RPC Proxy。`core.destroy()` 始终销毁 `rawClient`,不会在 `@mtcute/node` 0.32.0 的包装对象上调用 `destroy()`,从而避免私有字段错误。无论成功或失败,都应在 `finally` 中调用 `core.destroy()`,永久关闭连接、定时器和存储资源。销毁成功后两个客户端引用都会恢复为 `null`,SQLite 文件路径仍保留在 `core.sessionFilePath` 上。
167
170
 
168
171
  初始化 `.session` 时,库会在同一个 SQLite 数据库内创建单行 `session_metadata` 表,并在授权成功后写入账号 Metadata;不会自动创建 JSON 文件或第二个数据库连接。每次初始化都会让 `session_file` 与当前会话路径一致;初始化配置与首次授权时间作为注册快照保留,`reg_time` 取最终产生授权的注册或登录方法入口调用时间。重新授权只刷新用户名、姓名、Premium 状态及非空运行态字段。`first_name` 和 `last_name` 在注册或登录授权成功后自动从 Telegram 用户信息同步,缺失时写入 `NULL`。`completion_type` 只有 `sign_up`(实际执行 `auth.signUp` 创建账号)和 `login`(已有账号完成授权)两种;缺失字段写入 `NULL`。最新 `phone_code_hash`、已验证登录邮箱、成功使用的 reCAPTCHA token 和两步验证密码会随运行生命周期同步更新。数据库写入失败时会按 `50ms`、`150ms`、`300ms` 额外重试三次;Telegram RPC 已成功但 Metadata 最终仍失败时,可调用 `await core.retrySaveSessionMetadata()` 重试当前全部待写操作。
169
172
 
@@ -222,6 +225,13 @@ StringSession 优先读取 `session_str`,也兼容 `session_string`;两者
222
225
  SQLite 与 StringSession 中的 endpoint 只用于交叉校验;实际创建 Pool 客户端时会按 JSON 对应的
223
226
  官方 iOS 或 Android 平台,使用相同 DC ID 的内置官方 seed,不会连接上传文件指定的地址。
224
227
  `device_token` 可以省略、设为 `null` 或留空;空值按未提供处理,不会写入连接参数。
228
+ 导入会在写入账号池前主动检查账号状态,并且只接受 `UNFROZEN`:`FROZEN` 返回
229
+ `ACCOUNT_INVALID`,无法确认的 `UNKNOWN` 返回 `POOL_CONNECTION_FAILED`,两者都不会留下账号记录或
230
+ 可调度槽位。只有 Telegram RPC 本身真实返回 `FROZEN_METHOD_INVALID` 或
231
+ `FROZEN_PARTICIPANT_MISSING` 时,才会原样保留其 `code = 420` 和错误文本;内部按认证失效一类
232
+ 致命账号错误处置,不会把真实错误改写成 401。AppConfig RPC 的普通失败或超时才归为 `UNKNOWN`;
233
+ 若该 RPC 真实返回现有致命账号错误或 `FLOOD_WAIT`,导入会保留原错误并拒绝落库,池内自检则分别
234
+ 执行终态隔离或服务端时长冷却。
225
235
 
226
236
  `minWarmSlots` 可省略,默认值为 `10`,可设为正的 JavaScript 安全整数,不再固定限制为 50;
227
237
  `minWarmSlots * 5` 也必须是 JavaScript 安全整数。
@@ -273,6 +283,8 @@ console.log(response.status, response.waitTime, response.error);
273
283
  返回最后一次已实际发生的暖槽错误;如果尚未发生任何暖槽错误就无可用槽位,则直接返回 Pool busy。
274
284
  触发 `FLOOD_WAIT` 的账号会按 Telegram 返回的等待秒数退出暖槽并进入冷却,
275
285
  Pool 随即从库存异步补入其他账号。
286
+ 若暖槽返回冻结账号错误,Pool 会将该账号永久隔离并换用其他 `READY` 槽位;当前检测返回的错误仍保留
287
+ Telegram 原始 `code = 420` 和错误文本。
276
288
  `PHONE_NUMBER_FLOOD` 是目标手机号级错误,不换槽重试,只保护目标手机号 5 分钟且不处罚账号。
277
289
  明确检测结果缓存 5 分钟,最多保存 10,000 条;同一手机号的并发请求会合并为一次检测,
278
290
  基础设施错误不缓存,也不提供强制刷新。
@@ -291,9 +303,12 @@ single-flight RPC。即使当前只有一个等待者,后台检测仍可完成
291
303
  const accounts = await pool.listAccounts();
292
304
  const detail = await pool.getAccount(account.accountId);
293
305
  const testResult = await pool.testAccount(account.accountId);
306
+ const testReport = await pool.testAccounts({
307
+ abortSignal: new AbortController().signal,
308
+ });
294
309
  const status = await pool.getStatus();
295
310
 
296
- console.log(accounts, detail, testResult, status.runtime);
311
+ console.log(accounts, detail, testResult, testReport, status.runtime);
297
312
  console.log(accounts.map(({ phone, cooldownUntil }) => ({ phone, cooldownUntil })));
298
313
 
299
314
  // 删除会先停止派单,等待该账号当前任务结束,再断开连接并删除持久化记录。
@@ -302,10 +317,34 @@ const removed = await pool.removeAccount(account.accountId);
302
317
 
303
318
  账号运行态由 Pool 管理:可用账号处于 `STANDBY`、`RESERVED`、`CONNECTING`、`READY` 或
304
319
  `BUSY`;触发 flood 的账号进入 `COOLDOWN`,认证失效等致命错误会进入 `QUARANTINED`。
305
- `testAccount()` 是账号健康自检:它使用 `users.getUsers(inputUserSelf)` 验证该账号的授权和身份,
306
- 不会拿这个账号去检测某个外部手机号。验证成功会把隔离账号恢复为可调度状态。
320
+ `testAccount()` 是由管理员主动触发的账号健康自检,不会拿这个账号去检测某个外部手机号,也不会由
321
+ 协调器定时自动执行。`QUARANTINED` 是终态;自检不会把已隔离账号恢复为 `ACTIVE` 或重新加入调度。
307
322
  管理接口返回完整 `phone` 和 ISO 格式或 `null` 的 `cooldownUntil`,但不会包含 auth key、原始
308
- Metadata、session 或其他连接凭据。
323
+ Metadata、session、Telegram 冻结时间或申诉地址等内部探测字段。
324
+
325
+ `testAccounts()` 由使用者主动触发,会固定批次开始时的账号快照并严格串行调用单账号自检。同一个 Pool
326
+ 同时只运行一个批次;已经 `BUSY` 的账号不会被等待或抢断,而是记为 `FAILED` 后继续。已隔离账号不联网,
327
+ 直接记为 `QUARANTINED`;批次中的账号被删除或进入 `REMOVING` 时记为 `SKIPPED`。返回结构固定为:
328
+
329
+ ```js
330
+ {
331
+ total: 1,
332
+ healthy: 1,
333
+ quarantined: 0,
334
+ failed: 0,
335
+ skipped: 0,
336
+ results: [{
337
+ accountId: "account-id",
338
+ outcome: "HEALTHY",
339
+ account: { /* PoolAccount */ },
340
+ error: null,
341
+ }],
342
+ }
343
+ ```
344
+
345
+ `outcome` 只会是 `HEALTHY`、`QUARANTINED`、`FAILED` 或 `SKIPPED`;`account` 为当前
346
+ `PoolAccount` 或 `null`,`error` 为 `null` 或 `{ code: string | null, message: string }`。
347
+ 取消信号会停止批次并直接拒绝当前调用,不会把取消记成账号失败或改变账号健康状态。
309
348
 
310
349
  `getStatus()` 可用于健康检查和后台展示,包含生命周期、账号库存、各运行态槽位数、当前目标、
311
350
  策略上限、资源上限、资源压力和建连并发等信息。若业务需要等待初始暖槽,可以在 API 对外接流量前
@@ -373,13 +412,17 @@ Rust 实现从 `grammers_core` 根模块导出 `create_phone_status_pool()`、`P
373
412
  生命周期错误或内部协调错误才通过 `PhoneStatusPoolError` 返回,不应转换成业务 `BUSY`。
374
413
  Rust Pool 同样在共享的 10 秒总期限内对 `FLOOD_WAIT` 和暖槽 RPC 其他错误最多换槽重试三次,
375
414
  无 `READY` 槽位、期限耗尽或 `PHONE_NUMBER_FLOOD` 不会继续换槽。
415
+ Rust 与 Node.js 采用相同的冻结账号规则:导入时探测到 `FROZEN` 或 `UNKNOWN` 不落库,运行中发现冻结
416
+ 则进入终态 `QUARANTINED`。AppConfig 主动识别冻结返回 `ACCOUNT_INVALID`;Telegram RPC 真实返回的
417
+ `FROZEN_*` 错误仍在错误 source 链中保留 `code = 420`,不会改写成 401。公共账号结构不暴露冻结
418
+ 探测字段。AppConfig RPC 的致命账号错误与 `FLOOD_WAIT` 同样保留原始分类,不降级为 `UNKNOWN`。
376
419
  Rust 字段名使用 snake_case,通过 serde 序列化时使用 camelCase。资源上限使用 CPU、内存和文件
377
420
  描述符评估;Tokio 没有稳定的 event-loop 利用率指标,因此 Rust 状态不会伪造该项数据。
378
421
 
379
422
  ```rust,no_run
380
423
  use grammers_core::{
381
424
  CheckPhoneStatusInput, CloseOptions, ImportAccountInput, PhoneStatusCheckResponse,
382
- PhoneStatusPoolError, PhoneStatusPoolOptions, create_phone_status_pool,
425
+ PhoneStatusPoolError, PhoneStatusPoolOptions, TestAccountsInput, create_phone_status_pool,
383
426
  };
384
427
 
385
428
  # async fn example() -> Result<(), PhoneStatusPoolError> {
@@ -414,13 +457,15 @@ use grammers_core::{
414
457
  let accounts = pool.list_accounts().await?;
415
458
  let detail = pool.get_account(&account.account_id).await?;
416
459
  let tested = pool.test_account(&account.account_id).await?;
460
+ let test_report = pool.test_accounts(TestAccountsInput::default()).await?;
417
461
  let status = pool.get_status().await?;
418
462
  println!(
419
- "phone={} accounts={} detail={} tested={} ready={}",
463
+ "phone={} accounts={} detail={} tested={} healthy={} ready={}",
420
464
  account.phone,
421
465
  accounts.len(),
422
466
  detail.is_some(),
423
467
  tested.is_some(),
468
+ test_report.healthy,
424
469
  status.runtime.ready,
425
470
  );
426
471
 
@@ -445,7 +490,7 @@ use grammers_core::{
445
490
  使用相同的 Telethon/mtcute schema 自动识别、`session_file` stem 兼容和混合 schema 选择规则;
446
491
  mtcute 缺失 `dc_main` 时按其原语义使用默认生产 DC2。SQLite 与 StringSession 中的
447
492
  endpoint 只用于校验两个文件描述同一个会话;实际连接始终使用 grammers 内置的 Telegram DC
448
- 地址,上传文件不能指定 API 进程的 TCP 目标。`ImportAccountInput` 和
493
+ 地址,上传文件不能指定 API 进程的 TCP 目标。`ImportAccountInput`、`TestAccountsInput` 和
449
494
  `CheckPhoneStatusInput` 的 `abort_signal` 是仅运行时字段,使用 serde 反序列化输入时需要由 Rust
450
495
  调用方另行赋值。
451
496
 
@@ -472,7 +517,10 @@ console.log(result);
472
517
  ```
473
518
 
474
519
  JSON 必须包含与 `syncSessionJson()` 输出格式兼容的 `session_str`、`session_file`、`app_id`、`app_hash`
475
- 和客户端配置;自定义 iOS 版本还会携带 `override_layer` 以便完整还原。`session_file` 可以写完整文件名
520
+ 和客户端配置。导入已有授权 session 时,保存的 `app_version` 继续用于 `initConnection`;源文件保持
521
+ 只读,账号池新生成的待持久化 Metadata 会把 iOS `override_layer` 规范为当前 `tl.LAYER`。该字段不会传给
522
+ 底层客户端。重连不会重新授权,也不会自动重试
523
+ `auth.signUp` 或任何其他授权写操作。`session_file` 可以写完整文件名
476
524
  `account.session` 或同名 stem `account`,但不得包含目录组件。`device_token` 可以省略、设为 `null`
477
525
  或留空,空值按未提供处理。
478
526
  方法会以只读方式检查 SQLite schema,自动识别 Telethon 的 `sessions` 表或 mtcute 的
@@ -503,7 +551,8 @@ Grammers、Telethon `sessions` 或 mtcute `key_value`/`auth_keys` 会话,并
503
551
  旧导出 JSON 中同 stem 的 `.session` 名称,所有形式均不得包含目录组件。`app_id` 只需为正整数且
504
552
  `app_hash` 非空,因此不破坏已有自定义凭据;`device_token` 缺失、为 `null` 或空白时按未提供处理。
505
553
  Grammers 分支若提供非空 `device_token`,trim 后仍必须与内部 `session_metadata` 一致;省略或空值不会
506
- 从内部 Metadata 自动注入连接参数。
554
+ 从内部 Metadata 自动注入连接参数。临时客户端沿用保存的 iOS `app_version`,协议 layer 使用当前
555
+ 编译期 `tl::LAYER`(当前为 229),`override_layer` 不参与连接。
507
556
  输入字段使用 snake_case,结果序列化时使用与 npm 一致的 camelCase:
508
557
 
509
558
  ```rust,no_run