@mastra/telegram 0.1.3-alpha.0 → 0.2.0-alpha.0

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/dist/index.d.ts CHANGED
@@ -40,22 +40,50 @@ type TelegramCommand = string | {
40
40
  */
41
41
  declare const BOTFATHER_DEEP_LINK = "https://t.me/botfather";
42
42
  /**
43
- * Configuration for {@link TelegramProvider}.
44
- *
45
- * Telegram has no OAuth and no org-level parent credential: a BotFather bot
46
- * token *is* the credential (one token per bot). Multi-tenancy is therefore a
47
- * store of bot tokens — see {@link TelegramInstallation}.
43
+ * Self-managed credentials: bot tokens are supplied directly (provider default
44
+ * and/or per-`connect()`) and persisted in the install store. Mutually
45
+ * exclusive with {@link TelegramDelegatedCredentialsConfig}.
48
46
  */
49
- interface TelegramProviderConfig {
47
+ interface TelegramSelfManagedCredentialsConfig {
50
48
  /**
51
49
  * BotFather bot token to use as the default for {@link TelegramProvider.connect}
52
50
  * when the caller does not supply one per-agent. Setting this here matches the
53
51
  * shape of {@link SlackProvider} / {@link DiscordProvider} and lets the token
54
- * live on a Mastra Connect credential (or another vault) instead of on every
55
- * `connect()` call site. When both are set, an explicit
56
- * {@link TelegramConnectOptions.botToken} wins.
52
+ * live in one place instead of on every `connect()` call site. When both are
53
+ * set, an explicit {@link TelegramConnectOptions.botToken} wins.
57
54
  */
58
55
  botToken?: string;
56
+ tokenResolver?: never;
57
+ }
58
+ /**
59
+ * Delegated credentials: an external credential manager (e.g. the Mastra
60
+ * platform) owns the bot token. The provider never persists the token — it
61
+ * asks the resolver for the current token before each Bot API call, so a
62
+ * token re-pasted or rotated upstream takes effect without a restart.
63
+ *
64
+ * The resolver is the single source of truth: a direct `botToken` (config,
65
+ * `configure()`, or per-`connect()`) cannot be combined with it.
66
+ */
67
+ interface TelegramDelegatedCredentialsConfig {
68
+ /** Resolve the current BotFather bot token on demand. */
69
+ tokenResolver: () => Promise<string>;
70
+ botToken?: never;
71
+ }
72
+ /**
73
+ * How the provider obtains bot tokens: either directly (`botToken`,
74
+ * self-managed) or via a `tokenResolver` (externally managed) — never both.
75
+ */
76
+ type TelegramCredentialsConfig = TelegramSelfManagedCredentialsConfig | TelegramDelegatedCredentialsConfig;
77
+ /**
78
+ * Configuration for {@link TelegramProvider}.
79
+ *
80
+ * Telegram has no OAuth and no org-level parent credential: a BotFather bot
81
+ * token *is* the credential (one token per bot). Multi-tenancy is therefore a
82
+ * store of bot tokens — see {@link TelegramInstallation}. Credentials are
83
+ * either self-managed (`botToken`) or delegated (`tokenResolver`), never both
84
+ * — see {@link TelegramCredentialsConfig}.
85
+ */
86
+ interface TelegramProviderConfigBase {
59
87
  /**
60
88
  * Public HTTPS base URL used to register per-bot webhooks (`setWebhook`).
61
89
  * May be omitted and auto-detected from the Mastra server config, or set later.
@@ -179,6 +207,8 @@ interface TelegramProviderConfig {
179
207
  /** Called after an agent successfully connects a bot and the installation is persisted. */
180
208
  onInstall?: (installation: TelegramInstallation) => void | Promise<void>;
181
209
  }
210
+ /** See {@link TelegramProviderConfigBase} and {@link TelegramCredentialsConfig}. */
211
+ type TelegramProviderConfig = TelegramProviderConfigBase & TelegramCredentialsConfig;
182
212
  /** Options accepted by {@link TelegramProvider.connect}. */
183
213
  interface TelegramConnectOptions {
184
214
  /**
@@ -212,8 +242,19 @@ interface TelegramInstallation {
212
242
  webhookId: string;
213
243
  /** Whether a bot token has been ingested and validated. */
214
244
  status: 'active' | 'pending';
215
- /** BotFather bot token — the full credential. Present once ingested. */
245
+ /**
246
+ * BotFather bot token — the full credential. Present once ingested in
247
+ * self-managed mode. Absent in delegated mode (`tokenResolver`), where the
248
+ * external credential manager is the single source of truth and the token
249
+ * is never persisted locally.
250
+ */
216
251
  botToken?: string;
252
+ /**
253
+ * Telegram user id of the bot (from `getMe`). Used to detect two agents
254
+ * connecting the same bot when the token itself is not stored (delegated
255
+ * mode).
256
+ */
257
+ botUserId?: number;
217
258
  /**
218
259
  * Per-bot webhook shared secret, echoed by Telegram as the
219
260
  * `X-Telegram-Bot-Api-Secret-Token` header on every inbound POST.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/telegram-provider.ts","../src/install-store.ts","../src/telegram-client.ts","../src/commands.ts"],"mappings":";;;;;;;cAWa;;;;;;;KAQD;;;;;cAMC;;;;;UAaI;;EAEf;;EAEA;;;KAIU;EAA6B;EAAiB;;;;;;;cAO7C;;;;;;;;UASI;;;;;;;;;EASf;;;;;EAKA;;;;;;EAMA,UAAU;;;;;;;EAOV;;;;;;;EAOA;;;;;;;EAOA,OAAO;;;;;EAKP;;;;;;EAMA,cAAc;;;;;;EAMd,YAAY;;;;;;EAMZ,WAAW;;;;;;EAMX,eAAe;;;;;;;;;EASf,YAAY;;;;;;;EAOZ;;;;;EAYA,WAAW;;EAEX,cAAc;;EAEd,cAAc;;EAEd,QAAQ;;EAER,gBAAgB;;EAEhB,cAAc;;EAEd,oBAAoB;;;;;EAKpB,mBAAmB;;EAEnB,OAAO;;EAEP,cAAc;;;;;;;;EAQd,cAAc;;;;;;;EAOd,QAAQ;;EAER,SAAS;;EAET,aAAa,cAAc,gCAAgC;;;UAI5C;;;;;;EAMf;;EAEA;;;;;;EAMA,WAAW;;;;;;UAOI;;EAEf;;EAEA;;;;;EAKA;;EAEA;;EAEA;;;;;EAKA;;EAEA;;EAEA;;EAEA,WAAW;;EAEX,aAAa;;;;;;;;;;;iBC7NC,6BAA6B,QAAQ,KAAK;EACxD,WAAW;EACX;;;;;;;;;;;;;;;;;;;;;;;;cAiCW,4BAA4B;;WAC9B;EAYT,YAAY,SAAQ;;;;;EAQpB,SAAS,QAAQ;;;;;;EAejB,aAAa;;EAoBb,WAAW;;;;;;;EA4BL,cAAc;;;;;;;;;EAgCd,UAAU;IAAe;IAAqB;IAAkB;aAA6B;;;;;;;;;;EAkC7F,QAAQ,iBAAiB,UAAS,yBAA8B,QAAQ;;EAgFxE,WAAW,kBAAkB;;EA4B7B,qBAAqB,QAAQ;;;;;;EAW7B,gBAAgB,kBAAkB,QAAQ;;;;;;EAUhD;;;;;EAQA,WAAW,yBAAyB;;;;;cC1VzB;;;;;;;;cAkBA;;mBAEQ;mBACA;EAFnB,YACmB,SAAS,iBACT;;EAIb,WAAW,kBAAkB,QAAQ;;EAMrC,eAAe,oBAAoB,QAAQ;;EAM3C,KAAK,cAAc,uBAAuB;;EAK1C,QAAQ,QAAQ;;EAMhB,cAAc,kBAAkB;;;iBA4DxB,mBAAmB,SAAS,uBAAuB;;;;;;;;;iBCtD7C,MAAM,kBAAkB,sBAA6C,QAAQ;;UAqBlF;;EAEf;;EAEA;;EAEA;;EAEA;;;;;;;;iBASoB,WACpB,kBACA,SAAS,mBACT,sBACC;;;;;;;iBAemB,cACpB,kBACA,8BACA,sBACC;;UAOc;;EAEf,UAAU;;EAEV,QAAQ;;EAER;;;;;;;iBAQoB,cACpB,kBACA,SAAS,sBACT,sBACC;;;;;;;;iBAea;;;;;;;cC3JH,2BAA2B;;;;;;;;iBAaxB,kBAAkB,cAAc,gCAAgC"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/telegram-provider.ts","../src/install-store.ts","../src/telegram-client.ts","../src/commands.ts"],"mappings":";;;;;;;cAWa;;;;;;;KAQD;;;;;cAMC;;;;;UAaI;;EAEf;;EAEA;;;KAIU;EAA6B;EAAiB;;;;;;;cAO7C;;;;;;UAOI;;;;;;;;EAQf;EAEA;;;;;;;;;;;UAYe;;EAEf,qBAAqB;EACrB;;;;;;KAOU,4BAA4B,uCAAuC;;;;;;;;;;UAW9D;;;;;EAKf;;;;;;EAMA,UAAU;;;;;;;EAOV;;;;;;;EAOA;;;;;;;EAOA,OAAO;;;;;EAKP;;;;;;EAMA,cAAc;;;;;;EAMd,YAAY;;;;;;EAMZ,WAAW;;;;;;EAMX,eAAe;;;;;;;;;EASf,YAAY;;;;;;;EAOZ;;;;;EAYA,WAAW;;EAEX,cAAc;;EAEd,cAAc;;EAEd,QAAQ;;EAER,gBAAgB;;EAEhB,cAAc;;EAEd,oBAAoB;;;;;EAKpB,mBAAmB;;EAEnB,OAAO;;EAEP,cAAc;;;;;;;;EAQd,cAAc;;;;;;;EAOd,QAAQ;;EAER,SAAS;;EAET,aAAa,cAAc,gCAAgC;;;KAIjD,yBAAyB,6BAA6B;;UAGjD;;;;;;EAMf;;EAEA;;;;;;EAMA,WAAW;;;;;;UAOI;;EAEf;;EAEA;;;;;EAKA;;EAEA;;;;;;;EAOA;;;;;;EAMA;;;;;EAKA;;EAEA;;EAEA;;EAEA,WAAW;;EAEX,aAAa;;;;;;;;;;;iBC3QC,6BAA6B,QAAQ,KAAK;EACxD,WAAW;EACX;;;;;;;;;;;;;;;;;;;;;;;;cAiCW,4BAA4B;;WAC9B;EAYT,YAAY,SAAQ;;;;;EAkBpB,SAAS,QAAQ;;;;;;EAejB,aAAa;;EAoBb,WAAW;;;;;;;EA4BL,cAAc;;;;;;;;;EA8Gd,UAAU;IAAe;IAAqB;IAAkB;aAA6B;;;;;;;;;;EA0C7F,QAAQ,iBAAiB,UAAS,yBAA8B,QAAQ;;EAqHxE,WAAW,kBAAkB;;EAkD7B,qBAAqB,QAAQ;;;;;;EAW7B,gBAAgB,kBAAkB,QAAQ;;;;;;EAUhD;;;;;EAQA,WAAW,yBAAyB;;;;;cCrfzB;;;;;;;;cAmBA;;mBAEQ;mBACA;EAFnB,YACmB,SAAS,iBACT;;EAIb,WAAW,kBAAkB,QAAQ;;EAMrC,eAAe,oBAAoB,QAAQ;;EAM3C,KAAK,cAAc,uBAAuB;;EAK1C,QAAQ,QAAQ;;EAMhB,cAAc,kBAAkB;;;iBA8DxB,mBAAmB,SAAS,uBAAuB;;;;;;;;;iBCzD7C,MAAM,kBAAkB,sBAA6C,QAAQ;;UAqBlF;;EAEf;;EAEA;;EAEA;;EAEA;;;;;;;;iBASoB,WACpB,kBACA,SAAS,mBACT,sBACC;;;;;;;iBAemB,cACpB,kBACA,8BACA,sBACC;;UAOc;;EAEf,UAAU;;EAEV,QAAQ;;EAER;;;;;;;iBAQoB,cACpB,kBACA,SAAS,sBACT,sBACC;;;;;;;;iBAea;;;;;;;cC3JH,2BAA2B;;;;;;;;iBAaxB,kBAAkB,cAAc,gCAAgC"}
package/dist/index.js CHANGED
@@ -252,6 +252,7 @@ var TelegramInstallStore = class {
252
252
  #toRecord(install) {
253
253
  const data = {
254
254
  botToken: this.#enc(install.botToken),
255
+ botUserId: install.botUserId,
255
256
  secretToken: this.#enc(install.secretToken),
256
257
  username: install.username,
257
258
  webhookUrl: install.webhookUrl,
@@ -276,6 +277,7 @@ var TelegramInstallStore = class {
276
277
  webhookId: record.webhookId ?? "",
277
278
  status: record.status === "active" ? "active" : "pending",
278
279
  botToken: this.#dec(data.botToken),
280
+ botUserId: data.botUserId,
279
281
  secretToken: this.#dec(data.secretToken),
280
282
  username: data.username,
281
283
  webhookUrl: data.webhookUrl,
@@ -346,6 +348,7 @@ var TelegramProvider = class {
346
348
  #initPromise = null;
347
349
  #connectingBotTokens = /* @__PURE__ */ new Set();
348
350
  constructor(config = {}) {
351
+ if ("tokenResolver" in config && config.tokenResolver && "botToken" in config && config.botToken) throw new Error("TelegramProvider cannot be constructed with both `botToken` and `tokenResolver` — pick one credential mode (self-managed or delegated).");
349
352
  this.#config = config;
350
353
  }
351
354
  /**
@@ -420,15 +423,73 @@ var TelegramProvider = class {
420
423
  }
421
424
  }
422
425
  async #doInitialize() {
423
- const active = (await (await this.#getStore()).list()).filter((i) => i.status === "active");
426
+ const store = await this.#getStore();
427
+ const active = (await store.list()).filter((i) => i.status === "active");
424
428
  this.#configured = active.length > 0;
425
429
  for (const installation of active) try {
426
- await this.#activateInstallation(installation);
430
+ const prepared = await this.#migrateInstallation(installation, store);
431
+ if (!prepared) continue;
432
+ await this.#activateInstallation(prepared);
427
433
  } catch (err) {
428
434
  console.error(`[Telegram] Failed to restore installation "${installation.id}":`, err);
429
435
  }
430
436
  }
431
437
  /**
438
+ * Bring a stored installation up to the provider's current credential mode.
439
+ *
440
+ * When {@link TelegramProviderConfig.tokenResolver} is configured but the
441
+ * record was written under self-managed mode, the record still carries a
442
+ * `botToken` and may be missing `botUserId`. Left as-is, the adapter would
443
+ * keep using that stale token (bypassing rotation) and duplicate detection
444
+ * would fall back to token comparison. Resolve the current token, verify it
445
+ * points at the same bot, populate `botUserId` if missing, and drop the
446
+ * persisted token so future rotations flow through the resolver.
447
+ *
448
+ * For a legacy record with no `botUserId`, the "same bot" check needs an
449
+ * expected identity — so we `getMe` the stored `botToken` first and compare
450
+ * that identity to the resolver's. A stored-token lookup failure leaves the
451
+ * record untouched (we cannot prove it's still the same bot, and silently
452
+ * assigning `me.id` would let a repointed resolver retarget the install and
453
+ * orphan the old bot's webhook).
454
+ *
455
+ * A resolver failure — or an identity mismatch — is not fatal here: we log
456
+ * and leave the record untouched, so the operator can investigate before
457
+ * connect/disconnect on that installation.
458
+ */
459
+ async #migrateInstallation(installation, store) {
460
+ if (!this.#config.tokenResolver) return installation;
461
+ const needsMigration = installation.botToken !== void 0 || installation.botUserId === void 0;
462
+ const needsIdentityCheck = installation.botUserId !== void 0;
463
+ if (!needsMigration && !needsIdentityCheck) return installation;
464
+ try {
465
+ const resolved = await this.#config.tokenResolver();
466
+ if (!resolved) return installation;
467
+ const me = await getMe(resolved, this.#apiBaseUrl());
468
+ let expectedBotUserId = installation.botUserId;
469
+ if (expectedBotUserId === void 0 && installation.botToken) try {
470
+ expectedBotUserId = (await getMe(installation.botToken, this.#apiBaseUrl())).id;
471
+ } catch (err) {
472
+ console.warn(`[Telegram] Could not verify stored bot identity for installation "${installation.id}" during delegated-mode migration; leaving the record untouched.`, err);
473
+ return installation;
474
+ }
475
+ if (expectedBotUserId !== void 0 && expectedBotUserId !== me.id) {
476
+ console.warn(`[Telegram] Delegated credential for installation "${installation.id}" now resolves to bot ${me.id} but was bot ${expectedBotUserId}. Disconnect and reconnect the agent to adopt the new bot.`);
477
+ return null;
478
+ }
479
+ if (!needsMigration) return installation;
480
+ const { botToken: _dropped, ...rest } = installation;
481
+ const migrated = {
482
+ ...rest,
483
+ botUserId: me.id
484
+ };
485
+ await store.save(migrated);
486
+ return migrated;
487
+ } catch (err) {
488
+ console.warn(`[Telegram] Delegated-mode migration failed for installation "${installation.id}":`, err);
489
+ return installation;
490
+ }
491
+ }
492
+ /**
432
493
  * Update runtime provider settings. Pass `botToken` to change the default
433
494
  * bot token new {@link connect} calls fall back to when none is supplied
434
495
  * per-agent (matching {@link SlackProvider.configure}'s rotation pattern);
@@ -437,6 +498,7 @@ var TelegramProvider = class {
437
498
  * via {@link connect}/{@link disconnect}.
438
499
  */
439
500
  async configure(credentials) {
501
+ if (this.#config.tokenResolver && credentials?.botToken !== void 0) throw new Error("TelegramProvider was constructed with a tokenResolver — bot tokens are managed externally. Remove the tokenResolver to manage credentials manually via configure().");
440
502
  if (credentials === null) {
441
503
  this.#config = {
442
504
  ...this.#config,
@@ -473,7 +535,13 @@ var TelegramProvider = class {
473
535
  const store = await this.#getStore();
474
536
  const existing = await store.getByAgent(agentId);
475
537
  if (existing?.status === "active") throw new Error(`Agent "${agentId}" is already connected to Telegram. Disconnect first to reconnect.`);
476
- const botToken = options.botToken ?? this.#config.botToken;
538
+ if (this.#config.tokenResolver && options.botToken !== void 0) throw new Error("TelegramProvider was constructed with a tokenResolver — bot tokens are managed externally and cannot be supplied per connect() call.");
539
+ let botToken;
540
+ if (this.#config.tokenResolver) {
541
+ const resolved = await this.#config.tokenResolver();
542
+ if (!resolved) throw new Error("TelegramProvider tokenResolver returned an empty bot token. Attach a Telegram bot credential upstream before connecting an agent.");
543
+ botToken = resolved;
544
+ } else botToken = options.botToken ?? this.#config.botToken;
477
545
  if (!botToken) {
478
546
  const installationId = existing?.id ?? randomUUID();
479
547
  await store.save({
@@ -497,11 +565,11 @@ var TelegramProvider = class {
497
565
  this.#connectingBotTokens.add(botToken);
498
566
  }
499
567
  try {
568
+ const me = await getMe(botToken, this.#apiBaseUrl());
500
569
  if (mode === "webhook") {
501
- const duplicate = (await store.list()).find((i) => i.status === "active" && i.botToken === botToken);
570
+ const duplicate = (await store.list()).find((i) => i.status === "active" && i.agentId !== agentId && (i.botUserId !== void 0 ? i.botUserId === me.id : i.botToken === botToken));
502
571
  if (duplicate) throw new Error(`This Telegram bot is already connected to agent "${duplicate.agentId}". Disconnect it before connecting another agent.`);
503
572
  }
504
- const me = await getMe(botToken, this.#apiBaseUrl());
505
573
  const installationId = existing?.id ?? randomUUID();
506
574
  const webhookId = existing?.webhookId ?? randomUUID();
507
575
  const webhookUrl = mode === "webhook" ? `${baseUrl}/${PLATFORM}/events/${webhookId}` : void 0;
@@ -511,15 +579,16 @@ var TelegramProvider = class {
511
579
  agentId,
512
580
  webhookId,
513
581
  status: "active",
514
- botToken,
582
+ ...this.#config.tokenResolver ? {} : { botToken },
583
+ botUserId: me.id,
515
584
  secretToken: generateSecretToken(),
516
585
  username: options.name ?? me.username ?? me.first_name,
517
586
  webhookUrl,
518
587
  commands: commands.length ? commands : void 0,
519
588
  installedAt: existing?.installedAt ?? /* @__PURE__ */ new Date()
520
589
  };
521
- await this.#registerTransport(installation, mode);
522
- await this.#registerCommands(installation);
590
+ await this.#registerTransport(installation, mode, botToken);
591
+ await this.#registerCommands(installation, botToken);
523
592
  await store.save(installation);
524
593
  await this.#activateInstallation(installation);
525
594
  this.#configured = true;
@@ -543,8 +612,18 @@ var TelegramProvider = class {
543
612
  } catch (err) {
544
613
  console.warn(`[Telegram] Failed to stop polling for agent "${agentId}":`, err);
545
614
  }
546
- if (existing.botToken) try {
547
- await deleteWebhook(existing.botToken, true, this.#apiBaseUrl());
615
+ try {
616
+ let botToken;
617
+ if (existing.botToken) botToken = existing.botToken;
618
+ else if (this.#config.tokenResolver) {
619
+ const resolved = await this.#config.tokenResolver();
620
+ if (resolved && existing.botUserId !== void 0) {
621
+ const me = await getMe(resolved, this.#apiBaseUrl());
622
+ if (me.id !== existing.botUserId) console.warn(`[Telegram] Skipping deleteWebhook for agent "${agentId}": resolver now points at bot ${me.id} but this installation was bot ${existing.botUserId}.`);
623
+ else botToken = resolved;
624
+ } else if (resolved) botToken = resolved;
625
+ }
626
+ if (botToken) await deleteWebhook(botToken, true, this.#apiBaseUrl());
548
627
  } catch (err) {
549
628
  console.warn(`[Telegram] Failed to delete webhook for agent "${agentId}":`, err);
550
629
  }
@@ -618,22 +697,25 @@ var TelegramProvider = class {
618
697
  if (mode === "auto") return baseUrl ? "webhook" : "polling";
619
698
  return mode;
620
699
  }
621
- /** Register (or clear) the receive transport for a bot, enforcing the exclusion. */
622
- async #registerTransport(installation, mode) {
623
- if (!installation.botToken) return;
624
- if (mode === "webhook" && installation.webhookUrl && installation.secretToken) await setWebhook(installation.botToken, {
700
+ /**
701
+ * Register (or clear) the receive transport for a bot, enforcing the
702
+ * exclusion. The token is passed explicitly — delegated-mode installations
703
+ * do not persist one.
704
+ */
705
+ async #registerTransport(installation, mode, botToken) {
706
+ if (mode === "webhook" && installation.webhookUrl && installation.secretToken) await setWebhook(botToken, {
625
707
  url: installation.webhookUrl,
626
708
  secretToken: installation.secretToken,
627
709
  allowedUpdates: this.#config.allowedUpdates ?? [...DEFAULT_ALLOWED_UPDATES],
628
710
  dropPendingUpdates: true
629
711
  }, this.#apiBaseUrl());
630
- else await deleteWebhook(installation.botToken, true, this.#apiBaseUrl());
712
+ else await deleteWebhook(botToken, true, this.#apiBaseUrl());
631
713
  }
632
714
  /** Publish the bot's command list (best-effort — a failure won't block connect). */
633
- async #registerCommands(installation) {
634
- if (!installation.botToken || !installation.commands?.length) return;
715
+ async #registerCommands(installation, botToken) {
716
+ if (!installation.commands?.length) return;
635
717
  try {
636
- await setMyCommands(installation.botToken, {
718
+ await setMyCommands(botToken, {
637
719
  commands: installation.commands,
638
720
  scope: this.#config.commandScope
639
721
  }, this.#apiBaseUrl());
@@ -645,7 +727,7 @@ var TelegramProvider = class {
645
727
  const existing = this.#adapters.get(installation.id);
646
728
  if (existing) return existing;
647
729
  const adapter = createTelegramAdapter$1({
648
- botToken: installation.botToken,
730
+ botToken: installation.botToken ?? this.#config.tokenResolver,
649
731
  secretToken: installation.secretToken,
650
732
  userName: installation.username,
651
733
  apiBaseUrl: this.#apiBaseUrl(),