pryv 2.1.6 → 2.2.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/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020, Pryv S.A.
1
+ Copyright (c) 2020-2021, Pryv S.A.
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
package/README.md CHANGED
@@ -7,11 +7,19 @@ This JavaScript library is meant to facilitate writing NodeJS and browser apps f
7
7
  *Prerequisites*: Node 12
8
8
 
9
9
  - Setup: `npm run setup`
10
+
10
11
  - Build pryv.js library for browsers: `npm run build`, the result is published in `./dist`
12
+
11
13
  - Build documentation: `npm run doc`, the result is published in `./dist/docs`
14
+
15
+ Note: as per v2.1.7 `jsdoc` dev dependency has been removed from package.json .. it should be installed with `npm install jsoc --dev`
16
+
12
17
  - Node Tests: `npm run test`
18
+
13
19
  - Coverage: `npm run cover`, the result is visible in `./coverage`
20
+
14
21
  - Browser tests: **build**, then `npm run webserver` and open [https://l.rec.la:9443/tests/browser-tests.html?pryvServiceInfoUrl=https://zouzou.com/service/info](https://l.rec.la:9443/tests/browser-tests.html?pryvServiceInfoUrl=https://zouzou.com/service/info)
22
+
15
23
  - Update on CDN: After running **setup** and **build** scripts, run `npm run gh-pages ${COMMIT_MESSAGE}`. If this fails, run `npm run clear` to rebuild a fresh `dist/` folder
16
24
 
17
25
  ## Usage
@@ -59,10 +67,10 @@ This JavaScript library is meant to facilitate writing NodeJS and browser apps f
59
67
 
60
68
  #### Others distributions for browsers & extensions:
61
69
 
62
- - ES6: `https://api.pryv.com/lib-js/pryv-es6.js`
70
+ - ES6: `https://api.pryv.com/lib-js/pryv-es6.js`
63
71
  - Bundle: (Socket.io + Monitor + Lib-js) `https://api.pryv.com/lib-js/pryv-socket.io-monitor.js`.
64
- This library can be extended with two packages:
65
- - Socket.io extension: [https://github.com/pryv/lib-js-socket.io](https://github.com/pryv/lib-js-socket.io)
72
+ This library can be extended with two packages:
73
+ - Socket.io extension: [https://github.com/pryv/lib-js-socket.io](https://github.com/pryv/lib-js-socket.io)
66
74
  - Monitor extension: [https://github.com/pryv/lib-js-monitor](https://github.com/pryv/lib-js-monitor)
67
75
 
68
76
  #### Example on code pen:
@@ -71,7 +79,7 @@ This JavaScript library is meant to facilitate writing NodeJS and browser apps f
71
79
 
72
80
  #### Node.js
73
81
 
74
- Install with: `npm install pryv --save `
82
+ Install with: `npm install pryv --save `
75
83
 
76
84
  ```javascript
77
85
  const Pryv = require('pryv');
@@ -100,7 +108,7 @@ const connection = new Pryv.Connection(apiEndpoint);
100
108
 
101
109
  #### Within a WebPage with a login button
102
110
 
103
- The following code is an implementation of the [Pryv.io Authentication process](https://api.pryv.com/reference/#authenticate-your-app).
111
+ The following code is an implementation of the [Pryv.io Authentication process](https://api.pryv.com/reference/#authenticate-your-app).
104
112
 
105
113
  ```html
106
114
  <!doctype html>
@@ -135,7 +143,7 @@ The following code is an implementation of the [Pryv.io Authentication process](
135
143
  // referer: 'my test with lib-js', // optional string to track registration source
136
144
  }
137
145
  };
138
-
146
+
139
147
  function pryvAuthStateChange(state) { // called each time the authentication state changed
140
148
  console.log('##pryvAuthStateChange', state);
141
149
  if (state.id === Pryv.Auth.AuthStates.AUTHORIZED) {
@@ -266,7 +274,7 @@ try {
266
274
  #### result:
267
275
 
268
276
  ```javascript
269
- {
277
+ {
270
278
  eventsCount: 10000,
271
279
  meta:
272
280
  {
@@ -298,7 +306,7 @@ try {
298
306
  #### result:
299
307
 
300
308
  ```javascript
301
- {
309
+ {
302
310
  eventDeletionsCount: 150,
303
311
  eventsCount: 10000,
304
312
  meta:
@@ -331,6 +339,22 @@ const result = await connection.createEventWithFile(
331
339
  );
332
340
  ```
333
341
 
342
+ or from a Buffer
343
+
344
+ ```javascript
345
+ const filePath = './test/my_image.png';
346
+ const bufferData = fs.readFileSync(filePath);
347
+
348
+ const result = await connection.createEventWithFileFromBuffer(
349
+ {
350
+ type: 'picture/attached',
351
+ streamId: 'data'
352
+ },
353
+ bufferData,
354
+ 'my_image.png' // filename
355
+ );
356
+ ```
357
+
334
358
  #### Browser
335
359
 
336
360
  From an Input field
@@ -344,7 +368,7 @@ From an Input field
344
368
  'file0',
345
369
  document.getElementById('create-file').files[0]
346
370
  ) ;
347
-
371
+
348
372
  connection.createEventWithFormData(
349
373
  {
350
374
  type: 'file/attached',
@@ -378,9 +402,24 @@ connect.createEventWithFormData(
378
402
  // handle result here
379
403
  }
380
404
  );
405
+
406
+ // -- alternative with a filename
407
+
408
+ connect.createEventWithFileFromBuffer(
409
+ {
410
+ type: 'file/attached',
411
+ streamId: 'data'
412
+ },
413
+ blob, 'filename.txt') // here we can directly use the blob
414
+ .then(function (res, err) {
415
+ // handle result here
416
+ }
417
+ );
418
+
419
+
381
420
  ```
382
421
 
383
- ### High Frequency Events
422
+ ### High Frequency Events
384
423
 
385
424
  Reference: [https://api.pryv.com/reference/#hf-events](https://api.pryv.com/reference/#hf-events)
386
425
 
@@ -436,9 +475,9 @@ A Pryv.io deployment is a unique "Service", as an example **Pryv Lab** is a serv
436
475
 
437
476
  It relies on the content of a **service information** configuration, See: [Service Information API reference](https://api.pryv.com/reference/#service-info)
438
477
 
439
- #### Pryv.Service
478
+ #### Pryv.Service
440
479
 
441
- Exposes tools to interact with Pryv.io at a "Platform" level.
480
+ Exposes tools to interact with Pryv.io at a "Platform" level.
442
481
 
443
482
  ##### Initizalization with a service info URL
444
483
 
@@ -453,7 +492,7 @@ Service information properties can be overriden with specific values. This might
453
492
  ```javascript
454
493
  const serviceInfoUrl = 'https://reg.pryv.me/service/info';
455
494
  const serviceCustomizations = {
456
- name: 'Pryv Lab 2',
495
+ name: 'Pryv Lab 2',
457
496
  assets: {
458
497
  definitions: 'https://pryv.github.io/assets-pryv.me/index.json'
459
498
  }
@@ -465,7 +504,7 @@ const service = new Pryv.Service(serviceInfoUrl, serviceCustomizations);
465
504
 
466
505
  See: [Pryv.Service](https://pryv.github.io/js-lib/docs/Pryv.Service.html) for more details
467
506
 
468
- - `service.info()` - returns the content of the serviceInfo in a Promise
507
+ - `service.info()` - returns the content of the serviceInfo in a Promise
469
508
 
470
509
  ```javascript
471
510
  // example: get the name of the platform
@@ -480,7 +519,7 @@ See: [Pryv.Service](https://pryv.github.io/js-lib/docs/Pryv.Service.html) for mo
480
519
 
481
520
  #### Pryv.Browser - retrieve serviceInfo from query URL
482
521
 
483
- A single Web App might need to be run on different Pryv.io platforms. This is the case of most Pryv.io demonstrators.
522
+ A single Web App might need to be run on different Pryv.io platforms. This is the case of most Pryv.io demonstrators.
484
523
 
485
524
  The corresponding Pryv.io platform can be specified by providing the Service Information URL as query parameter `pryvServiceInfoUrl` as per the [Pryv App Guidelines](https://api.pryv.com/guides/app-guidelines/). It can be extracted using `Pryv.Browser.serviceInfoFromUrl()` .
486
525
 
@@ -488,7 +527,7 @@ Example of usage for web App with the url https://api.pryv.com/app-web-access/?p
488
527
 
489
528
  ```javascript
490
529
  let defaultServiceInfoUrl = 'https://reg.pryv.me/service/info';
491
- // if present override serviceInfoURL from URL query param "?pryvServiceInfoUrl=.."
530
+ // if present override serviceInfoURL from URL query param "?pryvServiceInfoUrl=.."
492
531
  serviceInfoUrl = Pryv.Browser.serviceInfoFromUrl() || defaultServiceInfoUrl;
493
532
 
494
533
  (async function () {
@@ -539,7 +578,7 @@ async init () {
539
578
 
540
579
  // set cookie key for authorization data - browser only
541
580
  this._cookieKey = 'pryv-libjs-' + this.authSettings.authRequest.requestingAppId;
542
-
581
+
543
582
  // initialize controller
544
583
  this.auth = new AuthController(this.authSettings, this.service, this);
545
584
  await this.auth.init();
@@ -661,8 +700,8 @@ For a more advanced scenario, you can check the default button implementation at
661
700
 
662
701
  #### Redirect user to the authentication page
663
702
 
664
- There is a possibility that you would like to register the user in another page. You can check the [`./web-demos/auth-with-redirection.html`](./web-demos/auth-with-redirection.html) example.
665
- Also you can try the same code in [https://api.pryv.com/lib-js/demos/auth-with-redirection.html](https://api.pryv.com/lib-js/demos/auth-with-redirection.html).
703
+ There is a possibility that you would like to register the user in another page. You can check the [`./web-demos/auth-with-redirection.html`](./web-demos/auth-with-redirection.html) example.
704
+ Also you can try the same code in [https://api.pryv.com/lib-js/demos/auth-with-redirection.html](https://api.pryv.com/lib-js/demos/auth-with-redirection.html).
666
705
  Here is the explanation how to [launch web-demos locally](#launch-web-demos-locally)
667
706
 
668
707
  ### Launch web demos locally
@@ -674,22 +713,30 @@ You can find html examples in the [`./web-demos`](/web-demos) directory. You can
674
713
  ```bash
675
714
  npm run webserver
676
715
  ```
677
-
716
+
678
717
  and open an example with the following URL **https://l.rec.la:9443/demos/EXAMPLE_NAME.html**, like: [https://l.rec.la:9443/demos/auth.html](https://l.rec.la:9443/demos/auth.html)
679
718
 
680
719
  2. as a simple html file (service information must be passed as JSON to avoid CORS problem).
681
720
 
682
721
  # Change Log
683
722
 
723
+ ## 2.2.0
724
+
725
+ - Added TypeScript typings – contribution from @ovesco
726
+
727
+ ## 2.1.7
728
+
729
+ - Removed JSDOC dev dependency for security reason
730
+
684
731
  ## 2.1.0
685
732
 
686
733
  - UI separated from the Authentication logic
687
734
  - Extendable UI feature was added
688
735
 
689
- ## 2.0.3
736
+ ## 2.0.3
690
737
 
691
- - Added Connection.username()
738
+ - Added Connection.username()
692
739
  - Various dependencies upgrades
693
740
  - Fixing Origin header in Browser distribution
694
741
 
695
- ## 2.0.1 Initial Release
742
+ ## 2.0.1 Initial Release
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pryv",
3
- "version": "2.1.6",
3
+ "version": "2.2.0",
4
4
  "homepage": "https://github.com/pryv/lib-js",
5
5
  "description": "Pryv Javascript Library",
6
6
  "keywords": [
@@ -17,11 +17,12 @@
17
17
  "name": "Pryv S.A."
18
18
  },
19
19
  "main": "src/index.js",
20
+ "types": "src/index.d.ts",
20
21
  "license": "BSD-3-Clause",
21
22
  "scripts": {
22
23
  "setup": "./scripts/setup-environment-dev.sh",
23
24
  "build": "webpack --config webpack.config.js",
24
- "doc": "node node_modules/jsdoc/jsdoc.js -c .jsdoc-conf.json",
25
+ "doc": "npx jsdoc -c .jsdoc-conf.json",
25
26
  "test": "mocha --reporter spec test/**/*.test.js --timeout 3000",
26
27
  "test-debug": "mocha --inpect-brk=40000 --reporter spec test/**/*.test.js ",
27
28
  "test:browser": "npm run build; ",
@@ -38,20 +39,19 @@
38
39
  }
39
40
  ],
40
41
  "dependencies": {
41
- "superagent": "^5.2.2"
42
+ "superagent": "^7.0.2"
42
43
  },
43
44
  "devDependencies": {
44
- "@pryv/lib-js-common": "git+https://github.com/pryv/lib-js-common.git#1.0.3",
45
- "@pryv/monitor": "^1.0.2",
46
- "@pryv/socket.io": "^1.0.2",
47
- "chai": "^4.2.0",
45
+ "@pryv/lib-js-common": "github:pryv/lib-js-common#1.0.6",
46
+ "@pryv/monitor": "^1.0.6",
47
+ "@pryv/socket.io": "^1.0.6",
48
+ "chai": "^4.3.4",
48
49
  "chai-as-promised": "^7.1.1",
49
50
  "cuid": "^2.1.8",
50
- "jsdoc": "^3.6.6",
51
- "mocha": "^6.2.3",
52
- "node-fetch": "^2.6.0",
53
- "nyc": "^14.1.1",
54
- "rec-la": "latest",
51
+ "mocha": "^9.1.3",
52
+ "node-fetch": "^2.6.1",
53
+ "nyc": "^15.1.0",
54
+ "rec.la": "latest",
55
55
  "universal-url": "^2.0.0",
56
56
  "zombie": "^6.1.4"
57
57
  }
package/src/Connection.js CHANGED
@@ -257,6 +257,23 @@ class Connection {
257
257
  return res.body
258
258
  }
259
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
+
260
277
  /**
261
278
  * Create an event with attached formData
262
279
  * !! BROWSER ONLY
package/src/index.d.ts ADDED
@@ -0,0 +1,845 @@
1
+ declare module 'pryv' {
2
+ type Timestamp = number;
3
+ type Identifier = string;
4
+ type Level = 'read' | 'contribute' | 'manage' | 'create-only';
5
+ type KeyValue = { [key: string]: string | number };
6
+
7
+ type Attachment = {
8
+ id: Identifier;
9
+ fileName: string;
10
+ type: string;
11
+ size: number;
12
+ readToken: string;
13
+ };
14
+
15
+ type Stream = {
16
+ id: Identifier;
17
+ name: string;
18
+ parentId?: Identifier;
19
+ clientData?: KeyValue;
20
+ children: Identifier[];
21
+ trashed?: boolean;
22
+ created: Timestamp;
23
+ createdBy: Identifier;
24
+ modified: Timestamp;
25
+ modifiedBy: Identifier;
26
+ };
27
+
28
+ type Event = {
29
+ id: Identifier;
30
+ streamIds: Identifier[];
31
+ streamId: Identifier;
32
+ time: Timestamp;
33
+ duration?: Timestamp;
34
+ type: string;
35
+ content?: any;
36
+ tags?: string[];
37
+ description?: string;
38
+ attachments?: Attachment[];
39
+ clientData?: KeyValue;
40
+ trashed?: boolean;
41
+ created: Timestamp;
42
+ createdBy: Identifier;
43
+ modified: Timestamp;
44
+ modifiedBy: Identifier;
45
+ };
46
+
47
+ type Permission = {
48
+ streamId: Identifier;
49
+ level: Level;
50
+ feature?: 'selfRevoke';
51
+ setting?: 'forbidden';
52
+ };
53
+
54
+ type Access = {
55
+ id: Identifier;
56
+ token: string;
57
+ type?: 'personal' | 'app' | 'shared';
58
+ name: string;
59
+ deviceName?: string;
60
+ permissions: Permission[];
61
+ lastUsed?: Timestamp;
62
+ expireAfter?: number;
63
+ expires?: Timestamp;
64
+ deleted?: Timestamp;
65
+ clientData?: KeyValue;
66
+ created: Timestamp;
67
+ createdBy: Identifier;
68
+ modified: Timestamp;
69
+ modifiedBy: Identifier;
70
+ };
71
+
72
+ type FollowedSlice = {
73
+ id: Identifier;
74
+ name: string;
75
+ url: string;
76
+ accessToken: string;
77
+ };
78
+
79
+ type AccountInformation = {
80
+ username: string;
81
+ email: string;
82
+ language: string;
83
+ storageUsed: {
84
+ dbDocuments: number;
85
+ attachedFiles: number;
86
+ };
87
+ };
88
+
89
+ // HTTP only
90
+ type AuditLog = {
91
+ id: Identifier;
92
+ type: string;
93
+ time: Timestamp;
94
+ forwardedFor: string;
95
+ action: string;
96
+ query: string;
97
+ accessId: string;
98
+ status: number;
99
+ errorMessage?: string;
100
+ errorId?: string;
101
+ };
102
+
103
+ type HFSeries = {
104
+ format: 'flatJSON';
105
+ fields: string[];
106
+ points: Array<number | string>;
107
+ };
108
+
109
+ type Run = {
110
+ status: number;
111
+ timestamp: Timestamp;
112
+ };
113
+
114
+ type WebHook = {
115
+ id: Identifier;
116
+ accessId: Identifier;
117
+ url: string;
118
+ minIntervalMs: number;
119
+ maxRetries: number;
120
+ currentRetries: number;
121
+ state: 'active' | 'inactive';
122
+ runCount: number;
123
+ failCount: number;
124
+ lastRun: Run;
125
+ runs: Run[];
126
+ created: Timestamp;
127
+ createdBy: Identifier;
128
+ modified: Timestamp;
129
+ modifiedBy: Identifier;
130
+ };
131
+
132
+ type ItemDeletion = {
133
+ id: Identifier;
134
+ deleted?: Timestamp;
135
+ };
136
+
137
+ type Error = {
138
+ id: string;
139
+ message: string;
140
+ data?: any;
141
+ subErrors?: Error[];
142
+ };
143
+
144
+ type StreamsQuery = {
145
+ any?: Identifier[];
146
+ all?: Identifier[];
147
+ not?: Identifier[];
148
+ };
149
+
150
+ type EventQueryParams = {
151
+ fromTime: Timestamp;
152
+ toTime: Timestamp;
153
+ streams: string[];
154
+ tags: string[];
155
+ types: string[];
156
+ running: boolean;
157
+ sortAscending: boolean;
158
+ skip: number;
159
+ limit: number;
160
+ state: 'default' | 'trashed' | 'all';
161
+ modifiedSince: Timestamp;
162
+ includeDeletion: boolean;
163
+ };
164
+
165
+ type EventQueryParamsStreamQuery = Omit<EventQueryParams, 'streams'> & {
166
+ streams: string[] | StreamsQuery;
167
+ };
168
+
169
+ type EditMetadata = 'created' | 'createdBy' | 'modified' | 'modifiedBy';
170
+
171
+ export type ApiCallMethods = {
172
+ // mfa
173
+ 'mfa.challenge': {
174
+ params: null;
175
+ res: {
176
+ message: string;
177
+ };
178
+ };
179
+ 'mfa.recover': {
180
+ params: {
181
+ recoveryCode: string;
182
+ username: string;
183
+ password: string;
184
+ appId: string;
185
+ };
186
+ res: {
187
+ message: string;
188
+ };
189
+ };
190
+
191
+ // events
192
+ 'events.get': {
193
+ params: Partial<EventQueryParamsStreamQuery>;
194
+ res: {
195
+ eventDeletions?: ItemDeletion[];
196
+ events: Event[];
197
+ };
198
+ };
199
+ 'events.getOne': {
200
+ params: {
201
+ id: Identifier;
202
+ includeHistory?: boolean;
203
+ };
204
+ res: {
205
+ event: Event;
206
+ history?: Event[];
207
+ };
208
+ };
209
+ 'events.create': {
210
+ params: Partial<Omit<Event, 'attachments' | EditMetadata>>;
211
+ res: {
212
+ event: Event;
213
+ };
214
+ };
215
+ 'events.update': {
216
+ params: {
217
+ id: Identifier;
218
+ update: Partial<Omit<Event, 'id' | 'attachments' | EditMetadata>>;
219
+ };
220
+ res: {
221
+ event: Event;
222
+ };
223
+ };
224
+ 'events.deleteAttachment': {
225
+ params: {
226
+ id: Identifier;
227
+ fileId: Identifier;
228
+ };
229
+ res: {
230
+ event: Event;
231
+ };
232
+ };
233
+ 'events.delete': {
234
+ params: {
235
+ id: Identifier;
236
+ };
237
+ res: {
238
+ event: Event;
239
+ };
240
+ };
241
+
242
+ // HFS
243
+ 'hfs.create': {
244
+ params: Partial<Omit<Event, 'attachments' | EditMetadata>>;
245
+ res: {
246
+ event: Event;
247
+ };
248
+ };
249
+ 'hfs.update': {
250
+ params: {
251
+ id: Identifier;
252
+ update: Partial<Omit<Event, 'id' | 'attachments' | EditMetadata>>;
253
+ };
254
+ res: {
255
+ event: Event;
256
+ };
257
+ };
258
+ 'hfs.delete': {
259
+ params: {
260
+ id: Identifier;
261
+ };
262
+ res: {
263
+ event: Event;
264
+ };
265
+ };
266
+
267
+ // Streams
268
+ 'streams.get': {
269
+ params: {
270
+ parentId?: Identifier;
271
+ state?: 'default' | 'all';
272
+ includeDeletionsSince?: Timestamp;
273
+ };
274
+ res: {
275
+ streams: Stream[];
276
+ streamDeletions?: ItemDeletion[];
277
+ };
278
+ };
279
+ 'streams.create': {
280
+ params: Partial<Omit<Stream, 'children' | EditMetadata>>;
281
+ res: {
282
+ stream: Stream;
283
+ };
284
+ };
285
+ 'streams.update': {
286
+ params: {
287
+ id: Identifier;
288
+ update: Partial<Stream>;
289
+ };
290
+ res: {
291
+ stream: Stream;
292
+ };
293
+ };
294
+ 'streams.delete': {
295
+ params: {
296
+ id: Identifier;
297
+ mergeEventsWithParents: 'true' | 'false';
298
+ };
299
+ res: {
300
+ stream: Stream;
301
+ };
302
+ };
303
+
304
+ // Accesses
305
+ 'accesses.get': {
306
+ params: {
307
+ includeExpired?: boolean;
308
+ includeDeletions?: boolean;
309
+ };
310
+ res: {
311
+ accesses: Access[];
312
+ accessDeletions?: Access[];
313
+ };
314
+ };
315
+ 'accesses.create': {
316
+ params: Partial<
317
+ Omit<Access, 'id' | 'lastUsed' | 'expires' | 'deleted' | EditMetadata>
318
+ >;
319
+ res: {
320
+ access: Access;
321
+ };
322
+ };
323
+ 'accesses.delete': {
324
+ params: {
325
+ id: Identifier;
326
+ };
327
+ res: {
328
+ accessDeletion: ItemDeletion;
329
+ relatedDeletions?: ItemDeletion[];
330
+ };
331
+ };
332
+ 'accesses.checkApp': {
333
+ params: {
334
+ requestingAppId: string;
335
+ deviceName?: string;
336
+ requestedPermissions: Array<Permission & { defaultName: string }>;
337
+ };
338
+ res: {
339
+ checkedPermissions?: Permission[];
340
+ mismatchingAccess?: Access;
341
+ matchingAccess?: Access;
342
+ };
343
+ };
344
+ getAccessInfo: {
345
+ params: null;
346
+ res: {
347
+ calls: KeyValue;
348
+ user: KeyValue;
349
+ };
350
+ };
351
+
352
+ // Webhooks
353
+ 'webhooks.get': {
354
+ params: null;
355
+ res: {
356
+ webhooks: WebHook[];
357
+ };
358
+ };
359
+ 'webhooks.getOne': {
360
+ params: {
361
+ id: Identifier;
362
+ };
363
+ res: {
364
+ webhook: WebHook;
365
+ };
366
+ };
367
+ 'webhooks.create': {
368
+ params: {
369
+ webhook: Partial<Pick<WebHook, 'url' | 'state'>>;
370
+ };
371
+ res: {
372
+ webhook: WebHook;
373
+ };
374
+ };
375
+ 'webhooks.update': {
376
+ params: {
377
+ id: Identifier;
378
+ update: Partial<Pick<WebHook, 'state'>>;
379
+ };
380
+ res: {
381
+ webhook: WebHook;
382
+ };
383
+ };
384
+ 'webhooks.delete': {
385
+ params: {
386
+ id: Identifier;
387
+ };
388
+ res: {
389
+ webhookDeletion: ItemDeletion;
390
+ };
391
+ };
392
+ 'webhooks.test': {
393
+ params: {
394
+ id: Identifier;
395
+ };
396
+ res: {
397
+ webhook: WebHook;
398
+ };
399
+ };
400
+
401
+ // Followed Slices
402
+ 'followedSlices.get': {
403
+ params: null;
404
+ res: {
405
+ followedSlices: FollowedSlice[];
406
+ };
407
+ };
408
+ 'followedSlices.create': {
409
+ params: Partial<Pick<FollowedSlice, 'name' | 'url' | 'accessToken'>>;
410
+ res: {
411
+ followedSlice: FollowedSlice;
412
+ };
413
+ };
414
+ 'followedSlices.update': {
415
+ params: {
416
+ id: Identifier;
417
+ update: Partial<Pick<FollowedSlice, 'name' | 'url' | 'accessToken'>>;
418
+ };
419
+ res: {
420
+ followedSlice: FollowedSlice;
421
+ };
422
+ };
423
+ 'followedSlices.delete': {
424
+ params: {
425
+ id: Identifier;
426
+ };
427
+ res: {
428
+ followedSliceDeletion: ItemDeletion;
429
+ };
430
+ };
431
+
432
+ // Profile sets
433
+ 'profile.getApp': {
434
+ params: null;
435
+ res: {
436
+ profile: KeyValue;
437
+ };
438
+ };
439
+ 'profile.updateApp': {
440
+ params: {
441
+ update: KeyValue;
442
+ };
443
+ res: {
444
+ profile: KeyValue;
445
+ };
446
+ };
447
+ 'profile.getPublic': {
448
+ params: null;
449
+ res: {
450
+ profile: KeyValue;
451
+ };
452
+ };
453
+ 'profile.updatePublic': {
454
+ params: {
455
+ update: KeyValue;
456
+ };
457
+ res: {
458
+ profile: KeyValue;
459
+ };
460
+ };
461
+ 'profile.getPrivate': {
462
+ params: null;
463
+ res: {
464
+ profile: KeyValue;
465
+ };
466
+ };
467
+ 'profile.updatePrivate': {
468
+ params: {
469
+ update: KeyValue;
470
+ };
471
+ res: {
472
+ profile: KeyValue;
473
+ };
474
+ };
475
+
476
+ // Account management
477
+ 'account.get': {
478
+ params: null;
479
+ res: {
480
+ account: AccountInformation;
481
+ };
482
+ };
483
+ 'account.update': {
484
+ params: {
485
+ update: Partial<Omit<AccountInformation, 'username'>>;
486
+ };
487
+ res: {
488
+ account: AccountInformation;
489
+ };
490
+ };
491
+ 'account.changePassword': {
492
+ params: {
493
+ oldPassword: string;
494
+ newPassword: string;
495
+ };
496
+ res: null;
497
+ };
498
+ 'account.requestPasswordReset': {
499
+ params: {
500
+ appId: string;
501
+ };
502
+ res: null;
503
+ };
504
+ 'account.resetPassword': {
505
+ params: {
506
+ resetToken: string;
507
+ newPassword: string;
508
+ appId: string;
509
+ };
510
+ res: null;
511
+ };
512
+ };
513
+
514
+ type UnionToIntersection<U> = (
515
+ U extends any ? (k: U) => any : never
516
+ ) extends (k: infer I) => any
517
+ ? I
518
+ : never;
519
+ type ApiCallResultUnion = ApiCallMethods[keyof ApiCallMethods]['res'];
520
+ type ApiCallResultTypes = UnionToIntersection<
521
+ NonNullable<ApiCallResultUnion>
522
+ >;
523
+
524
+ type PossibleError = {
525
+ error?: Error;
526
+ };
527
+
528
+ type ApiCallResult<K extends keyof ApiCallMethods> =
529
+ ApiCallMethods[K]['res'] & PossibleError;
530
+
531
+ export type ApiCallResultHandler<K extends keyof ApiCallMethods> = (
532
+ result: ApiCallResult<K>,
533
+ ) => Promise<any>;
534
+ export type StreamedEventsHandler = (event: Event) => void;
535
+
536
+ type StreamedEventsResult = {
537
+ eventsCount?: number;
538
+ eventsDeletionsCount?: number;
539
+ meta: {
540
+ apiVersion: string;
541
+ serverTime: number;
542
+ serial: string;
543
+ };
544
+ };
545
+
546
+ export type EventFileCreationParams = Partial<
547
+ Omit<Event, 'attachments' | EditMetadata>
548
+ >;
549
+ export type ApiCall<K extends keyof ApiCallMethods = keyof ApiCallMethods> =
550
+ K extends keyof ApiCallMethods
551
+ ? {
552
+ method: K;
553
+ params: ApiCallMethods[K]['params'];
554
+ handleResult?: ApiCallResultHandler<K>;
555
+ }
556
+ : never;
557
+
558
+ export type TypedApiCallResult = ApiCallResultTypes & PossibleError;
559
+
560
+ export type ApiCallProgressHandler = (percentage: number) => void;
561
+
562
+ interface AccessInfo extends Access {
563
+ calls: KeyValue;
564
+ user: KeyValue;
565
+ }
566
+
567
+ type EventApiCallRes = {
568
+ event?: Event;
569
+ } & PossibleError;
570
+
571
+ export interface Connection {
572
+ new (pryvApiEndpoint: string, service?: Service): Connection;
573
+ get service(): Service;
574
+ username(): Promise<string>;
575
+ api<Calls extends ApiCall[] = ApiCall[]>(
576
+ apiCalls: Calls,
577
+ res?: ApiCallProgressHandler[],
578
+ ): Promise<Array<TypedApiCallResult>>;
579
+ getEventsStreamed(
580
+ queryParams: Partial<EventQueryParamsStreamQuery>,
581
+ forEachEvent: StreamedEventsHandler,
582
+ ): Promise<StreamedEventsResult>;
583
+ createEventWithFile(
584
+ params: EventFileCreationParams,
585
+ filePath: string | Buffer | Blob,
586
+ ): Promise<EventApiCallRes>;
587
+ createEventWithFormData(
588
+ params: EventFileCreationParams,
589
+ formData: FormData,
590
+ ): Promise<EventApiCallRes>;
591
+ createEventWithFileFromBuffer(
592
+ params: EventFileCreationParams,
593
+ bufferData: string | Buffer,
594
+ filename: string,
595
+ ): Promise<EventApiCallRes>;
596
+ addPointsToHFEvent(
597
+ id: Identifier,
598
+ fields: string[],
599
+ values: Array<string | number>,
600
+ ): Promise<void>;
601
+ accessInfo(): Promise<AccessInfo>;
602
+
603
+ post(
604
+ path: string,
605
+ data: Object | any[],
606
+ queryParams: Object,
607
+ ): Promise<Object | Object[]>;
608
+ get(path: string, queryParams: Object): Promise<Object | Object[]>;
609
+ }
610
+
611
+ export type serviceCustomizations = {
612
+ name?: string;
613
+ assets?: {
614
+ definitions?: string;
615
+ };
616
+ };
617
+
618
+ export type PryvServiceInfo = {
619
+ register: string;
620
+ access: string;
621
+ api: string;
622
+ name: string;
623
+ home: string;
624
+ support: string;
625
+ terms: string;
626
+ eventTypes: string;
627
+ version: string;
628
+ };
629
+
630
+ export type AssetsConfig = {
631
+ baseUrl: string;
632
+ href: string;
633
+ favicon: {
634
+ [key: string]: string;
635
+ default: string;
636
+ };
637
+ css: {
638
+ [key: string]: string;
639
+ default: string;
640
+ };
641
+ 'lib-js': {
642
+ [key: string]: KeyValue | any;
643
+ };
644
+
645
+ [key: string]: any;
646
+ };
647
+
648
+ export interface Service {
649
+ new (
650
+ serviceInfoUrl: string,
651
+ serviceCustomizations?: serviceCustomizations,
652
+ ): Service;
653
+ info(forceFetch?: boolean): Promise<PryvServiceInfo>;
654
+ setServiceInfo(serviceInfo: Partial<PryvServiceInfo>): Promise<void>;
655
+ assets(forceFetch?: boolean): Promise<AssetsConfig>;
656
+ infoSync(): PryvServiceInfo | null;
657
+ apiEndpointFor(username: string, token: string): Promise<string>;
658
+ login(
659
+ username: string,
660
+ password: string,
661
+ appId: string,
662
+ originHeader?: string,
663
+ ): Promise<Connection>;
664
+ }
665
+
666
+ export type AuthRequestedPermission = {
667
+ streamId: Identifier;
668
+ defaultName: string;
669
+ level: Level;
670
+ };
671
+
672
+ export type States =
673
+ | 'LOADING'
674
+ | 'INITIALIZED'
675
+ | 'NEED_SIGNIN'
676
+ | 'ACCEPTED'
677
+ | 'SIGNOUT';
678
+
679
+ type ServiceInfo = {
680
+ access: string;
681
+ api: string;
682
+ assets: {
683
+ definitions: string;
684
+ };
685
+ eventTypes: string;
686
+ home: string;
687
+ name: string;
688
+ register: string;
689
+ serial: string;
690
+ support: string;
691
+ terms: string;
692
+ version: string;
693
+ };
694
+
695
+ type StateChangeTypes = {
696
+ LOADING: {};
697
+ INITIALIZED: {
698
+ serviceInfo: ServiceInfo;
699
+ };
700
+ NEED_SIGNIN: {
701
+ authUrl: string;
702
+ clientData: any;
703
+ code: number;
704
+ key: string;
705
+ lang: string;
706
+ oauthState: any;
707
+ poll: string;
708
+ poll_rate_ms: number;
709
+ requestedPermissions: Array<{
710
+ streamId: string;
711
+ level: Level;
712
+ defaultName: string;
713
+ }>;
714
+ requestingAppId: string;
715
+ returnUrl: any;
716
+ serviceInfo: ServiceInfo;
717
+ };
718
+ ACCEPTED: {
719
+ serviceInfo: ServiceInfo;
720
+ apiEndpoint: string;
721
+ username: string;
722
+ token: string;
723
+ };
724
+ SIGNOUT: {};
725
+ };
726
+
727
+ export type StateChange<K extends States> = StateChangeTypes[K] & {
728
+ id: K;
729
+ status: K;
730
+ };
731
+
732
+ export type AuthSettings = {
733
+ spanButtonID?: string;
734
+ onStateChange?: (state: StateChange<States>) => void;
735
+ returnURL?: string;
736
+ authRequest: {
737
+ requestingAppId: string;
738
+ languageCode?: string;
739
+ requestedPermissions: AuthRequestedPermission[];
740
+ returnUrl?: string | boolean;
741
+ referer?: string;
742
+ clientData?: Object;
743
+ };
744
+ };
745
+
746
+ type SetupAuth = (
747
+ settings: AuthSettings,
748
+ serviceInfoUrl: string,
749
+ serviceCustomizations?: serviceCustomizations,
750
+ humanInteraction?: any,
751
+ ) => Promise<Service>;
752
+
753
+ export type AuthStates = {
754
+ ERROR: 'ERROR';
755
+ LOADING: 'LOADING';
756
+ INITIALIZED: 'INITIALIZED';
757
+ NEED_SIGNIN: 'NEED_SIGNIN';
758
+ AUTHORIZED: 'ACCEPTED';
759
+ SIGNOUT: 'SIGNOUT';
760
+ REFUSED: 'REFUSED';
761
+ };
762
+
763
+ type AuthStatePayload = {
764
+ status: AuthStates[keyof AuthStates];
765
+ message?: string;
766
+ };
767
+
768
+ export interface CustomLoginButton {
769
+ init?: () => Promise<void>;
770
+ getAuthorizationData(): string;
771
+ onStateChange(state: AuthStatePayload): Promise<void>;
772
+ onClick(): void;
773
+ saveAuthorizationData?: (authData: string) => void;
774
+ deleteAuthorizationData?: () => Promise<void>;
775
+ }
776
+
777
+ export interface AuthController {
778
+ new (
779
+ authSettings: AuthSettings,
780
+ service: Service,
781
+ loginButton: CustomLoginButton,
782
+ ): AuthController;
783
+ init(): Promise<void>;
784
+ stopAuthRequest(msg: string): void;
785
+ handleClick(): Promise<void>;
786
+ getReturnURL(
787
+ returnURL: string,
788
+ windowLocationForTest: string,
789
+ navigatorForTests: string,
790
+ ): string | boolean;
791
+ startAuthRequest(): Promise<any>;
792
+ doPolling(): Promise<void>;
793
+ set state(newState: AuthStatePayload);
794
+ get state(): AuthStatePayload;
795
+ }
796
+
797
+ export interface Auth {
798
+ setupAuth: SetupAuth;
799
+ AuthStates: AuthStates;
800
+ AuthController: AuthController;
801
+ }
802
+
803
+ export interface CookieUtils {
804
+ set(cookieKey: string, value: any, expireInDays: number): void;
805
+ get(cookieKey: string): any;
806
+ del(cookieKey: string): void;
807
+ }
808
+
809
+ type getServiceInfoFromURL = (url: string) => string;
810
+
811
+ export interface Browser {
812
+ LoginButton: CustomLoginButton;
813
+ CookieUtils: CookieUtils;
814
+ AuthStates: AuthStates;
815
+ setupAuth: SetupAuth;
816
+ serviceInfoFromUrl: getServiceInfoFromURL;
817
+ }
818
+
819
+ type TokenAndApiEndpoint = {
820
+ endpoint: string;
821
+ token: string;
822
+ };
823
+
824
+ export interface utils {
825
+ isBrowser(): boolean;
826
+ extractTokenAndApiEndpoint(pryvApiEndpoint: string): TokenAndApiEndpoint;
827
+ buildPryvApiEndpoint(tokenAndApi: TokenAndApiEndpoint): string;
828
+ browserIsMobileOrTablet(navigator: string): boolean;
829
+ cleanURLFromPrYvParams(url: string): string;
830
+ getQueryParamsFromURL(url: string): KeyValue;
831
+ }
832
+
833
+ type version = string;
834
+
835
+ let Pryv: {
836
+ Service: Service;
837
+ Connection: Connection;
838
+ Auth: Auth;
839
+ Browser: Browser;
840
+ utils: utils;
841
+ version: version;
842
+ };
843
+
844
+ export default Pryv;
845
+ }
@@ -5,6 +5,13 @@ let conn = null;
5
5
  const { URL, URLSearchParams } = require('universal-url');
6
6
  const cuid = require('cuid');
7
7
 
8
+ const isNode = (typeof window === 'undefined');
9
+
10
+ let readFileSync;
11
+ if (isNode) { // node
12
+ readFileSync = require('fs').readFileSync;
13
+ }
14
+
8
15
  describe('Connection', () => {
9
16
 
10
17
  before(async function () {
@@ -183,35 +190,85 @@ describe('Connection', () => {
183
190
  });
184
191
 
185
192
  describe('Attachements', () => {
186
- it('Create event with attachemnt', async () => {
187
- let res = null;
193
+ it('Node Only: Create event with attachment from file', async function () {
194
+ if (!isNode) { this.skip(); }
195
+ const res = await conn.createEventWithFile({
196
+ type: 'picture/attached',
197
+ streamId: 'data'
198
+ }, './test/Y.png');
188
199
 
189
- if (typeof window === 'undefined') { // node
190
200
 
191
- res = await conn.createEventWithFile({
201
+ should.exist(res);
202
+ should.exist(res.event);
203
+ should.exist(res.event.attachments);
204
+ res.event.attachments.length.should.equal(1);
205
+ res.event.attachments[0].size.should.equal(14798);
206
+ res.event.attachments[0].type.should.equal('image/png');
207
+ res.event.attachments[0].fileName.should.equal('Y.png');
208
+ });
209
+
210
+ it('Node Only: Create event with attachment from Buffer', async function () {
211
+ if (!isNode) { this.skip(); }
212
+
213
+ const fileData = readFileSync('./test/Y.png');
214
+ const res = await conn.createEventWithFileFromBuffer({
192
215
  type: 'picture/attached',
193
216
  streamId: 'data'
194
- }, './test/Y.png');
217
+ }, fileData, 'Y.png');
195
218
 
196
- } else { // browser
197
- const formData = new FormData();
198
- var blob = new Blob(['Hello'], { type: "text/txt" });
199
- formData.append("webmasterfile", blob);
219
+ should.exist(res);
220
+ should.exist(res.event);
221
+ should.exist(res.event.attachments);
222
+ res.event.attachments.length.should.equal(1);
223
+ res.event.attachments[0].size.should.equal(14798);
224
+ res.event.attachments[0].type.should.equal('image/png');
225
+ res.event.attachments[0].fileName.should.equal('Y.png');
200
226
 
201
- res = await conn.createEventWithFormData({
202
- type: 'file/attached',
227
+ });
228
+
229
+ it('Browser Only: Create event with attachment from Buffer', async function () {
230
+ if (isNode) { this.skip(); }
231
+
232
+ const blob = new Blob(['Hello'], { type: "text/txt" });
233
+ const res = await conn.createEventWithFileFromBuffer({
234
+ type: 'picture/attached',
203
235
  streamId: 'data'
204
- }, formData);
236
+ }, blob, 'Hello.txt');
237
+
238
+ should.exist(res);
239
+ should.exist(res.event);
240
+ console.log(res.event);
241
+ should.exist(res.event.attachments);
242
+ res.event.attachments.length.should.equal(1);
243
+ res.event.attachments[0].size.should.equal(5);
244
+ res.event.attachments[0].type.should.equal('text/txt');
245
+ res.event.attachments[0].fileName.should.equal('Hello.txt');
246
+
247
+ });
248
+
249
+ it('Browser Only: Create event with attachment formData', async function () {
250
+ if (isNode) { this.skip(); }
205
251
 
206
- }
252
+ const formData = new FormData();
253
+ const blob = new Blob(['Hello'], { type: "text/txt" });
254
+ formData.append("webmasterfile", blob);
255
+
256
+ const res = await conn.createEventWithFormData({
257
+ type: 'file/attached',
258
+ streamId: 'data'
259
+ }, formData);
207
260
 
208
261
 
209
262
  should.exist(res);
210
263
  should.exist(res.event);
211
264
  should.exist(res.event.attachments);
212
265
  res.event.attachments.length.should.equal(1);
213
-
266
+ res.event.attachments[0].size.should.equal(5);
267
+ res.event.attachments[0].type.should.equal('text/txt');
268
+ res.event.attachments[0].fileName.should.equal('blob');
214
269
  });
270
+
271
+
215
272
  });
216
273
 
217
274
  describe('HF events', () => {
@@ -301,14 +358,14 @@ describe('Connection', () => {
301
358
  });
302
359
 
303
360
  it('no-events ', async () => {
304
- const queryParams = { fromTime: 0, toTime: now, tags: ['RANDOM-123'] };
361
+ const queryParams = { fromTime: 0, toTime: now, types: ['type/unexistent'] };
305
362
  function forEachEvent(event) { }
306
363
  const res = await conn.getEventsStreamed(queryParams, forEachEvent);
307
364
  expect(0).to.equal(res.eventsCount);
308
365
  });
309
366
 
310
367
  it('no-events includeDeletions', async () => {
311
- const queryParams = { fromTime: 0, toTime: now, tags: ['RANDOM-123'], includeDeletions: true, modifiedSince: 0 };
368
+ const queryParams = { fromTime: 0, toTime: now, types: ['type/unexistent'], includeDeletions: true, modifiedSince: 0 };
312
369
  function forEachEvent(event) { }
313
370
  const res = await conn.getEventsStreamed(queryParams, forEachEvent);
314
371
  expect(0).to.equal(res.eventsCount);
@@ -406,19 +463,6 @@ describe('Connection', () => {
406
463
  should.equal(newUser.access.name, accessInfoUser.name);
407
464
  });
408
465
 
409
- it('has same permissions', () => {
410
- should.exist(accessInfoUser);
411
- should.exist(accessInfoUser.permissions);
412
- let lengthPermission = accessInfoUser.permissions.length;
413
- should.equal(newUser.access.permissions.length, lengthPermission);
414
- for (let i = 0; i < lengthPermission; i++) {
415
- should.exist(accessInfoUser.permissions[i].streamId);
416
- should.equal(newUser.access.permissions[i].streamId, accessInfoUser.permissions[i].streamId);
417
- should.exist(accessInfoUser.permissions[i].level);
418
- should.equal(newUser.access.permissions[i].level, accessInfoUser.permissions[i].level);
419
- }
420
- });
421
-
422
466
  it('has same token', () => {
423
467
  should.exist(accessInfoUser.token);
424
468
  should.equal(newUser.access.token, accessInfoUser.token);
package/test/test-data.js CHANGED
@@ -61,9 +61,12 @@ async function prepare() {
61
61
  });
62
62
  }
63
63
  const apiEndpoint = serviceInfo.api.replace('{username}', username);
64
+
64
65
  // login user
66
+ const headers = {};
67
+ if (typeof window === 'undefined') { headers.Origin = 'https://l.rec.la'; }; // node only
65
68
  const loginRes = await superagent.post(apiEndpoint + 'auth/login')
66
- .set('Origin', 'https://l.rec.la')
69
+ .set(headers)
67
70
  .send({ username: username, password: username, appId: 'js-lib-test' });
68
71
 
69
72
  // create data stream
package/webpack.config.js CHANGED
@@ -24,7 +24,7 @@ module.exports = [
24
24
  { // es5 version
25
25
  mode: 'production',
26
26
  entry: {
27
- 'pryv': ['core-js/stable', './src/index.js'],
27
+ 'pryv': ['./src/index.js'],
28
28
  },
29
29
  output: {
30
30
  filename: '[name].js',
@@ -38,7 +38,7 @@ module.exports = [
38
38
  { // es5 version including socket.io and monitors
39
39
  mode: 'production',
40
40
  entry: {
41
- 'pryv-socket.io-monitor': ['core-js/stable', './src/index-socket.io-monitor.js'],
41
+ 'pryv-socket.io-monitor': ['./src/index-socket.io-monitor.js'],
42
42
  },
43
43
  output: {
44
44
  filename: '[name].js',
@@ -47,7 +47,13 @@ module.exports = [
47
47
  library: 'Pryv'
48
48
  },
49
49
  devtool: 'source-map',
50
- module: webpackBabelConfig
50
+ module: webpackBabelConfig,
51
+ resolve: {
52
+ fallback: {
53
+ 'fs': false,
54
+ 'path': false,
55
+ },
56
+ }
51
57
  },
52
58
  { // browser test suite (es6)
53
59
  mode: 'development',
@@ -61,11 +67,17 @@ module.exports = [
61
67
  library: 'browserTest'
62
68
  },
63
69
  plugins: [
64
- new webpack.IgnorePlugin(/zombie/),
70
+ new webpack.IgnorePlugin({resourceRegExp: /zombie/}),
65
71
  new CopyPlugin({ patterns: [
66
72
  { from: 'test/browser-tests.html' },
67
73
  ]})
68
74
  ],
69
75
  devtool: 'source-map',
76
+ resolve: {
77
+ fallback: {
78
+ 'fs': false,
79
+ 'path': false,
80
+ },
81
+ }
70
82
  }
71
83
  ];