@ethlete/query 0.1.0-next.16 → 0.1.0-next.17

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.
@@ -1,6 +1,6 @@
1
- import { __awaiter } from 'tslib';
2
1
  import { getCookie, deleteCookie, setCookie, DestroyService } from '@ethlete/core';
3
- import { Subject, timer, filter, takeWhile, switchMap, of, BehaviorSubject, interval, takeUntil, tap, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
2
+ import { filter, takeWhile, switchMap, of, BehaviorSubject, Subject, interval, takeUntil, tap, timer, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
3
+ import { __awaiter } from 'tslib';
4
4
  import * as i0 from '@angular/core';
5
5
  import { Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef } from '@angular/core';
6
6
  import { FormGroup } from '@angular/forms';
@@ -12,7 +12,6 @@ class CustomHeaderAuthProvider {
12
12
  }
13
13
  constructor(_config) {
14
14
  this._config = _config;
15
- this.queryClient = null;
16
15
  }
17
16
  cleanUp() {
18
17
  // noop
@@ -28,13 +27,35 @@ class BasicAuthProvider {
28
27
  }
29
28
  constructor(_config) {
30
29
  this._config = _config;
31
- this.queryClient = null;
32
30
  }
33
31
  cleanUp() {
34
32
  // noop
35
33
  }
36
34
  }
37
35
 
36
+ const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
37
+ const transformGql = (str) => {
38
+ str = Array.isArray(str) ? str.join('') : str;
39
+ const name = getOpName.exec(str);
40
+ return function (variables) {
41
+ const data = { query: str };
42
+ if (variables)
43
+ data['variables'] = JSON.stringify(variables);
44
+ if (name && name.length) {
45
+ const operationName = name[2];
46
+ if (operationName)
47
+ data['operationName'] = name[2];
48
+ }
49
+ return JSON.stringify(data);
50
+ };
51
+ };
52
+ const gql = (strings, ...values) => {
53
+ const str = strings.reduce((acc, cur, i) => {
54
+ return acc + cur + (values[i] || '');
55
+ }, '');
56
+ return str;
57
+ };
58
+
38
59
  const buildErrorMessage = (code, message) => `[@ethlete\\query:${code}] ${message}`;
39
60
  class QueryError extends Error {
40
61
  constructor(code, message, data) {
@@ -296,178 +317,6 @@ const request = (options) => __awaiter(void 0, void 0, void 0, function* () {
296
317
  }
297
318
  });
298
319
 
299
- const isBasicAuthProvider = (authProvider) => authProvider instanceof BasicAuthProvider;
300
- const isBearerAuthProvider = (authProvider) => authProvider instanceof BearerAuthProvider;
301
- const isCustomHeaderAuthProvider = (authProvider) => authProvider instanceof CustomHeaderAuthProvider;
302
- const decryptBearer = (token) => {
303
- try {
304
- const base64Url = token.split('.')[1];
305
- const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
306
- const jsonPayload = decodeURIComponent(atob(base64)
307
- .split('')
308
- .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
309
- .join(''));
310
- return JSON.parse(jsonPayload);
311
- }
312
- catch (error) {
313
- console.error(`Invalid bearer token: ${token}`, error);
314
- return null;
315
- }
316
- };
317
-
318
- class BearerAuthProvider {
319
- get header() {
320
- return { Authorization: `Bearer ${this._token}` };
321
- }
322
- constructor(_config) {
323
- var _a, _b, _c;
324
- this._config = _config;
325
- this._token = null;
326
- this._refreshToken = null;
327
- this._refreshTimerSubscription = null;
328
- this._failureCount = 0;
329
- this.queryClient = null;
330
- this.onRefreshInitiation$ = new Subject();
331
- this.onRefreshSuccess$ = new Subject();
332
- this.onRefreshFailure$ = new Subject();
333
- this._token = _config.token || null;
334
- this._refreshToken = (_b = (_a = _config.refreshConfig) === null || _a === void 0 ? void 0 : _a.token) !== null && _b !== void 0 ? _b : null;
335
- if (this._config.refreshConfig && this._token) {
336
- this._setupRefresh(this._config.refreshConfig);
337
- }
338
- else if ((_c = this._config.refreshConfig) === null || _c === void 0 ? void 0 : _c.cookieName) {
339
- const cookie = getCookie(this._config.refreshConfig.cookieName);
340
- if (!cookie) {
341
- this._autoDestruct();
342
- return;
343
- }
344
- this._refreshToken = cookie;
345
- this._refresh(this._config.refreshConfig);
346
- }
347
- else {
348
- this._autoDestruct();
349
- console.error('A BearerAuthProvider was created without token or refresh token. You should provide at least a cookieName where the refresh token might be stored.');
350
- }
351
- }
352
- cleanUp(config) {
353
- var _a, _b;
354
- (_a = this._refreshTimerSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
355
- this._refreshTimerSubscription = null;
356
- if (((_b = this._config.refreshConfig) === null || _b === void 0 ? void 0 : _b.cookieName) && !(config === null || config === void 0 ? void 0 : config.keepCookie)) {
357
- deleteCookie(this._config.refreshConfig.cookieName, '/');
358
- }
359
- }
360
- _autoDestruct() {
361
- var _a;
362
- this.cleanUp();
363
- (_a = this.queryClient) === null || _a === void 0 ? void 0 : _a.clearAuthProvider();
364
- }
365
- _setupRefresh(config) {
366
- var _a, _b;
367
- this.cleanUp({ keepCookie: true });
368
- if (!this._token) {
369
- return;
370
- }
371
- const bearer = decryptBearer(this._token);
372
- if (!bearer) {
373
- return;
374
- }
375
- const expiresInPropertyName = config.expiresInPropertyName || 'exp';
376
- const expiresIn = bearer[expiresInPropertyName];
377
- const fiveMinutes = 5 * 60 * 1000;
378
- const refreshBuffer = (_a = config.refreshBuffer) !== null && _a !== void 0 ? _a : fiveMinutes;
379
- if (expiresIn === undefined) {
380
- throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
381
- }
382
- const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
383
- const strategy = (_b = config.strategy) !== null && _b !== void 0 ? _b : "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
384
- switch (strategy) {
385
- case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
386
- this._refreshTimerSubscription = timer(remainingTime).subscribe(() => this._refresh(config));
387
- break;
388
- }
389
- }
390
- _refresh(config) {
391
- var _a, _b;
392
- return __awaiter(this, void 0, void 0, function* () {
393
- if (!this._refreshToken) {
394
- throw new Error('No refresh token found');
395
- }
396
- if (!this.queryClient) {
397
- throw new Error('Query client instance is null');
398
- }
399
- const { method, route, requestAdapter, responseAdapter, paramLocation } = config;
400
- const data = (_a = requestAdapter === null || requestAdapter === void 0 ? void 0 : requestAdapter(this._refreshToken)) !== null && _a !== void 0 ? _a : { refreshToken: this._refreshToken };
401
- const fullRoute = buildRoute({
402
- base: this.queryClient.config.baseRoute,
403
- route,
404
- queryParams: paramLocation === 'query' ? data : undefined,
405
- });
406
- const requestInit = { body: paramLocation === 'body' ? buildBody(data) : undefined, method };
407
- this.onRefreshInitiation$.next();
408
- try {
409
- const result = yield request({
410
- route: fullRoute,
411
- init: requestInit,
412
- });
413
- const tokens = responseAdapter ? responseAdapter(result.data) : result.data;
414
- if (!tokens.token) {
415
- throw new Error('Token not found in response');
416
- }
417
- if (!tokens.refreshToken) {
418
- throw new Error('Refresh token not found in response');
419
- }
420
- this._token = tokens.token;
421
- this._refreshToken = tokens.refreshToken;
422
- this.onRefreshSuccess$.next(tokens);
423
- if (config.cookieName) {
424
- setCookie(config.cookieName, tokens.refreshToken);
425
- }
426
- this._setupRefresh(config);
427
- this._failureCount = 0;
428
- }
429
- catch (error) {
430
- if (error instanceof Error) {
431
- this.onRefreshFailure$.next(yield buildRequestError(error, fullRoute, requestInit));
432
- }
433
- else {
434
- this.onRefreshFailure$.next(error);
435
- }
436
- this._failureCount++;
437
- if (this._failureCount <= ((_b = config.maxRefreshAttempts) !== null && _b !== void 0 ? _b : 3)) {
438
- this._setupRefresh(config);
439
- }
440
- else {
441
- this._autoDestruct();
442
- }
443
- }
444
- });
445
- }
446
- }
447
-
448
- const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
449
- const transformGql = (str) => {
450
- str = Array.isArray(str) ? str.join('') : str;
451
- const name = getOpName.exec(str);
452
- return function (variables) {
453
- const data = { query: str };
454
- if (variables)
455
- data['variables'] = JSON.stringify(variables);
456
- if (name && name.length) {
457
- const operationName = name[2];
458
- if (operationName)
459
- data['operationName'] = name[2];
460
- }
461
- return JSON.stringify(data);
462
- };
463
- };
464
- const gql = (strings, ...values) => {
465
- const str = strings.reduce((acc, cur, i) => {
466
- return acc + cur + (values[i] || '');
467
- }, '');
468
- return str;
469
- };
470
-
471
320
  function filterSuccess() {
472
321
  return function (source) {
473
322
  return source.pipe(filter((value) => isQueryStateSuccess(value)));
@@ -483,9 +332,14 @@ function filterQueryStates(allowedStates) {
483
332
  return source.pipe(filter((value) => value && allowedStates.includes(value.type)));
484
333
  };
485
334
  }
486
- function takeUntilResponse() {
335
+ function takeUntilResponse(config) {
487
336
  return function (source) {
488
- return source.pipe(takeWhile((value) => isQueryStateLoading(value), true));
337
+ return source.pipe(takeWhile((value) => {
338
+ if ((config === null || config === void 0 ? void 0 : config.excludeNull) && value === null) {
339
+ return false;
340
+ }
341
+ return isQueryStateLoading(value) || value === null;
342
+ }, true));
489
343
  };
490
344
  }
491
345
  function filterNull() {
@@ -728,6 +582,128 @@ class Query {
728
582
  }
729
583
  }
730
584
 
585
+ const isBasicAuthProvider = (authProvider) => authProvider instanceof BasicAuthProvider;
586
+ const isBearerAuthProvider = (authProvider) => authProvider instanceof BearerAuthProvider;
587
+ const isCustomHeaderAuthProvider = (authProvider) => authProvider instanceof CustomHeaderAuthProvider;
588
+ const decryptBearer = (token) => {
589
+ try {
590
+ const base64Url = token.split('.')[1];
591
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
592
+ const jsonPayload = decodeURIComponent(atob(base64)
593
+ .split('')
594
+ .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
595
+ .join(''));
596
+ return JSON.parse(jsonPayload);
597
+ }
598
+ catch (error) {
599
+ console.error(`Invalid bearer token: ${token}`, error);
600
+ return null;
601
+ }
602
+ };
603
+
604
+ class BearerAuthProvider {
605
+ get header() {
606
+ return { Authorization: `Bearer ${this._token}` };
607
+ }
608
+ get currentRefreshQuery$() {
609
+ return this._currentRefreshQuery$.asObservable();
610
+ }
611
+ get currentRefreshQuery() {
612
+ return this._currentRefreshQuery$.getValue();
613
+ }
614
+ constructor(_config) {
615
+ var _a, _b, _c, _d;
616
+ this._config = _config;
617
+ this._destroy$ = new Subject();
618
+ this._currentRefreshQuery$ = new BehaviorSubject(null);
619
+ this._token = null;
620
+ this._refreshToken = null;
621
+ const cookieToken = ((_a = _config.refreshConfig) === null || _a === void 0 ? void 0 : _a.cookieName) ? (_b = getCookie(_config.refreshConfig.cookieName)) !== null && _b !== void 0 ? _b : null : null;
622
+ this._token = _config.token || null;
623
+ this._refreshToken = ((_c = _config.refreshConfig) === null || _c === void 0 ? void 0 : _c.token) || cookieToken || null;
624
+ if (!this._token && !this._refreshToken) {
625
+ if (!((_d = _config.refreshConfig) === null || _d === void 0 ? void 0 : _d.cookieName)) {
626
+ console.error('A BearerAuthProvider was created without token or refresh token. You should provide at least a cookieName where the refresh token might be stored.');
627
+ }
628
+ return;
629
+ }
630
+ this._prepareForRefresh();
631
+ }
632
+ cleanUp() {
633
+ var _a;
634
+ this._destroy$.next(true);
635
+ this._destroy$.unsubscribe();
636
+ this._currentRefreshQuery$.next(null);
637
+ if ((_a = this._config.refreshConfig) === null || _a === void 0 ? void 0 : _a.cookieName) {
638
+ deleteCookie(this._config.refreshConfig.cookieName, '/');
639
+ }
640
+ }
641
+ _prepareForRefresh() {
642
+ var _a, _b;
643
+ if (!this._token || !this._config.refreshConfig) {
644
+ return;
645
+ }
646
+ const bearer = decryptBearer(this._token);
647
+ if (!bearer) {
648
+ return;
649
+ }
650
+ const expiresInPropertyName = this._config.refreshConfig.expiresInPropertyName || 'exp';
651
+ const expiresIn = bearer[expiresInPropertyName];
652
+ const fiveMinutes = 5 * 60 * 1000;
653
+ const refreshBuffer = (_a = this._config.refreshConfig.refreshBuffer) !== null && _a !== void 0 ? _a : fiveMinutes;
654
+ if (expiresIn === undefined) {
655
+ throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
656
+ }
657
+ const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
658
+ const strategy = (_b = this._config.refreshConfig.strategy) !== null && _b !== void 0 ? _b : "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
659
+ switch (strategy) {
660
+ case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
661
+ timer(remainingTime)
662
+ .pipe(takeUntil(this._destroy$))
663
+ .subscribe(() => this._refreshQuery());
664
+ break;
665
+ }
666
+ }
667
+ _refreshQuery() {
668
+ var _a, _b, _c, _d;
669
+ if (!this._refreshToken || !((_a = this._config.refreshConfig) === null || _a === void 0 ? void 0 : _a.queryCreator)) {
670
+ return;
671
+ }
672
+ const args = (_d = (_c = (_b = this._config.refreshConfig).requestArgsAdapter) === null || _c === void 0 ? void 0 : _c.call(_b, this._refreshToken, this._token)) !== null && _d !== void 0 ? _d : {
673
+ body: { refreshToken: this._refreshToken },
674
+ };
675
+ const query = this._config.refreshConfig.queryCreator.prepare(args).execute({ skipCache: true });
676
+ this._currentRefreshQuery$.next(query);
677
+ this._currentRefreshQuery$
678
+ .pipe(switchQueryState(), tap((state) => {
679
+ var _a, _b, _c;
680
+ if (isQueryStateSuccess(state)) {
681
+ if ((_a = this._config.refreshConfig) === null || _a === void 0 ? void 0 : _a.responseAdapter) {
682
+ const tokens = this._config.refreshConfig.responseAdapter(state.response);
683
+ this._token = tokens.token;
684
+ this._refreshToken = tokens.refreshToken || null;
685
+ }
686
+ else {
687
+ this._token = state.response['token'];
688
+ this._refreshToken = state.response['refreshToken'];
689
+ }
690
+ if (((_b = this._config.refreshConfig) === null || _b === void 0 ? void 0 : _b.cookieName) && this._refreshToken) {
691
+ setCookie(this._config.refreshConfig.cookieName, this._refreshToken);
692
+ }
693
+ this._prepareForRefresh();
694
+ }
695
+ else if (isQueryStateFailure(state)) {
696
+ this._token = null;
697
+ this._refreshToken = null;
698
+ if ((_c = this._config.refreshConfig) === null || _c === void 0 ? void 0 : _c.cookieName) {
699
+ deleteCookie(this._config.refreshConfig.cookieName, '/');
700
+ }
701
+ }
702
+ }), takeUntilResponse(), takeUntil(this._destroy$))
703
+ .subscribe();
704
+ }
705
+ }
706
+
731
707
  class QueryDirective {
732
708
  get query() {
733
709
  return this._query;
@@ -1312,7 +1288,6 @@ class QueryClient {
1312
1288
  throw new Error('The auth provider is already set. Please call clearAuthProvider() first.');
1313
1289
  }
1314
1290
  this._authProvider$.next(authProvider);
1315
- authProvider.queryClient = this;
1316
1291
  };
1317
1292
  this.clearAuthProvider = () => {
1318
1293
  var _a;