/** Per-device encrypted payload on the wire. */ export interface WireDeviceEncryptedPayload { deviceId: string; encryptedPayload: Uint8Array; senderPublicKey: Uint8Array; } /** Per-device wrapped AES-256-GCM file key for E2EE attachments. */ export interface WireDeviceWrappedKey { deviceId: string; wrappedKey: Uint8Array; senderPublicKey: Uint8Array; nonce: Uint8Array; } /** Pointer to an attachment in the customer's storage bucket. */ export interface WireAttachmentRef { attachmentId: string; storageHint: string; mimeType: string; sizeBytes: number; sha256: string; encryptionType: number; wrappedKeys?: WireDeviceWrappedKey[]; thumbnailAttachmentId?: string; } /** * Cleartext metadata that wakes a recipient's device. Never message content: the * relay can read every field here, which is the whole reason it can act on them. * * `delivery` says how the device should treat the push. The platform translates * it per transport rather than deciding for the app. */ export interface WirePushPayload { title?: string; body?: string; badge?: number; sound?: string; category?: string; threadId?: string; customJson?: string; /** Superseded by `delivery: 3`; still honoured by the server. */ voip?: boolean; /** 0 ALERT, 1 MUTABLE, 2 SILENT, 3 VOIP. */ delivery?: number; } export interface WireEnvelope { messageId: string; appId: string; fromUserId: string; toUserId: string; timestamp: number; encryptedPayload: Uint8Array; clientMessageId?: string; /** Multi-device: per-device encrypted payloads. */ devicePayloads?: WireDeviceEncryptedPayload[]; /** Sender's device ID. */ senderDeviceId?: string; /** 0 = E2EE (default), 1 = CLEARTEXT */ encryptionType?: number; /** Populated only when encryptionType = CLEARTEXT. */ plaintextPayload?: string; /** Zero or more attachment pointers (PROTOCOL_VERSION 4+). */ attachments?: WireAttachmentRef[]; /** Wakes the recipient when they have no live session (PROTOCOL_VERSION 5+). */ pushPayload?: WirePushPayload; } export interface WireAck { messageId: string; type: string; } export interface WireEvent { type: string; reason?: string; metadata?: string; } export interface WireCallFrame { type: string; callId?: string; targetUserId?: string; payload?: string; pushPayload?: WirePushPayload; } export interface WireBroadcastFrame { broadcastId: string; appId: string; channelId: string; publisherId: string; timestamp: number; encryptionType: number; encryptedPayload: Uint8Array; plaintextPayload: string; sequenceNumber: number; } export interface WireBroadcastNotification { broadcastId: string; channelId: string; publisherId: string; timestamp: number; encryptionType: number; encryptedPayload: Uint8Array; plaintextPayload: string; sequenceNumber: number; } export interface WireGroupMemberPayload { userId: string; devicePayloads: WireDeviceEncryptedPayload[]; } export interface WireGroupEnvelope { messageId: string; appId?: string; groupId: string; fromUserId: string; timestamp: number; clientMessageId?: string; senderDeviceId: string; encryptionType: number; plaintextPayload?: string; memberPayloads: WireGroupMemberPayload[]; attachments?: WireAttachmentRef[]; /** Wakes offline members (PROTOCOL_VERSION 5+). */ pushPayload?: WirePushPayload; } export interface WireGroupMessageNotification { messageId: string; groupId: string; fromUserId: string; timestamp: number; encryptionType: number; plaintextPayload?: string; devicePayloads: WireDeviceEncryptedPayload[]; senderDeviceId: string; attachments?: WireAttachmentRef[]; } export interface WireGroupAck { messageId: string; groupId: string; type: string; /** * Which member the acknowledgement is about. A group message has many * recipients, so the useful fact is which of them has it. Empty on * SERVER_RECEIVED, which concerns the relay rather than any member. */ memberUserId?: string; } export interface WireGroupCallFrame { type: string; callId: string; groupId: string; targetUserId?: string; /** * On the way out of a GROUP_CALL_INVITE: a JSON array of the user ids to * ring, or absent to ring the whole group. On everything else, and on the * way in, whatever that frame type carries. */ payload?: string; /** On GROUP_CALL_INVITE: lets the relay ring members who are not connected. */ pushPayload?: WirePushPayload; /** Set instead of groupId when the multi-party call belongs to a Room. */ roomId?: string; } /** * Edit frame, sender re-encrypts new content for all recipient devices. * Same shape sent in both directions, client to server (request) and * server to recipient devices (notification). */ export interface WireMessageEditFrame { type: string; editId: string; originalMessageId: string; appId: string; fromUserId: string; toUserId: string; timestamp: number; encryptionType: number; encryptedPayload?: Uint8Array; devicePayloads?: WireDeviceEncryptedPayload[]; senderDeviceId?: string; plaintextPayload?: string; clientEditId?: string; /** Set when the edited message was sent to a group. */ groupId?: string; /** Group E2EE edits sent to the relay: one payload set per member. */ memberPayloads?: WireGroupMemberPayload[]; } /** * Push token registration / unregister. Client -> server only. The server * acks with a regular Ack frame of type 'PUSH_REGISTERED' or * 'PUSH_UNREGISTERED' and correlation 'PUSH::'. */ export interface WirePushRegistrationFrame { type: 'PUSH_REGISTER' | 'PUSH_UNREGISTER'; platform: 'APNS' | 'FCM' | 'WEB_PUSH'; token: string; voipToken?: string; deviceId: string; /** APNs only: 'sandbox' | 'production'. Absent or empty means not said. */ apnsEnvironment?: string; } /** * Cross-device state sync frame (PROTOCOL_VERSION 6+). Same shape sent * client -> server and relayed server -> the user's other devices. */ export interface WireSyncFrame { type: string; messageId: string; conversationId?: string; timestamp: number; payload?: string; fromUserId?: string; } /** Tombstone frame, scope FOR_EVERYONE or FOR_ME. */ export interface WireMessageDeleteFrame { type: string; deleteId: string; originalMessageId: string; appId: string; fromUserId: string; toUserId: string; timestamp: number; scope: string; clientDeleteId?: string; /** Set when the deleted message was sent to a group. */ groupId?: string; } export type InboundFrame = { kind: 'envelope'; data: WireEnvelope; } | { kind: 'ack'; data: WireAck; } | { kind: 'event'; data: WireEvent; } | { kind: 'call'; data: WireCallFrame; } | { kind: 'broadcast'; data: WireBroadcastNotification; } | { kind: 'groupMessage'; data: WireGroupMessageNotification; } | { kind: 'groupAck'; data: WireGroupAck; } | { kind: 'groupCall'; data: WireGroupCallFrame; } | { kind: 'messageEdit'; data: WireMessageEditFrame; } | { kind: 'messageDelete'; data: WireMessageDeleteFrame; } | { kind: 'sync'; data: WireSyncFrame; }; export declare class ProtobufCodec { encodeEnvelope(value: WireEnvelope): Uint8Array; encodeAck(value: WireAck): Uint8Array; encodeCallFrame(value: WireCallFrame): Uint8Array; encodeBroadcastFrame(value: WireBroadcastFrame): Uint8Array; encodeGroupEnvelope(value: WireGroupEnvelope): Uint8Array; encodeGroupCallFrame(value: WireGroupCallFrame): Uint8Array; encodeGroupAck(value: WireGroupAck): Uint8Array; encodeMessageEditFrame(value: WireMessageEditFrame): Uint8Array; encodeMessageDeleteFrame(value: WireMessageDeleteFrame): Uint8Array; encodePushRegistrationFrame(value: WirePushRegistrationFrame): Uint8Array; encodeSyncFrame(value: WireSyncFrame): Uint8Array; decodeFrame(payload: Uint8Array): InboundFrame; private tryDecodeEnvelope; private tryDecodeAck; private tryDecodeEvent; private tryDecodeCallFrame; private tryDecodeBroadcastNotification; private tryDecodeGroupMessageNotification; private tryDecodeGroupAck; private tryDecodeGroupCallFrame; private tryDecodeSyncFrame; private tryDecodeMessageEditFrame; private tryDecodeMessageDeleteFrame; }