@qikdev/sdk 0.1.169 → 0.1.170

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