Skip to content

Add iMessage adapter#137

Open
underthestars-zhy wants to merge 33 commits intovercel:mainfrom
photon-hq:feat/imessage
Open

Add iMessage adapter#137
underthestars-zhy wants to merge 33 commits intovercel:mainfrom
photon-hq:feat/imessage

Conversation

@underthestars-zhy
Copy link

Summary

Adds a new @chat-adapter/imessage package that enables Chat SDK bots to communicate over iMessage. The adapter supports two modes:

  • Remote mode — connects to a Photon iMessage server over HTTP and Socket.IO, allowing the bot to run on any platform
  • Local mode — reads directly from the macOS iMessage database and sends via AppleScript (requires Full Disk Access)

Changes

New package: packages/adapter-imessage

File Description
src/index.ts Core adapter implementation with createiMessageAdapter() factory, remote/local mode support, message posting, editing, reactions, typing indicators, thread fetching, and message history
src/types.ts TypeScript types for iMessage webhook payloads, remote API responses, and adapter configuration
src/markdown.ts Format converter for iMessage — converts between mdast AST and plain text (iMessage doesn't support rich formatting)
src/index.test.ts Comprehensive test suite covering adapter initialization, message parsing, posting, editing, reactions, typing, thread/message fetching, and webhook handling
src/markdown.test.ts Tests for the markdown format converter
sample-messages.md Real-world webhook payload examples for reference
README.md Package documentation

Documentation

  • apps/docs/content/docs/adapters/imessage.mdx — Full adapter documentation with setup instructions for both remote and local modes, environment variables, and usage examples
  • apps/docs/content/docs/adapters/index.mdx — Updated adapters overview to include iMessage
  • apps/docs/content/docs/adapters/meta.json — Added iMessage to docs navigation

Configuration

  • turbo.json — Added IMESSAGE_* and PHOTON_* environment variables to the build config
  • README.md — Added iMessage to supported platforms table and packages list

Key design decisions

  • The adapter auto-detects mode from the IMESSAGE_LOCAL environment variable but also accepts explicit local: true/false in config
  • Remote mode uses Socket.IO for real-time message delivery and HTTP for API calls (post, edit, react, etc.)
  • Local mode depends on imessage-kit (optional peer dependency) for database access and AppleScript sending
  • The format converter strips rich formatting to plain text since iMessage doesn't support markdown natively
  • Thread IDs follow the SDK convention: imessage:{chatId}:{messageId}

Test plan

  • All new tests pass (pnpm --filter @chat-adapter/imessage test)
  • Tests cover: adapter creation, message parsing, posting, editing, reactions, typing indicators, thread fetching, message fetching, webhook handling, and format conversion
  • Both remote and local mode code paths are tested with mocked dependencies

underthestars-zhy and others added 19 commits February 26, 2026 15:10
All methods throw NotImplementedError as a starting point for
future implementation.
Introduce `createiMessageAdapter` to initialize the adapter using either
configuration objects or environment variables (`IMESSAGE_LOCAL`,
`IMESSAGE_SERVER_URL`, `IMESSAGE_API_KEY`). Add Photon AI iMessage kit
dependencies and rename the class to `iMessageAdapter`.
Remove userName config from iMessage adapter

Introduce SDK initialization to the adapter, instantiating `IMessageSDK`
for local mode and `AdvancedIMessageKit` for remote mode. Add
corresponding mocks and tests for the new dependencies.
Add comprehensive unit tests for the iMessage adapter covering
webhook parsing, gateway listener lifecycle, thread ID encode/decode,
and initialization. Introduce packages/adapter-imessage/src/types.ts
with typed event and payload models. Enforce macOS-only local mode and
use parseMarkdown from the chat package; mock external SDKs in tests.
Throws NotImplementedError in local mode; delegates to the SDK's
`messages.editMessage` in remote mode with backwards compatibility
message included.
Extracts message building logic into a shared `buildMessage` method,
allowing `parseMessage` to reuse it for both local and remote payloads
instead of throwing `NotImplementedError`.
Maps emoji names to iMessage tapbacks (love, like, dislike, laugh,
emphasize, question) and sends them via the remote SDK. Local mode
throws NotImplementedError since tapbacks require the remote API.
- Add `iMessageFormatConverter` with plain-text AST rendering (strips
  bold, italic, strikethrough; preserves lists, blockquotes, code)
- Accept `logger` in constructor config instead of deriving it from
  `chat.getLogger()` during `initialize()`
- Replace generic `Error` with `ValidationError` from shared package
- Add `sample-messages.md` with real-world webhook payload examples
- Add tests for markdown converter and update existing tests for new
  constructor signature
Add message history support for both local and remote modes.
Updates docs to reflect that message history is now supported.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 28, 2026 05:12
@vercel
Copy link
Contributor

vercel bot commented Feb 28, 2026

@underthestars-zhy is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new @chat-adapter/imessage package to the monorepo, enabling Chat SDK bots to send/receive iMessage via either a local macOS integration or a remote Photon-backed server, along with documentation updates and build/test configuration.

Changes:

  • Introduces packages/adapter-imessage with adapter implementation, format converter, types, tests, and package metadata.
  • Adds documentation pages/navigation entries for the new iMessage adapter and updates overview tables.
  • Updates repo configuration (turbo.json) and dependency lockfile to include new env vars and dependencies.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
turbo.json Adds iMessage-related environment variables to Turbo config.
pnpm-lock.yaml Adds dependencies for the new adapter package and transitive deps.
packages/adapter-imessage/vitest.config.ts Adds Vitest configuration for the new package.
packages/adapter-imessage/tsup.config.ts Adds tsup build configuration and externals for Photon SDKs.
packages/adapter-imessage/tsconfig.json Adds TypeScript config for the new package.
packages/adapter-imessage/src/types.ts Adds webhook/gateway payload and normalized message types.
packages/adapter-imessage/src/markdown.ts Adds plain-text format converter for iMessage.
packages/adapter-imessage/src/markdown.test.ts Adds tests for markdown/plain-text conversion behavior.
packages/adapter-imessage/src/index.ts Implements the adapter (local/remote), webhook handling, sending, reactions, typing, and history fetching.
packages/adapter-imessage/src/index.test.ts Adds tests covering adapter behavior across modes and webhook/gateway paths.
packages/adapter-imessage/sample-messages.md Adds example payloads for gateway/native webhooks and message events.
packages/adapter-imessage/package.json Declares the new package, deps, scripts, and publish metadata.
packages/adapter-imessage/README.md Adds package-level installation/usage documentation.
apps/docs/content/docs/adapters/meta.json Adds iMessage to docs navigation.
apps/docs/content/docs/adapters/index.mdx Updates adapter overview matrix to include iMessage.
apps/docs/content/docs/adapters/imessage.mdx Adds full iMessage adapter documentation page.
README.md Adds iMessage to the repo-level supported platforms/packages lists.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +372 to +374
encodeThreadId(platformData: iMessageThreadId): string {
return `imessage:${platformData.chatGuid}`;
}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description notes thread IDs follow imessage:{chatId}:{messageId}, but encodeThreadId()/decodeThreadId() only use imessage:{chatGuid}. Either update the implementation to match the documented thread ID format, or adjust the PR description/docs to match the actual format before release to avoid confusing SDK users.

Copilot uses AI. Check for mistakes.
Resolve conflicts in adapters/index.mdx (merge iMessage + Telegram
columns into all feature matrix tables) and pnpm-lock.yaml
(regenerate from upstream).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@socket-security
Copy link

socket-security bot commented Feb 28, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​photon-ai/​imessage-kit@​2.1.27510010094100
Added@​photon-ai/​advanced-imessage-kit@​1.14.37710010096100
Addedvitest@​2.1.9961007999100
Added@​types/​node@​22.19.131001008196100

View full report

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
underthestars-zhy and others added 8 commits February 28, 2026 15:19
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Create a dedicated `AdvancedIMessageKit` instance for
`startGatewayListener`
instead of reusing the shared `this.sdk` singleton. Previously, closing
the
listener would close the shared instance, breaking other methods that
depend
on it (e.g., `sendMessage`, `editMessage`).
Simplify the webhook handling to only support native `imessage-kit`
pay
Introduce a dedicated `token` config option and `IMESSAGE_GATEWAY_TOKEN`
env var for authenticating incoming webhooks via the
`x-imessage-gateway-token` header, distinct from the `apiKey` used for
remote server authentication.
Replaces the webhook-based message receiving approach with
`startGatewayListener()` as the sole supported method. Updates docs to
reflect the new serverless cron-based setup pattern using Vercel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants