@xmanrui/dsh-im 4.19.1 → 4.19.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.
@@ -524,10 +524,10 @@ export class TelegramBotClient {
524
524
 
525
525
  const fallback = await this.#sendPlain(target, text);
526
526
  const terminalText = fallback.deliveryOutcome === 'sent'
527
- ? '回复已发送。'
527
+ ? t('回复已发送。')
528
528
  : fallback.deliveryOutcome === 'unknown'
529
- ? '回复发送结果未能确认。'
530
- : '消息发送失败,请稍后重试。';
529
+ ? t('回复发送结果未能确认。')
530
+ : t('消息发送失败,请稍后重试。');
531
531
  try {
532
532
  await this.#api.editMessageText({
533
533
  chatId: target.chatId,
@@ -717,13 +717,13 @@ export class TelegramBotClient {
717
717
  keepalive: true,
718
718
  logger: this.#logger,
719
719
  });
720
- await stream.update(createTextDeliveryBlock('正在处理…', 'plain'));
720
+ await stream.update(createTextDeliveryBlock(t('正在处理…'), 'plain'));
721
721
  return stream;
722
722
  }
723
723
 
724
724
  const placeholder = await this.#api.sendMessage({
725
725
  chatId: target.chatId,
726
- text: '正在处理…',
726
+ text: t('正在处理…'),
727
727
  replyToMessageId: target.replyToMessageId,
728
728
  messageThreadId: target.messageThreadId,
729
729
  signal: this.#signal,
@@ -824,6 +824,14 @@ export class TelegramRuntime {
824
824
  #abortController = null;
825
825
  #pollTask = null;
826
826
  #starting = null;
827
+ // True only while #start() is between "started connecting" and "ready",
828
+ // which is the one window a skipped refresh must be reconciled. A refresh on
829
+ // a never-started or already-stopped runtime stays a no-op.
830
+ #connecting = false;
831
+ // True when a language switch arrived while the runtime was connecting, so a
832
+ // refreshCommandMenu() had nothing to push. Reconciled once startup
833
+ // completes, so the platform always ends up with the latest language.
834
+ #menuDirty = false;
827
835
 
828
836
  constructor({
829
837
  config,
@@ -902,6 +910,7 @@ export class TelegramRuntime {
902
910
 
903
911
  async #start() {
904
912
  await this.stop();
913
+ this.#connecting = true;
905
914
  this.#status.startedAt = new Date().toISOString();
906
915
  this.#status.connectionState = 'connecting';
907
916
  this.#status.lastError = null;
@@ -930,14 +939,7 @@ export class TelegramRuntime {
930
939
  throw error;
931
940
  }
932
941
  try {
933
- const commands = telegramCommandMenu(this.#commandCatalog);
934
- // Both operations use the existing default scope and language. Sending
935
- // the full list replaces old entries; an empty catalog clears that list.
936
- if (commands.length > 0) {
937
- await api.setMyCommands({ commands, signal: controller.signal });
938
- } else {
939
- await api.deleteMyCommands({ signal: controller.signal });
940
- }
942
+ await this.#sendCommandMenu(api, controller.signal);
941
943
  await api.setChatMenuButton({ menuButton: COMMANDS_MENU_BUTTON, signal: controller.signal });
942
944
  } catch (error) {
943
945
  this.#logger.warn?.(
@@ -973,6 +975,21 @@ export class TelegramRuntime {
973
975
  this.#status.connectionState = 'connected';
974
976
  this.#status.lastCheckedAt = now;
975
977
  this.#status.lastConnectedAt = now;
978
+ // A language switch that landed while we were connecting was skipped by
979
+ // refreshCommandMenu(); re-send the menu now that the API is usable, so
980
+ // the platform ends with the latest language instead of the one that was
981
+ // current when #sendCommandMenu first ran.
982
+ if (this.#menuDirty) {
983
+ this.#menuDirty = false;
984
+ try {
985
+ await this.#sendCommandMenu(api, controller.signal);
986
+ } catch (error) {
987
+ this.#logger.warn?.(
988
+ `[dsh-im:telegram] bot ${this.#config.botId} command menu catch-up failed:`,
989
+ error,
990
+ );
991
+ }
992
+ }
976
993
  this.#pollTask = this.#poll(cursor, controller.signal);
977
994
  this.#pollTask.catch((error) => {
978
995
  if (controller.signal.aborted) return;
@@ -988,6 +1005,51 @@ export class TelegramRuntime {
988
1005
  this.#status.lastError = error?.message ?? String(error);
989
1006
  await this.stop();
990
1007
  throw error;
1008
+ } finally {
1009
+ // Whether the bot is now ready or the attempt failed, the connecting
1010
+ // window is over. A failed attempt also drops any unreconciled dirty
1011
+ // flag: a later retry re-sends the menu from scratch in the current
1012
+ // language anyway.
1013
+ this.#connecting = false;
1014
+ this.#menuDirty = false;
1015
+ }
1016
+ }
1017
+
1018
+ // Both operations use the existing default scope and language. Sending the
1019
+ // full list replaces old entries; an empty catalog clears that list.
1020
+ async #sendCommandMenu(api, signal) {
1021
+ const commands = telegramCommandMenu(this.#commandCatalog);
1022
+ if (commands.length > 0) await api.setMyCommands({ commands, signal });
1023
+ else await api.deleteMyCommands({ signal });
1024
+ }
1025
+
1026
+ /**
1027
+ * Re-send the command menu in the current host message language.
1028
+ *
1029
+ * The menu Telegram shows is registered once per connection, so a language
1030
+ * change would otherwise stay invisible until the bot reconnected. This
1031
+ * replaces the text only: the chat menu button is owned by connect.
1032
+ * @returns whether a connected bot accepted the refreshed menu.
1033
+ */
1034
+ async refreshCommandMenu() {
1035
+ const api = this.#api;
1036
+ const signal = this.#abortController?.signal;
1037
+ if (!this.#status.ready || !api || !signal || signal.aborted) {
1038
+ // A refresh during an in-progress connection must not be lost: mark the
1039
+ // menu dirty so #start() reconciles it the moment the bot is ready. A
1040
+ // never-started or stopped runtime stays a no-op, as before.
1041
+ if (this.#connecting) this.#menuDirty = true;
1042
+ return false;
1043
+ }
1044
+ try {
1045
+ await this.#sendCommandMenu(api, signal);
1046
+ return true;
1047
+ } catch (error) {
1048
+ this.#logger.warn?.(
1049
+ `[dsh-im:telegram] bot ${this.#config.botId} command menu refresh failed:`,
1050
+ error,
1051
+ );
1052
+ return false;
991
1053
  }
992
1054
  }
993
1055