1 | Matrix Javascript SDK
|
2 | =====================
|
3 |
|
4 | This is the [Matrix](https://matrix.org) Client-Server r0 SDK for
|
5 | JavaScript. This SDK can be run in a browser or in Node.js.
|
6 |
|
7 | Quickstart
|
8 | ==========
|
9 |
|
10 | In a browser
|
11 | ------------
|
12 | Download either the full or minified version from
|
13 | https://github.com/matrix-org/matrix-js-sdk/releases/latest and add that as a
|
14 | ``<script>`` to your page. There will be a global variable ``matrixcs``
|
15 | attached to ``window`` through which you can access the SDK. See below for how to
|
16 | include libolm to enable end-to-end-encryption.
|
17 |
|
18 | Please check [the working browser example](examples/browser) for more information.
|
19 |
|
20 | In Node.js
|
21 | ----------
|
22 |
|
23 | Ensure you have the latest LTS version of Node.js installed.
|
24 |
|
25 | Using `yarn` instead of `npm` is recommended. Please see the Yarn [install guide](https://yarnpkg.com/docs/install/) if you do not have it already.
|
26 |
|
27 | ``yarn add matrix-js-sdk``
|
28 |
|
29 | ```javascript
|
30 | var sdk = require("matrix-js-sdk");
|
31 | var client = sdk.createClient("https://matrix.org");
|
32 | client.publicRooms(function(err, data) {
|
33 | console.log("Public Rooms: %s", JSON.stringify(data));
|
34 | });
|
35 | ```
|
36 |
|
37 | See below for how to include libolm to enable end-to-end-encryption. Please check
|
38 | [the Node.js terminal app](examples/node) for a more complex example.
|
39 |
|
40 | To start the client:
|
41 |
|
42 | ```javascript
|
43 | await client.startClient({initialSyncLimit: 10});
|
44 | ```
|
45 |
|
46 | You can perform a call to `/sync` to get the current state of the client:
|
47 |
|
48 | ```javascript
|
49 | client.once('sync', function(state, prevState, res) {
|
50 | if(state === 'PREPARED') {
|
51 | console.log("prepared");
|
52 | } else {
|
53 | console.log(state);
|
54 | process.exit(1);
|
55 | }
|
56 | });
|
57 | ```
|
58 |
|
59 | To send a message:
|
60 |
|
61 | ```javascript
|
62 | var content = {
|
63 | "body": "message text",
|
64 | "msgtype": "m.text"
|
65 | };
|
66 | client.sendEvent("roomId", "m.room.message", content, "", (err, res) => {
|
67 | console.log(err);
|
68 | });
|
69 | ```
|
70 |
|
71 | To listen for message events:
|
72 |
|
73 | ```javascript
|
74 | client.on("Room.timeline", function(event, room, toStartOfTimeline) {
|
75 | if (event.getType() !== "m.room.message") {
|
76 | return; // only use messages
|
77 | }
|
78 | console.log(event.event.content.body);
|
79 | });
|
80 | ```
|
81 |
|
82 | By default, the `matrix-js-sdk` client uses the `MemoryStore` to store events as they are received. For example to iterate through the currently stored timeline for a room:
|
83 |
|
84 | ```javascript
|
85 | Object.keys(client.store.rooms).forEach((roomId) => {
|
86 | client.getRoom(roomId).timeline.forEach(t => {
|
87 | console.log(t.event);
|
88 | });
|
89 | });
|
90 | ```
|
91 |
|
92 | What does this SDK do?
|
93 | ----------------------
|
94 |
|
95 | This SDK provides a full object model around the Matrix Client-Server API and emits
|
96 | events for incoming data and state changes. Aside from wrapping the HTTP API, it:
|
97 | - Handles syncing (via `/initialSync` and `/events`)
|
98 | - Handles the generation of "friendly" room and member names.
|
99 | - Handles historical `RoomMember` information (e.g. display names).
|
100 | - Manages room member state across multiple events (e.g. it handles typing, power
|
101 | levels and membership changes).
|
102 | - Exposes high-level objects like `Rooms`, `RoomState`, `RoomMembers` and `Users`
|
103 | which can be listened to for things like name changes, new messages, membership
|
104 | changes, presence changes, and more.
|
105 | - Handle "local echo" of messages sent using the SDK. This means that messages
|
106 | that have just been sent will appear in the timeline as 'sending', until it
|
107 | completes. This is beneficial because it prevents there being a gap between
|
108 | hitting the send button and having the "remote echo" arrive.
|
109 | - Mark messages which failed to send as not sent.
|
110 | - Automatically retry requests to send messages due to network errors.
|
111 | - Automatically retry requests to send messages due to rate limiting errors.
|
112 | - Handle queueing of messages.
|
113 | - Handles pagination.
|
114 | - Handle assigning push actions for events.
|
115 | - Handles room initial sync on accepting invites.
|
116 | - Handles WebRTC calling.
|
117 |
|
118 | Later versions of the SDK will:
|
119 | - Expose a `RoomSummary` which would be suitable for a recents page.
|
120 | - Provide different pluggable storage layers (e.g. local storage, database-backed)
|
121 |
|
122 | Usage
|
123 | =====
|
124 |
|
125 |
|
126 | Conventions
|
127 | -----------
|
128 |
|
129 | ### Emitted events
|
130 |
|
131 | The SDK will emit events using an ``EventEmitter``. It also
|
132 | emits object models (e.g. ``Rooms``, ``RoomMembers``) when they
|
133 | are updated.
|
134 |
|
135 | ```javascript
|
136 | // Listen for low-level MatrixEvents
|
137 | client.on("event", function(event) {
|
138 | console.log(event.getType());
|
139 | });
|
140 |
|
141 | // Listen for typing changes
|
142 | client.on("RoomMember.typing", function(event, member) {
|
143 | if (member.typing) {
|
144 | console.log(member.name + " is typing...");
|
145 | }
|
146 | else {
|
147 | console.log(member.name + " stopped typing.");
|
148 | }
|
149 | });
|
150 |
|
151 | // start the client to setup the connection to the server
|
152 | client.startClient();
|
153 | ```
|
154 |
|
155 | ### Promises and Callbacks
|
156 |
|
157 | Most of the methods in the SDK are asynchronous: they do not directly return a
|
158 | result, but instead return a [Promise](http://documentup.com/kriskowal/q/)
|
159 | which will be fulfilled in the future.
|
160 |
|
161 | The typical usage is something like:
|
162 |
|
163 | ```javascript
|
164 | matrixClient.someMethod(arg1, arg2).done(function(result) {
|
165 | ...
|
166 | });
|
167 | ```
|
168 |
|
169 | Alternatively, if you have a Node.js-style ``callback(err, result)`` function,
|
170 | you can pass the result of the promise into it with something like:
|
171 |
|
172 | ```javascript
|
173 | matrixClient.someMethod(arg1, arg2).nodeify(callback);
|
174 | ```
|
175 |
|
176 | The main thing to note is that it is an error to discard the result of a
|
177 | promise-returning function, as that will cause exceptions to go unobserved. If
|
178 | you have nothing better to do with the result, just call ``.done()`` on it. See
|
179 | http://documentup.com/kriskowal/q/#the-end for more information.
|
180 |
|
181 | Methods which return a promise show this in their documentation.
|
182 |
|
183 | Many methods in the SDK support *both* Node.js-style callbacks *and* Promises,
|
184 | via an optional ``callback`` argument. The callback support is now deprecated:
|
185 | new methods do not include a ``callback`` argument, and in the future it may be
|
186 | removed from existing methods.
|
187 |
|
188 | Examples
|
189 | --------
|
190 | This section provides some useful code snippets which demonstrate the
|
191 | core functionality of the SDK. These examples assume the SDK is setup like this:
|
192 |
|
193 | ```javascript
|
194 | var sdk = require("matrix-js-sdk");
|
195 | var myUserId = "@example:localhost";
|
196 | var myAccessToken = "QGV4YW1wbGU6bG9jYWxob3N0.qPEvLuYfNBjxikiCjP";
|
197 | var matrixClient = sdk.createClient({
|
198 | baseUrl: "http://localhost:8008",
|
199 | accessToken: myAccessToken,
|
200 | userId: myUserId
|
201 | });
|
202 | ```
|
203 |
|
204 | ### Automatically join rooms when invited
|
205 |
|
206 | ```javascript
|
207 | matrixClient.on("RoomMember.membership", function(event, member) {
|
208 | if (member.membership === "invite" && member.userId === myUserId) {
|
209 | matrixClient.joinRoom(member.roomId).done(function() {
|
210 | console.log("Auto-joined %s", member.roomId);
|
211 | });
|
212 | }
|
213 | });
|
214 |
|
215 | matrixClient.startClient();
|
216 | ```
|
217 |
|
218 | ### Print out messages for all rooms
|
219 |
|
220 | ```javascript
|
221 | matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
|
222 | if (toStartOfTimeline) {
|
223 | return; // don't print paginated results
|
224 | }
|
225 | if (event.getType() !== "m.room.message") {
|
226 | return; // only print messages
|
227 | }
|
228 | console.log(
|
229 | // the room name will update with m.room.name events automatically
|
230 | "(%s) %s :: %s", room.name, event.getSender(), event.getContent().body
|
231 | );
|
232 | });
|
233 |
|
234 | matrixClient.startClient();
|
235 | ```
|
236 |
|
237 | Output:
|
238 | ```
|
239 | (My Room) @megan:localhost :: Hello world
|
240 | (My Room) @megan:localhost :: how are you?
|
241 | (My Room) @example:localhost :: I am good
|
242 | (My Room) @example:localhost :: change the room name
|
243 | (My New Room) @megan:localhost :: done
|
244 | ```
|
245 |
|
246 | ### Print out membership lists whenever they are changed
|
247 |
|
248 | ```javascript
|
249 | matrixClient.on("RoomState.members", function(event, state, member) {
|
250 | var room = matrixClient.getRoom(state.roomId);
|
251 | if (!room) {
|
252 | return;
|
253 | }
|
254 | var memberList = state.getMembers();
|
255 | console.log(room.name);
|
256 | console.log(Array(room.name.length + 1).join("=")); // underline
|
257 | for (var i = 0; i < memberList.length; i++) {
|
258 | console.log(
|
259 | "(%s) %s",
|
260 | memberList[i].membership,
|
261 | memberList[i].name
|
262 | );
|
263 | }
|
264 | });
|
265 |
|
266 | matrixClient.startClient();
|
267 | ```
|
268 |
|
269 | Output:
|
270 | ```
|
271 | My Room
|
272 | =======
|
273 | (join) @example:localhost
|
274 | (leave) @alice:localhost
|
275 | (join) Bob
|
276 | (invite) @charlie:localhost
|
277 | ```
|
278 |
|
279 | API Reference
|
280 | =============
|
281 |
|
282 | A hosted reference can be found at
|
283 | http://matrix-org.github.io/matrix-js-sdk/index.html
|
284 |
|
285 | This SDK uses JSDoc3 style comments. You can manually build and
|
286 | host the API reference from the source files like this:
|
287 |
|
288 | ```
|
289 | $ yarn gendoc
|
290 | $ cd .jsdoc
|
291 | $ python -m SimpleHTTPServer 8005
|
292 | ```
|
293 |
|
294 | Then visit ``http://localhost:8005`` to see the API docs.
|
295 |
|
296 | End-to-end encryption support
|
297 | =============================
|
298 |
|
299 | The SDK supports end-to-end encryption via the Olm and Megolm protocols, using
|
300 | [libolm](https://gitlab.matrix.org/matrix-org/olm). It is left up to the
|
301 | application to make libolm available, via the ``Olm`` global.
|
302 |
|
303 | It is also necessry to call ``matrixClient.initCrypto()`` after creating a new
|
304 | ``MatrixClient`` (but **before** calling ``matrixClient.startClient()``) to
|
305 | initialise the crypto layer.
|
306 |
|
307 | If the ``Olm`` global is not available, the SDK will show a warning, as shown
|
308 | below; ``initCrypto()`` will also fail.
|
309 |
|
310 | ```
|
311 | Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined
|
312 | ```
|
313 |
|
314 | If the crypto layer is not (successfully) initialised, the SDK will continue to
|
315 | work for unencrypted rooms, but it will not support the E2E parts of the Matrix
|
316 | specification.
|
317 |
|
318 | To provide the Olm library in a browser application:
|
319 |
|
320 | * download the transpiled libolm (from https://packages.matrix.org/npm/olm/).
|
321 | * load ``olm.js`` as a ``<script>`` *before* ``browser-matrix.js``.
|
322 |
|
323 | To provide the Olm library in a node.js application:
|
324 |
|
325 | * ``yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz``
|
326 | (replace the URL with the latest version you want to use from
|
327 | https://packages.matrix.org/npm/olm/)
|
328 | * ``global.Olm = require('olm');`` *before* loading ``matrix-js-sdk``.
|
329 |
|
330 | If you want to package Olm as dependency for your node.js application, you can
|
331 | use ``yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz``. If your
|
332 | application also works without e2e crypto enabled, add ``--optional`` to mark it
|
333 | as an optional dependency.
|
334 |
|
335 |
|
336 | Contributing
|
337 | ============
|
338 | *This section is for people who want to modify the SDK. If you just
|
339 | want to use this SDK, skip this section.*
|
340 |
|
341 | First, you need to pull in the right build tools:
|
342 | ```
|
343 | $ yarn install
|
344 | ```
|
345 |
|
346 | Building
|
347 | --------
|
348 |
|
349 | To build a browser version from scratch when developing::
|
350 | ```
|
351 | $ yarn build
|
352 | ```
|
353 |
|
354 | To constantly do builds when files are modified (using ``watchify``)::
|
355 | ```
|
356 | $ yarn watch
|
357 | ```
|
358 |
|
359 | To run tests (Jasmine)::
|
360 | ```
|
361 | $ yarn test
|
362 | ```
|
363 |
|
364 | To run linting:
|
365 | ```
|
366 | $ yarn lint
|
367 | ```
|