We've acquired `chat` on npm. This plan covers renaming all packages and setting up automated publishing.
| Current Name | New Name | Version |
|--------------|----------|---------|
| `chat-sdk` | `chat` | 4.0.0 |
| `@chat-sdk/slack` | `@chat-adapter/slack` | 4.0.0 |
| `@chat-sdk/gchat` | `@chat-adapter/gchat` | 4.0.0 |
| `@chat-sdk/teams` | `@chat-adapter/teams` | 4.0.0 |
| `@chat-sdk/state-memory` | `@chat-adapter/state-memory` | 4.0.0 |
| `@chat-sdk/state-redis` | `@chat-adapter/state-redis` | 4.0.0 |
| `@chat-sdk/state-ioredis` | `@chat-adapter/state-ioredis` | 4.0.0 |
1. **Main package** (`packages/chat-sdk/package.json`):
- Change `"name": "chat-sdk"` → `"name": "chat"`
- Change `"version": "0.1.0"` → `"version": "4.0.0"`
2. **Adapter packages**:
- `packages/adapter-slack/package.json`: `@chat-sdk/slack` → `@chat-adapter/slack`
- `packages/adapter-gchat/package.json`: `@chat-sdk/gchat` → `@chat-adapter/gchat`
- `packages/adapter-teams/package.json`: `@chat-sdk/teams` → `@chat-adapter/teams`
- Update all versions to `4.0.0`
- Update dependency on `chat-sdk` → `chat`
3. **State packages**:
- `packages/state-memory/package.json`: `@chat-sdk/state-memory` → `@chat-adapter/state-memory`
- `packages/state-redis/package.json`: `@chat-sdk/state-redis` → `@chat-adapter/state-redis`
- `packages/state-ioredis/package.json`: `@chat-sdk/state-ioredis` → `@chat-adapter/state-ioredis`
- Update all versions to `4.0.0`
- Update dependency on `chat-sdk` → `chat`
Update `peerDependencies` and `dependencies` in each package:
```json
// Before
"peerDependencies": {
"chat-sdk": "workspace:*"
}
// After
"peerDependencies": {
"chat": "workspace:*"
}
```
Search and replace across the codebase:
| Find | Replace |
|------|---------|
| `from "chat-sdk"` | `from "chat"` |
| `from 'chat-sdk'` | `from 'chat'` |
| `import("chat-sdk")` | `import("chat")` |
| `from "@chat-sdk/slack"` | `from "@chat-adapter/slack"` |
| `from "@chat-sdk/gchat"` | `from "@chat-adapter/gchat"` |
| `from "@chat-sdk/teams"` | `from "@chat-adapter/teams"` |
| `from "@chat-sdk/state-memory"` | `from "@chat-adapter/state-memory"` |
| `from "@chat-sdk/state-redis"` | `from "@chat-adapter/state-redis"` |
| `from "@chat-sdk/state-ioredis"` | `from "@chat-adapter/state-ioredis"` |
Update any references to old package names in:
- `pnpm-workspace.yaml`
- `turbo.json` (task filters)
- Root `package.json` scripts
1. **README.md files** in each package
2. **Examples** (`examples/nextjs-chat/`)
3. **AGENTS.md** and other docs
4. **JSDoc comments** referencing package names
1. **Install changesets**:
```bash
pnpm add -D @changesets/cli
pnpm changeset init
```
2. **Configure `.changeset/config.json`**:
```json
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [
["chat", "@chat-adapter/*"]
],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["example-nextjs-chat"]
}
```
3. **Add GitHub Action** (`.github/workflows/release.yml`):
```yaml
name: Release
on:
push:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm build
- run: pnpm test
- name: Create Release Pull Request or Publish
uses: changesets/action@v1
with:
publish: pnpm changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```
4. **Add publish config to each package.json**:
```json
"publishConfig": {
"access": "public"
}
```
1. Run full build: `pnpm build`
2. Run typecheck: `pnpm typecheck`
3. Run lint: `pnpm lint`
4. Run tests: `pnpm test`
5. Test local linking in example app
| File | Changes |
|------|---------|
| `packages/chat-sdk/package.json` | Rename to `chat`, version 4.0.0 |
| `packages/adapter-slack/package.json` | Rename to `@chat-adapter/slack`, update deps |
| `packages/adapter-gchat/package.json` | Rename to `@chat-adapter/gchat`, update deps |
| `packages/adapter-teams/package.json` | Rename to `@chat-adapter/teams`, update deps |
| `packages/state-memory/package.json` | Rename to `@chat-adapter/state-memory`, update deps |
| `packages/state-redis/package.json` | Rename to `@chat-adapter/state-redis`, update deps |
| `packages/state-ioredis/package.json` | Rename to `@chat-adapter/state-ioredis`, update deps |
| `examples/nextjs-chat/package.json` | Update all dependencies |
| `packages/integration-tests/package.json` | Update all dependencies |
| `turbo.json` | Update package references |
| All `*.ts` files | Update import statements |
| All `README.md` files | Update package names in docs |
| `.changeset/config.json` | Create new |
| `.github/workflows/release.yml` | Create new |
1. Update all `package.json` files (names, versions, dependencies)
2. Run `pnpm install` to update lockfile
3. Update all import statements in source files
4. Update all import statements in test files
5. Update documentation
6. Set up changesets
7. Run full validation
8. Create initial changeset for 4.0.0 release
9. Commit and push
If issues arise:
1. Git revert the rename commit
2. Run `pnpm install` to restore lockfile
3. Previous npm versions remain available
7.2 KiB
Platform Limitations
This document outlines the capabilities and limitations of each chat platform adapter.
Feature Support Matrix
| Feature | Slack | Teams | Google Chat |
|---|---|---|---|
postMessage |
✅ | ✅ | ✅ |
editMessage |
✅ | ✅ | ✅ |
deleteMessage |
✅ | ✅ | ✅ |
addReaction |
✅ | ❌ | ⚠️* |
removeReaction |
✅ | ❌ | ⚠️* |
onReaction events |
✅ | ✅ | ✅* |
startTyping |
❌ | ✅ | ❌ |
fetchMessages |
✅ | ❌ | ✅ |
fetchThread |
✅ | ✅ | ✅ |
Platform-Specific Details
Slack
Limitations:
- Typing indicators: Slack does not provide an API for bots to show typing indicators. The
startTypingmethod is a no-op.
Notes:
- Bot user ID is auto-discovered via
auth.testAPI call during initialization - Supports both
bot_idanduserfields for message author identification - File attachments require appropriate OAuth scopes (
files:read)
Microsoft Teams
Limitations:
- Adding reactions: Teams Bot Framework does not expose APIs for bots to add reactions.
addReactionandremoveReactionwill throwNotImplementedError. - Message history: Teams does not provide a bot API to fetch message history.
fetchMessageswill throwNotImplementedError.
Supported:
- Reaction events: Bots can receive
MessageReactionactivities when users add/remove reactions viaonReaction(). - Typing indicators: Supported via
ActivityTypes.Typing
Notes:
- Bot identification uses
appIdmatching againstactivity.from.id - Service URL varies by tenant and must be preserved per conversation
- Proactive messaging requires storing conversation references
Google Chat
Limitations:
- Typing indicators: Google Chat does not provide an API for typing indicators. The
startTypingmethod is a no-op. - Reactions (addReaction/removeReaction): The Google Chat API does not support service account (app) authentication for adding or removing reactions. To use these methods, you must use domain-wide delegation to impersonate a user, but the reaction will appear as coming from that user, not the bot. This is a Google Chat API limitation.
Notes:
- Bot user ID is learned dynamically from message annotations (when bot is @mentioned)
- Supports both HTTP endpoint and Pub/Sub delivery modes
- Workspace Events API subscriptions are auto-managed for Pub/Sub mode
removeReactionworks by listing reactions and finding by emoji (extra API call)
isMe Detection
Each adapter detects if a message is from the bot itself using a helper method isMessageFromSelf():
Slack
- Checks
event.user === botUserId(primary - for messages sent as bot user) - Checks
event.bot_id === botId(secondary - forbot_messagesubtypes) - Both IDs are fetched during
initialize()viaauth.test - Returns
falseif neither ID is known (safe default)
Teams
- Checks exact match:
activity.from.id === appId - Checks suffix match:
activity.from.idends with:{appId}(handles28:{appId}format) - The app ID is always known from configuration
- Returns
falseif appId is not configured (safe default)
Google Chat
- Checks exact match:
message.sender.name === botUserId - Bot user ID is learned dynamically from message annotations when bot is @mentioned
- No fallback: Returns
falseif bot ID is not yet learned (safer than assuming all BOT messages are from self) - Bot ID is persisted to state for serverless environments
Error Handling
All adapters throw errors on API failures. Specific error types:
RateLimitError: Thrown when platform rate limits are exceeded (429 responses)NotImplementedError: Thrown when calling unsupported features
Reaction Events
The SDK provides onReaction() to handle emoji reaction events. Support varies by platform:
Platform Support
| Platform | Supported | Notes |
|---|---|---|
| Slack | ✅ | Via reaction_added and reaction_removed events |
| Teams | ✅ | Via reactionsAdded and reactionsRemoved in MessageReaction activities |
| Google Chat | ✅* | Requires Workspace Events API (Pub/Sub subscription) |
*Google Chat reaction events are only delivered via Pub/Sub (Workspace Events API), not direct HTTP webhooks.
GChat addReaction limitation: The Google Chat API does not support adding reactions with service account authentication. Bots can receive reaction events but cannot add reactions as themselves. To add reactions, use domain-wide delegation to impersonate a user (the reaction will appear from that user, not the bot).
Emoji Normalization
Platforms use different formats for emoji:
- Slack: Names like
+1,thumbsup,fire - Teams: Names like
like,heart,laugh - Google Chat: Unicode like
👍,🔥
The SDK normalizes these to EmojiValue objects with a common name property:
| Normalized Name | Slack | Teams | Google Chat |
|---|---|---|---|
thumbs_up |
+1, thumbsup |
like |
👍 |
thumbs_down |
-1, thumbsdown |
dislike |
👎 |
heart |
heart |
heart |
❤️, ❤ |
fire |
fire |
- | 🔥 |
check |
white_check_mark |
- | ✅, ✔️ |
rocket |
rocket |
- | 🚀 |
| ... | (86 total well-known emoji) |
Extending Emoji Types
You can extend the emoji system with custom emoji using createEmoji():
import { createEmoji, emoji } from "chat";
// Create custom emoji with cross-platform mappings
const myEmoji = createEmoji({
unicorn: { slack: "unicorn_face", gchat: "🦄" },
company_logo: { slack: "company", gchat: "🏢" },
});
// Use type-safe emoji values in reactions
chat.onReaction([emoji.thumbs_up, myEmoji.unicorn], async (event) => {
// event.emoji is an EmojiValue object
console.log(event.emoji.name); // "thumbs_up" or "unicorn"
});
For TypeScript module augmentation to extend the global emoji helper:
declare module "chat" {
interface CustomEmojiMap {
unicorn: true;
custom_team_emoji: true;
}
}
ReactionEvent Properties
| Property | Type | Description |
|---|---|---|
emoji |
EmojiValue |
Normalized emoji object with name, unicode, etc. |
rawEmoji |
string |
Platform-specific emoji (e.g., +1, like, or 👍) |
added |
boolean |
true if reaction was added, false if removed |
user |
Author |
The user who added/removed the reaction |
messageId |
string |
ID of the message that was reacted to |
threadId |
string |
Thread ID for the message |
adapter |
Adapter |
The adapter that received the event |
raw |
unknown |
Raw platform event data |
Markdown Support
| Feature | Slack | Teams | Google Chat |
|---|---|---|---|
| Bold | ✅ *text* |
✅ **text** |
✅ *text* |
| Italic | ✅ _text_ |
✅ _text_ |
✅ _text_ |
| Strikethrough | ✅ ~text~ |
✅ ~~text~~ |
✅ ~text~ |
| Code | ✅ `code` |
✅ `code` |
✅ `code` |
| Code blocks | ✅ | ✅ | ✅ |
| Links | ✅ <url|text> |
✅ [text](url) |
✅ [text](url) |
| Lists | ✅ | ✅ | ✅ |
| Blockquotes | ✅ > |
✅ > |
⚠️ Simulated with > prefix |
| Mentions | ✅ <@USER> |
✅ <at>name</at> |
✅ <users/{id}> |