Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-linq-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chat-adapter/linq": minor
---

Add Linq adapter for iMessage, SMS, and RCS messaging via the Linq Partner API
72 changes: 36 additions & 36 deletions apps/docs/content/docs/adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,51 @@ Ready to build your own? Follow the [building](/docs/contributing/building) guid

### Messaging

| Feature | [Slack](/adapters/slack) | [Teams](/adapters/teams) | [Google Chat](/adapters/google-chat) | [Discord](/adapters/discord) | [Telegram](/adapters/telegram) | [GitHub](/adapters/github) | [Linear](/adapters/linear) | [WhatsApp](/adapters/whatsapp) |
|---------|-------|-------|-------------|---------|---------|--------|--------|-----------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| File uploads | ✅ | ✅ | ❌ | ✅ | ⚠️ Single file | ❌ | ❌ | ✅ Images, audio, docs |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ❌ | ❌ |
| Scheduled messages | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Feature | [Slack](/adapters/slack) | [Teams](/adapters/teams) | [Google Chat](/adapters/google-chat) | [Discord](/adapters/discord) | [Telegram](/adapters/telegram) | [GitHub](/adapters/github) | [Linear](/adapters/linear) | [WhatsApp](/adapters/whatsapp) | [Linq](/adapters/linq) |
|---------|-------|-------|-------------|---------|---------|--------|--------|-----------|------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| File uploads | ✅ | ✅ | ❌ | ✅ | ⚠️ Single file | ❌ | ❌ | ✅ Images, audio, docs | ✅ |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ❌ | ❌ | ⚠️ Post+Edit |
| Scheduled messages | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

### Rich content

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | GFM Markdown | Markdown | WhatsApp templates |
| Buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard callbacks | ❌ | ❌ | ✅ Interactive replies |
| Link buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard URLs | ❌ | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Tables | ✅ Block Kit | ✅ GFM | ⚠️ ASCII | ✅ GFM | ⚠️ ASCII | ✅ GFM | ✅ GFM | ❌ |
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ Template variables |
| Images in cards | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Linq |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | GFM Markdown | Markdown | WhatsApp templates | Text fallback |
| Buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard callbacks | ❌ | ❌ | ✅ Interactive replies | ❌ |
| Link buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard URLs | ❌ | ❌ | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Tables | ✅ Block Kit | ✅ GFM | ⚠️ ASCII | ✅ GFM | ⚠️ ASCII | ✅ GFM | ✅ GFM | ❌ | ⚠️ ASCII |
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ Template variables | ✅ |
| Images in cards | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

### Conversations

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|
| Slash commands | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
| Typing indicator | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| DMs | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Linq |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|------|
| Slash commands | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | ✅ |
| Typing indicator | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ |
| DMs | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

### Message history

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|
| Fetch messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ✅ | ⚠️ Cached sent messages only |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ⚠️ Cached | ❌ | ❌ | ⚠️ Cached sent messages only |
| Fetch thread info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Fetch channel messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ❌ | ⚠️ Cached sent messages only |
| List threads | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Fetch channel info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Post channel message | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear | WhatsApp | Linq |
|---------|-------|-------|-------------|---------|----------|--------|--------|-----------|------|
| Fetch messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ✅ | ⚠️ Cached sent messages only | ✅ |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ⚠️ Cached | ❌ | ❌ | ⚠️ Cached sent messages only | ✅ |
| Fetch thread info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Fetch channel messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ❌ | ⚠️ Cached sent messages only | ✅ |
| List threads | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ |
| Fetch channel info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ |
| Post channel message | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |

<Callout type="info">
⚠️ indicates partial support — the feature works with limitations. See individual adapter pages for details.
Expand Down
1 change: 1 addition & 0 deletions examples/nextjs-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@chat-adapter/gchat": "workspace:*",
"@chat-adapter/github": "workspace:*",
"@chat-adapter/linear": "workspace:*",
"@chat-adapter/linq": "workspace:*",
"@chat-adapter/slack": "workspace:*",
"@chat-adapter/state-memory": "workspace:*",
"@chat-adapter/state-redis": "workspace:*",
Expand Down
23 changes: 23 additions & 0 deletions examples/nextjs-chat/src/lib/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@chat-adapter/gchat";
import { createGitHubAdapter, type GitHubAdapter } from "@chat-adapter/github";
import { createLinearAdapter, type LinearAdapter } from "@chat-adapter/linear";
import { createLinqAdapter, type LinqAdapter } from "@chat-adapter/linq";
import { createSlackAdapter, type SlackAdapter } from "@chat-adapter/slack";
import { createTeamsAdapter, type TeamsAdapter } from "@chat-adapter/teams";
import {
Expand All @@ -29,6 +30,7 @@ export interface Adapters {
gchat?: GoogleChatAdapter;
github?: GitHubAdapter;
linear?: LinearAdapter;
linq?: LinqAdapter;
slack?: SlackAdapter;
teams?: TeamsAdapter;
telegram?: TelegramAdapter;
Expand Down Expand Up @@ -91,6 +93,15 @@ const LINEAR_METHODS = [
"addReaction",
"fetchMessages",
];
const LINQ_METHODS = [
"postMessage",
"editMessage",
"deleteMessage",
"addReaction",
"removeReaction",
"startTyping",
"fetchMessages",
];
const TELEGRAM_METHODS = [
"postMessage",
"editMessage",
Expand Down Expand Up @@ -220,6 +231,18 @@ export function buildAdapters(): Adapters {
}
}

// Linq adapter (optional) - env vars: LINQ_API_TOKEN, LINQ_SIGNING_SECRET, LINQ_PHONE_NUMBER
if (process.env.LINQ_API_TOKEN) {
adapters.linq = withRecording(
createLinqAdapter({
userName: "Chat SDK Bot",
logger: logger.child("linq"),
}),
"linq",
LINQ_METHODS
);
}

// Telegram adapter (optional) - env vars: TELEGRAM_BOT_TOKEN
if (process.env.TELEGRAM_BOT_TOKEN) {
adapters.telegram = withRecording(
Expand Down
117 changes: 117 additions & 0 deletions packages/adapter-linq/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# @chat-adapter/linq

[![npm version](https://img.shields.io/npm/v/@chat-adapter/linq)](https://www.npmjs.com/package/@chat-adapter/linq)
[![npm downloads](https://img.shields.io/npm/dm/@chat-adapter/linq)](https://www.npmjs.com/package/@chat-adapter/linq)

Linq adapter for [Chat SDK](https://chat-sdk.dev), supporting iMessage, SMS, and RCS messaging via the Linq Partner API.

## Installation

```bash
pnpm add @chat-adapter/linq
```

## Usage

The adapter auto-detects `LINQ_API_TOKEN`, `LINQ_SIGNING_SECRET`, and `LINQ_PHONE_NUMBER` from environment variables:

```typescript
import { Chat } from "chat";
import { createLinqAdapter } from "@chat-adapter/linq";

const bot = new Chat({
userName: "mybot",
adapters: {
linq: createLinqAdapter(),
},
});

bot.onNewMention(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
```

## Webhook route

```typescript
// app/api/webhooks/linq/route.ts
import { bot } from "@/lib/bot";

export async function POST(request: Request): Promise<Response> {
return bot.webhooks.linq(request);
}
```

Configure this URL as your webhook endpoint in the Linq partner dashboard.

## Configuration

All options are auto-detected from environment variables when not provided.

| Option | Required | Description |
|--------|----------|-------------|
| `apiToken` | No* | Linq API token. Auto-detected from `LINQ_API_TOKEN` |
| `signingSecret` | No | Webhook signing secret for signature verification. Auto-detected from `LINQ_SIGNING_SECRET` |
| `phoneNumber` | No | Bot phone number, required for `openDM` and `listThreads`. Auto-detected from `LINQ_PHONE_NUMBER` |
| `preferredService` | No | Preferred messaging service: `"iMessage"`, `"SMS"`, or `"RCS"`. Defaults to auto fallback (iMessage → RCS → SMS) |
| `userName` | No | Bot display name (defaults to `"bot"`) |
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |

*`apiToken` is required — either via config or `LINQ_API_TOKEN` env var.

## Environment variables

```bash
LINQ_API_TOKEN=...
LINQ_SIGNING_SECRET=... # Optional, for webhook signature verification
LINQ_PHONE_NUMBER=... # Required for openDM and listThreads
```

## Webhook verification

When `signingSecret` is configured, the adapter verifies incoming webhooks using HMAC-SHA256 signatures. It checks the `x-webhook-signature` and `x-webhook-timestamp` headers and rejects requests with timestamps older than 5 minutes.

## Features

| Feature | Supported |
|---------|-----------|
| Mentions | Yes (all inbound messages treated as mentions) |
| Reactions (add/remove) | Yes |
| Cards | Text fallback |
| Modals | No |
| Slash commands | No |
| Streaming | Post+Edit fallback |
| DMs | Yes |
| Ephemeral messages | No |
| File uploads | Yes |
| Typing indicator | Yes |
| Message history | Yes |
| Fetch single message | Yes |
| List threads | Yes (requires `phoneNumber`) |

## Reactions

Linq supports a fixed set of reaction types that map to standard emoji names:

| Linq reaction | Emoji name |
|---------------|------------|
| `love` | `heart` |
| `like` | `thumbsup` |
| `dislike` | `thumbsdown` |
| `laugh` | `laughing` |
| `emphasize` | `exclamation` |
| `question` | `question` |

Reactions not in this list are sent as custom emoji.

## Thread ID format

Linq thread IDs follow the pattern `linq:{chatId}`.

## Notes

- Linq is an SMS/iMessage/RCS gateway — messages are plain text. Markdown formatting (bold, italic, links) is stripped to plain text automatically.
- Tables render as ASCII art in code blocks.
- All inbound messages are treated as mentions since Linq chats are direct conversations.
- `openDM` and `listThreads` require the `phoneNumber` config option.
- The adapter uses the Linq Partner API v3.
Loading
Loading