refactor(channels): share reset message construction across adapters

This commit is contained in:
William Valentin
2026-02-15 22:26:44 -08:00
parent 46538e71a8
commit 393aaf2743
7 changed files with 74 additions and 23 deletions
+3 -6
View File
@@ -17,7 +17,7 @@ import type {
ChannelAdapter,
ChannelStatus,
} from '../types.js';
import { normalizeResetCommandText, splitMessage } from '../utils.js';
import { buildResetInboundMessage, normalizeResetCommandText, splitMessage } from '../utils.js';
import type { PairingManager } from '../pairing.js';
/** Configuration for the Discord channel adapter. */
@@ -242,15 +242,12 @@ export class DiscordAdapter implements ChannelAdapter {
// ── Reset command ──
if (text === '!reset') {
this.messageHandler({
this.messageHandler(buildResetInboundMessage({
id: message.id,
channel: 'discord',
senderId: message.channelId,
senderName: message.author.username,
text: '!reset',
timestamp: Date.now(),
metadata: { isCommand: true, command: 'reset' },
});
}));
return;
}
+4 -7
View File
@@ -15,7 +15,7 @@ import type {
ChannelAdapter,
ChannelStatus,
} from '../types.js';
import { normalizeResetCommandText, splitMessage } from '../utils.js';
import { buildResetInboundMessage, normalizeResetCommandText, splitMessage } from '../utils.js';
import type { PairingManager } from '../pairing.js';
/** Configuration for the Slack channel adapter. */
@@ -357,16 +357,13 @@ export class SlackAdapter implements ChannelAdapter {
// Detect reset command
if (text === '!reset') {
this.messageHandler({
this.messageHandler(buildResetInboundMessage({
id: message.ts ?? '',
channel: 'slack',
senderId: peerId,
senderName,
text: '!reset',
timestamp: Date.now(),
metadata: { isCommand: true, command: 'reset' },
...(attachments.length > 0 && { attachments }),
});
attachments,
}));
return;
}
+36 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { normalizeResetCommandText, splitMessage } from './utils.js';
import { buildResetInboundMessage, normalizeResetCommandText, splitMessage } from './utils.js';
describe('splitMessage', () => {
it('returns single chunk for empty string', () => {
@@ -98,3 +98,38 @@ describe('normalizeResetCommandText', () => {
expect(normalizeResetCommandText('hello')).toBe('hello');
});
});
describe('buildResetInboundMessage', () => {
it('builds canonical reset command metadata and text', () => {
const message = buildResetInboundMessage({
id: 'id-1',
channel: 'slack',
senderId: 'C1:T1',
senderName: 'Alice',
timestamp: 123,
});
expect(message).toEqual({
id: 'id-1',
channel: 'slack',
senderId: 'C1:T1',
senderName: 'Alice',
text: '!reset',
timestamp: 123,
metadata: { isCommand: true, command: 'reset' },
});
});
it('includes attachments only when provided', () => {
const message = buildResetInboundMessage({
id: 'id-2',
channel: 'whatsapp',
senderId: '123@c.us',
attachments: [{ mimeType: 'image/png', url: 'https://example.com/a.png' }],
});
expect(message.attachments).toHaveLength(1);
expect(message.text).toBe('!reset');
expect(message.metadata).toEqual({ isCommand: true, command: 'reset' });
});
});
+24
View File
@@ -1,6 +1,7 @@
/**
* Shared utilities for channel adapters.
*/
import type { Attachment, InboundMessage } from './types.js';
/**
* Split a long message into chunks that respect a platform's character limit.
@@ -42,3 +43,26 @@ export function normalizeResetCommandText(text: string): string {
}
return text;
}
interface ResetMessageParams {
id: string;
channel: InboundMessage['channel'];
senderId: string;
senderName?: string;
timestamp?: number;
attachments?: Attachment[];
}
/** Build a normalized inbound reset command message. */
export function buildResetInboundMessage(params: ResetMessageParams): InboundMessage {
return {
id: params.id,
channel: params.channel,
senderId: params.senderId,
senderName: params.senderName,
text: '!reset',
timestamp: params.timestamp ?? Date.now(),
metadata: { isCommand: true, command: 'reset' },
...(params.attachments && params.attachments.length > 0 ? { attachments: params.attachments } : {}),
};
}
+4 -7
View File
@@ -17,7 +17,7 @@ import type {
ChannelAdapter,
ChannelStatus,
} from '../types.js';
import { normalizeResetCommandText, splitMessage } from '../utils.js';
import { buildResetInboundMessage, normalizeResetCommandText, splitMessage } from '../utils.js';
import type { PairingManager } from '../pairing.js';
/** Configuration for the WhatsApp channel adapter. */
@@ -313,16 +313,13 @@ export class WhatsAppAdapter implements ChannelAdapter {
// Detect reset command
if (text === '!reset') {
this.messageHandler({
this.messageHandler(buildResetInboundMessage({
id: message.id.id,
channel: 'whatsapp',
senderId: from,
senderName,
text: '!reset',
timestamp: Date.now(),
metadata: { isCommand: true, command: 'reset' },
...(attachments.length > 0 ? { attachments } : {}),
});
attachments,
}));
return;
}