import { ChannelOptions } from 'nice-grpc'; export { ChannelOptions as GrpcChannelOptions } from 'nice-grpc'; /** * Core streaming primitive used by every server-streaming SDK method. * * Wraps an async iterable source (typically from a gRPC server-streaming RPC) * Exposes `for await`, `.on()`, `.filter()`, `.map()`, `.take()`, `.close()`, * and `Symbol.asyncDispose`. * * Only one consumer is allowed per stream instance. Calling `.on()` or * iterating a stream that is already being consumed throws an error. * Use `.filter()` / `.map()` / `.take()` to derive new streams before * consuming them. */ declare class TypedEventStream implements AsyncIterable, AsyncDisposable { /** The underlying async iterable source. */ private readonly _source; /** Optional cleanup callback invoked when the stream is closed. */ private readonly _cleanup; /** Whether this stream has been closed. */ private _closed; /** Whether a consumer has already attached to this stream. */ private _consumed; /** * When a consumer is blocked on `next()`, this resolver lets `.close()` * interrupt it immediately. */ private _cancelResolve; constructor(source: AsyncIterable, cleanup?: () => Promise); [Symbol.asyncIterator](): AsyncIterator; /** * Subscribe to events with a callback. Returns an unsubscribe function that * stops the internal consumption loop. * * The callback may be synchronous or async. If async, back-pressure is * applied -- the next event is not delivered until the previous callback * resolves. Pass `onError` to handle callback or source errors; otherwise * errors are rethrown on the next microtask. */ on(callback: (event: T) => void | Promise, onError?: (error: unknown) => void): () => void; /** * Create a filtered sub-stream. When the predicate is a type-guard the * returned stream is narrowed to the guard type. */ filter(predicate: (event: T) => event is S): TypedEventStream; filter(predicate: (event: T) => boolean): TypedEventStream; /** Transform each event into a different shape. */ map(transform: (event: T) => U): TypedEventStream; /** * Yield the first `count` events, then close the parent stream. * * `count <= 0` returns an empty stream without consuming the parent. */ take(count: number): TypedEventStream; /** Signal the stream is done. Interrupts any pending iteration. */ close(): Promise; /** `Symbol.asyncDispose` -- enables `await using`. */ [Symbol.asyncDispose](): Promise; /** * Claim sole-consumer rights. Throws if the stream has already been * consumed or closed. */ private _claimConsumer; /** * Internal async generator that pulls from the source and respects the * closed flag. */ private _iterate; /** * Returns a promise that resolves to `undefined` when `.close()` is called. * If the stream is already closed, resolves immediately. */ private _cancelPromise; } /** * Shared types used across multiple resource namespaces. */ /** Options for automatic retry with exponential back-off. */ interface RetryOptions { /** Initial delay in milliseconds before the first retry. */ readonly initialDelay?: number; /** Maximum number of attempts (including the initial call). */ readonly maxAttempts?: number; /** Maximum delay in milliseconds between retries. */ readonly maxDelay?: number; } /** Caller-provided key that lets the server deduplicate retries. */ interface IdempotencyOptions { /** Stable key for one logical write. Reuse it only when retrying that same write. */ readonly clientMessageId?: string; } /** * Invoked once for every server heartbeat frame received on any * `subscribeEvents` / `watch` stream. * * The server emits heartbeats on a fixed cadence (~30s) even when no domain * events occur. Consumers can use this signal to run a stall watchdog: if no * heartbeat arrives within a grace window, the connection is likely half-open * and the stream should be torn down and re-established. Without this hook the * heartbeat frames are silently dropped and a half-open stall is undetectable * from the event stream alone. */ type HeartbeatHandler = () => void; /** * Lightweight string-union enums for the SDK's public API. * * These replace the generated protobuf numeric enums with human-readable * string literals. The mapper layer handles conversion to/from wire values. */ /** Current transfer state of an attachment. */ type TransferState = "pending" | "transferring" | "failed" | "finished" | "unknown"; /** Discriminates the kind of item a message represents. */ type MessageItemType = "normal" | "groupNameChange" | "participantChange" | "chatAction" | "unknown"; /** The underlying transport service for a chat or address. */ type ChatServiceType = "iMessage" | "SMS" | "RCS" | "unknown"; /** Sidecar attachment kind. */ type CompanionKind = "live-photo-video" | "unknown"; /** * Address-related domain types. */ /** * An address bound to one concrete transport service. */ interface SingleServiceAddressInfo { /** Canonical email or E.164 phone number for this participant. */ readonly address: string; /** ISO 3166-1 alpha-2 country code when Messages has one, else omitted. */ readonly country?: string; /** The concrete service this participant record is bound to. */ readonly service: ChatServiceType; } /** A canonical address paired with every service reported by the server. */ interface MultiServiceAddressInfo { /** Canonical email or E.164 phone number. */ readonly address: string; /** ISO 3166-1 alpha-2 country code when known, else `null`. */ readonly country: string | null; /** Service set reported by the server. */ readonly services: readonly ChatServiceType[]; } /** * Message effects and text effects. * * Apple identifies effects by long reverse-DNS strings. These `as const` * objects provide friendly names with full autocomplete and type narrowing -- * the developer never needs to type (or see) the raw identifiers. */ /** * Full-screen and bubble effects that can be applied when sending a message. * * @example * ```ts * await im.messages.sendText(chat, "Happy birthday!", { * effect: MessageEffect.confetti, * }); * ``` */ declare const MessageEffect: { readonly slam: "com.apple.MobileSMS.expressivesend.impact"; readonly loud: "com.apple.MobileSMS.expressivesend.loud"; readonly gentle: "com.apple.MobileSMS.expressivesend.gentle"; readonly invisible: "com.apple.MobileSMS.expressivesend.invisibleink"; readonly confetti: "com.apple.messages.effect.CKConfettiEffect"; readonly fireworks: "com.apple.messages.effect.CKFireworksEffect"; readonly balloons: "com.apple.messages.effect.CKBalloonEffect"; readonly heart: "com.apple.messages.effect.CKHeartEffect"; readonly lasers: "com.apple.messages.effect.CKLasersEffect"; readonly celebration: "com.apple.messages.effect.CKHappyBirthdayEffect"; readonly sparkles: "com.apple.messages.effect.CKSparklesEffect"; readonly spotlight: "com.apple.messages.effect.CKSpotlightEffect"; readonly echo: "com.apple.messages.effect.CKEchoEffect"; }; /** Union of all valid message-effect ID strings. */ type MessageEffect = (typeof MessageEffect)[keyof typeof MessageEffect]; /** * Per-character text effects (iOS 18+) that animate individual words or * phrases within a message. */ declare const TextEffect: { readonly big: "big"; readonly small: "small"; readonly shake: "shake"; readonly nod: "nod"; readonly explode: "explode"; readonly ripple: "ripple"; readonly bloom: "bloom"; readonly jitter: "jitter"; }; /** Union of all valid text-effect identifier strings. */ type TextEffect = (typeof TextEffect)[keyof typeof TextEffect]; /** * Attachment-related domain types. */ interface AttachmentInfo { readonly companionKind?: CompanionKind; readonly fileName: string; readonly guid: string; readonly isHidden: boolean; readonly isOutgoing: boolean; readonly isSticker: boolean; readonly mimeType: string; readonly originalGuid?: string; readonly totalBytes: number; readonly transferState: TransferState; readonly uti: string; } interface CompanionInfo { readonly fileName: string; readonly kind: CompanionKind; readonly mimeType: string; readonly totalBytes: number; } interface UploadAttachmentResult { /** Primary attachment metadata. Use `attachment.guid` with `messages.sendAttachment(...)`. */ readonly attachment: AttachmentInfo; /** Live Photo companion metadata when `input.companion` was provided. */ readonly companion?: CompanionInfo; } interface AttachmentInput { /** Optional Live Photo video bytes paired with the primary image. */ readonly companion?: { /** Raw companion video bytes. */ readonly data: Uint8Array; }; /** Raw file bytes to upload. */ readonly data: Uint8Array; /** Display filename stored with the attachment, including extension. */ readonly fileName: string; } type DownloadAttachmentChunk = { /** First frame: attachment metadata and optional companion metadata. */ readonly type: "header"; readonly info: AttachmentInfo; readonly companionInfo?: CompanionInfo; } | { /** Byte chunk for the primary attachment. */ readonly type: "primaryChunk"; readonly data: Uint8Array; } | { /** Byte chunk for the Live Photo companion video. */ readonly type: "companionChunk"; readonly data: Uint8Array; }; /** * Message-related domain types. */ interface TextFormat { readonly effectName?: string; readonly length: number; readonly start: number; readonly type: string; } type TextFormatInput = { readonly type: "bold"; readonly start: number; readonly length: number; } | { readonly type: "italic"; readonly start: number; readonly length: number; } | { readonly type: "underline"; readonly start: number; readonly length: number; } | { readonly type: "strikethrough"; readonly start: number; readonly length: number; } | { readonly type: "effect"; readonly start: number; readonly length: number; readonly effect: TextEffect; }; interface MessageMention { readonly address: string; readonly length: number; readonly start: number; } interface MessageReaction { readonly emoji?: string; readonly kind: "love" | "like" | "dislike" | "laugh" | "emphasize" | "question" | "emoji" | "sticker" | "unknown"; } interface SettableMessageReaction { /** Emoji character to send when `kind` is `"emoji"`. */ readonly emoji?: string; /** Tapback family to add or remove. Use `placeSticker(...)` for stickers. */ readonly kind: "love" | "like" | "dislike" | "laugh" | "emphasize" | "question" | "emoji"; } interface StickerPlacement { /** Optional clockwise rotation in Apple's normalized coordinate space. */ readonly rotation?: number; /** Optional scale factor for the sticker. */ readonly scale?: number; /** Optional rendered sticker width. */ readonly width?: number; /** Horizontal position in Apple's normalized coordinate space. */ readonly x: number; /** Vertical position in Apple's normalized coordinate space. */ readonly y: number; } interface MessageContent { readonly attachments: readonly AttachmentInfo[]; readonly balloonBundleId?: string; readonly expressiveSendStyleId?: string; readonly formatting: readonly TextFormat[]; readonly mentions: readonly MessageMention[]; readonly text?: string; } interface MessageAppliedReaction { readonly dateCreated: Date; readonly isFromMe: boolean; readonly messageGuid: string; readonly reaction: MessageReaction; readonly sender?: SingleServiceAddressInfo; readonly targetPartIndex?: number; } interface MessagePlacedSticker { readonly dateCreated: Date; readonly isFromMe: boolean; readonly messageGuid: string; readonly placement?: StickerPlacement; readonly sender?: SingleServiceAddressInfo; readonly sticker?: AttachmentInfo; readonly targetPartIndex?: number; } interface Message { readonly appliedReactions: readonly MessageAppliedReaction[]; readonly cachedRoomNames?: string; readonly chatActionType?: number; readonly chatGuids: readonly string[]; readonly content: MessageContent; readonly dataDetectorResultsPresent: boolean; readonly dateCreated: Date; readonly dateDelivered?: Date; readonly dateEdited?: Date; readonly dateExpressiveSendPlayed?: Date; readonly datePlayed?: Date; readonly dateRead?: Date; readonly dateRetracted?: Date; readonly destinationCallerId?: string; readonly didNotifyRecipient: boolean; readonly groupTitle?: string; readonly guid: string; readonly isArchived: boolean; readonly isAudioMessage: boolean; readonly isAutoReply: boolean; readonly isCorrupt: boolean; readonly isDelayed: boolean; readonly isDelivered: boolean; readonly isDeliveredQuietly: boolean; readonly isExpirable: boolean; readonly isForward: boolean; readonly isFromMe: boolean; readonly isSent: boolean; readonly isServiceMessage: boolean; readonly isSpam: boolean; readonly isSystemMessage: boolean; readonly itemType: MessageItemType; readonly partCount?: number; readonly placedStickers: readonly MessagePlacedSticker[]; readonly reaction?: MessageReaction; readonly reactionSelected?: boolean; readonly reactionTargetGuid?: string; readonly reactionTargetPartIndex?: number; readonly replyTargetGuid?: string; readonly sendErrorCode: number; readonly sender?: SingleServiceAddressInfo; readonly shareDirection?: number; readonly shareStatus?: number; readonly subject?: string; readonly threadOriginatorGuid?: string; readonly threadOriginatorPart?: string; } interface SendOptions { /** Stable idempotency key for this logical send. */ readonly clientMessageId?: string; /** Full-screen or bubble effect to apply to the outgoing message. */ readonly effect?: MessageEffect; /** Enable Apple's data-detector pass for links, dates, addresses, and similar text. */ readonly enableDataDetection?: boolean; /** Ask Messages to generate rich URL previews when possible. */ readonly enableLinkPreview?: boolean; /** UTF-16 ranges for bold, italic, underline, strikethrough, or text effects. */ readonly formatting?: readonly TextFormatInput[]; /** Message guid, or message guid plus multipart bubble index, to reply to. */ readonly replyTo?: string | { readonly guid: string; readonly partIndex?: number; }; /** Optional subject line for the outgoing message. */ readonly subject?: string; } /** * Visible layout of an iMessage mini-app card. Mirrors Apple's * `MSMessageTemplateLayout`. At least one of `caption`, `subcaption`, * `trailingCaption`, `trailingSubcaption`, or `image` must be set; * an entirely empty layout renders as a blank bubble and is rejected. * * Slot map: `caption` / `subcaption` render on the left, * `trailingCaption` / `trailingSubcaption` render on the right, and * `imageTitle` / `imageSubtitle` overlay `image`. * `image` and `imageTitle` must be set together; `imageSubtitle` * requires `image`. */ interface MiniAppLayout { /** Top-left, bold. The most prominent text slot. */ readonly caption?: string; /** JPEG preview image bytes. */ readonly image?: Uint8Array; /** Overlay text shown below `imageTitle`. Requires `image`. */ readonly imageSubtitle?: string; /** Overlay text shown above the image. Must be set together with `image`. */ readonly imageTitle?: string; /** Below `caption`, on the left. */ readonly subcaption?: string; /** Fallback text for surfaces that cannot render the full card. */ readonly summary?: string; /** Top-right. */ readonly trailingCaption?: string; /** Below `trailingCaption`, on the right. */ readonly trailingSubcaption?: string; } interface CustomizedMiniAppMessage { /** Display name of the owning app, shown by Messages fallback UI. */ readonly appName: string; /** Apple App Store numeric id of the owning app. When set, must be a positive integer. */ readonly appStoreId?: number; /** Bundle identifier of the iMessage extension target. Must not contain `:`. */ readonly extensionBundleId: string; /** Visible card layout. */ readonly layout: MiniAppLayout; /** 10-character uppercase alphanumeric Apple Team ID. */ readonly teamId: string; /** Absolute URL delivered to the installed extension on tap. */ readonly url: string; } interface MessagePart { /** Uploaded attachment guid for an attachment bubble. */ readonly attachmentGuid?: string; /** Optional display name for the attachment bubble. */ readonly attachmentName?: string; /** Server bubble index override for advanced multipart layouts. */ readonly bubbleIndex?: number; /** UTF-16 formatting ranges that apply to this part's `text`. */ readonly formatting?: readonly TextFormatInput[]; /** Address represented by this text part when sending an `@` mention. */ readonly mentionedAddress?: string; /** Text for a text or mention bubble. */ readonly text?: string; } /** * Filter + paging knobs shared by `messages.listRecent` and `messages.listInChat`. * * Note: `chatGuid` is *not* on this type. `listInChat` takes it as its own * required argument so the type system rejects calling `listRecent({ chatGuid })` * (which the server silently ignores). */ interface MessageListFilter { /** Return messages created after this time. */ readonly after?: Date; /** Return messages created before this time. */ readonly before?: Date; /** Limit results to outgoing (`true`) or incoming (`false`) messages. */ readonly isFromMe?: boolean; /** Limit results to read (`true`) or unread (`false`) messages. */ readonly isRead?: boolean; /** Number of messages per page. The server currently requires `1..100`. */ readonly pageSize?: number; /** Token returned by the previous page. */ readonly pageToken?: string; } interface MessageListPage { readonly messages: readonly Message[]; readonly nextPageToken?: string; } interface EmbeddedMediaItem { readonly data: Uint8Array; readonly mimeType: string; } type EmbeddedMedia = EmbeddedMediaItem; /** * Chat-related domain types. */ /** A conversation (direct or group) in iMessage. */ interface Chat { readonly chatIdentifier?: string; readonly displayName: string; readonly groupId?: string; readonly guid: string; readonly isArchived: boolean; readonly isFiltered: boolean; readonly isGroup: boolean; readonly lastMessage?: Message; readonly participants: readonly SingleServiceAddressInfo[]; readonly service: ChatServiceType; readonly unreadCount?: number; } interface CreateChatOptions { /** Pre-rendered attributed body for the opening message, when supplied. */ readonly attributedBody?: Uint8Array; /** Caller-generated idempotency key for chat creation and the optional opening send. */ readonly clientMessageId?: string; /** Full-screen or bubble effect for `message`. */ readonly effect?: MessageEffect; /** Optional opening text sent in the same server call that creates the chat. */ readonly message?: string; /** Optional subject line for the opening message. */ readonly subject?: string; } /** * Result of `chats.create`. */ interface CreateChatResult { readonly chat: Chat; readonly initialMessage?: Message; } /** * Poll-related domain types. */ interface PollOption { readonly creatorHandle?: string; readonly optionIdentifier: string; readonly text: string; } interface PollParticipantVote { readonly optionIdentifier: string; readonly participant: SingleServiceAddressInfo; } interface Poll { readonly chatGuid: string; readonly options: readonly PollOption[]; readonly pollMessageGuid: string; readonly title: string; readonly votes: readonly PollParticipantVote[]; } type PollChangeDelta = { readonly type: "created"; readonly title: string; readonly options: readonly PollOption[]; } | { readonly type: "optionAdded"; readonly title: string; readonly options: readonly PollOption[]; } | { readonly type: "voted"; readonly optionIdentifier: string; } | { readonly type: "unvoted"; readonly optionIdentifier: string; }; /** * Event types for live subscriptions and durable catch-up replay. */ interface EventContext { readonly actor?: SingleServiceAddressInfo; readonly chatGuid: string; readonly isFromMe: boolean; readonly occurredAt: Date; } type ChatEvent = (EventContext & { readonly type: "chat.backgroundChanged"; readonly sequence: number; }) | (EventContext & { readonly type: "chat.backgroundRemoved"; readonly sequence: number; }) | (EventContext & { readonly type: "chat.markedRead"; readonly sequence: number; }) | (EventContext & { readonly type: "chat.archived"; readonly sequence: number; }) | (EventContext & { readonly type: "chat.unarchived"; readonly sequence: number; }); type GroupChange = { readonly type: "displayNameChanged"; readonly displayName: string; } | { readonly type: "participantAdded"; readonly participant: SingleServiceAddressInfo; } | { readonly type: "participantRemoved"; readonly participant: SingleServiceAddressInfo; } | { readonly type: "participantLeft"; readonly participant: SingleServiceAddressInfo; } | { readonly type: "iconChanged"; } | { readonly type: "iconRemoved"; }; interface GroupEvent extends EventContext { readonly change: GroupChange; readonly sequence: number; readonly type: "group.changed"; } type MessageEvent = (EventContext & { readonly type: "message.received"; readonly sequence: number; readonly message: Message; }) | (EventContext & { readonly type: "message.edited"; readonly sequence: number; readonly messageGuid: string; readonly content: Message["content"]; readonly editedAt: Date; }) | (EventContext & { readonly type: "message.read"; readonly sequence: number; readonly messageGuid: string; readonly readAt: Date; }) | (EventContext & { readonly type: "message.unsent"; readonly sequence: number; readonly messageGuid: string; readonly retractedAt: Date; }) | (EventContext & { readonly type: "message.reactionAdded"; readonly sequence: number; readonly messageGuid: string; readonly reaction: MessageReaction; readonly targetPartIndex?: number; }) | (EventContext & { readonly type: "message.reactionRemoved"; readonly sequence: number; readonly messageGuid: string; readonly reaction: MessageReaction; readonly targetPartIndex?: number; }) | (EventContext & { readonly type: "message.stickerPlaced"; readonly sequence: number; readonly messageGuid: string; readonly sticker?: Message["placedStickers"][number]["sticker"]; readonly placement?: StickerPlacement; readonly targetPartIndex?: number; }); interface PollEvent extends EventContext { readonly delta: PollChangeDelta; readonly pollMessageGuid: string; readonly sequence: number; readonly type: "poll.changed"; } type LiveEvent = MessageEvent | ChatEvent | GroupEvent | PollEvent; type CatchUpEvent = LiveEvent | { readonly type: "catchup.complete"; readonly headSequence: number; }; interface EventTypeMap { "chat.archived": Extract; "chat.backgroundChanged": Extract; "chat.backgroundRemoved": Extract; "chat.markedRead": Extract; "chat.unarchived": Extract; "group.changed": GroupEvent; "message.edited": Extract; "message.reactionAdded": Extract; "message.reactionRemoved": Extract; "message.read": Extract; "message.received": Extract; "message.stickerPlaced": Extract; "message.unsent": Extract; "poll.changed": PollEvent; } type EventType = keyof EventTypeMap; interface GroupIcon { readonly data: Uint8Array; readonly mimeType: string; } /** * Shared friend location domain types. */ interface SharedFriendLocation { readonly accuracy?: number; readonly address: string; readonly expiresAt?: Date; readonly isLocatingInProgress: boolean; readonly latitude?: number; readonly locationTimestamp?: Date; readonly locationType: "legacy" | "live" | "shallow" | "unknown"; readonly longAddress?: string; readonly longitude?: number; readonly name?: string; readonly shortAddress?: string; } interface SharedFriendLocationUpdated { readonly location: SharedFriendLocation; readonly sourceSequence: number; } interface LocationRequestReceipt { readonly address: string; readonly messageGuid?: string; readonly reason?: string; readonly status: string; } /** Options for configuring the Advanced iMessage client. */ interface ClientOptions { /** The server address to connect to (e.g., `"localhost:50051"`). */ readonly address: string; /** When `true`, adds an `x-idempotency-key` header to mutating RPCs. */ readonly autoIdempotency?: boolean; /** * Extra `@grpc/grpc-js` channel options merged onto (and able to override) * the SDK defaults — including the built-in keepalive settings — for both * the unary and streaming channels. Tune keepalive here, e.g. * `{ "grpc.keepalive_time_ms": 15000 }`, without waiting for an SDK release. */ readonly channelOptions?: ChannelOptions; /** * Called once for every server heartbeat frame on any `subscribeEvents` / * `watch` stream. The server emits heartbeats on a fixed cadence even when * idle, so this is a liveness signal: drive a stall watchdog from it to * detect a half-open connection and re-establish the stream. Without it, * heartbeat frames are silently dropped. */ readonly onHeartbeat?: HeartbeatHandler; /** Retries retryable unary RPC failures; streaming RPCs are never retried automatically. */ readonly retry?: boolean | RetryOptions; /** Default unary RPC timeout in milliseconds; streaming RPCs are left open. */ readonly timeout?: number; /** Use TLS for the gRPC channel. Defaults to `true`; set `false` for local development. */ readonly tls?: boolean; /** Bearer token, or async function that returns a fresh bearer token per RPC. */ readonly token: string | (() => Promise); } /** * Address APIs. * * - `get(address)` returns the server's known address record, country, and * available transport services. * - `isFocusSilenced(address)` checks whether this device's Focus settings * would silence notifications from the address. * - `isIMessageAvailable(address)` checks live iMessage reachability. */ interface AddressesResource { get(address: string): Promise; isFocusSilenced(address: string): Promise; isIMessageAvailable(address: string): Promise; } /** * Attachment APIs. * * - `get(attachment)` fetches metadata for an uploaded or received * attachment. * - `upload(input)` uploads file bytes and optional Live Photo companion * data. * - `downloadStream(attachment)` streams a header frame followed by byte * chunks. */ interface AttachmentsResource { downloadStream(attachment: string): TypedEventStream; get(attachment: string): Promise; upload(input: AttachmentInput): Promise; } /** * Chat APIs. * * - `create(addresses, options)` creates a direct or group chat, optionally * with an opening message. * - `get(chat)` fetches one chat by guid. * - `count(options)` counts visible chats, optionally including archived * chats. * - `hasBackground(chat)` checks whether a chat has a custom background. * - `setBackground(chat, data)` replaces a chat background image. * - `removeBackground(chat)` clears a chat background image. * - `markRead(chat)` marks every unread message in the chat as read. * - `shareContactInfo(chat)` sends the local account's contact card. * - `setTyping(chat, isTyping)` starts or stops the transient typing * indicator. * - `subscribeEvents(filter)` streams chat changes. */ interface ChatsResource { count(options?: { includeArchived?: boolean; }): Promise; create(addresses: string[], options?: CreateChatOptions): Promise; get(chat: string): Promise; hasBackground(chat: string): Promise; markRead(chat: string): Promise; removeBackground(chat: string): Promise; setBackground(chat: string, data: Uint8Array): Promise; setTyping(chat: string, isTyping: boolean): Promise; shareContactInfo(chat: string): Promise; subscribeEvents(filter?: { chat?: string; }): TypedEventStream; } /** * Durable event-log APIs. * * - `catchUp(since)` replays durable message, chat, group, and poll events * after the last fully handled sequence, then emits `catchup.complete`. * * Use this after a disconnect before reopening live `subscribeEvents` streams. */ interface EventsResource { catchUp(since?: number): TypedEventStream; } /** * Group APIs. * * - `setDisplayName(chat, displayName, options)` renames a group chat. * - `addParticipants(chat, addresses, options)` invites addresses into a * group chat. * - `removeParticipants(chat, addresses, options)` removes addresses from a * group chat. * - `leave(chat, options)` makes the local account leave a group chat. * - `setIcon(chat, data, options)` replaces the group photo. * - `getIcon(chat)` downloads the group photo bytes and MIME type. * - `removeIcon(chat, options)` clears the group photo. * - `subscribeEvents(filter)` streams group changes. */ interface GroupsResource { addParticipants(chat: string, addresses: string[], options?: IdempotencyOptions): Promise; getIcon(chat: string): Promise; leave(chat: string, options?: IdempotencyOptions): Promise; removeIcon(chat: string, options?: IdempotencyOptions): Promise; removeParticipants(chat: string, addresses: string[], options?: IdempotencyOptions): Promise; setDisplayName(chat: string, displayName: string, options?: IdempotencyOptions): Promise; setIcon(chat: string, data: Uint8Array, options?: IdempotencyOptions): Promise; subscribeEvents(filter?: { chat?: string; }): TypedEventStream; } /** * Shared-location APIs. * * - `list()` returns every friend currently sharing a location. * - `get(address)` fetches the latest snapshot for one friend. * - `request(chat, address)` sends a visible Find My request card. * - `watch(address?)` streams location updates outside the durable event log. */ interface LocationsResource { get(address: string): Promise; list(): Promise; request(chat: string, address: string, options?: IdempotencyOptions): Promise; watch(address?: string): TypedEventStream; } /** * Message APIs. * * - `sendText(chat, text, options)` sends text with replies, subjects, * effects, rich links, data-detector scanning, and formatting. * - `sendAttachment(chat, attachment, options)` sends an uploaded attachment * by GUID with replies, effects, and audio-message mode. * - `sendMultipart(chat, parts, options)` sends multiple text / attachment / * mention bubbles atomically. * - `sendCustomizedMiniApp(chat, message, options)` sends a mini app card * backed by the caller's own iMessage extension. * - `edit(chat, message, newText, options)` edits an existing message. * - `unsend(chat, message, options)` retracts an existing message. * - `setReaction(chat, message, reaction, isSet, options)` adds or removes * a tapback / emoji reaction. * - `placeSticker(chat, message, sticker, placement, options)` places an * uploaded sticker attachment on a message. * - `notifySilenced(chat, message, options)` triggers Apple's Notify Anyway * action for a Focus-silenced conversation. * - `get(message)` fetches one message by its guid. * - `listRecent(filter)` pages through recent messages across chats. * - `listInChat(chat, filter)` pages through messages in one chat. * - `getEmbeddedMedia(chat, message)` downloads Digital Touch / handwritten * embedded media bytes. * - `subscribeEvents(filter)` streams live message changes. */ interface MessagesResource { edit(chat: string, message: string, newText: string, options?: { readonly backwardCompatText?: string; readonly clientMessageId?: string; readonly partIndex?: number; }): Promise; get(message: string): Promise; getEmbeddedMedia(chat: string, message: string): Promise; listInChat(chat: string, options?: MessageListFilter): Promise; listRecent(options?: MessageListFilter): Promise; notifySilenced(chat: string, message: string, options?: { readonly clientMessageId?: string; }): Promise; placeSticker(chat: string, message: string, sticker: string, placement: StickerPlacement, options?: { readonly clientMessageId?: string; readonly partIndex?: number; }): Promise; sendAttachment(chat: string, attachment: string, options?: { readonly clientMessageId?: string; readonly effect?: MessageEffect; readonly isAudioMessage?: boolean; readonly replyTo?: SendOptions["replyTo"]; }): Promise; sendCustomizedMiniApp(chat: string, message: CustomizedMiniAppMessage, options?: IdempotencyOptions): Promise; sendMultipart(chat: string, parts: readonly MessagePart[], options?: { readonly clientMessageId?: string; readonly enableDataDetection?: boolean; readonly effect?: MessageEffect; readonly replyTo?: SendOptions["replyTo"]; readonly subject?: string; }): Promise; sendText(chat: string, text: string, options?: SendOptions): Promise; setReaction(chat: string, message: string, reaction: SettableMessageReaction, isSet: boolean, options?: { readonly clientMessageId?: string; readonly partIndex?: number; }): Promise; subscribeEvents(filter?: { chat?: string; }): TypedEventStream; unsend(chat: string, message: string, options?: { readonly clientMessageId?: string; readonly partIndex?: number; }): Promise; } /** * Poll APIs. * * - `create(chat, title, choices, options)` creates a poll message. * - `get(pollMessage)` reads the latest poll state. * - `vote(pollMessage, optionId, options)` casts or changes the local * account's vote. * - `unvote(pollMessage, options)` removes the local account's vote. * - `addOption(pollMessage, text, options)` appends a new choice. * - `subscribeEvents(filter)` streams poll changes. */ interface PollsResource { addOption(pollMessage: string, text: string, options?: IdempotencyOptions): Promise; create(chat: string, title: string, choices: string[], options?: IdempotencyOptions): Promise; get(pollMessage: string): Promise; subscribeEvents(filter?: { pollMessage?: string; }): TypedEventStream; unvote(pollMessage: string, options?: IdempotencyOptions): Promise; vote(pollMessage: string, optionId: string, options?: IdempotencyOptions): Promise; } interface AdvancedIMessage extends AsyncDisposable { /** * Address APIs. * * - `get(address)` returns the server's known address record, country, and * available transport services. * - `isFocusSilenced(address)` checks whether this device's Focus settings * would silence notifications from the address. * - `isIMessageAvailable(address)` checks live iMessage reachability. */ readonly addresses: AddressesResource; /** * Attachment APIs. * * - `get(attachment)` fetches metadata for an uploaded or received * attachment. * - `upload(input)` uploads file bytes and optional Live Photo companion * data. * - `downloadStream(attachment)` streams a header frame followed by byte * chunks. */ readonly attachments: AttachmentsResource; /** * Chat APIs. * * - `create(addresses, options)` creates a direct or group chat, optionally * with an opening message. * - `get(chat)` fetches one chat by guid. * - `count(options)` counts visible chats, optionally including archived * chats. * - `hasBackground(chat)` checks whether a chat has a custom background. * - `setBackground(chat, data)` replaces a chat background image. * - `removeBackground(chat)` clears a chat background image. * - `markRead(chat)` marks every unread message in the chat as read. * - `shareContactInfo(chat)` sends the local account's contact card. * - `setTyping(chat, isTyping)` starts or stops the transient typing * indicator. * - `subscribeEvents(filter)` streams chat changes. */ readonly chats: ChatsResource; close(): Promise; /** * Durable event-log APIs. * * - `catchUp(since)` replays durable message, chat, group, and poll events * after the last fully handled sequence, then emits `catchup.complete`. * * Use this after a disconnect before reopening live `subscribeEvents` streams. */ readonly events: EventsResource; /** * Group APIs. * * - `setDisplayName(chat, displayName, options)` renames a group chat. * - `addParticipants(chat, addresses, options)` invites addresses into a * group chat. * - `removeParticipants(chat, addresses, options)` removes addresses from a * group chat. * - `leave(chat, options)` makes the local account leave a group chat. * - `setIcon(chat, data, options)` replaces the group photo. * - `getIcon(chat)` downloads the group photo bytes and MIME type. * - `removeIcon(chat, options)` clears the group photo. * - `subscribeEvents(filter)` streams group changes. */ readonly groups: GroupsResource; /** * Shared-location APIs. * * - `list()` returns every friend currently sharing a location. * - `get(address)` fetches the latest snapshot for one friend. * - `watch(address?)` streams location updates outside the durable event log. */ readonly locations: LocationsResource; /** * Message APIs. * * - `sendText(chat, text, options)` sends text with replies, subjects, * effects, link previews, data-detector scanning, and formatting. * - `sendAttachment(chat, attachment, options)` sends an uploaded attachment * by GUID with replies, effects, and audio-message mode. * - `sendMultipart(chat, parts, options)` sends multiple text / attachment / * mention bubbles atomically. * - `sendCustomizedMiniApp(chat, message, options)` sends a mini app card * backed by the caller's own iMessage extension. * - `edit(chat, message, newText, options)` edits an existing message. * - `unsend(chat, message, options)` retracts an existing message. * - `setReaction(chat, message, reaction, isSet, options)` adds or removes * a tapback / emoji reaction. * - `placeSticker(chat, message, sticker, placement, options)` places an * uploaded sticker attachment on a message. * - `notifySilenced(chat, message, options)` triggers Apple's Notify Anyway * action for a Focus-silenced conversation. * - `get(message)` fetches one message by its guid. * - `listRecent(filter)` pages through recent messages across chats. * - `listInChat(chat, filter)` pages through messages in one chat. * - `getEmbeddedMedia(chat, message)` downloads Digital Touch / handwritten * embedded media bytes. * - `subscribeEvents(filter)` streams live message changes. */ readonly messages: MessagesResource; /** * Poll APIs. * * - `create(chat, title, choices, options)` creates a poll message. * - `get(pollMessage)` reads the latest poll state. * - `vote(pollMessage, optionId, options)` casts or changes the local * account's vote. * - `unvote(pollMessage, options)` removes the local account's vote. * - `addOption(pollMessage, text, options)` appends a new choice. * - `subscribeEvents(filter)` streams poll changes. */ readonly polls: PollsResource; } /** * Creates an Advanced iMessage client with typed resource namespaces. * * Call {@link AdvancedIMessage.close} to release the underlying connection when done. * * @example * ```ts * const im = createClient({ * address: "localhost:50051", * token: "my-api-token", * }); * * await im.close(); * ``` */ declare function createClient(options: ClientOptions): AdvancedIMessage; /** * Canonical error codes returned by the server. * * Modelled as an `as const` object so that both the runtime values and the * union type are available, with full autocomplete. */ declare const ErrorCode: { readonly unauthenticated: "unauthenticated"; readonly tokenExpired: "tokenExpired"; readonly tokenBlocked: "tokenBlocked"; readonly unauthorized: "unauthorized"; readonly dailyLimitExceeded: "dailyLimitExceeded"; readonly recipientLimitExceeded: "recipientLimitExceeded"; readonly uploadRateExceeded: "uploadRateExceeded"; readonly contentDuplicateExceeded: "contentDuplicateExceeded"; readonly recipientCoolingDown: "recipientCoolingDown"; readonly recipientLocked: "recipientLocked"; readonly sendReceiveRatioExceeded: "sendReceiveRatioExceeded"; readonly duplicateMessage: "duplicateMessage"; readonly chatNotFound: "chatNotFound"; readonly messageNotFound: "messageNotFound"; readonly attachmentNotFound: "attachmentNotFound"; readonly addressNotFound: "addressNotFound"; readonly sharedFriendLocationNotFound: "sharedFriendLocationNotFound"; readonly groupIconNotFound: "groupIconNotFound"; readonly pollNotFound: "pollNotFound"; readonly invalidArgument: "invalidArgument"; readonly preconditionFailed: "preconditionFailed"; readonly operationNotSupported: "operationNotSupported"; readonly attachmentNotReady: "attachmentNotReady"; readonly privateApiUnavailable: "privateApiUnavailable"; readonly serviceUnavailable: "serviceUnavailable"; readonly timeout: "timeout"; readonly internalError: "internalError"; readonly databaseError: "databaseError"; readonly networkError: "networkError"; }; /** Union of all known error code strings. */ type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode]; /** * Error class hierarchy for the advanced-imessage-ts SDK. * * Inspired by Stripe's error design: a single base class with typed subclasses * so callers can use `instanceof` to handle specific failure modes rather than * inspecting boolean flags or string codes. * * A factory function in `error-handler.ts` maps gRPC errors to the correct * subclass automatically. */ interface IMessageErrorOptions { /** The original error that caused this one. */ readonly cause?: Error; /** Canonical error code from the server. */ readonly code: ErrorCode; /** Arbitrary key-value pairs providing additional context. */ readonly context?: Record; /** Numeric gRPC status code (mirrors `nice-grpc-common` Status enum). */ readonly grpcCode: number; /** Whether the caller should retry the request. */ readonly retryable: boolean; } /** * Base error for every failure surfaced by the SDK. * * All properties are `readonly` -- errors are informational, not mutable. */ declare class IMessageError extends Error { readonly code: ErrorCode; readonly retryable: boolean; readonly grpcCode: number; readonly context: Record; constructor(message: string, options: IMessageErrorOptions); } /** * The request could not be authenticated or the caller lacks permission. * * Maps from gRPC `UNAUTHENTICATED` and `PERMISSION_DENIED`. */ declare class AuthenticationError extends IMessageError { constructor(message: string, options: IMessageErrorOptions); } /** * The requested resource was not found. * * Maps from gRPC `NOT_FOUND`. */ declare class NotFoundError extends IMessageError { constructor(message: string, options: IMessageErrorOptions); } /** * A rate limit or quota was exceeded. * * Maps from gRPC `RESOURCE_EXHAUSTED`. */ declare class RateLimitError extends IMessageError { constructor(message: string, options: IMessageErrorOptions); } /** * The request contained invalid arguments or a failed precondition. * * Maps from gRPC `INVALID_ARGUMENT` and `FAILED_PRECONDITION`. */ declare class ValidationError extends IMessageError { constructor(message: string, options: IMessageErrorOptions); } /** * The server is unreachable or the request timed out. * * Maps from gRPC `UNAVAILABLE` and `DEADLINE_EXCEEDED`. */ declare class ConnectionError extends IMessageError { constructor(message: string, options: IMessageErrorOptions); } export { type AddressesResource, type AdvancedIMessage, type AttachmentInfo, type AttachmentInput, type AttachmentsResource, AuthenticationError, type CatchUpEvent, type Chat, type ChatEvent, type ChatServiceType, type ChatsResource, type ClientOptions, type CompanionInfo, ConnectionError, type CreateChatOptions, type CreateChatResult, type CustomizedMiniAppMessage, type DownloadAttachmentChunk, type EmbeddedMedia, type EmbeddedMediaItem, ErrorCode, type EventType, type EventTypeMap, type EventsResource, type GroupChange, type GroupEvent, type GroupIcon, type GroupsResource, type HeartbeatHandler, IMessageError, type IdempotencyOptions, type LiveEvent, type LocationRequestReceipt, type LocationsResource, type Message, type MessageAppliedReaction, type MessageContent, MessageEffect, type MessageEvent, type MessageItemType, type MessageListFilter, type MessageListPage, type MessageMention, type MessagePart, type MessagePlacedSticker, type MessageReaction, type MessagesResource, type MiniAppLayout, type MultiServiceAddressInfo, NotFoundError, type Poll, type PollChangeDelta, type PollEvent, type PollOption, type PollParticipantVote, type PollsResource, RateLimitError, type RetryOptions, type SendOptions, type SettableMessageReaction, type SharedFriendLocation, type SharedFriendLocationUpdated, type SingleServiceAddressInfo, type StickerPlacement, TextEffect, type TextFormat, type TextFormatInput, type TransferState, TypedEventStream, type UploadAttachmentResult, ValidationError, createClient };