pryv 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsdoc-conf.json +29 -0
- package/.mocharc.js +13 -0
- package/LICENSE.md +27 -0
- package/README.md +723 -0
- package/package.json +57 -0
- package/scripts/setup-environment-dev.sh +28 -0
- package/scripts/upload.sh +15 -0
- package/src/Auth/AuthController.js +276 -0
- package/src/Auth/AuthStates.js +20 -0
- package/src/Auth/LoginMessages.js +29 -0
- package/src/Auth/index.js +43 -0
- package/src/Browser/CookieUtils.js +51 -0
- package/src/Browser/LoginButton.js +199 -0
- package/src/Browser/index.js +55 -0
- package/src/Connection.js +331 -0
- package/src/Pryv.js +19 -0
- package/src/Service.js +197 -0
- package/src/ServiceAssets.js +162 -0
- package/src/index-socket.io-monitor.js +4 -0
- package/src/index.html +17 -0
- package/src/index.js +3 -0
- package/src/lib/browser-getEventStreamed.js +80 -0
- package/src/lib/json-parser.js +156 -0
- package/src/utils.js +136 -0
- package/test/Browser.AuthController.test.js +97 -0
- package/test/Browser.test.js +79 -0
- package/test/Connection.test.js +455 -0
- package/test/Service.test.js +89 -0
- package/test/ServiceAssets.test.js +79 -0
- package/test/Y.png +0 -0
- package/test/browser-index.js +11 -0
- package/test/browser-tests.html +31 -0
- package/test/helpers.js +8 -0
- package/test/load-test-account.js +108 -0
- package/test/test-data.js +92 -0
- package/test/utils.test.js +68 -0
- package/web-demos/auth-with-redirection.html +72 -0
- package/web-demos/auth.html +77 -0
- package/web-demos/custom-login-button.html +158 -0
- package/web-demos/index.html +186 -0
- package/web-demos/service-info.json +13 -0
- package/web-demos/stream-examples.html +80 -0
- package/webpack.config.js +71 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
const Cookies = require('./CookieUtils');
|
|
2
|
+
const AuthStates = require('../Auth/AuthStates');
|
|
3
|
+
const AuthController = require('../Auth/AuthController');
|
|
4
|
+
const Service = require('../Service');
|
|
5
|
+
const Messages = require('../Auth/LoginMessages');
|
|
6
|
+
const utils = require('../utils');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @memberof Pryv.Browser
|
|
10
|
+
*/
|
|
11
|
+
class LoginButton {
|
|
12
|
+
|
|
13
|
+
constructor(authSettings, service) {
|
|
14
|
+
this.authSettings = authSettings;
|
|
15
|
+
this.service = service;
|
|
16
|
+
this.serviceInfo = service.infoSync();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* setup button and load assets
|
|
21
|
+
*/
|
|
22
|
+
async init () {
|
|
23
|
+
// initialize button visuals
|
|
24
|
+
setupButton(this);
|
|
25
|
+
this.languageCode = this.authSettings.authRequest.languageCode || 'en';
|
|
26
|
+
this.messages = Messages(this.languageCode);
|
|
27
|
+
if (this.loginButtonText) {
|
|
28
|
+
await loadAssets(this);
|
|
29
|
+
}
|
|
30
|
+
// set cookie key for authorization data
|
|
31
|
+
this._cookieKey = 'pryv-libjs-' + this.authSettings.authRequest.requestingAppId;
|
|
32
|
+
|
|
33
|
+
// initialize controller
|
|
34
|
+
this.auth = new AuthController(this.authSettings, this.service, this);
|
|
35
|
+
await this.auth.init();
|
|
36
|
+
|
|
37
|
+
return this.service;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onClick () {
|
|
41
|
+
this.auth.handleClick();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async onStateChange (state) {
|
|
45
|
+
switch (state.status) {
|
|
46
|
+
case AuthStates.LOADING:
|
|
47
|
+
this.text = getLoadingMessage(this);
|
|
48
|
+
break;
|
|
49
|
+
case AuthStates.INITIALIZED:
|
|
50
|
+
this.text = getInitializedMessage(this, this.serviceInfo.name);
|
|
51
|
+
break;
|
|
52
|
+
case AuthStates.NEED_SIGNIN:
|
|
53
|
+
const loginUrl = state.authUrl || state.url; // url is deprecated
|
|
54
|
+
if (this.authSettings.authRequest.returnURL) { // open on same page (no Popup)
|
|
55
|
+
location.href = loginUrl;
|
|
56
|
+
return;
|
|
57
|
+
} else {
|
|
58
|
+
startLoginScreen(this, loginUrl);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case AuthStates.AUTHORIZED:
|
|
62
|
+
this.text = state.username;
|
|
63
|
+
this.saveAuthorizationData({
|
|
64
|
+
apiEndpoint: state.apiEndpoint,
|
|
65
|
+
username: state.username
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
case AuthStates.SIGNOUT:
|
|
69
|
+
const message = this.messages.SIGNOUT_CONFIRM ? this.messages.SIGNOUT_CONFIRM : 'Logout ?';
|
|
70
|
+
if (confirm(message)) {
|
|
71
|
+
this.deleteAuthorizationData();
|
|
72
|
+
this.auth.init();
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case AuthStates.ERROR:
|
|
76
|
+
this.text = getErrorMessage(this, state.message);
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
console.log('WARNING Unhandled state for Login: ' + state.status);
|
|
80
|
+
}
|
|
81
|
+
if (this.loginButtonText) {
|
|
82
|
+
this.loginButtonText.innerHTML = this.text;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getAuthorizationData () {
|
|
87
|
+
return Cookies.get(this._cookieKey);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
saveAuthorizationData (authData) {
|
|
91
|
+
Cookies.set(this._cookieKey,authData);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async deleteAuthorizationData () {
|
|
95
|
+
Cookies.del(this._cookieKey);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* not mandatory to implement as non-browsers don't have this behaviour
|
|
100
|
+
* @param {*} authController
|
|
101
|
+
*/
|
|
102
|
+
async finishAuthProcessAfterRedirection (authController) {
|
|
103
|
+
// this step should be applied only for the browser
|
|
104
|
+
if (!utils.isBrowser()) return;
|
|
105
|
+
|
|
106
|
+
// 3. Check if there is a prYvkey as result of "out of page login"
|
|
107
|
+
const url = window.location.href;
|
|
108
|
+
let pollUrl = retrievePollUrl(url);
|
|
109
|
+
if (pollUrl !== null) {
|
|
110
|
+
try {
|
|
111
|
+
const res = await utils.superagent.get(pollUrl);
|
|
112
|
+
authController.state = res.body;
|
|
113
|
+
} catch (e) {
|
|
114
|
+
authController.state = {
|
|
115
|
+
status: AuthStates.ERROR,
|
|
116
|
+
message: 'Cannot fetch result',
|
|
117
|
+
error: e
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function retrievePollUrl (url) {
|
|
123
|
+
const params = utils.getQueryParamsFromURL(url);
|
|
124
|
+
let pollUrl = null;
|
|
125
|
+
if (params.prYvkey) { // deprecated method - To be removed
|
|
126
|
+
pollUrl = authController.serviceInfo.access + params.prYvkey;
|
|
127
|
+
}
|
|
128
|
+
if (params.prYvpoll) {
|
|
129
|
+
pollUrl = params.prYvpoll;
|
|
130
|
+
}
|
|
131
|
+
return pollUrl;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function startLoginScreen (loginButton, authUrl) {
|
|
137
|
+
let screenX = typeof window.screenX !== 'undefined' ? window.screenX : window.screenLeft,
|
|
138
|
+
screenY = typeof window.screenY !== 'undefined' ? window.screenY : window.screenTop,
|
|
139
|
+
outerWidth = typeof window.outerWidth !== 'undefined' ?
|
|
140
|
+
window.outerWidth : document.body.clientWidth,
|
|
141
|
+
outerHeight = typeof window.outerHeight !== 'undefined' ?
|
|
142
|
+
window.outerHeight : (document.body.clientHeight - 22),
|
|
143
|
+
width = 400,
|
|
144
|
+
height = 620,
|
|
145
|
+
left = parseInt(screenX + ((outerWidth - width) / 2), 10),
|
|
146
|
+
top = parseInt(screenY + ((outerHeight - height) / 2.5), 10),
|
|
147
|
+
features = (
|
|
148
|
+
'width=' + width +
|
|
149
|
+
',height=' + height +
|
|
150
|
+
',left=' + left +
|
|
151
|
+
',top=' + top +
|
|
152
|
+
',scrollbars=yes'
|
|
153
|
+
);
|
|
154
|
+
loginButton.popup = window.open(authUrl, 'prYv Sign-in', features);
|
|
155
|
+
|
|
156
|
+
if (!loginButton.popup) {
|
|
157
|
+
// loginButton.auth.stopAuthRequest('FAILED_TO_OPEN_WINDOW');
|
|
158
|
+
console.log('Pop-up blocked. A second click should allow it.');
|
|
159
|
+
} else if (window.focus) {
|
|
160
|
+
loginButton.popup.focus();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function setupButton(loginBtn) {
|
|
165
|
+
loginBtn.loginButtonSpan = document.getElementById(loginBtn.authSettings.spanButtonID);
|
|
166
|
+
|
|
167
|
+
if (!loginBtn.loginButtonSpan) {
|
|
168
|
+
console.log('WARNING: Pryv.Browser initialized with no spanButtonID');
|
|
169
|
+
} else {
|
|
170
|
+
// up to the time the button is loaded use the Span to display eventual
|
|
171
|
+
// error messages
|
|
172
|
+
loginBtn.loginButtonText = loginBtn.loginButtonSpan;
|
|
173
|
+
|
|
174
|
+
// bind actions dynamically to the button click
|
|
175
|
+
loginBtn.loginButtonSpan.addEventListener('click', loginBtn.onClick.bind(loginBtn));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Loads the style from the service info
|
|
181
|
+
*/
|
|
182
|
+
async function loadAssets(loginBtn) {
|
|
183
|
+
const assets = await loginBtn.service.assets();
|
|
184
|
+
loginBtn.loginButtonSpan.innerHTML = await assets.loginButtonGetHTML();
|
|
185
|
+
loginBtn.loginButtonText = document.getElementById('pryv-access-btn-text');
|
|
186
|
+
}
|
|
187
|
+
module.exports = LoginButton;
|
|
188
|
+
|
|
189
|
+
function getErrorMessage (loginButton, message) {
|
|
190
|
+
return loginButton.messages.ERROR + ': ' + message;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function getLoadingMessage (loginButton) {
|
|
194
|
+
return loginButton.messages.LOADING;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function getInitializedMessage (loginButton, serviceName) {
|
|
198
|
+
return loginButton.messages.LOGIN + ': ' + serviceName;
|
|
199
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const LoginButton = require('./LoginButton');
|
|
2
|
+
const CookieUtils = require('./CookieUtils');
|
|
3
|
+
const Service = require('../Service');
|
|
4
|
+
const utils = require('../utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @memberof Pryv
|
|
8
|
+
* @namespace Pryv.Browser
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Start an authentication process
|
|
13
|
+
* @memberof Pryv.Browser
|
|
14
|
+
* @param {Object} settings
|
|
15
|
+
* @param {Object} settings.authRequest See https://api.pryv.com/reference/#data-structure-access
|
|
16
|
+
* @param {string} [settings.authRequest.languageCode] Language code, as per LoginButton Messages: 'en', 'fr
|
|
17
|
+
* @param {string} settings.authRequest.requestingAppId Application id, ex: 'my-app'
|
|
18
|
+
* @param {Object} settings.authRequest.requestedPermissions
|
|
19
|
+
* @param {string | boolean} settings.authRequest.returnURL : false, // set this if you don't want a popup
|
|
20
|
+
* @param {string} [settings.authRequest.referer] To track registration source
|
|
21
|
+
* @param {string} settings.spanButtonID set and <span> id in DOM to insert default login button or null for custom
|
|
22
|
+
* @param {Browser.AuthStateChangeHandler} settings.onStateChange
|
|
23
|
+
* @param {string} [settings.returnURL=auto#] Set to "self#" to disable popup and force using the same page. Set a custom url when process is finished (specific use cases). Should always end by # ? or &
|
|
24
|
+
* @param {string} serviceInfoUrl
|
|
25
|
+
* @param {Object} [serviceCustomizations] override properties of serviceInfoUrl
|
|
26
|
+
* @returns {Pryv.Service}
|
|
27
|
+
*/
|
|
28
|
+
async function setupAuth (settings, serviceInfoUrl, serviceCustomizations, HumanInteraction = LoginButton) {
|
|
29
|
+
|
|
30
|
+
let service = new Service(serviceInfoUrl, serviceCustomizations);
|
|
31
|
+
await service.info()
|
|
32
|
+
|
|
33
|
+
const humanInteraction = new HumanInteraction(settings, service);
|
|
34
|
+
await HumanInteraction.init();
|
|
35
|
+
|
|
36
|
+
return service;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Util to grab parameters from url query string
|
|
41
|
+
* @param {*} url
|
|
42
|
+
*/
|
|
43
|
+
function getServiceInfoFromURL (url) {
|
|
44
|
+
const queryParams = utils.getQueryParamsFromURL(url || window.location.href);
|
|
45
|
+
return queryParams['pryvServiceInfoUrl'];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
LoginButton: LoginButton,
|
|
50
|
+
CookieUtils: CookieUtils,
|
|
51
|
+
// retro-compatibility for lib-js < 2.0.9
|
|
52
|
+
AuthStates: require('../Auth/AuthStates'),
|
|
53
|
+
setupAuth: require('../Auth').setupAuth,
|
|
54
|
+
serviceInfoFromUrl: getServiceInfoFromURL
|
|
55
|
+
};
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
|
|
2
|
+
const utils = require('./utils.js');
|
|
3
|
+
|
|
4
|
+
const jsonParser = require('./lib/json-parser');
|
|
5
|
+
|
|
6
|
+
const browserGetEventStreamed = require('./lib/browser-getEventStreamed');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @class Connection
|
|
11
|
+
* A connection is an authenticated link to a Pryv.io account.
|
|
12
|
+
*
|
|
13
|
+
* @type {TokenAndEndpoint}
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* create a connection for the user 'tom' on 'pryv.me' backend with the token 'TTZycvBTiq'
|
|
17
|
+
* const conn = new Pryv.Connection('https://TTZycvBTiq@tom.pryv.me');
|
|
18
|
+
*
|
|
19
|
+
* @property {string} [token]
|
|
20
|
+
* @property {string} endpoint
|
|
21
|
+
* @memberof Pryv
|
|
22
|
+
*
|
|
23
|
+
* @constructor
|
|
24
|
+
* @this {Connection}
|
|
25
|
+
* @param {PryvApiEndpoint} pryvApiEndpoint
|
|
26
|
+
* @param {Pryv.Service} [service] - eventually initialize Connection with a Service
|
|
27
|
+
*/
|
|
28
|
+
class Connection {
|
|
29
|
+
|
|
30
|
+
constructor(pryvApiEndpoint, service) {
|
|
31
|
+
const { token, endpoint } = utils.extractTokenAndApiEndpoint(pryvApiEndpoint);
|
|
32
|
+
this.token = token;
|
|
33
|
+
this.endpoint = endpoint;
|
|
34
|
+
this.options = {};
|
|
35
|
+
this.options.chunkSize = 1000;
|
|
36
|
+
this._deltaTime = { value: 0, weight: 0 };
|
|
37
|
+
if (! service instanceof Service) { throw new Error('Invalid service param'); }
|
|
38
|
+
this._service = service;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* get Pryv.Service object relative to this connection
|
|
43
|
+
* @readonly
|
|
44
|
+
* @property {Pryv.Service} service
|
|
45
|
+
*/
|
|
46
|
+
get service() {
|
|
47
|
+
if (this._service) return this._service;
|
|
48
|
+
this._service = new Service(this.endpoint + 'service/info');
|
|
49
|
+
return this._service;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* get username.
|
|
54
|
+
* It's async as in it constructed from access info
|
|
55
|
+
* @param {*} arrayOfAPICalls
|
|
56
|
+
* @param {*} progress
|
|
57
|
+
*/
|
|
58
|
+
async username() {
|
|
59
|
+
const accessInfo = await this.accessInfo();
|
|
60
|
+
return accessInfo.user.username;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* get access info
|
|
65
|
+
* It's async as it is constructed with get function.
|
|
66
|
+
*/
|
|
67
|
+
async accessInfo(){
|
|
68
|
+
return this.get("access-info", null);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Issue a Batch call https://api.pryv.com/reference/#call-batch .
|
|
73
|
+
* arrayOfAPICalls will be splited in multiple calls if the size is > `conn.options.chunkSize` .
|
|
74
|
+
* Default chunksize is 1000.
|
|
75
|
+
* @param {Array.<MethodCall>} arrayOfAPICalls Array of Method Calls
|
|
76
|
+
* @param {Function} [progress] Return percentage of progress (0 - 100);
|
|
77
|
+
* @returns {Promise<Array>} Promise to Array of results matching each method call in order
|
|
78
|
+
*/
|
|
79
|
+
async api(arrayOfAPICalls, progress) {
|
|
80
|
+
function httpHandler(batchCall) {
|
|
81
|
+
return this.post('', batchCall);
|
|
82
|
+
};
|
|
83
|
+
return await this._chunkedBatchCall(arrayOfAPICalls, progress, httpHandler.bind(this));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
async _chunkedBatchCall(arrayOfAPICalls, progress, callHandler) {
|
|
90
|
+
if (! Array.isArray(arrayOfAPICalls)) {
|
|
91
|
+
throw new Error('Pryv.api() takes an array as input');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const res = [];
|
|
95
|
+
let percent = 0;
|
|
96
|
+
for (let cursor = 0; arrayOfAPICalls.length >= cursor; cursor += this.options.chunkSize) {
|
|
97
|
+
const thisBatch = [];
|
|
98
|
+
const cursorMax = Math.min(cursor + this.options.chunkSize, arrayOfAPICalls.length);
|
|
99
|
+
// copy only method and params into a back call to be exuted
|
|
100
|
+
for (let i = cursor; i < cursorMax ; i++) {
|
|
101
|
+
thisBatch.push({ method: arrayOfAPICalls[i].method, params: arrayOfAPICalls[i].params});
|
|
102
|
+
}
|
|
103
|
+
const resRequest = await callHandler(thisBatch);
|
|
104
|
+
|
|
105
|
+
// result checks
|
|
106
|
+
if (! resRequest || ! Array.isArray(resRequest.results)) {
|
|
107
|
+
throw new Error('API call result is not an Array: ' + JSON.stringify(resRequest));
|
|
108
|
+
}
|
|
109
|
+
if (resRequest.results.length != thisBatch.length) {
|
|
110
|
+
throw new Error('API call result Array does not match request: ' + JSON.stringify(resRequest));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
// eventually call handleResult
|
|
115
|
+
for (let i = 0; i < resRequest.results.length; i++) {
|
|
116
|
+
if (arrayOfAPICalls[i + cursor].handleResult) {
|
|
117
|
+
await arrayOfAPICalls[i + cursor].handleResult.call(null, resRequest.results[i]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
Array.prototype.push.apply(res, resRequest.results)
|
|
121
|
+
percent = Math.round(100 * res.length / arrayOfAPICalls.length);
|
|
122
|
+
if (progress) { progress(percent, res); }
|
|
123
|
+
}
|
|
124
|
+
return res;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Post to API return results
|
|
129
|
+
* @param {(Array | Object)} data
|
|
130
|
+
* @param {Object} queryParams
|
|
131
|
+
* @param {string} path
|
|
132
|
+
* @returns {Promise<Array|Object>} Promise to result.body
|
|
133
|
+
*/
|
|
134
|
+
async post(path, data, queryParams) {
|
|
135
|
+
const now = Date.now() / 1000;
|
|
136
|
+
const res = await this.postRaw(path, data, queryParams);
|
|
137
|
+
this._handleMeta(res.body, now);
|
|
138
|
+
return res.body;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Raw Post to API return superagent object
|
|
143
|
+
* @param {Array | Object} data
|
|
144
|
+
* @param {Object} queryParams
|
|
145
|
+
* @param {string} path
|
|
146
|
+
* @returns {request.superagent} Promise from superagent's post request
|
|
147
|
+
*/
|
|
148
|
+
async postRaw(path, data, queryParams) {
|
|
149
|
+
return this._post(path)
|
|
150
|
+
.query(queryParams)
|
|
151
|
+
.send(data);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
_post(path) {
|
|
155
|
+
return utils.superagent.post(this.endpoint + path)
|
|
156
|
+
.set('Authorization', this.token)
|
|
157
|
+
.set('accept', 'json');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Post to API return results
|
|
162
|
+
* @param {Object} queryParams
|
|
163
|
+
* @param {string} path
|
|
164
|
+
* @returns {Promise<Array|Object>} Promise to result.body
|
|
165
|
+
*/
|
|
166
|
+
async get(path, queryParams) {
|
|
167
|
+
const now = Date.now() / 1000;
|
|
168
|
+
const res = await this.getRaw(path, queryParams);
|
|
169
|
+
this._handleMeta(res.body, now);
|
|
170
|
+
return res.body
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Raw Get to API return superagent object
|
|
175
|
+
* @param {Object} queryParams
|
|
176
|
+
* @param {string} path
|
|
177
|
+
* @returns {request.superagent} Promise from superagent's get request
|
|
178
|
+
*/
|
|
179
|
+
getRaw(path, queryParams) {
|
|
180
|
+
path = path || '';
|
|
181
|
+
return utils.superagent.get(this.endpoint + path)
|
|
182
|
+
.set('Authorization', this.token)
|
|
183
|
+
.set('accept', 'json')
|
|
184
|
+
.query(queryParams);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* ADD Data Points to HFEvent (flatJSON format)
|
|
189
|
+
* https://api.pryv.com/reference/#add-hf-series-data-points
|
|
190
|
+
*/
|
|
191
|
+
async addPointsToHFEvent(eventId, fields, points) {
|
|
192
|
+
const res = await this.post('events/' + eventId + '/series',
|
|
193
|
+
{
|
|
194
|
+
format: 'flatJSON',
|
|
195
|
+
fields: fields,
|
|
196
|
+
points: points
|
|
197
|
+
});
|
|
198
|
+
if (!res.status === 'ok') {
|
|
199
|
+
throw new Error('Failed loading serie: ' + JSON.stringify(res.status));
|
|
200
|
+
}
|
|
201
|
+
return res;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Streamed get Event.
|
|
206
|
+
* Fallbacks to not streamed, for browsers that does not support `fetch()` API
|
|
207
|
+
* @see https://api.pryv.com/reference/#get-events
|
|
208
|
+
* @param {Object} queryParams See `events.get` parameters
|
|
209
|
+
* @param {Function} forEachEvent Function taking one event as parameter. Will be called for each event
|
|
210
|
+
* @returns {Promise<Object>} Promise to result.body transformed with `eventsCount: {count}` replacing `events: [...]`
|
|
211
|
+
*/
|
|
212
|
+
async getEventsStreamed(queryParams, forEachEvent) {
|
|
213
|
+
const myParser = jsonParser(forEachEvent, queryParams.includeDeletions);
|
|
214
|
+
let res = null;
|
|
215
|
+
if (typeof window === 'undefined') { // node
|
|
216
|
+
res = await this.getRaw('events', queryParams)
|
|
217
|
+
.buffer(false)
|
|
218
|
+
.parse(myParser);
|
|
219
|
+
|
|
220
|
+
} else if (typeof fetch !== 'undefined' && !(typeof navigator != 'undefined' && navigator.product == 'ReactNative')) { // browser supports fetch and it is not react native
|
|
221
|
+
res = await browserGetEventStreamed(this, queryParams, myParser);
|
|
222
|
+
|
|
223
|
+
} else { // browser no fetch supports
|
|
224
|
+
console.log('WARNING: Browser does not support fetch() required by Pryv.Connection.getEventsStreamed()');
|
|
225
|
+
res = await this.getRaw('events', queryParams);
|
|
226
|
+
res.body.eventsCount = 0;
|
|
227
|
+
if (res.body.events) {
|
|
228
|
+
res.body.events.forEach(forEachEvent);
|
|
229
|
+
res.body.eventsCount += res.body.events.length;
|
|
230
|
+
delete res.body.events;
|
|
231
|
+
}
|
|
232
|
+
if (res.body.eventDeletions) { // deletions are in a seprated Array
|
|
233
|
+
res.body.eventDeletions.forEach(forEachEvent);
|
|
234
|
+
res.body.eventsCount += res.body.eventDeletions.length;
|
|
235
|
+
delete res.body.eventDeletions;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const now = Date.now() / 1000;
|
|
240
|
+
this._handleMeta(res.body, now);
|
|
241
|
+
return res.body
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create an event with attached file
|
|
246
|
+
* NODE.jS ONLY
|
|
247
|
+
* @param {Event} event
|
|
248
|
+
* @param {string} filePath
|
|
249
|
+
*/
|
|
250
|
+
async createEventWithFile(event, filePath) {
|
|
251
|
+
const res = await this._post('events')
|
|
252
|
+
.field('event', JSON.stringify(event))
|
|
253
|
+
.attach('file', filePath);
|
|
254
|
+
|
|
255
|
+
const now = Date.now() / 1000;
|
|
256
|
+
this._handleMeta(res.body, now);
|
|
257
|
+
return res.body
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Create an event from a Buffer
|
|
262
|
+
* NODE.jS ONLY
|
|
263
|
+
* @param {Event} event
|
|
264
|
+
* @param {Buffer} bufferData
|
|
265
|
+
* @param {string} fileName
|
|
266
|
+
*/
|
|
267
|
+
async createEventWithFileFromBuffer(event, bufferData, filename) {
|
|
268
|
+
const res = await this._post('events')
|
|
269
|
+
.field('event', JSON.stringify(event))
|
|
270
|
+
.attach('file', bufferData, filename);
|
|
271
|
+
|
|
272
|
+
const now = Date.now() / 1000;
|
|
273
|
+
this._handleMeta(res.body, now);
|
|
274
|
+
return res.body
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Create an event with attached formData
|
|
279
|
+
* !! BROWSER ONLY
|
|
280
|
+
* @param {Event} event
|
|
281
|
+
* @param {FormData} formData https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
|
|
282
|
+
*/
|
|
283
|
+
async createEventWithFormData(event, formData) {
|
|
284
|
+
formData.append('event', JSON.stringify(event));
|
|
285
|
+
const res = await this._post('events').send(formData);
|
|
286
|
+
return res.body
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Difference in second between the API and locatime
|
|
291
|
+
* deltaTime is refined at each (non Raw) API call
|
|
292
|
+
* @readonly
|
|
293
|
+
* @property {number} deltaTime
|
|
294
|
+
*/
|
|
295
|
+
get deltaTime() {
|
|
296
|
+
return this._deltaTime.value;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Pryv API Endpoint of this connection
|
|
301
|
+
* @readonly
|
|
302
|
+
* @property {PryvApiEndpoint} deltaTime
|
|
303
|
+
*/
|
|
304
|
+
get apiEndpoint() {
|
|
305
|
+
return utils.buildPryvApiEndpoint(this);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// private method that handle meta data parsing
|
|
309
|
+
_handleMeta(res, requestLocalTimestamp) {
|
|
310
|
+
if (!res.meta) throw new Error('Cannot find .meta in response.');
|
|
311
|
+
if (!res.meta.serverTime) throw new Error('Cannot find .meta.serverTime in response.');
|
|
312
|
+
|
|
313
|
+
// update deltaTime and weight it
|
|
314
|
+
this._deltaTime.value = (this._deltaTime.value * this._deltaTime.weight + res.meta.serverTime - requestLocalTimestamp) / ++this._deltaTime.weight;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
module.exports = Connection;
|
|
321
|
+
|
|
322
|
+
// service is require "after" to allow circular require
|
|
323
|
+
const Service = require('./Service');
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* API Method call, for batch call https://api.pryv.com/reference/#call-batch
|
|
327
|
+
* @typedef {Object} MethodCall
|
|
328
|
+
* @property {string} method - The method id
|
|
329
|
+
* @property {(Object|Array)} params - The call parameters as required by the method.
|
|
330
|
+
* @property {(Function|Promise)} [handleResult] - Will be called with the result corresponding to this specific call.
|
|
331
|
+
*/
|
package/src/Pryv.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Pryv library
|
|
4
|
+
* @version 1.0
|
|
5
|
+
* @exports Pryv
|
|
6
|
+
* @property {Pryv.Service} Service - To interact with Pryv.io at a "Platform level"
|
|
7
|
+
* @property {Pryv.Connection} Connection - To interact with an individual's (user) data set
|
|
8
|
+
* @property {Pryv.Browser} Browser - Browser Tools - Access request helpers and visuals (button)
|
|
9
|
+
* @property {Pryv.utils} utils - Exposes **superagent** for HTTP calls and tools to manipulate Pryv's Api Endpoints
|
|
10
|
+
*/
|
|
11
|
+
module.exports = {
|
|
12
|
+
Service: require('./Service'),
|
|
13
|
+
Connection: require('./Connection'),
|
|
14
|
+
Auth: require('./Auth'),
|
|
15
|
+
Browser: require('./Browser'),
|
|
16
|
+
utils: require('./utils'),
|
|
17
|
+
version: require('../package.json').version
|
|
18
|
+
}
|
|
19
|
+
|