This JavaScript library is meant to facilitate writing NodeJS and browser apps for a Pryv.io platform, it follows the Pryv.io App Guidelines.
Prerequisites: Node 12
- Setup:
npm run setup
- Build pryv.js library for browsers:
npm run build
, the result is published in./dist
- Build documentation:
npm run doc
, the result is published in./dist/docs
- Node Tests:
npm run test
- Coverage:
npm run cover
, the result is visible in./coverage
- Browser tests: build, then
npm run webserver
and open https://l.rec.la:9443/tests/browser-tests.html?pryvServiceInfoUrl=https://zouzou.com/service/info - Update on CDN: After running setup and build scripts, run
npm run gh-pages ${COMMIT_MESSAGE}
. If this fails, runnpm run clear
to rebuild a freshdist/
folder
- Import
- Obtaining a Pryv.Connection
- API calls
- Advanced usage of API calls with optional individual result and progress callbacks
- Get Events Streamed
- Events with Attachments
- High Frequency Events
- Service Information and assets
- Pryv.Browser & Visual assets
<script src="https://api.pryv.com/lib-js/pryv.js"></script>
- ES6:
https://api.pryv.com/lib-js/pryv-es6.js
- Bundle: (Socket.io + Monitor + Lib-js)
https://api.pryv.com/lib-js/pryv-socket.io-monitor.js
. This library can be extended with two packages:- Socket.io extension: https://github.com/pryv/lib-js-socket.io
- Monitor extension: https://github.com/pryv/lib-js-monitor
- Save notes and measure simple form: Example on codepen.io
Install with: npm install pryv --save
const Pryv = require('pryv');
A connection is an authenticated link to a Pryv.io account.
The format of the API endpoint can be found in your platform's service information under the api
property. The most frequent one has the following format: https://{token}@{api-endpoint}
const apiEndpoint = 'https://[email protected]';
const connection = new Pryv.Connection(apiEndpoint);
const service = new Pryv.Service('https://reg.pryv.me/service/info');
const apiEndpoint = await service.apiEndpointFor(username, token);
const connection = new Pryv.Connection(apiEndpoint);
The following code is an implementation of the Pryv.io Authentication process.
<!doctype html>
<html>
<head>
<title>Pryv - Javascript Lib</title>
<script src="https://api.pryv.com/lib-js/pryv.js"></script>
</head>
<body>
<span id="pryv-button"></span>
<script>
var connection = null;
var authSettings = {
spanButtonID: 'pryv-button', // span id the DOM that will be replaced by the Service specific button
onStateChange: pryvAuthStateChange, // event Listener for Authentication steps
authRequest: { // See: https://api.pryv.com/reference/#auth-request
requestingAppId: 'lib-js-test',
languageCode: 'fr', // optional (default english)
requestedPermissions: [
{
streamId: 'test',
defaultName: 'test',
level: 'manage'
}
],
clientData: {
'app-web-auth:description': {
'type': 'note/txt', 'content': 'This is a consent message.'
}
},
// referer: 'my test with lib-js', // optional string to track registration source
}
};
function pryvAuthStateChange(state) { // called each time the authentication state changed
console.log('##pryvAuthStateChange', state);
if (state.id === Pryv.Browser.AuthStates.AUTHORIZED) {
connection = new Pryv.Connection(state.apiEndpoint);
logToConsole('# Browser succeeded for user ' + connection.apiEndpoint);
}
if (state.id === Pryv.Browser.AuthStates.LOGOUT) {
connection = null;
logToConsole('# Logout');
}
}
var serviceInfoUrl = 'https://api.pryv.com/lib-js/demos/service-info.json';
(async function () {
var service = await Pryv.Browser.setupAuth(authSettings, serviceInfoUrl);
})();
</script>
</body>
</html>
Implementation of access info.
const apiEndpoint = 'https://[email protected]';
const connection = new Pryv.Connection(apiEndpoint);
const accessInfo = await connection.accessInfo();
const serviceInfoUrl = 'https://reg.pryv.me/service/info';
const appId = 'lib-js-sample';
const service = new Pryv.Service(serviceInfoUrl);
const connection = await service.login(username, password, appId);
Api calls are based on the batch
call specifications: Call batch API reference
const apiCalls = [
{
"method": "streams.create",
"params": { "id": "heart", "name": "Heart" }
},
{
"method": "events.create",
"params": { "time": 1385046854.282, "streamId": "heart", "type": "frequency/bpm", "content": 90 }
},
{
"method": "events.create",
"params": { "time": 1385046854.283, "streamId": "heart", "type": "frequency/bpm", "content": 120 }
}
]
try {
const result = await connection.api(apiCalls)
} catch (e) {
// handle error
}
let count = 0;
// the following will be called on each API method result it was provided for
function handleResult(result) { console.log('Got result ' + count++ + ': ' + JSON.stringify(result)); }
function progress(percentage) { console.log('Processed: ' + percentage + '%'); }
const apiCalls = [
{
method: 'streams.create',
params: { id: 'heart', name: 'Heart' }
},
{
method: 'events.create',
params: { time: 1385046854.282, streamId: 'heart', type: 'frequency/bpm', content: 90 },
handleResult: handleResult
},
{
method: 'events.create',
params: { time: 1385046854.283, streamId: 'heart', type: 'frequency/bpm', content: 120 },
handleResult: handleResult
}
]
try {
const result = await connection.api(apiCalls, progress)
} catch (e) {
// handle error
}
When events.get
will provide a large result set, it is recommended to use a method that streams the result instead of the batch API call.
Pryv.Connection.getEventsStreamed()
parses the response JSON as soon as data is available and calls the forEachEvent()
callback on each event object.
The callback is meant to store the events data, as the function does not return the API call result, which could overflow memory in case of JSON deserialization of a very large data set. Instead, the function returns an events count and eventually event deletions count as well as the common metadata.
const now = (new Date()).getTime() / 1000;
const queryParams = { fromTime: 0, toTime: now, limit: 10000};
const events = [];
function forEachEvent(event) {
events.push(event);
}
try {
const result = await connection.getEventsStreamed(queryParams, forEachEvent);
} catch (e) {
// handle error
}
{
eventsCount: 10000,
meta:
{
apiVersion: '1.4.26',
serverTime: 1580728336.864,
serial: '2019061301'
}
}
const now = (new Date()).getTime() / 1000;
const queryParams = { fromTime: 0, toTime: now, includeDeletions: true, modifiedSince: 0};
const events = [];
function forEachEvent(event) {
events.push(event);
// events with .deleted or/and .trashed properties can be tracked here
}
try {
const result = await connection.getEventsStreamed(queryParams, forEachEvent);
} catch (e) {
// handle error
}
{
eventDeletionsCount: 150,
eventsCount: 10000,
meta:
{
apiVersion: '1.4.26',
serverTime: 1580728336.864,
serial: '2019061301'
}
}
This shortcut allows to create an event with an attachment in a single API call.
const filePath = './test/my_image.png';
const result = await connection.createEventWithFile(
{
type: 'picture/attached',
streamId: 'data'
},
filePath
);
From an Input field
<input type="file" id="file-upload"><button onClick='uploadFile()'>Save Value</button>
<script>
var formData = new FormData();
formData.append(
'file0',
document.getElementById('create-file').files[0]
) ;
connection.createEventWithFormData(
{
type: 'file/attached',
streamId: 'test'
},
formData)
.then(function (res, err) {
// handle result here
}
);
</script>
Progamatically created content:
var formData = new FormData();
var blob = new Blob(
['Hello'],
{ type: "text/txt" }
);
formData.append("webmasterfile", blob);
connect.createEventWithFormData(
{
type: 'file/attached',
streamId: 'data'
},
formData)
.then(function (res, err) {
// handle result here
}
);
Reference: https://api.pryv.com/reference/#hf-events
function generateSerie() {
const serie = [];
for (let t = 0; t < 100000, t++) { // t will be the deltatime in seconds
serie.push([t, Math.sin(t/1000)]);
}
return serie;
}
const pointsA = generateSerie();
const pointsB = generateSerie();
function postHFData(points) { // must return a Promise
return async function (result) { // will be called each time an HF event is created
return await connection.addPointsToHFEvent(result.event.id, ['deltaTime', 'value'], points);
}
}
const apiCalls = [
{
method: 'streams.create',
params: { id: 'signal1', name: 'Signal1' }
},
{
method: 'streams.create',
params: { id: 'signal2', name: 'Signal2' }
},
{
method: 'events.create',
params: { streamId: 'signal1', type: 'serie:frequency/bpm' },
handleResult: postHFData(pointsA)
},
{
method: 'events.create',
params: { streamId: 'signal2', type: 'serie:frequency/bpm' },
handleResult: postHFData(pointsB)
}
]
try {
const result = await connection.api(apiCalls)
} catch (e) {
// handle error
}
A Pryv.io deployment is a unique "Service", as an example Pryv Lab is a service, deployed on the pryv.me domain name.
It relies on the content of a service information configuration, See: Service Information API reference
Exposes tools to interact with Pryv.io at a "Platform" level.
const service = new Pryv.Service('https://reg.pryv.me/service/info');
Service information properties can be overriden with specific values. This might be useful to test new designs on production platforms.
const serviceInfoUrl = 'https://reg.pryv.me/service/info';
const serviceCustomizations = {
name: 'Pryv Lab 2',
assets: {
definitions: 'https://pryv.github.io/assets-pryv.me/index.json'
}
}
const service = new Pryv.Service(serviceInfoUrl, serviceCustomizations);
See: Pryv.Service for more details
-
service.info()
- returns the content of the serviceInfo in a Promise// example: get the name of the platform const serviceName = await service.info().name
-
service.infoSync()
: returns the cached content of the serviceInfo, requiresservice.info()
to be called first. -
service.apiEndpointFor(username, token)
Will return the corresponding API endpoint for the provided credentials,token
can be omitted.
A single Web App might need to be run on different Pryv.io platforms. This is the case of most Pryv.io demonstrators.
The corresponding Pryv.io platform can be specified by providing the Service Information URL as query parameter pryvServiceInfoUrl
as per the Pryv App Guidelines. It can be extracted using Pryv.Browser.serviceInfoFromUrl()
.
Example of usage for web App with the url https://api.pryv.com/app-web-access/?pryvServiceInfoUrl=https://reg.pryv.me/service/info
let defaultServiceInfoUrl = 'https://reg.pryv.me/service/info';
// if present override serviceInfoURL from URL query param "?pryvServiceInfoUrl=.."
serviceInfoUrl = Pryv.Browser.serviceInfoFromUrl() || defaultServiceInfoUrl;
(async function () {
var service = await Pryv.Browser.setupAuth(authSettings, serviceInfoUrl, serviceCustomizations);
})();
To customize assets and visuals refer to: pryv.me assets github
To customize the Sign in Button refer to: sign in button in pryv.me assets
(service.assets()).setAllDefaults()
: loads the css
and favicon
properties of assets definitions.
(async function () {
const service = await Pryv.Browser.setupAuth(authSettings, serviceInfoUrl);
(await service.assets()).setAllDefaults(); // will load the default Favicon and CSS for this platform
})();
- Added Connection.username()
- Various dependencies upgrades
- Fixing Origin header in Browser distribution