@qikdev/sdk 0.1.169 → 0.1.180

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.
Files changed (71) hide show
  1. package/.gitlab-ci.yml +24 -0
  2. package/dist/main.js +1 -1
  3. package/jsdoc.conf +10 -0
  4. package/package.json +5 -24
  5. package/public/docs/access.html +3826 -0
  6. package/public/docs/api.html +1356 -0
  7. package/public/docs/auth.html +2180 -0
  8. package/public/docs/cache.html +351 -0
  9. package/public/docs/content.html +2560 -0
  10. package/public/docs/files.html +779 -0
  11. package/public/docs/filter.html +1355 -0
  12. package/public/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  13. package/public/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  14. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  15. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  16. package/public/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  17. package/public/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  18. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  19. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  20. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  21. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  22. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  23. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  24. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  25. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  26. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  27. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  28. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  29. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  30. package/public/docs/index.html +96 -0
  31. package/public/docs/qik.access.js.html +790 -0
  32. package/public/docs/qik.api.js.html +511 -0
  33. package/public/docs/qik.auth.js.html +1006 -0
  34. package/public/docs/qik.cache.js.html +131 -0
  35. package/public/docs/qik.content.js.html +918 -0
  36. package/public/docs/qik.core.js.html +301 -0
  37. package/public/docs/qik.files.js.html +219 -0
  38. package/public/docs/qik.filter.js.html +611 -0
  39. package/public/docs/qik.socket.js.html +416 -0
  40. package/public/docs/qik.system.js.html +117 -0
  41. package/public/docs/qik.utils.js.html +1467 -0
  42. package/public/docs/scripts/collapse.js +20 -0
  43. package/public/docs/scripts/linenumber.js +25 -0
  44. package/public/docs/scripts/nav.js +12 -0
  45. package/public/docs/scripts/polyfill.js +4 -0
  46. package/public/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  47. package/public/docs/scripts/prettify/lang-css.js +2 -0
  48. package/public/docs/scripts/prettify/prettify.js +28 -0
  49. package/public/docs/scripts/search.js +83 -0
  50. package/public/docs/socket.html +810 -0
  51. package/public/docs/styles/jsdoc.css +765 -0
  52. package/public/docs/styles/prettify.css +79 -0
  53. package/public/docs/system.html +197 -0
  54. package/src/api/qik.access.js +790 -0
  55. package/src/api/qik.api.js +431 -0
  56. package/src/api/qik.auth.js +938 -0
  57. package/src/api/qik.cache.js +63 -0
  58. package/src/api/qik.content.js +858 -0
  59. package/src/api/qik.core.js +246 -0
  60. package/src/api/qik.files.js +150 -0
  61. package/src/api/qik.filter.js +543 -0
  62. package/src/api/qik.geo.js +895 -0
  63. package/src/api/qik.socket.js +348 -0
  64. package/src/api/qik.system.js +49 -0
  65. package/src/api/qik.utils.js +1410 -0
  66. package/src/index.js +20 -0
  67. package/src/version.js +1 -0
  68. package/test/index.spec.js +41 -0
  69. package/test/mocha.opts +0 -0
  70. package/dist/sdk.js +0 -2
  71. package/dist/sdk.js.LICENSE.txt +0 -8
@@ -0,0 +1,938 @@
1
+ import axios from 'axios';
2
+ import { EventDispatcher } from './qik.utils.js';
3
+
4
+ ///////////////////////////////////////////////////
5
+
6
+ /**
7
+ * Creates a new instance of QikAuth a module of the SDK
8
+ * that contains all helper functions to do with authentication and user session management
9
+ * @alias auth
10
+ * @constructor
11
+ * @hideconstructor
12
+ * @param {QikAPI} qik A reference to the parent instance of the QikCore module. This module is usually created by a QikCore instance that passes itself in as the first argument.
13
+ */
14
+
15
+ var QikAuth = function(qik) {
16
+
17
+ if (!qik.api) {
18
+ throw new Error(`Please ensure that QikAPI exists before QikAuth`);
19
+ }
20
+
21
+ //Keep track of any refresh requests
22
+ var inflightRefreshRequest;
23
+
24
+ ///////////////////////////////////////////////////
25
+
26
+ var sessionStorage = {};
27
+ var store = sessionStorage;
28
+ const tokenBufferSeconds = 10;
29
+
30
+ ///////////////////////////////////////////////////
31
+
32
+ const service = {
33
+ debug: false,
34
+ }
35
+
36
+ Object.defineProperty(service, 'store', {
37
+ value: store,
38
+ writable: false,
39
+ });
40
+
41
+ //Create a new dispatcher
42
+ const dispatcher = new EventDispatcher();
43
+ dispatcher.bootstrap(service);
44
+
45
+ ///////////////////////////////////////////////////
46
+
47
+ function dispatch(parameters) {
48
+
49
+ //Get the current user
50
+ var user = store.user;
51
+
52
+ //Dispatch the change to the listeners
53
+ if (service.onChange) {
54
+ service.onChange(user);
55
+ }
56
+
57
+ //Dispatch the change event
58
+ dispatcher.dispatch('change', user, parameters);
59
+ }
60
+
61
+
62
+ ///////////////////////////////////////////////////
63
+
64
+ /**
65
+ * @alias auth.set
66
+ * @description Manually set current user session
67
+ * @param {Object} user The user session object to set as the current user session
68
+ * @param {Object} parameters Additional parameters to dispatch
69
+ * @param {Boolean} stopDispatch Whether to supress dispatching a 'change' event.
70
+ * @example
71
+ *
72
+ * const userSession = {_id:'61eca4746971e75c1fc670cf', firstName:'Daffy', lastName:'Duck' ...};
73
+ * sdk.auth.set(userSession);
74
+ */
75
+
76
+ service.set = function(user, parameters, stopDispatch) {
77
+
78
+ if (JSON.stringify(store.user) != JSON.stringify(user)) {
79
+ store.user = user;
80
+ if (!stopDispatch) {
81
+ return dispatch(parameters)
82
+ }
83
+ }
84
+
85
+ }
86
+
87
+
88
+ ///////////////////////////////////////////////////
89
+
90
+ /**
91
+ * @alias auth.logout
92
+ * @description Clear the current user session from memory and erase all caches
93
+ * @example
94
+ * sdk.auth.logout();
95
+ */
96
+
97
+ service.logout = function() {
98
+ delete store.user;
99
+ qik.cache.reset();
100
+ return dispatch()
101
+ }
102
+
103
+ ///////////////////////////////////////////////////
104
+
105
+ /**
106
+ * @alias auth.changeOrganisation
107
+ * @description Manually set current user session
108
+ * @param {(String|Object)} organisation The id of the organisation to switch into
109
+ * @param {Object} options Additional options
110
+ * @param {Boolean} options.disableAutoAuthentication By default when switching organisation, the current user session
111
+ * will be updated to reflect a session in the new organisation, you can use this option to disable that behavior and instead return the
112
+ * user session without dispatching any events
113
+ * @example
114
+ *
115
+ * sdk.auth.changeOrganisation('61eca4746971e75c1fc670cf');
116
+ * // Current user session will be automatically updated
117
+ *
118
+ * const newSession = await sdk.auth.changeOrganisation('61eca4746971e75c1fc670cf', {disableAutoAuthentication:true});
119
+ * // Current user session will not be updated
120
+ * sdk.auth.set(newSession);
121
+ */
122
+ service.changeOrganisation = function(organisationID, options) {
123
+
124
+ //Ensure we just have the ID
125
+ organisationID = qik.utils.id(organisationID);
126
+
127
+ //////////////////////////
128
+
129
+ if (!options) {
130
+ options = {};
131
+ }
132
+
133
+ //////////////////////////
134
+
135
+ //Change the users current tokens straight away
136
+ var autoAuthenticate = true;
137
+
138
+ if (options.disableAutoAuthentication) {
139
+ autoAuthenticate = false;
140
+ }
141
+
142
+ //////////////////////////
143
+
144
+ return new Promise(function(resolve, reject) {
145
+
146
+
147
+ qik.api.post(`/user/switch/${organisationID}`)
148
+ .then(function(response) {
149
+
150
+ if (autoAuthenticate) {
151
+ qik.cache.reset();
152
+ service.set(response.data);
153
+ }
154
+
155
+ resolve(response.data);
156
+ })
157
+ .catch(reject)
158
+
159
+ })
160
+ }
161
+
162
+ ///////////////////////////////////////////////////
163
+
164
+ /**
165
+ * @alias auth.impersonate
166
+ * @description Impersonate another user within your organisation
167
+ * @param {(String|Object)} persona The id of the user persona you want to impersonate
168
+ * @param {Object} options Additional options
169
+ * @param {Boolean} options.disableAutoAuthentication By default when impersonating a user, the current user session
170
+ * will be updated automatically to reflect the new session, you can use this option to disable that behavior and instead return the
171
+ * new impersonation user session without dispatching any events
172
+ * @example
173
+ *
174
+ * sdk.auth.impersonate('61eca4746971e75c1fc670cf');
175
+ * // Current user session will be automatically updated
176
+ *
177
+ * const newSession = await sdk.auth.impersonate('61eca4746971e75c1fc670cf', {disableAutoAuthentication:true});
178
+ * // Current user session will not be updated
179
+ * sdk.auth.set(newSession);
180
+ */
181
+ service.impersonate = function(personaID, options) {
182
+
183
+ //Ensure we just have the ID
184
+ personaID = qik.utils.id(personaID);
185
+
186
+ //////////////////////////
187
+
188
+ if (!options) {
189
+ options = {};
190
+ }
191
+
192
+ //////////////////////////
193
+
194
+ //Change the users current tokens straight away
195
+ var autoAuthenticate = true;
196
+
197
+ if (options.disableAutoAuthentication) {
198
+ autoAuthenticate = false;
199
+ }
200
+
201
+ //////////////////////////
202
+
203
+ var promise = qik.api.post(`/user/impersonate/${personaID}`)
204
+
205
+ promise.then(function(res) {
206
+
207
+ if (autoAuthenticate) {
208
+ qik.cache.reset();
209
+ service.set(res.data);
210
+ }
211
+ }, function(err) {});
212
+
213
+
214
+ return promise;
215
+
216
+ }
217
+
218
+ ///////////////////////////////////////////////////
219
+
220
+ /**
221
+ * @alias auth.login
222
+ * @description Login and authenticate as a user
223
+ * @param {Object} credentials The credentials used to login
224
+ * @param {String} credentials.email The email address to login to
225
+ * @param {String} credentials.password The password to login with
226
+ * @param {String} credentials.mfa The MFA (Multi Factor Authentication) code
227
+ * @param {Object} options Additional options
228
+ * @param {Boolean} options.disableAutoAuthentication By default when logging in the current user session
229
+ * will be updated automatically to reflect the new session, you can use this option to disable that behavior and instead return the
230
+ * session that was logged in to without dispatching any events
231
+ * @example
232
+ *
233
+ * const credentials = {
234
+ * email:'me@email.com',
235
+ * password:'******',
236
+ * mfa:'1234',
237
+ * }
238
+ *
239
+ * sdk.auth.login(credentials);
240
+ * // Current user session will be automatically updated
241
+ *
242
+ * const newSession = await sdk.auth.login(credentials, {disableAutoAuthentication:true});
243
+ * // Current user session will not be updated
244
+ * sdk.auth.set(newSession);
245
+ */
246
+ service.login = async function(credentials, options) {
247
+
248
+ if (!options) {
249
+ options = {};
250
+ }
251
+
252
+ //////////////////////////
253
+
254
+ //Change the users current tokens straight away
255
+ var autoAuthenticate = true;
256
+
257
+ if (options.disableAutoAuthentication) {
258
+ autoAuthenticate = false;
259
+ }
260
+
261
+ //////////////////////////////////////
262
+
263
+ var promise = new Promise(loginCheck)
264
+
265
+ function loginCheck(resolve, reject) {
266
+
267
+ if (!credentials) {
268
+ return reject({
269
+ message: 'Missing credentials!',
270
+ })
271
+ }
272
+
273
+ if (!credentials.email || !credentials.email.length) {
274
+ return reject({
275
+ message: 'Username was not provided',
276
+ })
277
+ }
278
+
279
+ if (!credentials.password || !credentials.password.length) {
280
+ return reject({
281
+ message: 'Password was not provided',
282
+ })
283
+ }
284
+
285
+ /////////////////////////////////////////////
286
+
287
+ var postOptions = {
288
+ bypassInterceptor: true
289
+ }
290
+
291
+ /////////////////////////////////////////////
292
+
293
+ var url = `${qik.apiURL}/user/login`;
294
+
295
+ /////////////////////////////////////////////
296
+
297
+ //If we have a specified url
298
+ if (options.url) {
299
+ url = options.url;
300
+ }
301
+
302
+ /////////////////////////////////////////////
303
+
304
+ qik.api.post(url, credentials, postOptions).then(function(res) {
305
+
306
+ if (autoAuthenticate) {
307
+ service.set(res.data);
308
+
309
+ }
310
+
311
+ resolve(res);
312
+ }, reject);
313
+ }
314
+
315
+ //////////////////////////////////////
316
+
317
+ return promise;
318
+
319
+ }
320
+
321
+ ///////////////////////////////////////////////////
322
+
323
+ service.signup = async function(credentials, options) {
324
+
325
+ if (!options) {
326
+ options = {};
327
+ }
328
+
329
+
330
+ //////////////////////////
331
+
332
+ //Change the users current tokens straight away
333
+ var autoAuthenticate = true;
334
+
335
+ if (options.disableAutoAuthentication) {
336
+ autoAuthenticate = false;
337
+ }
338
+
339
+ //////////////////////////////////////
340
+
341
+ var promise = new Promise(signupCheck)
342
+
343
+ function signupCheck(resolve, reject) {
344
+
345
+ if (!credentials) {
346
+ return reject({
347
+ message: 'No details provided',
348
+ })
349
+ }
350
+
351
+ if (!credentials.firstName || !credentials.firstName.length) {
352
+ return reject({
353
+ message: 'First Name was not provided',
354
+ })
355
+ }
356
+
357
+ if (!credentials.lastName || !credentials.lastName.length) {
358
+ return reject({
359
+ message: 'Last Name was not provided',
360
+ })
361
+ }
362
+
363
+ if (!credentials.email || !credentials.email.length) {
364
+ return reject({
365
+ message: 'Email/Username was not provided',
366
+ })
367
+ }
368
+
369
+
370
+ if (!credentials.password || !credentials.password.length) {
371
+ return reject({
372
+ message: 'Password was not provided',
373
+ })
374
+ }
375
+
376
+ if (!credentials.confirmPassword || !credentials.confirmPassword.length) {
377
+ return reject({
378
+ message: 'Confirm Password was not provided',
379
+ })
380
+ }
381
+
382
+ if (credentials.confirmPassword != credentials.password) {
383
+ return reject({
384
+ message: 'Your passwords do not match',
385
+ })
386
+ }
387
+
388
+ /////////////////////////////////////////////
389
+
390
+ var postOptions = {
391
+ bypassInterceptor: true
392
+ }
393
+
394
+ /////////////////////////////////////////////
395
+
396
+ var url = `${qik.apiURL}/user/signup`;
397
+
398
+ /////////////////////////////////////////////
399
+
400
+ //If we are authenticating as an application
401
+ if (options.application) {
402
+
403
+ //The url is relative to the domain
404
+ url = `${qik.domain || ''}/qik/application/signup`;
405
+ }
406
+
407
+ //If we have a specified url
408
+ if (options.url) {
409
+ url = options.url;
410
+ }
411
+
412
+ /////////////////////////////////////////////
413
+
414
+ qik.api.post(url, credentials, postOptions).then(function(res) {
415
+
416
+ if (autoAuthenticate) {
417
+ service.set(res.data);
418
+ }
419
+
420
+ resolve(res);
421
+ }, reject);
422
+ }
423
+
424
+ //////////////////////////////////////
425
+
426
+ return promise;
427
+
428
+ }
429
+
430
+
431
+ ///////////////////////////////////////////////////
432
+
433
+ /**
434
+ * @alias auth.retrieveUserFromResetToken
435
+ * @description Retrieve user session through use of a valid reset token,
436
+ * Reset tokens are short lived tokens that can be generated when a user has forgotten their password or their
437
+ * password has been reset by an administrator
438
+ * @param {String} resetToken The token to use to authenticate
439
+ * @param {Object} options Additional options for the request
440
+ * @example
441
+ *
442
+ * const resetToken = 'XXX-324623-$$...';
443
+ *
444
+ * // Retrieve the user session by providing a reset token
445
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
446
+ */
447
+ service.retrieveUserFromResetToken = async function(resetToken, options) {
448
+
449
+ if (!options) {
450
+ options = {};
451
+ }
452
+
453
+ var postOptions = {
454
+ bypassInterceptor: true
455
+ }
456
+
457
+ return new Promise(function(resolve, reject) {
458
+ qik.api.get(options.url || `${qik.apiURL}/user/reset/${resetToken}`, postOptions).then(function(res) {
459
+ return resolve(res.data);
460
+ }, reject);
461
+ });
462
+
463
+ }
464
+
465
+ ///////////////////////////////////////////////////
466
+
467
+ /**
468
+ * @alias auth.updateUserWithToken
469
+ * @description Update a user's credentials through use of a reset token
470
+ * @param {String} resetToken The token to use to authenticate
471
+ * @param {Object} body Updates to be made to the user
472
+ * @param {Object} options Additional options for the request
473
+ * @param {Boolean} options.disableAutoAuthentication By default the current user session
474
+ * will be updated automatically to reflect the new updated session, you can use this option to disable that behavior
475
+ * and instead return the result without dispatching any events
476
+ * @example
477
+ *
478
+ * const resetToken = 'XXX-324623-$$...';
479
+ *
480
+ * // Retrieve the user session by providing a reset token
481
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
482
+ */
483
+ service.updateUserWithToken = async function(resetToken, body, options) {
484
+
485
+ if (!options) {
486
+ options = {};
487
+ }
488
+
489
+ //////////////////////////
490
+
491
+ //Change the users current tokens straight away
492
+ var autoAuthenticate = true;
493
+
494
+ if (options.disableAutoAuthentication) {
495
+ autoAuthenticate = false;
496
+ }
497
+
498
+ //////////////////////////////////////
499
+
500
+ return new Promise(function(resolve, reject) {
501
+
502
+ var postOptions = {
503
+ bypassInterceptor: true
504
+ }
505
+
506
+ qik.api.post(options.url || `${qik.apiURL}/user/reset/${resetToken}`, body, postOptions)
507
+ .then(function(res) {
508
+
509
+ //If we should automatically authenticate
510
+ //once the request is successful
511
+ //Then clear caches and update the session
512
+ if (autoAuthenticate) {
513
+ qik.cache.reset();
514
+ service.set(res.data);
515
+ }
516
+
517
+ return resolve(res.data);
518
+ }, reject);
519
+ });
520
+
521
+ }
522
+
523
+ /**
524
+ * @alias auth.sendResetPasswordRequest
525
+ * @description This function allows a reset token to be generated and emailed to the requesting user
526
+ * allowing them to modify their user details
527
+ * @param {Object} body Details for the reset request
528
+ * @param {String} body.email The email of the user to generate a token for
529
+ * @example
530
+ *
531
+ * const resetToken = 'XXX-324623-$$...';
532
+ *
533
+ * // Retrieve the user session by providing a reset token
534
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
535
+ */
536
+ service.sendResetPasswordRequest = function(details, options) {
537
+
538
+ if (!options) {
539
+ options = {};
540
+ }
541
+
542
+ if (!details) {
543
+ return Promise.reject({
544
+ message: 'No details were provided for password reset request',
545
+ })
546
+ }
547
+
548
+ if (!details.email || !details.email.length) {
549
+ return Promise.reject({
550
+ message: 'Email is required but was not provided',
551
+ })
552
+ }
553
+
554
+ return new Promise(function(resolve, reject) {
555
+
556
+ var postOptions = {
557
+ bypassInterceptor: true
558
+ }
559
+
560
+ qik.api.post(options.url || `${qik.apiURL}/user/forgot`, details, postOptions).then(resolve, reject);
561
+ })
562
+ }
563
+
564
+
565
+ ///////////////////////////////////////////////////
566
+
567
+ /**
568
+ * @alias auth.ensureValidToken
569
+ * @description This function forces a check to ensure that the current access token has not expired.
570
+ * If the token has expired, the user session will be refreshed with a new token.
571
+ * @param {Boolean} forceRefresh Whether to force the current token to be refreshed, even if it has not yet expired.
572
+ * @example
573
+ *
574
+ * // Check to ensure that the current access token is valid
575
+ * sdk.auth.ensureValidToken();
576
+ *
577
+ * // Force the token to be refreshed, even if the current token in use has not yet expired.
578
+ * sdk.auth.ensureValidToken(true);
579
+ */
580
+ service.ensureValidToken = async function(forceRefresh) {
581
+
582
+ var currentUser = service.getCurrentUser();
583
+ if (!currentUser) {
584
+
585
+ return Promise.reject('No user');
586
+ }
587
+
588
+ var { token } = currentUser;
589
+ if (!token) {
590
+
591
+ return Promise.reject('No token');
592
+ }
593
+
594
+ /////////////////////////////////////////////////////
595
+
596
+ //Check our date
597
+ var now = new Date();
598
+
599
+ //Give us a bit of buffer so that the backend doesn't beat us to
600
+ //retiring the token
601
+ now.setSeconds(now.getSeconds() + tokenBufferSeconds);
602
+
603
+ /////////////////////////////////////////////////////
604
+
605
+ var expires = new Date(token.expires);
606
+
607
+ if (forceRefresh) {
608
+ console.log('force refresh valid token', token.refreshToken)
609
+ return await service.refreshAccessToken(token.refreshToken);
610
+ }
611
+
612
+ //If the token is still fresh
613
+ if (now < expires) {
614
+
615
+ return token;
616
+ } else {
617
+
618
+ return await service.refreshAccessToken(token.refreshToken);
619
+ }
620
+
621
+
622
+ }
623
+
624
+ ///////////////////////////////////////////////////
625
+
626
+ const refreshContext = {};
627
+
628
+ service.refreshAccessToken = async function(refreshToken) {
629
+
630
+ // /////////////////////////////////////////////
631
+
632
+ // if (appContext) {
633
+
634
+ // } else {
635
+
636
+ // }
637
+
638
+ // /////////////////////////////////////////////
639
+
640
+ //If there is already a request in progress
641
+ if (refreshContext.inflightRefreshRequest) {
642
+
643
+ return refreshContext.inflightRefreshRequest;
644
+ }
645
+
646
+ /////////////////////////////////////////////////////
647
+
648
+ //Create an refresh request
649
+
650
+ refreshContext.inflightRefreshRequest = new Promise(function(resolve, reject) {
651
+
652
+ //Bypass the interceptor on all token refresh calls
653
+ //Because we don't need to add the access token etc onto it
654
+
655
+ qik.api.post(`/user/refresh`, {
656
+ refreshToken: refreshToken
657
+ }, {
658
+ bypassInterceptor: true,
659
+ withoutToken: true,
660
+ })
661
+ .then(function tokenRefreshComplete(res) {
662
+
663
+ //Update the user with any changes
664
+ //returned back from the refresh request
665
+ if (!res) {
666
+
667
+ refreshContext.inflightRefreshRequest = null;
668
+ return reject();
669
+
670
+ } else {
671
+ //Update with our new session
672
+ service.set(res.data);
673
+
674
+
675
+ dispatch();
676
+ }
677
+
678
+ //Resolve with the new token
679
+ resolve(res.data.token);
680
+
681
+ //Remove the inflight request
682
+ setTimeout(function() {
683
+ refreshContext.inflightRefreshRequest = null;
684
+ })
685
+
686
+
687
+ })
688
+ .catch(function(err) {
689
+
690
+
691
+ //TODO Check if invalid_refresh_token
692
+
693
+
694
+
695
+ setTimeout(function() {
696
+ refreshContext.inflightRefreshRequest = null;
697
+ });
698
+ reject(err);
699
+
700
+
701
+
702
+ });
703
+ });
704
+
705
+ //Return the refresh request
706
+ return refreshContext.inflightRefreshRequest;
707
+ }
708
+
709
+ ///////////////////////////////////////////////////
710
+
711
+ var retryCount = 0;
712
+
713
+ /**
714
+ * @alias auth.sync
715
+ * @description A useful function to sync the current user session with the server.
716
+ * @example
717
+ *
718
+ * // Makes request to the API and updates the current user session to match the response
719
+ * sdk.auth.sync();
720
+ */
721
+ service.sync = function() {
722
+
723
+ return qik.api.get('/user')
724
+ .then(function(res) {
725
+
726
+
727
+ if (res.data) {
728
+ if (store.user) {
729
+ Object.assign(store.user.session, res.data);
730
+ }
731
+ } else {
732
+ service.set(null);
733
+ }
734
+
735
+
736
+ retryCount = 0;
737
+
738
+ dispatch();
739
+ })
740
+ .catch(function(err) {
741
+
742
+ // if (retryCount > 2) {
743
+ service.set(null);
744
+ retryCount = 0;
745
+ dispatch();
746
+ // } else {
747
+
748
+ // retryCount++;
749
+ // service.sync();
750
+ // }
751
+
752
+
753
+ });
754
+ }
755
+
756
+ /////////////////////////////////////////////////////
757
+
758
+ /**
759
+ * @alias auth.getCurrentUser
760
+ * @description Retrieves the current user session
761
+ * @example
762
+ *
763
+ * const me = sdk.auth.getCurrentUser();
764
+ */
765
+ service.getCurrentUser = function() {
766
+ return store.user;
767
+ }
768
+
769
+
770
+ /**
771
+ * @alias auth.getCurrentToken
772
+ * @description Retrieves the current access token. If the user is authenticated
773
+ * the response will be the current user's access token, otherwise will fall back to the
774
+ * applications token.
775
+ * @example
776
+ * const currentAccessToken = sdk.auth.getCurrentToken();
777
+ */
778
+ service.getCurrentToken = function() {
779
+
780
+
781
+ var user = service.getCurrentUser();
782
+
783
+ //User is not logged in
784
+ if (!user) {
785
+
786
+ //But there is an application token
787
+ if (qik.applicationToken) {
788
+ //use that instead
789
+ return qik.applicationToken;
790
+ }
791
+
792
+ //No token
793
+ return;
794
+ }
795
+
796
+ var { token } = user;
797
+ if (!token) {
798
+ return;
799
+ }
800
+
801
+ return token.accessToken;
802
+
803
+ }
804
+
805
+ /////////////////////////////////////////////////////
806
+
807
+ qik.api.interceptors.request.use(async function(config) {
808
+
809
+ //If we want to bypass the interceptor
810
+ //then just return the request
811
+ if (config.bypassInterceptor) {
812
+ return config;
813
+ }
814
+
815
+ //////////////////////////////
816
+
817
+ //Get the original request
818
+ var originalRequest = config;
819
+
820
+ //////////////////////////////
821
+
822
+ var userDetails = await service.getCurrentUser();
823
+ var accessToken;
824
+ var refreshToken;
825
+ var expiryDate;
826
+
827
+ if (userDetails) {
828
+ var { token } = userDetails;
829
+ if (token) {
830
+ accessToken = token.accessToken;
831
+ refreshToken = token.refreshToken;
832
+ expiryDate = token.expires;
833
+ }
834
+ }
835
+
836
+ //////////////////////////////
837
+
838
+ //If there is a user token
839
+ if (accessToken) {
840
+ //Set the token of the request as the user's access token
841
+ originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
842
+
843
+
844
+ } else {
845
+ //Return the original request without a token
846
+
847
+ return originalRequest;
848
+ }
849
+
850
+ /////////////////////////////////////////////////////
851
+
852
+ //If no refresh token
853
+ if (!refreshToken) {
854
+
855
+
856
+ //Continue with the original request
857
+ return originalRequest;
858
+ }
859
+
860
+ /////////////////////////////////////////////////////
861
+
862
+ //We have a refresh token so we need to check
863
+ //whether our access token is stale and needs to be refreshed
864
+ var now = new Date();
865
+
866
+ //Give us a bit of buffer so that the backend doesn't beat us to
867
+ //retiring the token
868
+ now.setSeconds(now.getSeconds() + tokenBufferSeconds);
869
+
870
+ /////////////////////////////////////////////////////
871
+
872
+ var expires = new Date(expiryDate);
873
+
874
+ //If the token is still fresh
875
+ if (now < expires) {
876
+ //Return the original request
877
+ return originalRequest;
878
+ }
879
+
880
+ /////////////////////////////////////////////////////
881
+
882
+ return new Promise(async function(resolve, reject) {
883
+
884
+ //Refresh the token
885
+ await service.refreshAccessToken(refreshToken)
886
+ .then(function(newToken) {
887
+
888
+ //Update the original request with our new token
889
+ originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
890
+ //And continue onward
891
+ return resolve(originalRequest);
892
+ })
893
+ .catch(function(err) {
894
+
895
+ return reject(err);
896
+ });
897
+ });
898
+
899
+
900
+ },
901
+ function(error) {
902
+ return Promise.reject(error);
903
+ })
904
+
905
+
906
+
907
+ /////////////////////////////////////////////////////
908
+
909
+ qik.api.interceptors.response.use(function(response) {
910
+ return response;
911
+ }, function(err) {
912
+
913
+ //////////////////////////////
914
+
915
+ //Get the response status
916
+ var status = (err && err.response && err.response.status) || err.status;
917
+
918
+
919
+ switch (status) {
920
+ case 401:
921
+ service.logout();
922
+ break;
923
+ default:
924
+ //Some other error
925
+ break;
926
+ }
927
+
928
+ /////////////////////////////////////////////////////
929
+
930
+ return Promise.reject(err);
931
+ })
932
+
933
+ return service;
934
+
935
+ }
936
+
937
+
938
+ export default QikAuth;