@ethlete/query 0.1.0-next.15 → 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,8 +1,8 @@
1
+ import { getCookie, deleteCookie, setCookie, DestroyService } from '@ethlete/core';
2
+ import { filter, takeWhile, switchMap, of, BehaviorSubject, Subject, interval, takeUntil, tap, timer, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
1
3
  import { __awaiter } from 'tslib';
2
- import { Subject, timer, filter, takeWhile, switchMap, of, BehaviorSubject, interval, takeUntil, tap, fromEvent, startWith, concat, take, debounceTime, combineLatest, map, distinctUntilChanged } from 'rxjs';
3
4
  import * as i0 from '@angular/core';
4
5
  import { Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef } from '@angular/core';
5
- import { DestroyService } from '@ethlete/core';
6
6
  import { FormGroup } from '@angular/forms';
7
7
  import { Router, ActivatedRoute } from '@angular/router';
8
8
 
@@ -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,147 +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;
324
- this._config = _config;
325
- this._refreshToken = null;
326
- this._refreshTimerSubscription = null;
327
- this._failureCount = 0;
328
- this.queryClient = null;
329
- this.onRefreshInitiation$ = new Subject();
330
- this.onRefreshSuccess$ = new Subject();
331
- this.onRefreshFailure$ = new Subject();
332
- this._token = _config.token;
333
- this._refreshToken = (_b = (_a = _config.refreshConfig) === null || _a === void 0 ? void 0 : _a.token) !== null && _b !== void 0 ? _b : null;
334
- if (this._config.refreshConfig) {
335
- this._setupRefresh(this._config.refreshConfig);
336
- }
337
- }
338
- cleanUp() {
339
- var _a;
340
- (_a = this._refreshTimerSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
341
- this._refreshTimerSubscription = null;
342
- }
343
- _setupRefresh(config) {
344
- var _a, _b;
345
- this.cleanUp();
346
- const bearer = decryptBearer(this._token);
347
- if (!bearer) {
348
- return;
349
- }
350
- const expiresInPropertyName = config.expiresInPropertyName || 'exp';
351
- const expiresIn = bearer[expiresInPropertyName];
352
- const fiveMinutes = 5 * 60 * 1000;
353
- const refreshBuffer = (_a = config.refreshBuffer) !== null && _a !== void 0 ? _a : fiveMinutes;
354
- if (expiresIn === undefined) {
355
- throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
356
- }
357
- const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
358
- const strategy = (_b = config.strategy) !== null && _b !== void 0 ? _b : "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
359
- switch (strategy) {
360
- case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
361
- this._refreshTimerSubscription = timer(remainingTime).subscribe(() => this._refresh(config));
362
- break;
363
- }
364
- }
365
- _refresh(config) {
366
- var _a, _b;
367
- return __awaiter(this, void 0, void 0, function* () {
368
- if (!this._refreshToken) {
369
- throw new Error('No refresh token found');
370
- }
371
- if (!this.queryClient) {
372
- throw new Error('Query client instance is null');
373
- }
374
- const { method, route, requestAdapter, responseAdapter, paramLocation } = config;
375
- const data = (_a = requestAdapter === null || requestAdapter === void 0 ? void 0 : requestAdapter(this._refreshToken)) !== null && _a !== void 0 ? _a : { refreshToken: this._refreshToken };
376
- const fullRoute = buildRoute({
377
- base: this.queryClient.config.baseRoute,
378
- route,
379
- queryParams: paramLocation === 'query' ? data : undefined,
380
- });
381
- const requestInit = { body: paramLocation === 'body' ? buildBody(data) : undefined, method };
382
- this.onRefreshInitiation$.next();
383
- try {
384
- const result = yield request({
385
- route: fullRoute,
386
- init: requestInit,
387
- });
388
- const tokens = responseAdapter ? responseAdapter(result.data) : result.data;
389
- if (!tokens.token) {
390
- throw new Error('Token not found in response');
391
- }
392
- if (!tokens.refreshToken) {
393
- throw new Error('Refresh token not found in response');
394
- }
395
- this._token = tokens.token;
396
- this._refreshToken = tokens.refreshToken;
397
- this.onRefreshSuccess$.next(tokens);
398
- this._setupRefresh(config);
399
- this._failureCount = 0;
400
- }
401
- catch (error) {
402
- if (error instanceof Error) {
403
- this.onRefreshFailure$.next(yield buildRequestError(error, fullRoute, requestInit));
404
- }
405
- else {
406
- this.onRefreshFailure$.next(error);
407
- }
408
- this._failureCount++;
409
- if (this._failureCount <= ((_b = config.maxRefreshAttempts) !== null && _b !== void 0 ? _b : 3)) {
410
- this._setupRefresh(config);
411
- }
412
- }
413
- });
414
- }
415
- }
416
-
417
- const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
418
- const transformGql = (str) => {
419
- str = Array.isArray(str) ? str.join('') : str;
420
- const name = getOpName.exec(str);
421
- return function (variables) {
422
- const data = { query: str };
423
- if (variables)
424
- data['variables'] = JSON.stringify(variables);
425
- if (name && name.length) {
426
- const operationName = name[2];
427
- if (operationName)
428
- data['operationName'] = name[2];
429
- }
430
- return JSON.stringify(data);
431
- };
432
- };
433
- const gql = (strings, ...values) => {
434
- const str = strings.reduce((acc, cur, i) => {
435
- return acc + cur + (values[i] || '');
436
- }, '');
437
- return str;
438
- };
439
-
440
320
  function filterSuccess() {
441
321
  return function (source) {
442
322
  return source.pipe(filter((value) => isQueryStateSuccess(value)));
@@ -452,9 +332,14 @@ function filterQueryStates(allowedStates) {
452
332
  return source.pipe(filter((value) => value && allowedStates.includes(value.type)));
453
333
  };
454
334
  }
455
- function takeUntilResponse() {
335
+ function takeUntilResponse(config) {
456
336
  return function (source) {
457
- 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));
458
343
  };
459
344
  }
460
345
  function filterNull() {
@@ -697,6 +582,128 @@ class Query {
697
582
  }
698
583
  }
699
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
+
700
707
  class QueryDirective {
701
708
  get query() {
702
709
  return this._query;
@@ -781,9 +788,9 @@ class QueryDirective {
781
788
  }
782
789
  }
783
790
  }
784
- QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
785
- QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.1", type: QueryDirective, isStandalone: true, selector: "[query]", inputs: { query: "query", cache: ["queryCache", "cache"] }, ngImport: i0 });
786
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: QueryDirective, decorators: [{
791
+ QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
792
+ QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.2", type: QueryDirective, isStandalone: true, selector: "[query]", inputs: { query: "query", cache: ["queryCache", "cache"] }, ngImport: i0 });
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: QueryDirective, decorators: [{
787
794
  type: Directive,
788
795
  args: [{
789
796
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1079,9 +1086,9 @@ class InfinityQueryDirective {
1079
1086
  this._data$.next([]);
1080
1087
  }
1081
1088
  }
1082
- InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1083
- InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.1", type: InfinityQueryDirective, isStandalone: true, selector: "[infinityQuery]", inputs: { infinityQuery: "infinityQuery" }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService], exportAs: ["infinityQuery"], ngImport: i0 });
1084
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: InfinityQueryDirective, decorators: [{
1089
+ InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1090
+ InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.2", type: InfinityQueryDirective, isStandalone: true, selector: "[infinityQuery]", inputs: { infinityQuery: "infinityQuery" }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService], exportAs: ["infinityQuery"], ngImport: i0 });
1091
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: InfinityQueryDirective, decorators: [{
1085
1092
  type: Directive,
1086
1093
  args: [{
1087
1094
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1132,9 +1139,9 @@ class InfinityQueryTriggerDirective {
1132
1139
  this._observer.observe(this._elementRef.nativeElement);
1133
1140
  }
1134
1141
  }
1135
- InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1136
- InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.1", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[infinityQueryTrigger], infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
1137
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1142
+ InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1143
+ InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.2", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[infinityQueryTrigger], infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
1144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.2", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1138
1145
  type: Directive,
1139
1146
  args: [{
1140
1147
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1233,12 +1240,15 @@ class QueryClient {
1233
1240
  return this._clientConfig;
1234
1241
  }
1235
1242
  get authProvider() {
1236
- return this._authProvider;
1243
+ return this._authProvider$.getValue();
1244
+ }
1245
+ get authProvider$() {
1246
+ return this._authProvider$.asObservable();
1237
1247
  }
1238
1248
  constructor(_clientConfig) {
1239
1249
  var _a, _b;
1240
1250
  this._clientConfig = _clientConfig;
1241
- this._authProvider = null;
1251
+ this._authProvider$ = new BehaviorSubject(null);
1242
1252
  this.get = (queryConfig) => this.fetch(Object.assign(Object.assign({}, queryConfig), { method: 'GET' }));
1243
1253
  this.post = (queryConfig) => this.fetch(Object.assign(Object.assign({}, queryConfig), { method: 'POST' }));
1244
1254
  this.put = (queryConfig) => this.fetch(Object.assign(Object.assign({}, queryConfig), { method: 'PUT' }));
@@ -1274,16 +1284,15 @@ class QueryClient {
1274
1284
  };
1275
1285
  };
1276
1286
  this.setAuthProvider = (authProvider) => {
1277
- if (this._authProvider) {
1287
+ if (this.authProvider) {
1278
1288
  throw new Error('The auth provider is already set. Please call clearAuthProvider() first.');
1279
1289
  }
1280
- this._authProvider = authProvider;
1281
- authProvider.queryClient = this;
1290
+ this._authProvider$.next(authProvider);
1282
1291
  };
1283
1292
  this.clearAuthProvider = () => {
1284
1293
  var _a;
1285
- (_a = this._authProvider) === null || _a === void 0 ? void 0 : _a.cleanUp();
1286
- this._authProvider = null;
1294
+ (_a = this.authProvider) === null || _a === void 0 ? void 0 : _a.cleanUp();
1295
+ this._authProvider$.next(null);
1287
1296
  };
1288
1297
  this._store = new QueryStore({
1289
1298
  enableChangeLogging: (_a = _clientConfig.logging) === null || _a === void 0 ? void 0 : _a.queryStateChanges,