pryv 2.4.7 → 3.0.0
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/package.json +4 -3
- package/src/Auth/AuthController.js +46 -29
- package/src/Auth/index.js +3 -3
- package/src/Browser/CookieUtils.js +8 -5
- package/src/Browser/LoginButton.js +7 -4
- package/src/Connection.js +171 -119
- package/src/Service.js +44 -42
- package/src/ServiceAssets.js +17 -11
- package/src/globals.d.ts +76 -0
- package/src/index.d.ts +167 -39
- package/src/index.js +3 -1
- package/src/lib/PryvError.js +30 -0
- package/src/lib/{browser-getEventStreamed.js → getEventStreamed.js} +2 -7
- package/src/lib/json-parser.js +1 -2
- package/src/utils.js +68 -7
- package/test/Browser.AuthController.test.js +10 -10
- package/test/Browser.test.js +10 -10
- package/test/Connection.test.js +7 -33
- package/test/Service.test.js +6 -8
- package/test/ServiceAssets.test.js +8 -9
- package/test/utils.test.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pryv",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Pryv JavaScript library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Pryv",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"author": "Pryv S.A. <info@pryv.com> (https://pryv.com)",
|
|
19
19
|
"main": "src/index.js",
|
|
20
20
|
"types": "src/index.d.ts",
|
|
21
|
-
"dependencies": {
|
|
22
|
-
|
|
21
|
+
"dependencies": {},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.0.0"
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -7,13 +7,15 @@ const AuthStates = require('./AuthStates');
|
|
|
7
7
|
const Messages = require('./LoginMessages');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Controller for authentication flow
|
|
11
|
+
* @memberof pryv.Auth
|
|
11
12
|
*/
|
|
12
13
|
class AuthController {
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {
|
|
15
|
+
* Create an AuthController
|
|
16
|
+
* @param {AuthSettings} settings - Authentication settings
|
|
17
|
+
* @param {Service} service - Pryv service instance
|
|
18
|
+
* @param {CustomLoginButton} loginButton - Login button implementation
|
|
17
19
|
*/
|
|
18
20
|
constructor (settings, service, loginButton) {
|
|
19
21
|
this.settings = settings;
|
|
@@ -50,9 +52,8 @@ class AuthController {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* @returns {Service}
|
|
55
|
+
* Initialize the auth controller. Call this right after instantiation.
|
|
56
|
+
* @returns {Promise<Service>} Promise resolving to the Service instance
|
|
56
57
|
*/
|
|
57
58
|
async init () {
|
|
58
59
|
this.serviceInfo = this.service.infoSync();
|
|
@@ -73,6 +74,7 @@ class AuthController {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
if (loginButton != null && loginButton.finishAuthProcessAfterRedirection != null) {
|
|
77
|
+
// @ts-ignore - this is a valid AuthController
|
|
76
78
|
await loginButton.finishAuthProcessAfterRedirection(this);
|
|
77
79
|
}
|
|
78
80
|
|
|
@@ -87,7 +89,8 @@ class AuthController {
|
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
/**
|
|
90
|
-
*
|
|
92
|
+
* Handle button click - triggers appropriate action based on current state
|
|
93
|
+
* @returns {Promise<void>}
|
|
91
94
|
*/
|
|
92
95
|
async handleClick () {
|
|
93
96
|
if (isAuthorized.call(this)) {
|
|
@@ -113,11 +116,12 @@ class AuthController {
|
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* @param {
|
|
119
|
-
* @param {
|
|
120
|
-
* @param {
|
|
119
|
+
* Compute the return URL for authentication redirect.
|
|
120
|
+
* Used only in browser environments.
|
|
121
|
+
* @param {string} [returnURL] - The return URL setting ('auto#', 'self#', or custom URL)
|
|
122
|
+
* @param {string} [windowLocationForTest] - Mock window.location.href for testing
|
|
123
|
+
* @param {string|Navigator} [navigatorForTests] - Mock navigator for testing
|
|
124
|
+
* @returns {string|boolean} The computed return URL, or false if using popup mode
|
|
121
125
|
*/
|
|
122
126
|
getReturnURL (
|
|
123
127
|
returnURL,
|
|
@@ -154,17 +158,30 @@ class AuthController {
|
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Start the authentication request and polling process
|
|
163
|
+
* @returns {Promise<void>}
|
|
164
|
+
* @see https://pryv.github.io/reference/#auth-request
|
|
165
|
+
*/
|
|
157
166
|
async startAuthRequest () {
|
|
167
|
+
// @ts-ignore - postAccess uses .call(this) for context
|
|
158
168
|
this.state = await postAccess.call(this);
|
|
159
169
|
|
|
160
170
|
await doPolling.call(this);
|
|
161
171
|
|
|
172
|
+
/** @this {AuthController} */
|
|
162
173
|
async function postAccess () {
|
|
163
174
|
try {
|
|
164
|
-
const
|
|
165
|
-
.
|
|
166
|
-
|
|
167
|
-
|
|
175
|
+
const { response, body } = await utils.fetchPost(
|
|
176
|
+
// @ts-ignore - this is bound via .call()
|
|
177
|
+
this.serviceInfo.access,
|
|
178
|
+
// @ts-ignore - this is bound via .call()
|
|
179
|
+
this.settings.authRequest
|
|
180
|
+
);
|
|
181
|
+
if (!response.ok) {
|
|
182
|
+
throw new Error('Access request failed: ' + JSON.stringify(body));
|
|
183
|
+
}
|
|
184
|
+
return body;
|
|
168
185
|
} catch (e) {
|
|
169
186
|
this.state = {
|
|
170
187
|
status: AuthStates.ERROR,
|
|
@@ -175,31 +192,31 @@ class AuthController {
|
|
|
175
192
|
}
|
|
176
193
|
}
|
|
177
194
|
|
|
195
|
+
/** @this {AuthController} */
|
|
178
196
|
async function doPolling () {
|
|
179
|
-
|
|
197
|
+
// @ts-ignore - this is bound via .call()
|
|
198
|
+
if (this.state?.status !== AuthStates.NEED_SIGNIN) {
|
|
180
199
|
return;
|
|
181
200
|
}
|
|
182
|
-
|
|
201
|
+
// @ts-ignore - this is bound via .call()
|
|
202
|
+
const pollResponse = await pollAccess(this.state?.poll);
|
|
183
203
|
|
|
184
204
|
if (pollResponse.status === AuthStates.NEED_SIGNIN) {
|
|
185
|
-
|
|
205
|
+
// @ts-ignore - this is bound via .call()
|
|
206
|
+
setTimeout(await doPolling.bind(this), this.state?.poll_rate_ms);
|
|
186
207
|
} else {
|
|
187
208
|
this.state = pollResponse;
|
|
188
209
|
}
|
|
189
210
|
|
|
190
211
|
async function pollAccess (pollUrl) {
|
|
191
212
|
try {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
} catch (e) {
|
|
195
|
-
if (e.response &&
|
|
196
|
-
e.response.status === 403 &&
|
|
197
|
-
e.response.body &&
|
|
198
|
-
e.response.body.status === 'REFUSED') {
|
|
213
|
+
const { response, body } = await utils.fetchGet(pollUrl);
|
|
214
|
+
if (response.status === 403 && body?.status === 'REFUSED') {
|
|
199
215
|
return { status: AuthStates.INITIALIZED };
|
|
200
|
-
} else {
|
|
201
|
-
return { status: AuthStates.ERROR, message: 'Error while polling for auth request', error: e };
|
|
202
216
|
}
|
|
217
|
+
return body;
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return { status: AuthStates.ERROR, message: 'Error while polling for auth request', error: e };
|
|
203
220
|
}
|
|
204
221
|
}
|
|
205
222
|
}
|
package/src/Auth/index.js
CHANGED
|
@@ -29,11 +29,11 @@ module.exports = {
|
|
|
29
29
|
* @param {string | boolean} settings.authRequest.returnURL : false, // set this if you don't want a popup
|
|
30
30
|
* @param {string} [settings.authRequest.referer] To track registration source
|
|
31
31
|
* @param {string} settings.spanButtonID set and <span> id in DOM to insert default login button or null for custom
|
|
32
|
-
* @param {
|
|
33
|
-
* @param {string} [settings.returnURL
|
|
32
|
+
* @param {Function} settings.onStateChange
|
|
33
|
+
* @param {string} [settings.returnURL] Set to "self#" to disable popup and force using the same page
|
|
34
34
|
* @param {string} serviceInfoUrl
|
|
35
35
|
* @param {Object} [serviceCustomizations] override properties of serviceInfoUrl
|
|
36
|
-
* @returns {
|
|
36
|
+
* @returns {Promise<Service>}
|
|
37
37
|
*/
|
|
38
38
|
async function setupAuth (settings, serviceInfoUrl, serviceCustomizations, HumanInteraction = LoginButton) {
|
|
39
39
|
const service = new Service(serviceInfoUrl, serviceCustomizations);
|
|
@@ -18,9 +18,10 @@ module.exports = {
|
|
|
18
18
|
/**
|
|
19
19
|
* Set a local cookie
|
|
20
20
|
* @memberof pryv.Browser.CookieUtils
|
|
21
|
+
* @template T
|
|
21
22
|
* @param {string} cookieKey - The key for the cookie
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {number} expireInDays - Expiration date in days from now
|
|
23
|
+
* @param {T} value - The value (will be JSON stringified)
|
|
24
|
+
* @param {number} [expireInDays=365] - Expiration date in days from now
|
|
24
25
|
*/
|
|
25
26
|
function set (cookieKey, value, expireInDays) {
|
|
26
27
|
if (!utils.isBrowser()) return;
|
|
@@ -31,7 +32,7 @@ function set (cookieKey, value, expireInDays) {
|
|
|
31
32
|
myDate.setDate(myDate.getDate() + expireInDays);
|
|
32
33
|
let cookieStr = encodeURIComponent(cookieKey) + '=' +
|
|
33
34
|
encodeURIComponent(JSON.stringify(value)) +
|
|
34
|
-
';expires=' + myDate.
|
|
35
|
+
';expires=' + myDate.toUTCString() +
|
|
35
36
|
';domain=.' + hostName + ';path=' + path;
|
|
36
37
|
// do not add SameSite when removing a cookie
|
|
37
38
|
if (expireInDays >= 0) cookieStr += ';SameSite=Strict';
|
|
@@ -41,7 +42,9 @@ function set (cookieKey, value, expireInDays) {
|
|
|
41
42
|
/**
|
|
42
43
|
* Return the value of a local cookie
|
|
43
44
|
* @memberof pryv.Browser.CookieUtils
|
|
44
|
-
* @
|
|
45
|
+
* @template T
|
|
46
|
+
* @param {string} cookieKey - The key
|
|
47
|
+
* @returns {T|undefined} The parsed cookie value or undefined if not found
|
|
45
48
|
*/
|
|
46
49
|
function get (cookieKey) {
|
|
47
50
|
const name = encodeURIComponent(cookieKey);
|
|
@@ -54,7 +57,7 @@ function get (cookieKey) {
|
|
|
54
57
|
/**
|
|
55
58
|
* Delete a local cookie
|
|
56
59
|
* @memberof pryv.Browser.CookieUtils
|
|
57
|
-
* @param cookieKey - The key
|
|
60
|
+
* @param {string} cookieKey - The key
|
|
58
61
|
*/
|
|
59
62
|
function del (cookieKey) {
|
|
60
63
|
set(cookieKey, { deleted: true }, -1);
|
|
@@ -28,6 +28,7 @@ class LoginButton {
|
|
|
28
28
|
setupButton(this);
|
|
29
29
|
this.languageCode = this.authSettings.authRequest.languageCode || 'en';
|
|
30
30
|
this.messages = Messages(this.languageCode);
|
|
31
|
+
// @ts-ignore - loginButtonText is set by setupButton
|
|
31
32
|
if (this.loginButtonText) {
|
|
32
33
|
await loadAssets(this);
|
|
33
34
|
}
|
|
@@ -84,7 +85,9 @@ class LoginButton {
|
|
|
84
85
|
default:
|
|
85
86
|
console.log('WARNING Unhandled state for Login: ' + state.status);
|
|
86
87
|
}
|
|
88
|
+
// @ts-ignore - loginButtonText is set by setupButton
|
|
87
89
|
if (this.loginButtonText) {
|
|
90
|
+
// @ts-ignore
|
|
88
91
|
this.loginButtonText.innerHTML = this.text;
|
|
89
92
|
}
|
|
90
93
|
}
|
|
@@ -114,8 +117,8 @@ class LoginButton {
|
|
|
114
117
|
const pollUrl = retrievePollUrl(url);
|
|
115
118
|
if (pollUrl !== null) {
|
|
116
119
|
try {
|
|
117
|
-
const
|
|
118
|
-
authController.state =
|
|
120
|
+
const { body } = await utils.fetchGet(pollUrl);
|
|
121
|
+
authController.state = body;
|
|
119
122
|
} catch (e) {
|
|
120
123
|
authController.state = {
|
|
121
124
|
status: AuthStates.ERROR,
|
|
@@ -148,8 +151,8 @@ async function startLoginScreen (loginButton, authUrl) {
|
|
|
148
151
|
const outerHeight = typeof window.outerHeight !== 'undefined' ? window.outerHeight : (document.body.clientHeight - 22);
|
|
149
152
|
const width = 400;
|
|
150
153
|
const height = 620;
|
|
151
|
-
const left =
|
|
152
|
-
const top =
|
|
154
|
+
const left = Math.floor(screenX + ((outerWidth - width) / 2));
|
|
155
|
+
const top = Math.floor(screenY + ((outerHeight - height) / 2.5));
|
|
153
156
|
const features = (
|
|
154
157
|
'width=' + width +
|
|
155
158
|
',height=' + height +
|