* feat(chat): make message dedup TTL configurable to prevent Slack retry duplicates
* changeset
* fix
* bump default to 5 min
* fix
* Fix: Test, JSDoc, and README all reference the old default dedupe TTL of 60,000ms after the constant was changed to 300,000ms (5 minutes), causing test failure.
This commit fixes the issue reported at packages/chat/src/chat.test.ts:140
**Bug:**
The `DEDUPE_TTL_MS` constant in `packages/chat/src/chat.ts` line 51 was changed from `60_000` (60 seconds) to `5 * 60 * 1000` (300,000 ms = 5 minutes). However, three other locations were not updated to match:
1. **Test (`chat.test.ts` line 140):** The test "should use default dedupe TTL of 60 seconds" asserts that `mockState.set` is called with `60_000` as the TTL. Since the actual code now uses `300_000`, the test fails — confirmed by running the test suite which shows 1 failed test: expected `60000` but received `300000`.
2. **JSDoc (`types.ts` line 40):** The documentation comment says "Defaults to 60000 (60 seconds)" which is incorrect — it's now 300000 (5 minutes).
3. **README.md (line 52):** The Configuration table lists the default as `60000` which is now wrong.
**Evidence:** Running `npx vitest run` shows 1 test failure out of 443 tests. After applying the fix, all 443 tests pass.
**Fix:**
1. Updated the test in `chat.test.ts`: Changed the test description from "60 seconds" to "5 minutes" and the expected value from `60_000` to `300_000`.
2. Updated the JSDoc in `types.ts`: Changed "Defaults to 60000 (60 seconds)" to "Defaults to 300000 (5 minutes)".
3. Updated the README.md: Changed the default value in the Configuration table from `60000` to `300000`.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: NicolasMontone <montonenicolas01@gmail.com>
* fix
---------
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
* [chat] add Channel abstraction as first-class citizen alongside Thread
Introduces a Channel concept — the container that holds threads — enabling
channel-level operations, thread-to-channel navigation, and natural support
for threadless platforms (iMessage, WhatsApp, SMS).
Design:
- Postable base interface: shared by both Thread and Channel, providing id,
adapter, isDM, state/setState, messages (newest-first async iterator),
post, postEphemeral, startTyping, mentionUser. Enables polymorphic code
that works with either entity.
- Channel interface (extends Postable): adds name, threads() async iterator,
and fetchInfo(). ChannelImpl provides the concrete implementation with
backward message pagination, thread listing, posting, state management
(channel-state: key prefix), and workflow serialization (chat:Channel).
- Thread updates: Thread now extends Postable and gains a `channel` getter
(lazy-created, cached ChannelImpl) and a `messages` getter (newest-first
backward iterator) alongside the existing `allMessages` (oldest-first).
- Channel ID format: derived from thread IDs by dropping the thread part.
Default: first two colon-separated parts (slack:C123, gchat:spaces/ABC).
Adapters override via optional channelIdFromThreadId() method.
- Adapter interface additions (all optional): channelIdFromThreadId,
fetchChannelMessages, listThreads, fetchChannelInfo, postChannelMessage.
- Chat class: chat.channel(channelId) method creates a Channel by ID,
auto-inferring adapter from the prefix. Reviver handles chat:Channel.
- Slack adapter: implements all five channel methods using
conversations.history (vs conversations.replies for threads),
conversations.info, and chat.postMessage without thread_ts.
- Mock adapter: updated with all channel methods for testing.
- 32 new tests covering ChannelImpl, thread.channel, deriveChannelId,
and the backward messages iterator.
Usage:
// Navigate from thread to channel
const channel = thread.channel;
// Get a channel directly
const channel = chat.channel("slack:C123ABC");
// Iterate messages newest first
for await (const msg of channel.messages) { ... }
// List threads in a channel
for await (const t of channel.threads()) { ... }
// Post to channel top-level
await channel.post("Hello channel!");
TODO:
- Add replay tests for channel operations against recorded webhook data
- Implement channel methods in non-Slack adapters (GChat, Teams, Discord,
GitHub, Linear) — currently they fall back to the default/no-op behavior
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* channel-post-sample
* Better metadata
* Fix bug
* Fixes
* Other adapters
* Fix-gchat
* Fix-discord
* Fix-discord-threads
* Discord replay
* Teams tests and fix pre-existing failures
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>