Skip to content

Commit 105b31c

Browse files
committed
feat(app): tag User-Agent with concrete receiver class name
The App constructor now emits a second `addAppMetadata` entry whose name includes the receiver's class name (e.g. `@slack/bolt-HTTPReceiver`). Having the receiver type in outbound WebClient User-Agent strings lets the Slack team see which receivers are actually deployed in the wild and prioritize missing features accordingly. Closes #1150
1 parent 3f6ea49 commit 105b31c

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

src/App.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,21 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
366366
// Since v3.4, WebClient starts sharing logger with App
367367
this.clientOptions.logger = this.logger;
368368
}
369+
370+
// Tag the User-Agent with the concrete receiver class before any
371+
// WebClient is constructed. WebClient snapshots `getUserAgent()` into
372+
// its axios headers at construction time, so this must run before
373+
// `new WebClient(...)` below (see #1150).
374+
const receiverTypeName = receiver
375+
? receiver.constructor.name
376+
: this.socketMode
377+
? 'SocketModeReceiver'
378+
: 'HTTPReceiver';
379+
addAppMetadata({
380+
name: `${packageJson.name}-${receiverTypeName}`,
381+
version: packageJson.version,
382+
});
383+
369384
// The public WebClient instance (app.client)
370385
// Since v3.4, it can have the passed token in the case of single workspace installation.
371386
this.client = new WebClient(token, this.clientOptions);

test/unit/App/basic.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,23 @@ describe('App basic features', () => {
346346
// TODO: tests for providing endpoints option
347347
});
348348

349+
describe('receiver-type app metadata', () => {
350+
it('should tag the user-agent metadata with the concrete receiver class name', () => {
351+
const addAppMetadata = sinon.fake();
352+
const customOverrides = mergeOverrides(
353+
{ '@slack/web-api': { addAppMetadata } },
354+
withSuccessfulBotUserFetchingWebClient(fakeBotId, fakeBotUserId),
355+
);
356+
const MockApp = importApp(customOverrides);
357+
new MockApp({ receiver: new FakeReceiver(), authorize: noop });
358+
const names: string[] = addAppMetadata.getCalls().map((call) => call.args[0].name);
359+
assert.isTrue(
360+
names.some((name) => name.endsWith('-FakeReceiver')),
361+
`expected an addAppMetadata call ending in "-FakeReceiver", got ${JSON.stringify(names)}`,
362+
);
363+
});
364+
});
365+
349366
describe('#start', () => {
350367
it('should pass calls through to receiver', async () => {
351368
// Arrange

0 commit comments

Comments
 (0)