@mastra/discord 1.2.1 → 1.3.0-alpha.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.
package/dist/index.d.cts CHANGED
@@ -138,9 +138,9 @@ interface DiscordProviderConfig {
138
138
  */
139
139
  waitUntil?: WaitUntilFn;
140
140
  /**
141
- * Start the Gateway WebSocket (core-owned) so the bot receives DMs, @mentions,
142
- * and reactions in addition to slash commands. Set `false` for interactions-
143
- * only serverless deployments. Forwarded to the adapter entry as `gateway`.
141
+ * Start the Gateway WebSocket (provider-owned reconnect loop with backoff)
142
+ * so the bot receives DMs, @mentions, and reactions in addition to slash
143
+ * commands. Set `false` for interactions-only serverless deployments.
144
144
  *
145
145
  * @default true
146
146
  */
@@ -265,6 +265,42 @@ interface DiscordInstallation {
265
265
  commandVersions?: Record<string, string>;
266
266
  /** When the installation was created. */
267
267
  installedAt: Date;
268
+ /**
269
+ * The bot's guild ids at the moment a pending invite was issued. Lets
270
+ * {@link DiscordProvider.reconcileInstallation} confirm the install after the
271
+ * operator completes the invite in another tab: exactly one guild appearing
272
+ * since the snapshot is the authorized guild, so the install activates
273
+ * without waiting for a first interaction. `undefined` when the snapshot
274
+ * couldn't be taken (or the bot is in too many guilds to page) — the install
275
+ * then activates only via the first interaction, as before. Cleared on
276
+ * activation.
277
+ */
278
+ guildSnapshot?: string[];
279
+ /**
280
+ * When the invite flow that owns {@link guildSnapshot} was last (re)started.
281
+ * The snapshot is only trusted for a bounded claim window after this moment
282
+ * (see `SNAPSHOT_TTL_MS` in `reconcile.ts`) — an abandoned Connect click must
283
+ * not claim a guild the bot joins days later. Set on every invite-flow
284
+ * `connect()`, including when the fetch that should have produced
285
+ * {@link guildSnapshot} failed. Cleared on activation.
286
+ */
287
+ snapshotAt?: Date;
288
+ /**
289
+ * The Discord application {@link guildSnapshot} was taken against. A baseline
290
+ * from app A says nothing about app B's membership — after `configure()`
291
+ * swaps the bot token, every guild B was already in would look newly
292
+ * authorized. Reconciliation and snapshot reuse require it to match the
293
+ * current app. Cleared on activation.
294
+ */
295
+ snapshotApplicationId?: string;
296
+ /**
297
+ * The guild `connect()` explicitly targeted (`options.guildId`) when the
298
+ * pending invite was issued, if any. Reconciliation only auto-activates this
299
+ * install on that guild — a different guild appearing in the bot's
300
+ * membership contradicts the caller's intent and waits for an authoritative
301
+ * first interaction instead. Cleared on activation.
302
+ */
303
+ targetGuildId?: string;
268
304
  }
269
305
  //#endregion
270
306
  //#region src/discord-provider.d.ts
@@ -272,8 +308,10 @@ interface DiscordInstallation {
272
308
  * Resolve the per-adapter config the provider applies to the Discord entry in
273
309
  * `AgentChannels.adapters`. Discord has native embeds + action-row buttons, so
274
310
  * `toolDisplay` defaults to `'cards'` (unlike Telegram's `'text'`); `streaming`
275
- * post-and-edits the interaction followup; `gateway` (default `true`) makes core
276
- * own the DM/mention Gateway reconnection loop.
311
+ * post-and-edits the interaction followup; `gateway` (default `true`) makes the
312
+ * **provider** run the DM/mention Gateway reconnection loop. (The adapter entry
313
+ * handed to `AgentChannels` always carries `gateway: false` — core's loop must
314
+ * never start; see `#createAgentChannels`.)
277
315
  */
278
316
  declare function resolveDiscordAdapterConfig(config: Pick<DiscordProviderConfig, 'streaming' | 'typingStatus' | 'toolDisplay' | 'gateway'>): {
279
317
  streaming: StreamingConfig;
@@ -295,11 +333,15 @@ declare function resolveDiscordAdapterConfig(config: Pick<DiscordProviderConfig,
295
333
  * member) or lazily off the first inbound interaction's authoritative `guild_id`
296
334
  * (see {@link activateGuild}).
297
335
  *
298
- * **Gateway is core's job.** The mounted interactions route only ever receives
299
- * HTTP Interactions (PING, slash commands, buttons). DMs / @mentions / reactions
300
- * arrive over the Gateway WebSocket, whose reconnection loop core owns: setting
301
- * `gateway: true` (default) on the adapter entry is enough — the wrapper never
302
- * calls `startGatewayListener` or runs a reconnect loop.
336
+ * **Gateway is the provider's job.** The mounted interactions route only ever
337
+ * receives HTTP Interactions (PING, slash commands, buttons). DMs / @mentions /
338
+ * reactions arrive over the Gateway WebSocket, whose reconnection loop the
339
+ * provider owns ({@link #startGatewayLoop} → `./gateway-loop`): one abortable
340
+ * loop per installation, exponential backoff on failed connects, parked on a
341
+ * revoked token. Core's `AgentChannels` loop is explicitly disabled
342
+ * (`gateway: false` on the adapter entry) — it reconnects with no backoff and
343
+ * cannot be stopped, which is how a failing IDENTIFY once tripped Discord's
344
+ * 1000-connect abuse limit and got the bot token force-reset.
303
345
  *
304
346
  * Implemented (issues `mastra-discord-13x.2` + `.3`): the app-config +
305
347
  * guild-keyed install store, `connect()`/`disconnect()`, OAuth2 invite-URL
@@ -363,17 +405,46 @@ declare class DiscordProvider implements ChannelProvider {
363
405
  */
364
406
  activateGuild(webhookId: string, guildId: string): Promise<DiscordInstallation | null>;
365
407
  /**
366
- * Disconnect an agent from Discord: remove its installation row and drop the
367
- * adapter entry.
368
- *
369
- * **Limitation:** the Gateway loop is owned by core (it calls
370
- * `startGatewayListener` itself; there is no `stopGatewayListener`), so
371
- * disconnect cannot kill an in-flight gateway window — it lapses at the next
372
- * duration boundary. Contrast Telegram's clean `stopPolling()`.
408
+ * Disconnect an agent from Discord: abort its Gateway loop, remove its
409
+ * installation row, and drop the adapter entry.
373
410
  */
374
411
  disconnect(agentId: string): Promise<void>;
375
- /** List installations (public info only — no secrets). */
412
+ /**
413
+ * List installations (public info only — no secrets). A pure read: pending
414
+ * installs are confirmed through the write-authorized
415
+ * {@link reconcileInstallation} path, never as a listing side effect.
416
+ */
376
417
  listInstallations(): Promise<ChannelInstallationInfo[]>;
418
+ /**
419
+ * Activate an agent's pending install if its invite has since been completed.
420
+ *
421
+ * The invite URL carries no `redirect_uri` (the app would have to allowlist
422
+ * every operator origin), so nothing calls back when the operator authorizes
423
+ * the bot — and a pending install has no adapter, so no interaction or
424
+ * gateway event can reach it either. Instead, each pending install carries a
425
+ * {@link DiscordInstallation.guildSnapshot} taken when the invite was issued;
426
+ * this diffs it against the bot's current membership and activates the
427
+ * install when exactly one new, uncontested guild has appeared (the full
428
+ * claim rules live in {@link planReconcile}). The claim analysis spans every
429
+ * install — other pending invites contest the diff — but only **this**
430
+ * agent's install can activate: the caller holds write access for this agent
431
+ * alone. Anything ambiguous stays pending and retries on the next call, with
432
+ * the first interaction as the authoritative fallback. Best-effort: failures
433
+ * log and resolve rather than throw.
434
+ *
435
+ * Called by the server's reconcile route (write-authorized); Studio invokes
436
+ * it on window focus while a connect is in flight. Returns the (possibly
437
+ * just-activated) installation's public info, or `null` when the agent has
438
+ * no installation.
439
+ *
440
+ * Limitation: the bot-invite URL is per-app, not per-install, so when the
441
+ * operator invites the bot to a new server *for an already-active install*
442
+ * (as `connect()`'s already-connected error suggests) while an invite for
443
+ * another agent is outstanding, nothing distinguishes the two intents — the
444
+ * new guild can be attributed to the pending install. Reconciliation is only
445
+ * reliable while a single invite flow is in progress.
446
+ */
447
+ reconcileInstallation(agentId: string): Promise<ChannelInstallationInfo | null>;
377
448
  /** The full installation for an agent (no secrets live on it), or `null`. */
378
449
  getInstallation(agentId: string): Promise<DiscordInstallation | null>;
379
450
  /** Whether the Discord app is configured (credentials resolvable). */
package/dist/index.d.ts CHANGED
@@ -138,9 +138,9 @@ interface DiscordProviderConfig {
138
138
  */
139
139
  waitUntil?: WaitUntilFn;
140
140
  /**
141
- * Start the Gateway WebSocket (core-owned) so the bot receives DMs, @mentions,
142
- * and reactions in addition to slash commands. Set `false` for interactions-
143
- * only serverless deployments. Forwarded to the adapter entry as `gateway`.
141
+ * Start the Gateway WebSocket (provider-owned reconnect loop with backoff)
142
+ * so the bot receives DMs, @mentions, and reactions in addition to slash
143
+ * commands. Set `false` for interactions-only serverless deployments.
144
144
  *
145
145
  * @default true
146
146
  */
@@ -265,6 +265,42 @@ interface DiscordInstallation {
265
265
  commandVersions?: Record<string, string>;
266
266
  /** When the installation was created. */
267
267
  installedAt: Date;
268
+ /**
269
+ * The bot's guild ids at the moment a pending invite was issued. Lets
270
+ * {@link DiscordProvider.reconcileInstallation} confirm the install after the
271
+ * operator completes the invite in another tab: exactly one guild appearing
272
+ * since the snapshot is the authorized guild, so the install activates
273
+ * without waiting for a first interaction. `undefined` when the snapshot
274
+ * couldn't be taken (or the bot is in too many guilds to page) — the install
275
+ * then activates only via the first interaction, as before. Cleared on
276
+ * activation.
277
+ */
278
+ guildSnapshot?: string[];
279
+ /**
280
+ * When the invite flow that owns {@link guildSnapshot} was last (re)started.
281
+ * The snapshot is only trusted for a bounded claim window after this moment
282
+ * (see `SNAPSHOT_TTL_MS` in `reconcile.ts`) — an abandoned Connect click must
283
+ * not claim a guild the bot joins days later. Set on every invite-flow
284
+ * `connect()`, including when the fetch that should have produced
285
+ * {@link guildSnapshot} failed. Cleared on activation.
286
+ */
287
+ snapshotAt?: Date;
288
+ /**
289
+ * The Discord application {@link guildSnapshot} was taken against. A baseline
290
+ * from app A says nothing about app B's membership — after `configure()`
291
+ * swaps the bot token, every guild B was already in would look newly
292
+ * authorized. Reconciliation and snapshot reuse require it to match the
293
+ * current app. Cleared on activation.
294
+ */
295
+ snapshotApplicationId?: string;
296
+ /**
297
+ * The guild `connect()` explicitly targeted (`options.guildId`) when the
298
+ * pending invite was issued, if any. Reconciliation only auto-activates this
299
+ * install on that guild — a different guild appearing in the bot's
300
+ * membership contradicts the caller's intent and waits for an authoritative
301
+ * first interaction instead. Cleared on activation.
302
+ */
303
+ targetGuildId?: string;
268
304
  }
269
305
  //#endregion
270
306
  //#region src/discord-provider.d.ts
@@ -272,8 +308,10 @@ interface DiscordInstallation {
272
308
  * Resolve the per-adapter config the provider applies to the Discord entry in
273
309
  * `AgentChannels.adapters`. Discord has native embeds + action-row buttons, so
274
310
  * `toolDisplay` defaults to `'cards'` (unlike Telegram's `'text'`); `streaming`
275
- * post-and-edits the interaction followup; `gateway` (default `true`) makes core
276
- * own the DM/mention Gateway reconnection loop.
311
+ * post-and-edits the interaction followup; `gateway` (default `true`) makes the
312
+ * **provider** run the DM/mention Gateway reconnection loop. (The adapter entry
313
+ * handed to `AgentChannels` always carries `gateway: false` — core's loop must
314
+ * never start; see `#createAgentChannels`.)
277
315
  */
278
316
  declare function resolveDiscordAdapterConfig(config: Pick<DiscordProviderConfig, 'streaming' | 'typingStatus' | 'toolDisplay' | 'gateway'>): {
279
317
  streaming: StreamingConfig;
@@ -295,11 +333,15 @@ declare function resolveDiscordAdapterConfig(config: Pick<DiscordProviderConfig,
295
333
  * member) or lazily off the first inbound interaction's authoritative `guild_id`
296
334
  * (see {@link activateGuild}).
297
335
  *
298
- * **Gateway is core's job.** The mounted interactions route only ever receives
299
- * HTTP Interactions (PING, slash commands, buttons). DMs / @mentions / reactions
300
- * arrive over the Gateway WebSocket, whose reconnection loop core owns: setting
301
- * `gateway: true` (default) on the adapter entry is enough — the wrapper never
302
- * calls `startGatewayListener` or runs a reconnect loop.
336
+ * **Gateway is the provider's job.** The mounted interactions route only ever
337
+ * receives HTTP Interactions (PING, slash commands, buttons). DMs / @mentions /
338
+ * reactions arrive over the Gateway WebSocket, whose reconnection loop the
339
+ * provider owns ({@link #startGatewayLoop} → `./gateway-loop`): one abortable
340
+ * loop per installation, exponential backoff on failed connects, parked on a
341
+ * revoked token. Core's `AgentChannels` loop is explicitly disabled
342
+ * (`gateway: false` on the adapter entry) — it reconnects with no backoff and
343
+ * cannot be stopped, which is how a failing IDENTIFY once tripped Discord's
344
+ * 1000-connect abuse limit and got the bot token force-reset.
303
345
  *
304
346
  * Implemented (issues `mastra-discord-13x.2` + `.3`): the app-config +
305
347
  * guild-keyed install store, `connect()`/`disconnect()`, OAuth2 invite-URL
@@ -363,17 +405,46 @@ declare class DiscordProvider implements ChannelProvider {
363
405
  */
364
406
  activateGuild(webhookId: string, guildId: string): Promise<DiscordInstallation | null>;
365
407
  /**
366
- * Disconnect an agent from Discord: remove its installation row and drop the
367
- * adapter entry.
368
- *
369
- * **Limitation:** the Gateway loop is owned by core (it calls
370
- * `startGatewayListener` itself; there is no `stopGatewayListener`), so
371
- * disconnect cannot kill an in-flight gateway window — it lapses at the next
372
- * duration boundary. Contrast Telegram's clean `stopPolling()`.
408
+ * Disconnect an agent from Discord: abort its Gateway loop, remove its
409
+ * installation row, and drop the adapter entry.
373
410
  */
374
411
  disconnect(agentId: string): Promise<void>;
375
- /** List installations (public info only — no secrets). */
412
+ /**
413
+ * List installations (public info only — no secrets). A pure read: pending
414
+ * installs are confirmed through the write-authorized
415
+ * {@link reconcileInstallation} path, never as a listing side effect.
416
+ */
376
417
  listInstallations(): Promise<ChannelInstallationInfo[]>;
418
+ /**
419
+ * Activate an agent's pending install if its invite has since been completed.
420
+ *
421
+ * The invite URL carries no `redirect_uri` (the app would have to allowlist
422
+ * every operator origin), so nothing calls back when the operator authorizes
423
+ * the bot — and a pending install has no adapter, so no interaction or
424
+ * gateway event can reach it either. Instead, each pending install carries a
425
+ * {@link DiscordInstallation.guildSnapshot} taken when the invite was issued;
426
+ * this diffs it against the bot's current membership and activates the
427
+ * install when exactly one new, uncontested guild has appeared (the full
428
+ * claim rules live in {@link planReconcile}). The claim analysis spans every
429
+ * install — other pending invites contest the diff — but only **this**
430
+ * agent's install can activate: the caller holds write access for this agent
431
+ * alone. Anything ambiguous stays pending and retries on the next call, with
432
+ * the first interaction as the authoritative fallback. Best-effort: failures
433
+ * log and resolve rather than throw.
434
+ *
435
+ * Called by the server's reconcile route (write-authorized); Studio invokes
436
+ * it on window focus while a connect is in flight. Returns the (possibly
437
+ * just-activated) installation's public info, or `null` when the agent has
438
+ * no installation.
439
+ *
440
+ * Limitation: the bot-invite URL is per-app, not per-install, so when the
441
+ * operator invites the bot to a new server *for an already-active install*
442
+ * (as `connect()`'s already-connected error suggests) while an invite for
443
+ * another agent is outstanding, nothing distinguishes the two intents — the
444
+ * new guild can be attributed to the pending install. Reconciliation is only
445
+ * reliable while a single invite flow is in progress.
446
+ */
447
+ reconcileInstallation(agentId: string): Promise<ChannelInstallationInfo | null>;
377
448
  /** The full installation for an agent (no secrets live on it), or `null`. */
378
449
  getInstallation(agentId: string): Promise<DiscordInstallation | null>;
379
450
  /** Whether the Discord app is configured (credentials resolvable). */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/discord-provider.ts","../src/install-store.ts","../src/discord-client.ts","../src/commands.ts","../src/crypto.ts"],"mappings":";;;;;;;;;;;;cAgBa;;cAGA;;;;;;;;cASA;WACX;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;;;;;;;cAUW;;cAWA;;;;;;UAOI;;EAEf;;EAEA;;;KAIU;EAAiC;EAAc;;;;;;;;UAQ1C;;EAEf;;EAEA;;EAEA;;;;;;;;;;UAWe;;;;;;;;;EASf,MAAM,QAAQ;;;;;EAKd;;;;;;EAMA,UAAU;;;;;EAKV;;;;;;;EAOA;;;;;EAKA;;;;;;EAMA,WAAW;;;;;;;;;;EAUX;;;;;EAKA,YAAY;;;;;;;;EAQZ;;;;;EAKA;;;;;;EAMA,mBAAmB;;EAEnB,SAAS;;;;;;;;EAQT,YAAY;;;;;;EAMZ;;EASA,WAAW;;EAEX,cAAc;;EAEd,cAAc;;EAEd,QAAQ;;EAER,gBAAgB;;EAEhB,cAAc;;EAEd,oBAAoB;;EAEpB,mBAAmB;;EAEnB,OAAO;;EAEP,cAAc;;;;;;;;EAQd,cAAc;;;;;;;EAOd,QAAQ;;EAER,aAAa,cAAc,+BAA+B;;;UAI3C;;;;;;;EAOf;;EAEA;;;;;EAKA,WAAW;;EAEX;;;;;;;;;UAUe;;EAEf;;EAEA;;;;;EAKA;;;;;EAKA;;EAEA;;EAEA;;EAEA,WAAW;;;;;;EAMX,kBAAkB;;EAElB,aAAa;;;;;;;;;;;iBChQC,4BACd,QAAQ,KAAK;EAEb,WAAW;EACX;EACA,aAAa;EACb;;;;;;;;;;;;;;;;;;;;;;;;;;;cAmCW,2BAA2B;;WAC7B;EAoCT,YAAY,SAAQ;;;;;EAYpB,SAAS,QAAQ;;;;;;;;;EAwCjB,aAAa;;EAoBb,WAAW;;;;;;EAgCL,cAAc;;;;;;;;;EAiCd,UAAU,aAAa,QAAQ,2BAA2B;;;;;;;;;;;;;;EAmE1D,QAAQ,iBAAiB,UAAS,wBAA6B,QAAQ;;;;;;;EA6EvE,cAAc,mBAAmB,kBAAkB,QAAQ;;;;;;;;;;EAmD3D,WAAW,kBAAkB;;EAY7B,qBAAqB,QAAQ;;EAO7B,gBAAgB,kBAAkB,QAAQ;;EAMhD;;EAKA,WAAW,yBAAyB;;;;;cCtdzB;;;;;;;;;;;;;cAgCA;;mBAEQ;mBACA;EAFnB,YACmB,SAAS,iBACT;;EAMb,gBAAgB,QAAQ;;EAaxB,cAAc,KAAK,mBAAmB;;EAUtC,mBAAmB;;EAOnB,WAAW,kBAAkB,QAAQ;;EAMrC,eAAe,oBAAoB,QAAQ;;;;;;;;;;;;;;;;EAoB3C,aAAa,kBAAkB,QAAQ;;EAqBvC,KAAK,cAAc,sBAAsB;;EAKzC,QAAQ,QAAQ;;EAMhB,cAAc,kBAAkB;;;iBA6DxB,mBAAmB,SAAS,sBAAsB;;;;;;;;UC/JjD;;EAEf;;EAEA;;;;;;EAMA;;;;;;;;;;;;iBAmBoB,eACpB,kBACA,gBACA,cACA,qBACA,iBACC,QAAQ;;;;;;;iBA+BW,YACpB,kBACA,sBACC,QAAQ;;;;;;;;;;;;;;iBAyBW,iBACpB,kBACA,iBACA,sBACC;;;;;;;;iBA8EmB,sBACpB,kBACA,uBACA,iBACA,mBAAmB,kBACnB,sBACC;;;;;;;;iBAcmB,uBACpB,kBACA,uBACA,mBAAmB,kBACnB,sBACC;;UAOc;;EAEf;;EAEA;;EAEA;;;;;EAKA;;;;;;;;;iBAUc,eAAe,SAAS;;;;;;;;;cCjQ3B,2BAA2B;;;;;;;;;;iBAaxB,kBAAkB,cAAc,oCAAoC;;;;;;;iBAyBpE,aAAa,mBAAmB;;;;iBC3BhC,YAAY;;iBAKZ,QAAQ,mBAAmB;;iBAU3B,QAAQ,eAAe"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/discord-provider.ts","../src/install-store.ts","../src/discord-client.ts","../src/commands.ts","../src/crypto.ts"],"mappings":"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"}