npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@photon-ai/advanced-imessage-kit

v1.4.1

Published

Powerful TypeScript iMessage SDK with real-time message processing

Readme

Banner

Advanced iMessage Kit

A powerful TypeScript SDK for iMessage with real-time messaging support

TypeScript License Discord

Advanced iMessage Kit is a full-featured iMessage SDK for reading, sending, and automating iMessage conversations on macOS. Perfect for building AI agents, automation tools, and chat applications.


Features

| Feature | Description | Method | Example | | ------- | ----------- | ------ | ------- | | Send Messages | Send text messages to any contact | messages.sendMessage() | message-send.ts | | Reply to Messages | Reply inline to a specific message | messages.sendMessage() | message-reply.ts | | Message Effects | Send with effects (confetti, fireworks, etc.) | messages.sendMessage() | message-effects.ts | | Unsend Messages | Retract a sent message | messages.unsendMessage() | message-unsend.ts | | Send Tapbacks | React with ❤️ 👍 👎 😂 ‼️ ❓ | messages.sendReaction() | message-reaction.ts | | Query Messages | Search and filter message history | messages.getMessages() | message-search.ts | | Message History | View messages, reactions, polls, stickers | chats.getChatMessages() | message-history.ts | | Send Attachments | Send images, files, documents | attachments.sendAttachment() | message-attachment.ts | | Send Audio Messages | Send voice messages | attachments.sendAttachment() | message-audio.ts | | Send Stickers | Send sticker as standalone message | attachments.sendSticker() | message-sticker.ts | | Reply Stickers | Attach sticker to a message bubble | attachments.sendSticker() | message-reply-sticker.ts | | Download Attachments | Download received files and media | attachments.downloadAttachment() | attachment-download.ts | | Get Chats | List all conversations | chats.getChats() | chat-fetch.ts | | Manage Group Chats | Add/remove members, rename groups | chats.addParticipant() | chat-group.ts | | Typing Indicators | Show "typing..." status | chats.startTyping() | message-typing.ts | | Get Contacts | Fetch device contacts | contacts.getContacts() | contact-list.ts | | Share Contact Card | Share your contact info in chat | contacts.shareContactCard() | message-contact-card.ts | | Check iMessage Availability | Verify if contact uses iMessage | handles.getHandleAvailability() | service-check.ts | | Server Info | Get server status and config | server.getServerInfo() | server-info.ts | | Message Statistics | Get message counts and analytics | server.getMessageStats() | message-stats.ts | | Create Polls | Create interactive polls in chat | polls.create() | poll-create.ts | | Vote on Polls | Vote or unvote on poll options | polls.vote() | poll-create.ts | | Add Poll Options | Add options to existing polls | polls.addOption() | poll-add-option.ts | | Find My Friends (WIP) | Get friends' locations | icloud.getFindMyFriends() | findmy-friends.ts | | Real-time Events | Listen for new messages, typing, etc. | sdk.on() | listen-simple.ts | | Auto Reply | Build automated reply bots | sdk.on() | auto-reply-hey.ts |


Quick Start

Installation

npm install @photon-ai/advanced-imessage-kit
# or
bun add @photon-ai/advanced-imessage-kit

Basic Usage

import { SDK } from "@photon-ai/advanced-imessage-kit";

const sdk = SDK({
  serverUrl: "http://localhost:1234",
});

await sdk.connect();

sdk.on("new-message", (message) => {
  console.log("New message:", message.text);
});

await sdk.messages.sendMessage({
  chatGuid: "iMessage;-;+1234567890",
  message: "Hello World!",
});

await sdk.close();

Configuration

interface ClientConfig {
  serverUrl?: string; // Server URL, defaults to "http://localhost:1234"
  apiKey?: string; // API key (if server requires authentication)
  logLevel?: "debug" | "info" | "warn" | "error"; // Log level, defaults to "info"
}

Core Concepts

chatGuid Format

chatGuid is the unique identifier for a conversation. The format is service;-;address:

  • iMessage DM: iMessage;-;+1234567890 or iMessage;-;[email protected]
  • SMS DM: SMS;-;+1234567890
  • Group chat: iMessage;+;chat123456789
  • Auto-detect: any;-;+1234567890 (SDK automatically detects the service type)

How to Get IDs

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Phone / Email  │────▶│  Build chatGuid │────▶│  Send Message   │
│  +1234567890    │     │ any;-;+123...   │     │  sendMessage()  │
└─────────────────┘     └─────────────────┘     └─────────────────┘

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   getChats()    │────▶│  Get chat.guid  │────▶│  Use for other  │
│   List chats    │     │                 │     │  operations     │
└─────────────────┘     └─────────────────┘     └─────────────────┘

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  sendMessage()  │────▶│ Get message.guid│────▶│  edit/unsend    │
│   Send message  │     │                 │     │  sendReaction   │
└─────────────────┘     └─────────────────┘     └─────────────────┘

Messages

Examples: message-send.ts | message-unsend.ts | message-reaction.ts | message-search.ts

Send Messages

// Send a text message
const message = await sdk.messages.sendMessage({
  chatGuid: "iMessage;-;+1234567890",
  message: "Hello!",
});

// With subject and effect
await sdk.messages.sendMessage({
  chatGuid: "iMessage;-;+1234567890",
  message: "Happy Birthday!",
  subject: "Wishes",
  effectId: "com.apple.messages.effect.CKConfettiEffect",
});

// Reply to a message
await sdk.messages.sendMessage({
  chatGuid: "iMessage;-;+1234567890",
  message: "This is a reply",
  selectedMessageGuid: "original-message-guid",
});

Message Effects:

| Effect | effectId | | ------------- | ------------------------------------------------- | | Confetti | com.apple.messages.effect.CKConfettiEffect | | Fireworks | com.apple.messages.effect.CKFireworksEffect | | Balloons | com.apple.messages.effect.CKBalloonEffect | | Hearts | com.apple.messages.effect.CKHeartEffect | | Lasers | com.apple.messages.effect.CKHappyBirthdayEffect | | Shooting Star | com.apple.messages.effect.CKShootingStarEffect | | Sparkles | com.apple.messages.effect.CKSparklesEffect | | Echo | com.apple.messages.effect.CKEchoEffect | | Spotlight | com.apple.messages.effect.CKSpotlightEffect | | Gentle | com.apple.MobileSMS.expressivesend.gentle | | Loud | com.apple.MobileSMS.expressivesend.loud | | Slam | com.apple.MobileSMS.expressivesend.impact | | Invisible Ink | com.apple.MobileSMS.expressivesend.invisibleink |

Example: message-effects.ts

Query Messages

// Get a single message
const message = await sdk.messages.getMessage("message-guid");

// Query messages
const messages = await sdk.messages.getMessages({
  chatGuid: "iMessage;-;+1234567890",
  limit: 50,
  offset: 0,
  sort: "DESC", // DESC = newest first, ASC = oldest first
  before: Date.now(),
  after: Date.now() - 86400000, // Last 24 hours
});

// Search messages
const results = await sdk.messages.searchMessages({
  query: "keyword",
  chatGuid: "iMessage;-;+1234567890", // Optional
  limit: 20,
});

// Get counts
const total = await sdk.messages.getMessageCount();
const sent = await sdk.messages.getSentMessageCount();
const updated = await sdk.messages.getUpdatedMessageCount();

Unsend Messages

await sdk.messages.unsendMessage({
  messageGuid: "message-guid-to-unsend",
  partIndex: 0, // Optional
});

Example: message-unsend.ts

Send Tapbacks

await sdk.messages.sendReaction({
  chatGuid: "iMessage;-;+1234567890",
  messageGuid: "target-message-guid",
  reaction: "love", // love, like, dislike, laugh, emphasize, question
  partIndex: 0, // Optional
});

// Remove a Tapback (prefix with -)
await sdk.messages.sendReaction({
  chatGuid: "iMessage;-;+1234567890",
  messageGuid: "target-message-guid",
  reaction: "-love", // -love, -like, -dislike, -laugh, -emphasize, -question
});

Example: message-reaction.ts

Other Message Operations

// Trigger message notification
await sdk.messages.notifyMessage("message-guid");

// Get embedded media
const media = await sdk.messages.getEmbeddedMedia("message-guid");

Chats

Examples: chat-fetch.ts | chat-group.ts | message-typing.ts

Get Chats

const chats = await sdk.chats.getChats({
  withLastMessage: true, // Include last message
  withArchived: false, // Include archived chats
  offset: 0,
  limit: 50,
});

// Get chat count
const count = await sdk.chats.getChatCount();

Get Single Chat

const chat = await sdk.chats.getChat("chat-guid", {
  with: ["participants", "lastMessage"],
});

Create Chat

const newChat = await sdk.chats.createChat({
  addresses: ["+1234567890", "+0987654321"],
  message: "Hello everyone!", // Optional initial message
  service: "iMessage", // "iMessage" or "SMS"
  method: "private-api", // "apple-script" or "private-api"
});

Chat Status

// Mark as read/unread
await sdk.chats.markChatRead("chat-guid");
await sdk.chats.markChatUnread("chat-guid");

// Delete chat
await sdk.chats.deleteChat("chat-guid");

Typing Indicators

// Show "typing..."
await sdk.chats.startTyping("chat-guid");

// Stop showing
await sdk.chats.stopTyping("chat-guid");

Example: message-typing.ts

Get Chat Messages

const messages = await sdk.chats.getChatMessages("chat-guid", {
  limit: 100,
  offset: 0,
  sort: "DESC",
  before: Date.now(),
  after: Date.now() - 86400000,
});

Manage Group Chats

// Rename group
await sdk.chats.updateChat("chat-guid", {
  displayName: "New Group Name",
});

// Add participant
await sdk.chats.addParticipant("chat-guid", "+1234567890");

// Remove participant
await sdk.chats.removeParticipant("chat-guid", "+1234567890");

// Leave group
await sdk.chats.leaveChat("chat-guid");

Group Icon

// Set group icon
await sdk.chats.setGroupIcon("chat-guid", "/path/to/image.jpg");

// Get group icon
const iconBuffer = await sdk.chats.getGroupIcon("chat-guid");

// Remove group icon
await sdk.chats.removeGroupIcon("chat-guid");

Example: chat-group.ts


Attachments

Examples: message-attachment.ts | message-audio.ts | message-reply-sticker.ts | attachment-download.ts

Send Attachments

const message = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: "/path/to/file.jpg",
  fileName: "custom-name.jpg", // Optional
});

Send Audio Messages

const message = await sdk.attachments.sendAttachment({
  chatGuid: "iMessage;-;+1234567890",
  filePath: "/path/to/audio.m4a",
  isAudioMessage: true,
});

Example: message-audio.ts

Send Stickers

Stickers can be sent in two ways:

Standalone Sticker - Sends as its own message (like sending an image, but with sticker styling):

await sdk.attachments.sendSticker({
  chatGuid: "iMessage;-;+1234567890",
  filePath: "/path/to/sticker.png",
});

Example: message-sticker.ts

Reply Sticker (Tapback Sticker) - Attaches to an existing message bubble:

await sdk.attachments.sendSticker({
  chatGuid: "iMessage;-;+1234567890",
  filePath: "/path/to/sticker.png",
  selectedMessageGuid: "target-message-guid", // Required for reply sticker
  stickerX: 0.5, // Position X (0-1), default: 0.5
  stickerY: 0.5, // Position Y (0-1), default: 0.5
  stickerScale: 0.75, // Scale (0-1), default: 0.75
  stickerRotation: 0, // Rotation in radians, default: 0
  stickerWidth: 300, // Width in pixels, default: 300
});

Example: message-reply-sticker.ts

Get Attachment Info

// Get attachment details
const attachment = await sdk.attachments.getAttachment("attachment-guid");

// Get total count
const count = await sdk.attachments.getAttachmentCount();

Download Attachments

// Download attachment
const buffer = await sdk.attachments.downloadAttachment("attachment-guid", {
  original: true, // Download original file
  force: false, // Force re-download
  width: 800, // Image width (for thumbnails)
  height: 600, // Image height
  quality: 80, // Image quality
});

// Download Live Photo video
const liveBuffer = await sdk.attachments.downloadAttachmentLive(
  "attachment-guid"
);

// Get blurhash (for placeholders)
const blurhash = await sdk.attachments.getAttachmentBlurhash("attachment-guid");

Example: attachment-download.ts


Contacts

Example: contact-list.ts

Get Contacts

const contacts = await sdk.contacts.getContacts();

Get Contact Card

// Get contact card by phone or email
const card = await sdk.contacts.getContactCard("+1234567890");
// {
//   firstName: "John",
//   lastName: "Doe",
//   emails: ["[email protected]"],
//   phones: ["+1234567890"],
//   ...
// }

Share Contact Card

Share your contact card with a chat:

// Check if sharing is recommended
const shouldShare = await sdk.contacts.shouldShareContact("chat-guid");
// Returns false if you've already shared or they haven't shared theirs

// Share your contact card
await sdk.contacts.shareContactCard("chat-guid");

Example: message-contact-card.ts


Handles

Examples: service-check.ts | handle-query.ts

A Handle represents a messaging address (phone number or email).

Query Handles

// Query handles
const result = await sdk.handles.queryHandles({
  address: "+1234567890", // Optional, filter by address
  with: ["chats"], // Optional, include related chats
  offset: 0,
  limit: 50,
});

// Get single handle
const handle = await sdk.handles.getHandle("handle-guid");

// Get total count
const count = await sdk.handles.getHandleCount();

Check Service Availability

Check if a phone/email supports iMessage or FaceTime:

// First parameter is the address (phone or email), not handle guid
const hasIMessage = await sdk.handles.getHandleAvailability(
  "+1234567890",
  "imessage"
);
const hasFaceTime = await sdk.handles.getHandleAvailability(
  "+1234567890",
  "facetime"
);

// Choose service based on availability
const chatGuid = hasIMessage ? `iMessage;-;+1234567890` : `SMS;-;+1234567890`;

Example: service-check.ts

Get Focus Status

const focusStatus = await sdk.handles.getHandleFocusStatus("handle-guid");

Server

Examples: message-stats.ts | server-info.ts

Get Server Info

const info = await sdk.server.getServerInfo();
// {
//   os_version: "14.0",
//   server_version: "1.0.0",
//   private_api: true,
//   helper_connected: true,
//   detected_icloud: "[email protected]",
//   ...
// }

Message Statistics

const stats = await sdk.server.getMessageStats();
// {
//   total: 12345,
//   sent: 5000,
//   received: 7345,
//   last24h: 50,
//   last7d: 300,
//   last30d: 1000,
// }

Media Statistics

// All media stats
const mediaStats = await sdk.server.getMediaStatistics();

// Per-chat media stats
const chatMediaStats = await sdk.server.getMediaStatisticsByChat();

Server Logs

const logs = await sdk.server.getServerLogs(100); // Get last 100 logs

Polls

Examples: poll-create.ts | poll-add-option.ts

Create Polls

const pollMessage = await sdk.polls.create({
  chatGuid: "iMessage;-;+1234567890",
  title: "What should we do?", // Optional
  options: ["Option A", "Option B", "Option C"],
});

console.log("Poll GUID:", pollMessage.guid);

Example: poll-create.ts

Add Poll Options

await sdk.polls.addOption({
  chatGuid: "iMessage;-;+1234567890",
  pollMessageGuid: "poll-message-guid",
  optionText: "New Option D",
});

Example: poll-add-option.ts

Vote on Polls

// Vote on a poll option
await sdk.polls.vote({
  chatGuid: "iMessage;-;+1234567890",
  pollMessageGuid: "poll-message-guid",
  optionIdentifier: "option-uuid", // UUID of the option to vote for
});

// Remove your vote
await sdk.polls.unvote({
  chatGuid: "iMessage;-;+1234567890",
  pollMessageGuid: "poll-message-guid",
  optionIdentifier: "option-uuid",
});

Parse Poll Messages

Use the poll-utils helper functions to parse and display poll messages:

import {
  isPollMessage,
  isPollVote,
  parsePollDefinition,
  parsePollVotes,
  getPollSummary,
  getOptionTextById,
} from "@photon-ai/advanced-imessage-kit/lib/poll-utils";

sdk.on("new-message", (message) => {
  if (isPollMessage(message)) {
    if (isPollVote(message)) {
      // Parse vote data
      const voteData = parsePollVotes(message);
      console.log("Votes:", voteData?.votes);

      // Get option text for each vote
      voteData?.votes.forEach((vote) => {
        const optionText = getOptionTextById(vote.voteOptionIdentifier);
        console.log(`${vote.participantHandle} voted for "${optionText}"`);
      });
    } else {
      // Parse poll definition
      const pollData = parsePollDefinition(message);
      console.log("Poll title:", pollData?.title);
      console.log("Options:", pollData?.options);
    }

    // Or get a formatted summary
    console.log(getPollSummary(message));
  }
});

Note: Poll definitions are automatically cached when received. When a vote arrives, the SDK looks up the corresponding option text from the cache. If you receive a vote for a poll that was created before the SDK started, the option text won't be available and will show the UUID instead.


iCloud (Work in Progress)

Example: findmy-friends.ts

Find My Friends

// Get friends' locations
const friends = await sdk.icloud.getFindMyFriends();

// Refresh location data
await sdk.icloud.refreshFindMyFriends();

Example: findmy-friends.ts


Real-time Events

Examples: listen-simple.ts | listen-advanced.ts | auto-reply-hey.ts

The SDK receives real-time events from the server via Socket.IO.

Connection Events

sdk.on("ready", () => {
  console.log("SDK connected and ready");
});

sdk.on("disconnect", () => {
  console.log("Disconnected");
});

sdk.on("error", (error) => {
  console.error("Error:", error);
});

Message Events

// New message
sdk.on("new-message", (message) => {
  console.log("New message:", message.text);
  console.log("From:", message.handle?.address);
  console.log("From me:", message.isFromMe);
});

// Message status update (delivered, read, etc.)
sdk.on("updated-message", (message) => {
  if (message.dateRead) console.log("Message read");
  else if (message.dateDelivered) console.log("Message delivered");
});

// Send failed
sdk.on("message-send-error", (data) => {
  console.error("Send failed:", data);
});

Chat Events

// Chat read status changed
sdk.on("chat-read-status-changed", ({ chatGuid, read }) => {
  console.log(`Chat ${chatGuid} marked as ${read ? "read" : "unread"}`);
});

Typing Indicators

sdk.on("typing-indicator", ({ display, guid }) => {
  console.log(`${guid} ${display ? "is typing" : "stopped typing"}`);
});

Group Events

sdk.on("group-name-change", (message) => {
  console.log("Group renamed to:", message.groupTitle);
});

sdk.on("participant-added", (message) => {
  console.log("Someone joined the group");
});

sdk.on("participant-removed", (message) => {
  console.log("Someone was removed from the group");
});

sdk.on("participant-left", (message) => {
  console.log("Someone left the group");
});

sdk.on("group-icon-changed", (message) => {
  console.log("Group icon changed");
});

sdk.on("group-icon-removed", (message) => {
  console.log("Group icon removed");
});

Find My Friends Events (WIP)

sdk.on("new-findmy-location", (location) => {
  console.log(`${location.handle} location updated:`, location.coordinates);
});

Remove Event Listeners

const handler = (message) => console.log(message);
sdk.on("new-message", handler);

// Remove specific listener
sdk.off("new-message", handler);

// Remove all listeners
sdk.removeAllListeners("new-message");

Best Practices

Resource Management

// Graceful shutdown
process.on("SIGINT", async () => {
  await sdk.close();
  process.exit(0);
});

Message Deduplication

The SDK includes built-in message deduplication to prevent processing duplicates during network instability:

// Clear processed messages (prevent memory leaks)
sdk.clearProcessedMessages(1000);

// Get processed message count
const count = sdk.getProcessedMessageCount();

Error Handling

try {
  await sdk.messages.sendMessage({
    chatGuid: "invalid-guid",
    message: "test",
  });
} catch (error) {
  if (error.response?.status === 404) {
    console.error("Chat not found");
  } else {
    console.error("Send failed:", error.message);
  }
}

Auto-create Chats

When sending to a contact you've never messaged before, the SDK automatically creates the chat:

// Works even without existing chat history
await sdk.messages.sendMessage({
  chatGuid: "any;-;+1234567890",
  message: "Hi, this is John",
});
// SDK detects the chat doesn't exist, creates it, then sends

Examples

Run any example with Bun:

bun run examples/<filename>.ts

Getting Started

| File | Description | | --------------------------------------------------------- | -------------------------------------- | | listen-simple.ts | Listen with formatted output | | listen-advanced.ts | Listen with full JSON and startup info | | message-send.ts | Send text messages | | message-attachment.ts | Send attachments | | message-audio.ts | Send audio messages |

Message Operations

| File | Description | | ----------------------------------------------------- | ------------------ | | message-reply.ts | Reply to messages | | message-unsend.ts | Unsend messages | | message-reaction.ts | Send Tapbacks | | message-effects.ts | Message effects | | message-search.ts | Search messages | | message-history.ts | Message history |

Chats & Groups

| File | Description | | ----------------------------------------------------- | ------------------- | | chat-fetch.ts | Get chat list | | chat-group.ts | Manage groups | | message-typing.ts | Typing indicators |

Contacts & Services

| File | Description | | --------------------------------------------------------------- | ----------------------------- | | contact-list.ts | Get contacts | | message-contact-card.ts | Share contact card | | service-check.ts | Check iMessage availability | | message-service-check.ts | Monitor message service types |

Attachments & Media

| File | Description | | --------------------------------------------------------------- | ------------------------- | | attachment-download.ts | Download attachments | | message-sticker.ts | Send standalone stickers | | message-reply-sticker.ts | Send reply stickers |

Polls

| File | Description | | --------------------------------------------------- | ---------------- | | poll-create.ts | Create polls | | poll-add-option.ts | Add poll options |

Server & Advanced

| File | Description | | ------------------------------------------------- | ----------------------- | | server-info.ts | Server info and logs | | message-stats.ts | Message statistics | | findmy-friends.ts | Find My Friends (WIP) | | auto-reply-hey.ts | Auto reply bot |


LLMs

Download llms.txt for language model context:


License

MIT License

Author

@Artist-MOBAI