This document explains how to create a bridge and documents the available API.
mx-puppet-bridge
tries to make it easy to implement puppeting bridges. As such, it provides an API for people to use to make it as easy as possible.
As such, you create an instance of the PuppetBridge
class, listen to events on it to receive things from matrix, use methods of it to send things to matrix and register some callbacks for better integration.
The protocol implementation can set certain features to say that it supports something. These all default to not implemented. This allows this puppet bridge to have automatic fallbacks.
file // file sending implemented
image // image sending implemented
audio // audio sending implemented
video // video sending implemented
sticker // sticker sending implemented
presence // presence handling implemented
typingTimeout (number) // timeout for typing in ms
edit // if the protocol imlementation has edit support
Pro-Tip: if your protocol implementation auto-detects file types, only set the feature file
! That will cause image
, audio
, video
and sticker
to fall back to that.
Each matrix user can create as many puppet bridges as they want. Among all users a unique puppetId
(number) exists. This is for the protocol implementation to be able to keep track what goes where.
Each protocol implementation sets a roomId
(string). This needs to be a unique identifier to a room among only the puppetId. The protocol implementation needs to handle that 1:1 rooms and other rooms all have unique IDs. (e.g. remote protocol internal room ID)
Similar to the roomId, the protocol needs to set a userId
(string). This is a unique identifier for a remote user among only the puppetId. (e.g. remote protocol internal puppet ID)
These object types appear throughout the API.
This object is needed for sending or receiving room-related things from and to matrix
{
roomId: string; // the remote ID of the room
puppetId: number; // index number of the puppet
avatarUrl: string; (optional) // avatar URL of the room icon
avatarBuffer: Buffer; (optional) // avatar buffer of the room icon
name: string; (optional) // name of the room
topic: string; (optional) // topic of the room
isDirect: boolean; (optional) // flag if the room is a 1:1 room
}
This object is needed for sending or receiving user-related things from and to matrix
{
userId: string; // the remote ID of the user
puppetId: number; // index number of the puppet
avatarUrl: string; (optional) // avatar URL of the user
avatarBuffer: Buffer; (optional) // avatar buffer of the user
name: string; (optional) // name of the user
}
This object is a combination of IRemoteRoom
and IRemoteUser
. Used to combind which user sent something where
{
room: IRemoteRoom; // room to send to
user: IRemoteUser; // user which sent something
eventId: string; (optional) // the remote event ID
externalUrl: string; (optional) // an external URL referring to this event
}
This object holds the main data for a message event
{
body: string; // the plain text body
formattedBody: string; (optional) // if present, the html formatting of the message
emote: boolean; (optional) // if the messgae is an emote (/me) message
notice: boolean; (optional) // if the message is a bot message
eventId: string; (optional) // the event ID. When receiving to send to remote, the matrix one, when sending to matrix, the remote one
}
This object holds the main data for a file event
{
filename: string; // the filename of the file
info?: {
mimetype?: string; // the mimetype of the file
size?: number; // the byte size of the file
w?: number; // the width, if it is an image or a video
h?: number; // the height, if it is an image or a video
};
mxc: string; // the mxc content uri of the file
url: string; // an accessible URL of the file
eventId: string; (optional) // the event ID. When receiving to send to remote, the matrix one, when sending to matrix, the remote one
}
Events are used so that the protocol implementation can listen to them and thus handle stuffs from matrix
A message has been sent from matrix! Event parameters:
room: IRemoteRoom; // the room where to send to
data: IMessageEvent; // the data on the message
asUser: ISendingUser | null, // optionally, as which user to send
event: any; // the raw message event
If feature enabled, an edit has been made from matrix Event parameters:
room: IRemoteRoom; // the room where the edit happened
eventId: string; // the remote event ID of the original event
data: IMessageEvent; // the data on the new message
asUser: ISendingUser | null, // optionally, as which user to send
event: any; // the raw message event
A redact happened from matrix Event parameters:
room: IRemoteRoom; // the room where the redact happened
eventId: string; // the remote event ID that got redacted
asUser: ISendingUser | null, // optionally, as which user to send
event: any; // the raw redact event
File events are image
, audio
, video
, sticker
and file
. Appropriate fallbacks are used if feature not enabled, all the way back to plain text messages. They all use the same parameters
room: IRemoteRoom; // the room where to send to
data: IFileEvent; // the data on the file
asUser: ISendingUser | null, // optionally, as which user to send
event: any; // the raw file event
A presence event from matrix Event parameters:
puppetId: number; // the puppet id
presence: IPresenceEvent; // the presence
asUser: ISendingUser | null, // optionally, as which user to send
rawEvent: any; // raw event
A typing event from matrix Event parameters:
room: IRemoteRoom; // the room where the typing happened
typing: boolean; // true / false
asUser: ISendingUser | null, // optionally, as which user to send
rawEvent: any; // raw event
A read event from matrix Event parameters:
room: IRemoteRoom; // the room where the read happened
eventId: string; // the remote event id where the read happened
content: any; // the content of the event
asUser: ISendingUser | null, // optionally, as which user to send
rawEvent: any; // raw event
This event is emitted if a new puppet has been created via the provisioner. The protocol implementation is expected to start bridging this puppet.
puppetId: number; // the NEW!!! puppetId of the puppet
data: any; // the provisioning data set by the protocol implementation
This event is emitted if a puppet has been deleted via the provisioner. The protocol implementation is expected to stop bridging this puppet.
puppetId: number; // delete this puppet
This event is emitted if the puppet (matrix user) changes their name
puppetId: number;
name: string;
This event is emitted if the puppet (matrix user) changes their avatar
puppetId: number;
url: string;
mxc: string;
sendMessage
sends a text message over to matrix. Parameters are:
params: IReceiveParams; // room and user where/who sent something
opts: IMessageEvent; // what to send
sendEdit
sends an edit over to matrix. Parameters are:
params: IReceiveParams; // room and user who made the edit
eventId: string; // the remote event ID that got edited
opts: IMessageEvent; // the new message
ix: number = 0; // optional, index of the message to edit, if multiple are found
sendRedact
sends a redact over to matrix. Parameters are:
params: IReceiveParams; // room and user who made the redact
eventId: string; // the remote event ID that got redacted
Again, multiple file sending messages for different file formats and for autodetecting. They all have the same parameters. The methods are sendImage
, sendAudio
, sendVideo
, sendFile
, sendFileDetect
. Parameters are
params: IReceiveParams; // room and user where/who sent something
thing: string | Buffer; // either a URL or a buffer of the file to send
name: string (optional); // name of the file
getPuppetMxidInfo
gets the mxid information, or null, of a puppet.
It takes the parameters:
puppetId: number;
sendStatusMessage
sends a status message - either to the status room or into a specified room.
puppetId: number | IRemoteRoom; // if it is IRemoteRoom then it sends to that room
msg: string; // markdown formatted string
getMxidForUser
gets the mxid for a given user, obaying puppeting stuff
user: IRemoteUser;
setUserTyping
sets if a user is typing in a room or not
params: IReceiveParams;
typing: boolean;
sendReadReceipt
senda a read receipt
params: IReceiveParams; // eventId is required in this case
setUserPresence
sets the presence of a user
user: IRemoteUser;
presence: "online" | "offline" | "unavailable";
updateRoom
triggers a remote updating of a room
room: IRemoteRoom;
bridgeRoom
triggers the bridging of a room, or updates it if it exists
room: IRemoteRoom;
unbridgeRoom
triggers a room to be unbridged, e.g. if in a 1:1 conversation the remote user left the room
room: IRemoteRoom;
same as unbridgeRoom but it takes the mxid of a room
mxid: string;
updateUser
triggers a remote updating of a user
user: IRemoteUser
setPuppetData
sets the puppeting data provided by the protocol information, to e.g. be able to add metadata. BE SURE TO KEEP THE REQUIRED DATA FOR THE PROTOCOL
puppetId: number;
data: any;
setUserId
sets what the remote user ID of the puppet is
puppetId: number;
data: any;
These are needed to insert events the protocol implementation sends out to the remote protocol into the event store. They are called with eventStore.method
, e.g. eventStore.insert
insert
inserts a new event into the event store. Parameters are:
puppetId: number;
matrixId: string; // you have this from the IMessageEvent and IFileEvent received from the bridge
remoteId: string; // the remote event Id
Hooks are crucial for provisioning. Setting them is done via calling setHooknameHook
with the hook function as parameter, e.g. if the hook name is createRoom
then you call setCreateRoomHook
This hook is called when a room is created. It is expected to return full information on the room. E.g. if the protocol implementation, for performance reasons, mostly only sends around room IDs, this should get name, topic and avatar.
Returns IRemoteRoom | null
Takes:
room: IRemoteRoom;
Same as createRoom
but for users
Returns IRemoteUser | null
Takes:
user: IRemoteUser;
This hook should return a human-readable description of a puppet, given the data provided.
Returns: string
Takes:
puppetId: number;
data: any; // the data set by the protocol implementation
html: boolean; // if the reply should be HTML or not
This is crucial for provisioning: It will be called when a user tries to link to the remote server using the link
command, and should return a data object that the protocol implementation will continue to use. e.g. a token
Returns:
success: boolean; // if this was successful
error: string (optional); // string to show if this wasn't successful, this can also be used to provide further login steps to the user
data: any (only when successful); // the resulting data needed to start puppets
userId: string (optional); // the user id of that puppet
fn: (str: string) => IRetData (optional, only_when_not_successful); // if set, this function will be called by the next message send by the user, this can be used for example for the user providing auth tokens acquired from following the steps previously described in the `error` message.
Takes:
str: string;
Just return a nice header for the bot to send in chat for provisioning
Returns: string
Takes: none