Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
A Javascript client library for Ably Realtime, a realtime data delivery platform.
This repo contains the Ably Javascript client library, for the browser (including IE8+), Nodejs, React Native, NativeScript and Cordova.
For complete API documentation, see the Ably documentation.
npm install ably
For the realtime library:
var realtime = require('ably').Realtime;
For the rest-only library:
var rest = require('ably').Rest;
Include the Ably library in your HTML:
<script src="https://cdn.ably.io/lib/ably.min-1.js"></script>
The Ably client library follows Semantic Versioning. To lock into a major or minor version of the client library, you can specify a specific version number such as https://cdn.ably.io/lib/ably.min-1.js for all v1.* versions, or https://cdn.ably.io/lib/ably.min-1.0.js for all v1.0.* versions, or you can lock into a single release with https://cdn.ably.io/lib/ably.min-1.0.9.js. Note you can load the non-minified version by omitting min-
from the URL such as https://cdn.ably.io/lib/ably-1.0.js. See https://github.com/ably/ably-js/tags for a list of tagged releases.
For the realtime library:
var realtime = Ably.Realtime;
For the REST only library:
var rest = Ably.Rest;
For React Native, do not use this package. Instead use the ably-react-native package, which wraps ably-js and adds react-native-specific dependencies. See that repo for install instructions.
The TypeScript typings are included in the package and so all you have to do is:
import * as Ably from 'ably';
let realtime = new Ably.Realtime(options);
WebPack will search your node_modules
folder by default, so if you include ably
in your package.json
file, when running Webpack the following will allow you to require
Ably. Alternatively, you can reference the ably-commonjs.js
static file directly if not in your node_modules
folder.
var Ably = require('ably/browser/static/ably-commonjs.js');
var realtime = new Ably.Realtime(options);
If you are using ES6 and or a transpiler that suppots ES6 modules with WebPack, you can include Ably as follows:
import Ably from 'ably/browser/static/ably-commonjs.js'
let realtime = new Ably.Realtime(options)
See the ably-js-react-native repo for React Native usage details.
See the ably-js-nativescript repo for NativeScript usage details.
All examples assume a client has been created as follows:
// basic auth with an API key
var client = new Ably.Realtime(<key string>)
// using a token string
var client = new Ably.Realtime(<token string>)
// using an Options object, see https://www.ably.io/documentation/rest/usage#options
// which must contain at least one auth option, i.e. at least
// one of: key, token, tokenDetails, authUrl, or authCallback
var client = new Ably.Realtime(<options>)
Successful connection:
client.connection.on('connected', function() {
# successful connection
});
Failed connection:
client.connection.on('failed', function() {
# failed connection
});
Given:
var channel = client.channels.get('test');
Subscribe to all events:
channel.subscribe(function(message) {
message.name // 'greeting'
message.data // 'Hello World!'
});
Only certain events:
channel.subscribe('myEvent', function(message) {
message.name // 'myEvent'
message.data // 'myData'
});
// Publish a single message with name and data
channel.publish('greeting', 'Hello World!');
// Optionally, you can use a callback to be notified of success or failure
channel.publish('greeting', 'Hello World!', function(err) {
if(err) {
console.log('publish failed with error ' + err);
} else {
console.log('publish succeeded');
}
})
// Publish several messages at once
channel.publish([{name: 'greeting', data: 'Hello World!'}, ...], callback);
channel.history(function(err, messagesPage) {
messagesPage // PaginatedResult
messagesPage.items // array of Message
messagesPage.items[0].data // payload for first message
messagesPage.items.length // number of messages in the current page of history
messagesPage.hasNext() // true if there are further pages
messagesPage.isLast() // true if this page is the last page
messagesPage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
// Can optionally take an options param, see https://www.ably.io/documentation/rest-api/#message-history
channel.history({start: ..., end: ..., limit: ..., direction: ...}, function(err, messagesPage) { ...});
Getting presence:
channel.presence.get(function(err, presenceSet) {
presenceSet // array of PresenceMessages
});
Note that presence#get on a realtime channel does not return a PaginatedResult, as the library maintains a local copy of the presence set.
Entering (and leaving) the presence set:
channel.presence.enter('my status', function(err) {
// now I am entered
});
channel.presence.update('new status', function(err) {
// my presence data is updated
});
channel.presence.leave(function(err) {
// I've left the presence set
});
If you are using a client which is allowed to use any clientId -- that is, if you didn't specify a clientId when initializing the client, and are using basic auth or a token witha wildcard clientId (see https://www.ably.io/documentation/general/authentication for more information), you can use
channel.presence.enterClient('myClientId', 'status', function(err) { ... });
// and similiarly, updateClient and leaveClient
channel.presence.history(function(err, messagesPage) { // PaginatedResult
messagesPage.items // array of PresenceMessage
messagesPage.items[0].data // payload for first message
messagesPage.items.length // number of messages in the current page of history
messagesPage.hasNext() // true if there are further pages
messagesPage.isLast() // true if this page is the last page
messagesPage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
// Can optionally take an options param, see https://www.ably.io/documentation/rest-api/#message-history
channel.presence.history({start: ..., end: ..., limit: ..., direction: ...}, function(err, messagesPage) { ...});
When a 128 bit or 256 bit key is provided to the library, the data
attributes of all messages are encrypted and decrypted automatically using that key. The secret key is never transmitted to Ably. See https://www.ably.io/documentation/realtime/encryption
// Generate a random 256-bit key for demonstration purposes (in
// practice you need to create one and distribute it to clients yourselves)
Ably.Realtime.Crypto.generateRandomKey(function(err, key) {
var channel = client.channels.get('channelName', { cipher: { key: key } })
channel.subscribe(function(message) {
message.name // 'name is not encrypted'
message.data // 'sensitive data is encrypted'
});
channel.publish('name is not encrypted', 'sensitive data is encrypted');
})
You can also change the key on an existing channel using setOptions (which takes a callback which is called after the new encryption settings have taken effect):
channel.setOptions({cipher: {key: <key>}}, function() {
// New encryption settings are in effect
})
All examples assume a client and/or channel has been created as follows:
// basic auth with an API key
var client = new Ably.Rest(<key string>)
// using token auth
var client = new Ably.Rest(<token string>)
// using an Options object, see https://www.ably.io/documentation/realtime/usage#client-options
// which must contain at least one auth option, i.e. at least
// one of: key, token, tokenDetails, authUrl, or authCallback
var client = new Ably.Rest(<options>)
Given:
var channel = client.channels.get('test');
// Publish a single message with name and data
channel.publish('greeting', 'Hello World!');
// Optionally, you can use a callback to be notified of success or failure
channel.publish('greeting', 'Hello World!', function(err) {
if(err) {
console.log('publish failed with error ' + err);
} else {
console.log('publish succeeded');
}
})
// Publish several messages at once
channel.publish([{name: 'greeting', data: 'Hello World!'}, ...], callback);
channel.history(function(err, messagesPage) {
messagesPage // PaginatedResult
messagesPage.items // array of Message
messagesPage.items[0].data // payload for first message
messagesPage.items.length // number of messages in the current page of history
messagesPage.hasNext() // true if there are further pages
messagesPage.isLast() // true if this page is the last page
messagesPage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
// Can optionally take an options param, see https://www.ably.io/documentation/rest-api/#message-history
channel.history({start: ..., end: ..., limit: ..., direction: ...}, function(err, messagesPage) { ...});
channel.presence.get(function(err, presencePage) { // PaginatedResult
presencePage.items // array of PresenceMessage
presencePage.items[0].data // payload for first message
presencePage.items.length // number of messages in the current page of members
presencePage.hasNext() // true if there are further pages
presencePage.isLast() // true if this page is the last page
presencePage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
channel.presence.history(function(err, messagesPage) { // PaginatedResult
messagesPage.items // array of PresenceMessage
messagesPage.items[0].data // payload for first message
messagesPage.items.length // number of messages in the current page of history
messagesPage.hasNext() // true if there are further pages
messagesPage.isLast() // true if this page is the last page
messagesPage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
// Can optionally take an options param, see https://www.ably.io/documentation/rest-api/#message-history
channel.history({start: ..., end: ..., limit: ..., direction: ...}, function(err, messagesPage) { ...});
See https://www.ably.io/documentation/general/authentication for an explanation of Ably's authentication mechanism.
Requesting a token:
client.auth.requestToken(function(err, tokenDetails) {
// tokenDetails is instance of TokenDetails
// see https://www.ably.io/documentation/rest/authentication/#token-details for its properties
// Now we have the token, we can send it to someone who can instantiate a client with it:
var clientUsingToken = new Ably.Realtime(tokenDetails.token);
});
// requestToken can take two optional params
// tokenParams: https://www.ably.io/documentation/rest/authentication/#token-params
// authOptions: https://www.ably.io/documentation/rest/authentication/#auth-options
client.auth.requestToken(tokenParams, authOptions, function(err, tokenDetails) { ... });
Creating a token request (for example, on a server in response to a
request by a client using the authCallback
or authUrl
mechanisms):
client.auth.createTokenRequest(function(err, tokenRequest) {
// now send the tokenRequest back to the client, which will
// use it to request a token and connect to Ably
});
// createTokenRequest can take two optional params
// tokenParams: https://www.ably.io/documentation/rest/authentication/#token-params
// authOptions: https://www.ably.io/documentation/rest/authentication/#auth-options
client.auth.createTokenRequest(tokenParams, authOptions, function(err, tokenRequest) { ... });
client.stats(function(err, statsPage) { // statsPage as PaginatedResult
statsPage.items // array of Stats
statsPage.items[0].inbound.rest.messages.count; // total messages published over REST
statsPage.items.length; // number of stats in the current page of history
statsPage.hasNext() // true if there are further pages
statsPage.isLast() // true if this page is the last page
statsPage.next(function(nextPage) { ... }); // retrieves the next page as PaginatedResult
});
client.time(function(err, time) { ... }); // time is in ms since epoch
To run both the NodeUnit & Karma Browser tests, simply run the following command:
grunt test
Run the NodeUnit test suite
grunt test:nodeunit
Or run just one or more test files
grunt test:nodeunit --test spec/realtime/auth.test.js
Browser tests are run using Karma test runner.
grunt test:karma
Simply open spec/nodeunit.html in your browser to run the test suite with a nice GUI.
Note: If any files have been added or remove, running the task grunt requirejs
will ensure all the necessary RequireJS dependencies are loaded into the browser by updating spec/support/browser_file_list.js
Run the following command to start a local Nodeunit test runner web server
grunt test:webserver
Open your browser to http://localhost:3000. If you are usig a remote browser, refer to https://docs.saucelabs.com/reference/sauce-connect/ for instructions on setting up a local tunnel to your Nodeunit runner web server.
If you would like to run the tests through Karma, then:
Start a Karma server
karma server
You can optionally connect your browser to the server, visit http://localhost:9876/
Click on the Debug button in the top right, and open your browser's debugging console.
Then run the tests against the Karma server. The test:karma:run
command will concatenate the Ably files beforehand so any changes made in the source will be reflected in the test run.
grunt test:karma:run
All tests are run against the sandbox environment by default. However, the following environment variables can be set before running the Karma server to change the environment the tests are run against.
ABLY_ENV
- defaults to sandbox, however this can be set to another known environment such as 'staging'ABLY_REALTIME_HOST
- explicitly tell the client library to use an alternate host for real-time websocket communication.ABLY_REST_HOST
- explicitly tell the client library to use an alternate host for REST communication.ABLY_PORT
- non-TLS port to use for the tests, defaults to 80ABLY_TLS_PORT
- TLS port to use for the tests, defaults to 443ABLY_USE_TLS
- true or false to enable/disable use of TLS respectivelyABLY_LOG_LEVEL
- Log level for the client libraries, defaults to 2, 4 is MICRO
When using the test webserver grunt test:webserver
the following test variables can be configured by appending them as params in the URL such as http://localhost:3000/nodeunit.html?log_level=4
.
env
- defaults to sandbox, however this can be set to another known environment such as 'staging'realtime_host
- explicitly tell the client library to use an alternate host for real-time websocket communication.host
- explicitly tell the client library to use an alternate host for REST communication.port
- non-TLS port to use for the tests, defaults to 80tls_port
- TLS port to use for the tests, defaults to 443tls
- true or false to enable/disable use of TLS respectivelylog_level
- Log level for the client libraries, defaults to 2, 4 is MICRO
Please visit http://support.ably.io/ for access to our knowledgebase and to ask for any assistance.
You can also view the community reported Github issues.
To see what has changed in recent versions, see the CHANGELOG.
ably-common
repo (git submodule init && git submodule update
)git checkout -b my-new-feature
)git commit -am 'Add some feature'
)grunt test
)git push origin my-new-feature
)grunt compiler
grunt release:patch
(or: "major", "minor", "patch", "prepatch")grunt release:deploy
Copyright (c) 2016 Ably Real-time Ltd, Licensed under the Apache License, Version 2.0. Refer to LICENSE for the license terms.
1.0.9 (2017-11-22)
Add ability for an auth server to trigger a client to move to the failed state by returning an HTTP 403 #434
Enable transient publishes when publish is called on a channel that isn't already attached #430
Fix bug where qs params provided in an authUrl were being discarded after first use #433
Default to logging timestamps on all platforms
Tweak websocket error log levels to avoid logging non-error closes at ERROR level
[note: 1.0.8 was an npm-only release to fix a minor build error in the published artifact]
FAQs
Realtime client library for Ably, the realtime messaging service
The npm package ably receives a total of 77,498 weekly downloads. As such, ably popularity was classified as popular.
We found that ably demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.