@ethlete/query 0.1.0-next.2 → 0.1.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/auth/auth-provider.types.mjs +1 -1
- package/esm2020/lib/auth/auth-provider.utils.mjs +1 -1
- package/esm2020/lib/auth/basic-auth-provider.mjs +4 -5
- package/esm2020/lib/auth/bearer-auth-provider.mjs +117 -60
- package/esm2020/lib/auth/custom-header-auth-provider.mjs +4 -5
- package/esm2020/lib/directives/infinity-query-trigger.directive.mjs +3 -3
- package/esm2020/lib/directives/infinity-query.directive.mjs +36 -11
- package/esm2020/lib/directives/query.directive.mjs +20 -19
- package/esm2020/lib/infinite-query/infinity-query.mjs +11 -11
- package/esm2020/lib/infinite-query/infinity-query.types.mjs +1 -1
- package/esm2020/lib/query/query.mjs +53 -23
- package/esm2020/lib/query/query.types.mjs +1 -1
- package/esm2020/lib/query/query.utils.mjs +42 -4
- package/esm2020/lib/query-client/query-client.mjs +15 -13
- package/esm2020/lib/query-client/query-client.types.mjs +1 -1
- package/esm2020/lib/query-form/query-form.mjs +13 -9
- package/esm2020/lib/query-form/query-form.types.mjs +1 -1
- package/esm2020/lib/query-form/query-form.utils.mjs +21 -1
- package/esm2020/lib/request/request.mjs +4 -2
- package/esm2020/lib/request/request.util.mjs +16 -8
- package/esm2020/lib/utils/deep-freeze.util.mjs +5 -1
- package/fesm2015/ethlete-query.mjs +445 -250
- package/fesm2015/ethlete-query.mjs.map +1 -1
- package/fesm2020/ethlete-query.mjs +432 -244
- package/fesm2020/ethlete-query.mjs.map +1 -1
- package/lib/auth/auth-provider.types.d.ts +30 -22
- package/lib/auth/auth-provider.utils.d.ts +2 -1
- package/lib/auth/basic-auth-provider.d.ts +0 -2
- package/lib/auth/bearer-auth-provider.d.ts +14 -14
- package/lib/auth/custom-header-auth-provider.d.ts +0 -2
- package/lib/directives/infinity-query-trigger.directive.d.ts +1 -1
- package/lib/directives/infinity-query.directive.d.ts +7 -2
- package/lib/directives/query.directive.d.ts +5 -5
- package/lib/infinite-query/infinity-query.types.d.ts +7 -4
- package/lib/query/query.d.ts +5 -3
- package/lib/query/query.types.d.ts +32 -15
- package/lib/query/query.utils.d.ts +22 -5
- package/lib/query-client/query-client.d.ts +11 -10
- package/lib/query-client/query-client.types.d.ts +9 -9
- package/lib/query-form/query-form.d.ts +1 -1
- package/lib/query-form/query-form.types.d.ts +13 -3
- package/lib/query-form/query-form.utils.d.ts +5 -0
- package/lib/request/request.types.d.ts +10 -10
- package/lib/utils/deep-freeze.util.d.ts +1 -1
- package/package.json +6 -6
|
@@ -1,38 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCookie, setCookie, deleteCookie, DestroyService, equal, clone } 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';
|
|
2
3
|
import * as i0 from '@angular/core';
|
|
3
4
|
import { Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef } from '@angular/core';
|
|
4
5
|
import { FormGroup } from '@angular/forms';
|
|
5
6
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
6
7
|
|
|
7
8
|
class CustomHeaderAuthProvider {
|
|
8
|
-
constructor(_config) {
|
|
9
|
-
this._config = _config;
|
|
10
|
-
this.queryClient = null;
|
|
11
|
-
}
|
|
12
9
|
get header() {
|
|
13
10
|
return { [this._config.name]: this._config.value };
|
|
14
11
|
}
|
|
12
|
+
constructor(_config) {
|
|
13
|
+
this._config = _config;
|
|
14
|
+
}
|
|
15
15
|
cleanUp() {
|
|
16
16
|
// noop
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
class BasicAuthProvider {
|
|
21
|
-
constructor(_config) {
|
|
22
|
-
this._config = _config;
|
|
23
|
-
this.queryClient = null;
|
|
24
|
-
}
|
|
25
21
|
get header() {
|
|
26
22
|
return { Authorization: `Basic ${this._basicAuthString}` };
|
|
27
23
|
}
|
|
28
24
|
get _basicAuthString() {
|
|
29
25
|
return btoa(`${this._config.username}:${this._config.password}`);
|
|
30
26
|
}
|
|
27
|
+
constructor(_config) {
|
|
28
|
+
this._config = _config;
|
|
29
|
+
}
|
|
31
30
|
cleanUp() {
|
|
32
31
|
// noop
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
|
|
36
|
+
const transformGql = (str) => {
|
|
37
|
+
str = Array.isArray(str) ? str.join('') : str;
|
|
38
|
+
const name = getOpName.exec(str);
|
|
39
|
+
return function (variables) {
|
|
40
|
+
const data = { query: str };
|
|
41
|
+
if (variables)
|
|
42
|
+
data['variables'] = JSON.stringify(variables);
|
|
43
|
+
if (name && name.length) {
|
|
44
|
+
const operationName = name[2];
|
|
45
|
+
if (operationName)
|
|
46
|
+
data['operationName'] = name[2];
|
|
47
|
+
}
|
|
48
|
+
return JSON.stringify(data);
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const gql = (strings, ...values) => {
|
|
52
|
+
const str = strings.reduce((acc, cur, i) => {
|
|
53
|
+
return acc + cur + (values[i] || '');
|
|
54
|
+
}, '');
|
|
55
|
+
return str;
|
|
56
|
+
};
|
|
57
|
+
|
|
36
58
|
const buildErrorMessage = (code, message) => `[@ethlete\\query:${code}] ${message}`;
|
|
37
59
|
class QueryError extends Error {
|
|
38
60
|
constructor(code, message, data) {
|
|
@@ -200,12 +222,20 @@ const buildRequestError = async (error, route, requestInit) => {
|
|
|
200
222
|
}
|
|
201
223
|
if (isFetchResponse(error)) {
|
|
202
224
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
203
|
-
let detail;
|
|
225
|
+
let detail = null;
|
|
204
226
|
try {
|
|
205
|
-
detail = await error.
|
|
227
|
+
detail = await error.json();
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// noop
|
|
206
231
|
}
|
|
207
|
-
|
|
208
|
-
|
|
232
|
+
if (!detail) {
|
|
233
|
+
try {
|
|
234
|
+
detail = await error.text();
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// noop
|
|
238
|
+
}
|
|
209
239
|
}
|
|
210
240
|
const err = {
|
|
211
241
|
code: error.status,
|
|
@@ -234,12 +264,12 @@ const buildBody = (body) => {
|
|
|
234
264
|
if (typeof body === 'string') {
|
|
235
265
|
return body;
|
|
236
266
|
}
|
|
237
|
-
if (typeof body === 'object') {
|
|
238
|
-
return JSON.stringify(body);
|
|
239
|
-
}
|
|
240
267
|
if (body instanceof FormData) {
|
|
241
268
|
return body;
|
|
242
269
|
}
|
|
270
|
+
if (typeof body === 'object') {
|
|
271
|
+
return JSON.stringify(body);
|
|
272
|
+
}
|
|
243
273
|
throw invalidBodyError(body);
|
|
244
274
|
};
|
|
245
275
|
const transformMethod = (method) => {
|
|
@@ -270,7 +300,9 @@ const request = async (options) => {
|
|
|
270
300
|
if (!response.ok) {
|
|
271
301
|
throw response;
|
|
272
302
|
}
|
|
273
|
-
const
|
|
303
|
+
const isJsonResponse = response.headers.get('Content-Type')?.includes('application/json');
|
|
304
|
+
const isTextResponse = response.headers.get('Content-Type')?.includes('text/plain');
|
|
305
|
+
const data = (isJsonResponse ? await response.json() : isTextResponse ? await response.text() : null);
|
|
274
306
|
const expiresInSeconds = options.cacheAdapter
|
|
275
307
|
? options.cacheAdapter(response.headers)
|
|
276
308
|
: extractExpiresInSeconds(response.headers);
|
|
@@ -282,152 +314,6 @@ const request = async (options) => {
|
|
|
282
314
|
}
|
|
283
315
|
};
|
|
284
316
|
|
|
285
|
-
const isBasicAuthProvider = (authProvider) => authProvider instanceof BasicAuthProvider;
|
|
286
|
-
const isBearerAuthProvider = (authProvider) => authProvider instanceof BearerAuthProvider;
|
|
287
|
-
const isCustomHeaderAuthProvider = (authProvider) => authProvider instanceof CustomHeaderAuthProvider;
|
|
288
|
-
const decryptBearer = (token) => {
|
|
289
|
-
try {
|
|
290
|
-
const base64Url = token.split('.')[1];
|
|
291
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
292
|
-
const jsonPayload = decodeURIComponent(atob(base64)
|
|
293
|
-
.split('')
|
|
294
|
-
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
295
|
-
.join(''));
|
|
296
|
-
return JSON.parse(jsonPayload);
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
console.error(`Invalid bearer token: ${token}`, error);
|
|
300
|
-
return null;
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
class BearerAuthProvider {
|
|
305
|
-
constructor(_config) {
|
|
306
|
-
this._config = _config;
|
|
307
|
-
this._refreshToken = null;
|
|
308
|
-
this._refreshTimerSubscription = null;
|
|
309
|
-
this.queryClient = null;
|
|
310
|
-
this.onRefreshInitiation$ = new Subject();
|
|
311
|
-
this.onRefreshSuccess$ = new Subject();
|
|
312
|
-
this.onRefreshFailure$ = new Subject();
|
|
313
|
-
this._token = _config.token;
|
|
314
|
-
this._refreshToken = _config.refreshConfig?.token ?? null;
|
|
315
|
-
if (this._config.refreshConfig) {
|
|
316
|
-
this._setupRefresh(this._config.refreshConfig);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
get header() {
|
|
320
|
-
return { Authorization: `Bearer ${this._token}` };
|
|
321
|
-
}
|
|
322
|
-
cleanUp() {
|
|
323
|
-
this._refreshTimerSubscription?.unsubscribe();
|
|
324
|
-
this._refreshTimerSubscription = null;
|
|
325
|
-
}
|
|
326
|
-
_setupRefresh(config) {
|
|
327
|
-
const bearer = decryptBearer(this._token);
|
|
328
|
-
if (!bearer) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
const expiresInPropertyName = config.expiresInPropertyName || 'exp';
|
|
332
|
-
const expiresIn = bearer[expiresInPropertyName];
|
|
333
|
-
const fiveMinutes = 5 * 60 * 1000;
|
|
334
|
-
if (expiresIn === undefined) {
|
|
335
|
-
throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
|
|
336
|
-
}
|
|
337
|
-
const remainingTime = new Date(expiresIn * 1000).getTime() - fiveMinutes - new Date().getTime();
|
|
338
|
-
const strategy = config.strategy ?? "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
|
|
339
|
-
switch (strategy) {
|
|
340
|
-
case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
|
|
341
|
-
this._refreshTimerSubscription = timer(remainingTime).subscribe(() => this._refresh(config));
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
async _refresh(config) {
|
|
346
|
-
if (!this._refreshToken) {
|
|
347
|
-
throw new Error('No refresh token found');
|
|
348
|
-
}
|
|
349
|
-
if (!this.queryClient) {
|
|
350
|
-
throw new Error('Query client instance is null');
|
|
351
|
-
}
|
|
352
|
-
const { method, route, bodyAdapter, responseAdapter } = config;
|
|
353
|
-
const fullRoute = buildRoute({
|
|
354
|
-
base: this.queryClient.config.baseRoute,
|
|
355
|
-
route,
|
|
356
|
-
});
|
|
357
|
-
const body = bodyAdapter ? bodyAdapter(this._refreshToken) : { refreshToken: this._refreshToken };
|
|
358
|
-
const requestInit = { body: buildBody(body), method };
|
|
359
|
-
this.onRefreshInitiation$.next();
|
|
360
|
-
try {
|
|
361
|
-
const result = await request({
|
|
362
|
-
route: fullRoute,
|
|
363
|
-
init: requestInit,
|
|
364
|
-
});
|
|
365
|
-
const tokens = responseAdapter ? responseAdapter(result.data) : result.data;
|
|
366
|
-
if (!tokens.token) {
|
|
367
|
-
throw new Error('Token not found in response');
|
|
368
|
-
}
|
|
369
|
-
if (!tokens.refreshToken) {
|
|
370
|
-
throw new Error('Refresh token not found in response');
|
|
371
|
-
}
|
|
372
|
-
this._token = tokens.token;
|
|
373
|
-
this._refreshToken = tokens.refreshToken;
|
|
374
|
-
this.onRefreshSuccess$.next(tokens);
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
if (error instanceof Error) {
|
|
378
|
-
this.onRefreshFailure$.next(await buildRequestError(error, fullRoute, requestInit));
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
this.onRefreshFailure$.next(error);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
|
|
388
|
-
const transformGql = (str) => {
|
|
389
|
-
str = Array.isArray(str) ? str.join('') : str;
|
|
390
|
-
const name = getOpName.exec(str);
|
|
391
|
-
return function (variables) {
|
|
392
|
-
const data = { query: str };
|
|
393
|
-
if (variables)
|
|
394
|
-
data['variables'] = JSON.stringify(variables);
|
|
395
|
-
if (name && name.length) {
|
|
396
|
-
const operationName = name[2];
|
|
397
|
-
if (operationName)
|
|
398
|
-
data['operationName'] = name[2];
|
|
399
|
-
}
|
|
400
|
-
return JSON.stringify(data);
|
|
401
|
-
};
|
|
402
|
-
};
|
|
403
|
-
const gql = (strings, ...values) => {
|
|
404
|
-
const str = strings.reduce((acc, cur, i) => {
|
|
405
|
-
return acc + cur + (values[i] || '');
|
|
406
|
-
}, '');
|
|
407
|
-
return str;
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
const deepFreeze = (object) => {
|
|
411
|
-
// Retrieve the property names defined on object
|
|
412
|
-
const propNames = Object.getOwnPropertyNames(object);
|
|
413
|
-
// Freeze properties before freezing self
|
|
414
|
-
for (const name of propNames) {
|
|
415
|
-
const value = object[name];
|
|
416
|
-
if (value && typeof value === 'object') {
|
|
417
|
-
deepFreeze(value);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
return Object.freeze(object);
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Dummy function for providing types while not breaking inference.
|
|
425
|
-
* **This function always returns null.**
|
|
426
|
-
* @see https://github.com/microsoft/TypeScript/issues/26242
|
|
427
|
-
* @returns null
|
|
428
|
-
*/
|
|
429
|
-
const def = () => null;
|
|
430
|
-
|
|
431
317
|
function filterSuccess() {
|
|
432
318
|
return function (source) {
|
|
433
319
|
return source.pipe(filter((value) => isQueryStateSuccess(value)));
|
|
@@ -438,9 +324,34 @@ function filterFailure() {
|
|
|
438
324
|
return source.pipe(filter((value) => isQueryStateFailure(value)));
|
|
439
325
|
};
|
|
440
326
|
}
|
|
441
|
-
function
|
|
327
|
+
function filterQueryStates(allowedStates) {
|
|
442
328
|
return function (source) {
|
|
443
|
-
return source.pipe(
|
|
329
|
+
return source.pipe(filter((value) => value && allowedStates.includes(value.type)));
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function takeUntilResponse(config) {
|
|
333
|
+
return function (source) {
|
|
334
|
+
return source.pipe(takeWhile((value) => {
|
|
335
|
+
if (config?.excludeNull && value === null) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
return isQueryStateLoading(value) || value === null;
|
|
339
|
+
}, true));
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function filterNull() {
|
|
343
|
+
return function (source) {
|
|
344
|
+
return source.pipe(filter((value) => value !== null));
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function switchQueryState() {
|
|
348
|
+
return function (source) {
|
|
349
|
+
return source.pipe(switchMap((value) => value?.state$ ?? of(null)));
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function switchQueryCollectionState() {
|
|
353
|
+
return function (source) {
|
|
354
|
+
return source.pipe(switchMap((value) => value?.query.state$ ?? of(null)));
|
|
444
355
|
};
|
|
445
356
|
}
|
|
446
357
|
const isQueryStateLoading = (state) => state?.type === "LOADING" /* QueryStateType.Loading */;
|
|
@@ -468,23 +379,23 @@ const isGqlQueryConfig = (config) => {
|
|
|
468
379
|
}
|
|
469
380
|
return true;
|
|
470
381
|
};
|
|
382
|
+
const isQuery = (query) => {
|
|
383
|
+
if (!query || typeof query !== 'object' || Array.isArray(query)) {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
if (!('state$' in query)) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
return true;
|
|
390
|
+
};
|
|
391
|
+
const createQueryCollection = (
|
|
392
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
393
|
+
queryMap) => new BehaviorSubject(null);
|
|
394
|
+
const extractQuery = (v) => (isQuery(v) ? v : v?.query) ?? null;
|
|
471
395
|
|
|
472
396
|
class Query {
|
|
473
|
-
constructor(_client, _queryConfig, _route, _args) {
|
|
474
|
-
this._client = _client;
|
|
475
|
-
this._queryConfig = _queryConfig;
|
|
476
|
-
this._route = _route;
|
|
477
|
-
this._args = _args;
|
|
478
|
-
this._currentId = 0;
|
|
479
|
-
this._abortController = new AbortController();
|
|
480
|
-
this._pollingSubscription = null;
|
|
481
|
-
this._state$ = new BehaviorSubject({
|
|
482
|
-
type: "PREPARED" /* QueryStateType.Prepared */,
|
|
483
|
-
meta: { id: this._currentId },
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
397
|
get _nextId() {
|
|
487
|
-
return this._currentId
|
|
398
|
+
return ++this._currentId;
|
|
488
399
|
}
|
|
489
400
|
get state$() {
|
|
490
401
|
return this._state$.asObservable();
|
|
@@ -502,6 +413,20 @@ class Query {
|
|
|
502
413
|
}
|
|
503
414
|
return ts < Date.now();
|
|
504
415
|
}
|
|
416
|
+
constructor(_client, _queryConfig, _route, _args) {
|
|
417
|
+
this._client = _client;
|
|
418
|
+
this._queryConfig = _queryConfig;
|
|
419
|
+
this._route = _route;
|
|
420
|
+
this._args = _args;
|
|
421
|
+
this._currentId = 0;
|
|
422
|
+
this._abortController = new AbortController();
|
|
423
|
+
this._pollingSubscription = null;
|
|
424
|
+
this._onAbort$ = new Subject();
|
|
425
|
+
this._state$ = new BehaviorSubject({
|
|
426
|
+
type: "PREPARED" /* QueryStateType.Prepared */,
|
|
427
|
+
meta: { id: this._currentId },
|
|
428
|
+
});
|
|
429
|
+
}
|
|
505
430
|
clone() {
|
|
506
431
|
return this._client.fetch(this._queryConfig);
|
|
507
432
|
}
|
|
@@ -516,11 +441,12 @@ class Query {
|
|
|
516
441
|
if (isQueryStateLoading(this._state$.value)) {
|
|
517
442
|
this.abort();
|
|
518
443
|
}
|
|
519
|
-
const meta =
|
|
444
|
+
const meta = { id };
|
|
520
445
|
this._state$.next({
|
|
521
446
|
type: "LOADING" /* QueryStateType.Loading */,
|
|
522
447
|
meta,
|
|
523
448
|
});
|
|
449
|
+
this._updateUseResultInDependencies();
|
|
524
450
|
let body = null;
|
|
525
451
|
let contentType = null;
|
|
526
452
|
if (isGqlQueryConfig(this._queryConfig)) {
|
|
@@ -556,6 +482,10 @@ class Query {
|
|
|
556
482
|
};
|
|
557
483
|
}
|
|
558
484
|
}
|
|
485
|
+
// For form data we need to remove content type header because browser will set it automatically including boundary
|
|
486
|
+
if (headers && 'Content-Type' in headers && headers['Content-Type'] === 'multipart/form-data') {
|
|
487
|
+
delete headers['Content-Type'];
|
|
488
|
+
}
|
|
559
489
|
request({
|
|
560
490
|
route: this._route,
|
|
561
491
|
init: {
|
|
@@ -570,7 +500,11 @@ class Query {
|
|
|
570
500
|
const isResponseObject = typeof response === 'object';
|
|
571
501
|
const isGql = isGqlQueryConfig(this._queryConfig);
|
|
572
502
|
let responseData = null;
|
|
573
|
-
if (isGql &&
|
|
503
|
+
if (isGql &&
|
|
504
|
+
isResponseObject &&
|
|
505
|
+
!!response.data &&
|
|
506
|
+
typeof response.data === 'object' &&
|
|
507
|
+
'data' in response.data) {
|
|
574
508
|
responseData = response.data['data'];
|
|
575
509
|
}
|
|
576
510
|
else {
|
|
@@ -581,9 +515,9 @@ class Query {
|
|
|
581
515
|
: responseData;
|
|
582
516
|
this._state$.next({
|
|
583
517
|
type: "SUCCESS" /* QueryStateType.Success */,
|
|
584
|
-
response:
|
|
585
|
-
rawResponse:
|
|
586
|
-
meta:
|
|
518
|
+
response: transformedResponse,
|
|
519
|
+
rawResponse: responseData,
|
|
520
|
+
meta: { ...meta, expiresAt: response.expiresInTimestamp },
|
|
587
521
|
});
|
|
588
522
|
})
|
|
589
523
|
.catch((error) => this._handleExecuteError(error, meta));
|
|
@@ -592,6 +526,7 @@ class Query {
|
|
|
592
526
|
abort() {
|
|
593
527
|
this._abortController.abort();
|
|
594
528
|
this._abortController = new AbortController();
|
|
529
|
+
this._onAbort$.next();
|
|
595
530
|
return this;
|
|
596
531
|
}
|
|
597
532
|
poll(config) {
|
|
@@ -608,6 +543,26 @@ class Query {
|
|
|
608
543
|
this._pollingSubscription = null;
|
|
609
544
|
return this;
|
|
610
545
|
}
|
|
546
|
+
_updateUseResultInDependencies() {
|
|
547
|
+
if (!this._args?.useResultIn?.length) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
this.state$
|
|
551
|
+
.pipe(filterSuccess(), takeUntil(this._onAbort$), takeUntilResponse(), tap((state) => {
|
|
552
|
+
if (!this._args?.useResultIn) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
for (const query of this._args.useResultIn) {
|
|
556
|
+
query._state$.next({
|
|
557
|
+
type: "SUCCESS" /* QueryStateType.Success */,
|
|
558
|
+
meta: { ...state.meta, id: query._nextId },
|
|
559
|
+
rawResponse: state.rawResponse,
|
|
560
|
+
response: state.response,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}))
|
|
564
|
+
.subscribe();
|
|
565
|
+
}
|
|
611
566
|
_handleExecuteError(error, meta) {
|
|
612
567
|
if (isAbortRequestError(error)) {
|
|
613
568
|
this._state$.next({
|
|
@@ -628,7 +583,178 @@ class Query {
|
|
|
628
583
|
}
|
|
629
584
|
}
|
|
630
585
|
|
|
586
|
+
const isBasicAuthProvider = (authProvider) => authProvider instanceof BasicAuthProvider;
|
|
587
|
+
const isBearerAuthProvider = (authProvider) => authProvider instanceof BearerAuthProvider;
|
|
588
|
+
const isCustomHeaderAuthProvider = (authProvider) => authProvider instanceof CustomHeaderAuthProvider;
|
|
589
|
+
const decryptBearer = (token) => {
|
|
590
|
+
try {
|
|
591
|
+
const base64Url = token.split('.')[1];
|
|
592
|
+
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
593
|
+
const jsonPayload = decodeURIComponent(atob(base64)
|
|
594
|
+
.split('')
|
|
595
|
+
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
596
|
+
.join(''));
|
|
597
|
+
return JSON.parse(jsonPayload);
|
|
598
|
+
}
|
|
599
|
+
catch (error) {
|
|
600
|
+
console.error(`Invalid bearer token: ${token}`, error);
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
class BearerAuthProvider {
|
|
606
|
+
get header() {
|
|
607
|
+
return { Authorization: `Bearer ${this._tokens$.getValue().token}` };
|
|
608
|
+
}
|
|
609
|
+
get tokens$() {
|
|
610
|
+
return this._tokens$.asObservable();
|
|
611
|
+
}
|
|
612
|
+
get tokens() {
|
|
613
|
+
return this._tokens$.getValue();
|
|
614
|
+
}
|
|
615
|
+
get currentRefreshQuery$() {
|
|
616
|
+
return this._currentRefreshQuery$.asObservable();
|
|
617
|
+
}
|
|
618
|
+
get currentRefreshQuery() {
|
|
619
|
+
return this._currentRefreshQuery$.getValue();
|
|
620
|
+
}
|
|
621
|
+
constructor(_config) {
|
|
622
|
+
this._config = _config;
|
|
623
|
+
this._destroy$ = new Subject();
|
|
624
|
+
this._currentRefreshQuery$ = new BehaviorSubject(null);
|
|
625
|
+
this._tokens$ = new BehaviorSubject({
|
|
626
|
+
token: null,
|
|
627
|
+
refreshToken: null,
|
|
628
|
+
});
|
|
629
|
+
const cookieEnabled = _config.refreshConfig?.cookieEnabled ?? true;
|
|
630
|
+
const cookieToken = _config.refreshConfig?.cookieName && cookieEnabled ? getCookie(_config.refreshConfig.cookieName) ?? null : null;
|
|
631
|
+
this._tokens$.next({
|
|
632
|
+
token: _config.token || null,
|
|
633
|
+
refreshToken: _config.refreshConfig?.token || cookieToken || null,
|
|
634
|
+
});
|
|
635
|
+
if (!this.tokens.token && !this.tokens.refreshToken) {
|
|
636
|
+
if (!_config.refreshConfig?.cookieName) {
|
|
637
|
+
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.');
|
|
638
|
+
}
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
if (this.tokens.token) {
|
|
642
|
+
this._prepareForRefresh();
|
|
643
|
+
if (this.tokens.refreshToken && this._config.refreshConfig?.cookieName) {
|
|
644
|
+
setCookie(this._config.refreshConfig.cookieName, this.tokens.refreshToken);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (this.tokens.refreshToken) {
|
|
648
|
+
this._refreshQuery();
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
cleanUp() {
|
|
652
|
+
this._destroy$.next(true);
|
|
653
|
+
this._destroy$.unsubscribe();
|
|
654
|
+
this._currentRefreshQuery$.next(null);
|
|
655
|
+
if (this._config.refreshConfig?.cookieName) {
|
|
656
|
+
deleteCookie(this._config.refreshConfig.cookieName, '/');
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
enableCookie() {
|
|
660
|
+
if (!this._config.refreshConfig?.cookieName) {
|
|
661
|
+
throw new Error('No cookie name was provided');
|
|
662
|
+
}
|
|
663
|
+
if (!this.tokens.refreshToken) {
|
|
664
|
+
throw new Error('No refresh token was provided');
|
|
665
|
+
}
|
|
666
|
+
this._config.refreshConfig.cookieEnabled = true;
|
|
667
|
+
setCookie(this._config.refreshConfig.cookieName, this.tokens.refreshToken);
|
|
668
|
+
}
|
|
669
|
+
disableCookie() {
|
|
670
|
+
if (!this._config.refreshConfig?.cookieName) {
|
|
671
|
+
throw new Error('No cookie name was provided');
|
|
672
|
+
}
|
|
673
|
+
this._config.refreshConfig.cookieEnabled = false;
|
|
674
|
+
deleteCookie(this._config.refreshConfig.cookieName, '/');
|
|
675
|
+
}
|
|
676
|
+
_prepareForRefresh() {
|
|
677
|
+
if (!this.tokens.token || !this._config.refreshConfig) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
const bearer = decryptBearer(this.tokens.token);
|
|
681
|
+
if (!bearer) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const expiresInPropertyName = this._config.refreshConfig.expiresInPropertyName || 'exp';
|
|
685
|
+
const expiresIn = bearer[expiresInPropertyName];
|
|
686
|
+
const fiveMinutes = 5 * 60 * 1000;
|
|
687
|
+
const refreshBuffer = this._config.refreshConfig.refreshBuffer ?? fiveMinutes;
|
|
688
|
+
if (expiresIn === undefined) {
|
|
689
|
+
throw new Error(`Bearer token does not contain an '${expiresInPropertyName}' property`);
|
|
690
|
+
}
|
|
691
|
+
const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
|
|
692
|
+
const strategy = this._config.refreshConfig.strategy ?? "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */;
|
|
693
|
+
switch (strategy) {
|
|
694
|
+
case "beforeExpiration" /* AuthBearerRefreshStrategy.BeforeExpiration */:
|
|
695
|
+
timer(remainingTime)
|
|
696
|
+
.pipe(takeUntil(this._destroy$))
|
|
697
|
+
.subscribe(() => this._refreshQuery());
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
_refreshQuery() {
|
|
702
|
+
const currentRefreshToken = this.tokens.refreshToken;
|
|
703
|
+
if (!currentRefreshToken || !this._config.refreshConfig) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const args = this._config.refreshConfig.requestArgsAdapter?.({
|
|
707
|
+
token: this.tokens.token,
|
|
708
|
+
refreshToken: currentRefreshToken,
|
|
709
|
+
}) ?? {
|
|
710
|
+
body: { refreshToken: currentRefreshToken },
|
|
711
|
+
};
|
|
712
|
+
const query = this._config.refreshConfig.queryCreator.prepare(args).execute({ skipCache: true });
|
|
713
|
+
this._currentRefreshQuery$.next(query);
|
|
714
|
+
this._currentRefreshQuery$
|
|
715
|
+
.pipe(switchQueryState(), tap((state) => {
|
|
716
|
+
if (isQueryStateSuccess(state)) {
|
|
717
|
+
if (this._config.refreshConfig?.responseAdapter) {
|
|
718
|
+
const tokens = this._config.refreshConfig.responseAdapter(state.response);
|
|
719
|
+
this._tokens$.next(tokens);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
this._tokens$.next({
|
|
723
|
+
token: state.response['token'],
|
|
724
|
+
refreshToken: state.response['refreshToken'],
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
const cookieEnabled = this._config.refreshConfig?.cookieEnabled ?? true;
|
|
728
|
+
if (this._config.refreshConfig?.cookieName && this.tokens.refreshToken && cookieEnabled) {
|
|
729
|
+
setCookie(this._config.refreshConfig.cookieName, this.tokens.refreshToken);
|
|
730
|
+
}
|
|
731
|
+
this._prepareForRefresh();
|
|
732
|
+
}
|
|
733
|
+
else if (isQueryStateFailure(state)) {
|
|
734
|
+
this._tokens$.next({ token: null, refreshToken: null });
|
|
735
|
+
if (this._config.refreshConfig?.cookieName) {
|
|
736
|
+
deleteCookie(this._config.refreshConfig.cookieName, '/');
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}), takeUntilResponse(), takeUntil(this._destroy$))
|
|
740
|
+
.subscribe();
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
631
744
|
class QueryDirective {
|
|
745
|
+
get query() {
|
|
746
|
+
return this._query;
|
|
747
|
+
}
|
|
748
|
+
set query(v) {
|
|
749
|
+
this._query = v;
|
|
750
|
+
this._subscribeToQuery();
|
|
751
|
+
}
|
|
752
|
+
get cache() {
|
|
753
|
+
return this._cache;
|
|
754
|
+
}
|
|
755
|
+
set cache(v) {
|
|
756
|
+
this._cache = v;
|
|
757
|
+
}
|
|
632
758
|
constructor(_mainTemplateRef, _viewContainerRef, _errorHandler, _cdr) {
|
|
633
759
|
this._mainTemplateRef = _mainTemplateRef;
|
|
634
760
|
this._viewContainerRef = _viewContainerRef;
|
|
@@ -645,19 +771,6 @@ class QueryDirective {
|
|
|
645
771
|
};
|
|
646
772
|
this._cache = false;
|
|
647
773
|
}
|
|
648
|
-
get query() {
|
|
649
|
-
return this._query;
|
|
650
|
-
}
|
|
651
|
-
set query(v) {
|
|
652
|
-
this._query = v;
|
|
653
|
-
this._subscribeToQuery();
|
|
654
|
-
}
|
|
655
|
-
get cache() {
|
|
656
|
-
return this._cache;
|
|
657
|
-
}
|
|
658
|
-
set cache(v) {
|
|
659
|
-
this._cache = v;
|
|
660
|
-
}
|
|
661
774
|
static ngTemplateContextGuard(dir, ctx) {
|
|
662
775
|
return true;
|
|
663
776
|
}
|
|
@@ -673,7 +786,8 @@ class QueryDirective {
|
|
|
673
786
|
if (!this.query) {
|
|
674
787
|
return;
|
|
675
788
|
}
|
|
676
|
-
const
|
|
789
|
+
const query = isQuery(this.query) ? this.query : this.query.query;
|
|
790
|
+
const sub = query.state$.pipe(tap((state) => this._updateView(state))).subscribe();
|
|
677
791
|
this._subscription = sub;
|
|
678
792
|
}
|
|
679
793
|
_updateView(state) {
|
|
@@ -709,9 +823,9 @@ class QueryDirective {
|
|
|
709
823
|
}
|
|
710
824
|
}
|
|
711
825
|
}
|
|
712
|
-
QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
713
|
-
QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
714
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
826
|
+
QueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
827
|
+
QueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.4", type: QueryDirective, isStandalone: true, selector: "[query]", inputs: { query: "query", cache: ["queryCache", "cache"] }, ngImport: i0 });
|
|
828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: QueryDirective, decorators: [{
|
|
715
829
|
type: Directive,
|
|
716
830
|
args: [{
|
|
717
831
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -727,16 +841,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.9", ngImpor
|
|
|
727
841
|
|
|
728
842
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
729
843
|
class InfinityQuery {
|
|
730
|
-
constructor(_config) {
|
|
731
|
-
this._config = _config;
|
|
732
|
-
this._currentPage$ = new BehaviorSubject(null);
|
|
733
|
-
this._currentCalculatedPage$ = new BehaviorSubject(null);
|
|
734
|
-
this._totalPages$ = new BehaviorSubject(null);
|
|
735
|
-
this._itemsPerPage$ = new BehaviorSubject(this._config.limitParam?.value ?? 10);
|
|
736
|
-
this._currentQuery$ = new BehaviorSubject(null);
|
|
737
|
-
this._data$ = new BehaviorSubject([]);
|
|
738
|
-
this._subscriptions = [];
|
|
739
|
-
}
|
|
740
844
|
get currentPage$() {
|
|
741
845
|
return this._currentPage$.asObservable();
|
|
742
846
|
}
|
|
@@ -773,6 +877,16 @@ class InfinityQuery {
|
|
|
773
877
|
get data() {
|
|
774
878
|
return this._data$.getValue();
|
|
775
879
|
}
|
|
880
|
+
constructor(_config) {
|
|
881
|
+
this._config = _config;
|
|
882
|
+
this._currentPage$ = new BehaviorSubject(null);
|
|
883
|
+
this._currentCalculatedPage$ = new BehaviorSubject(null);
|
|
884
|
+
this._totalPages$ = new BehaviorSubject(null);
|
|
885
|
+
this._itemsPerPage$ = new BehaviorSubject(this._config.limitParam?.value ?? 10);
|
|
886
|
+
this._currentQuery$ = new BehaviorSubject(null);
|
|
887
|
+
this._data$ = new BehaviorSubject([]);
|
|
888
|
+
this._subscriptions = [];
|
|
889
|
+
}
|
|
776
890
|
nextPage() {
|
|
777
891
|
const newPage = (this._currentPage$.value ?? 0) + 1;
|
|
778
892
|
const calculatedPage = this._config?.pageParam?.valueCalculator?.({
|
|
@@ -891,6 +1005,7 @@ const skipPaginationPageParamCalculator = ({ page, itemsPerPage }) => itemsPerPa
|
|
|
891
1005
|
const INFINITY_QUERY_TOKEN = new InjectionToken('INFINITY_QUERY_TOKEN');
|
|
892
1006
|
class InfinityQueryDirective {
|
|
893
1007
|
constructor() {
|
|
1008
|
+
this._queryConfigChanged$ = new Subject();
|
|
894
1009
|
this._viewContext = {
|
|
895
1010
|
$implicit: null,
|
|
896
1011
|
infinityQuery: null,
|
|
@@ -904,17 +1019,19 @@ class InfinityQueryDirective {
|
|
|
904
1019
|
itemsPerPage: null,
|
|
905
1020
|
};
|
|
906
1021
|
this._infinityQueryInstance = null;
|
|
907
|
-
this._destroy$ =
|
|
1022
|
+
this._destroy$ = inject(DestroyService, { host: true }).destroy$;
|
|
908
1023
|
this._cdr = inject(ChangeDetectorRef);
|
|
909
1024
|
this._viewContainerRef = inject(ViewContainerRef);
|
|
910
1025
|
this._mainTemplateRef = inject((TemplateRef));
|
|
911
1026
|
this._errorHandler = inject(ErrorHandler);
|
|
1027
|
+
this._data$ = new BehaviorSubject([]);
|
|
912
1028
|
this._isMainViewCreated = false;
|
|
913
1029
|
}
|
|
914
1030
|
get infinityQuery() {
|
|
915
1031
|
return this._infinityQuery;
|
|
916
1032
|
}
|
|
917
1033
|
set infinityQuery(v) {
|
|
1034
|
+
this._cleanup();
|
|
918
1035
|
this._infinityQuery = v;
|
|
919
1036
|
this._infinityQueryInstance = this._setupInfinityQuery(v);
|
|
920
1037
|
this._loadNextPage();
|
|
@@ -925,6 +1042,12 @@ class InfinityQueryDirective {
|
|
|
925
1042
|
get instance() {
|
|
926
1043
|
return this._infinityQueryInstance;
|
|
927
1044
|
}
|
|
1045
|
+
get data$() {
|
|
1046
|
+
return this._data$.asObservable();
|
|
1047
|
+
}
|
|
1048
|
+
get data() {
|
|
1049
|
+
return this._data$.getValue();
|
|
1050
|
+
}
|
|
928
1051
|
static ngTemplateContextGuard(dir, ctx) {
|
|
929
1052
|
return true;
|
|
930
1053
|
}
|
|
@@ -932,8 +1055,6 @@ class InfinityQueryDirective {
|
|
|
932
1055
|
this._renderMainView();
|
|
933
1056
|
}
|
|
934
1057
|
ngOnDestroy() {
|
|
935
|
-
this._destroy$.next(true);
|
|
936
|
-
this._destroy$.unsubscribe();
|
|
937
1058
|
this.instance?._destroy();
|
|
938
1059
|
}
|
|
939
1060
|
_setupInfinityQuery(config) {
|
|
@@ -972,15 +1093,17 @@ class InfinityQueryDirective {
|
|
|
972
1093
|
this._viewContext.currentPage = null;
|
|
973
1094
|
this._viewContext.itemsPerPage = null;
|
|
974
1095
|
this._viewContext.totalPages = null;
|
|
1096
|
+
this._data$.next([]);
|
|
975
1097
|
}
|
|
976
1098
|
this._cdr.markForCheck();
|
|
977
|
-
}), takeUntil(this._destroy$))
|
|
1099
|
+
}), takeUntil(this._destroy$), takeUntil(this._queryConfigChanged$))
|
|
978
1100
|
.subscribe();
|
|
979
1101
|
instance.data$
|
|
980
1102
|
.pipe(tap((data) => {
|
|
981
1103
|
this._viewContext.infinityQuery = this._viewContext.$implicit = data;
|
|
1104
|
+
this._data$.next(data);
|
|
982
1105
|
this._cdr.markForCheck();
|
|
983
|
-
}), takeUntil(this._destroy$))
|
|
1106
|
+
}), takeUntil(this._destroy$), takeUntil(this._queryConfigChanged$))
|
|
984
1107
|
.subscribe();
|
|
985
1108
|
return instance;
|
|
986
1109
|
}
|
|
@@ -996,16 +1119,31 @@ class InfinityQueryDirective {
|
|
|
996
1119
|
this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
|
|
997
1120
|
}
|
|
998
1121
|
}
|
|
1122
|
+
_cleanup() {
|
|
1123
|
+
this._queryConfigChanged$.next(true);
|
|
1124
|
+
this.instance?._destroy();
|
|
1125
|
+
this._viewContext.loading = false;
|
|
1126
|
+
this._viewContext.error = null;
|
|
1127
|
+
this._viewContext.infinityQuery = null;
|
|
1128
|
+
this._viewContext.$implicit = null;
|
|
1129
|
+
this._viewContext.isFirstLoad = false;
|
|
1130
|
+
this._viewContext.canLoadMore = false;
|
|
1131
|
+
this._viewContext.currentPage = null;
|
|
1132
|
+
this._viewContext.itemsPerPage = null;
|
|
1133
|
+
this._viewContext.totalPages = null;
|
|
1134
|
+
this._data$.next([]);
|
|
1135
|
+
}
|
|
999
1136
|
}
|
|
1000
|
-
InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1001
|
-
InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
1002
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1137
|
+
InfinityQueryDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1138
|
+
InfinityQueryDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.4", type: InfinityQueryDirective, isStandalone: true, selector: "[infinityQuery]", inputs: { infinityQuery: "infinityQuery" }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService], exportAs: ["infinityQuery"], ngImport: i0 });
|
|
1139
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: InfinityQueryDirective, decorators: [{
|
|
1003
1140
|
type: Directive,
|
|
1004
1141
|
args: [{
|
|
1005
1142
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
1006
1143
|
selector: '[infinityQuery]',
|
|
1144
|
+
exportAs: 'infinityQuery',
|
|
1007
1145
|
standalone: true,
|
|
1008
|
-
providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }],
|
|
1146
|
+
providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }, DestroyService],
|
|
1009
1147
|
}]
|
|
1010
1148
|
}], propDecorators: { infinityQuery: [{
|
|
1011
1149
|
type: Input
|
|
@@ -1048,9 +1186,9 @@ class InfinityQueryTriggerDirective {
|
|
|
1048
1186
|
this._observer.observe(this._elementRef.nativeElement);
|
|
1049
1187
|
}
|
|
1050
1188
|
}
|
|
1051
|
-
InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1052
|
-
InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
1053
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1189
|
+
InfinityQueryTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1190
|
+
InfinityQueryTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.4", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[infinityQueryTrigger], infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
|
|
1191
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
|
|
1054
1192
|
type: Directive,
|
|
1055
1193
|
args: [{
|
|
1056
1194
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -1142,9 +1280,18 @@ config, args) => {
|
|
|
1142
1280
|
};
|
|
1143
1281
|
|
|
1144
1282
|
class QueryClient {
|
|
1283
|
+
get config() {
|
|
1284
|
+
return this._clientConfig;
|
|
1285
|
+
}
|
|
1286
|
+
get authProvider() {
|
|
1287
|
+
return this._authProvider$.getValue();
|
|
1288
|
+
}
|
|
1289
|
+
get authProvider$() {
|
|
1290
|
+
return this._authProvider$.asObservable();
|
|
1291
|
+
}
|
|
1145
1292
|
constructor(_clientConfig) {
|
|
1146
1293
|
this._clientConfig = _clientConfig;
|
|
1147
|
-
this._authProvider = null;
|
|
1294
|
+
this._authProvider$ = new BehaviorSubject(null);
|
|
1148
1295
|
this.get = (queryConfig) => this.fetch({
|
|
1149
1296
|
...queryConfig,
|
|
1150
1297
|
method: 'GET',
|
|
@@ -1201,38 +1348,31 @@ class QueryClient {
|
|
|
1201
1348
|
};
|
|
1202
1349
|
};
|
|
1203
1350
|
this.setAuthProvider = (authProvider) => {
|
|
1204
|
-
if (this.
|
|
1351
|
+
if (this.authProvider) {
|
|
1205
1352
|
throw new Error('The auth provider is already set. Please call clearAuthProvider() first.');
|
|
1206
1353
|
}
|
|
1207
|
-
this._authProvider
|
|
1208
|
-
authProvider.queryClient = this;
|
|
1354
|
+
this._authProvider$.next(authProvider);
|
|
1209
1355
|
};
|
|
1210
1356
|
this.clearAuthProvider = () => {
|
|
1211
|
-
this.
|
|
1212
|
-
this._authProvider
|
|
1357
|
+
this.authProvider?.cleanUp();
|
|
1358
|
+
this._authProvider$.next(null);
|
|
1213
1359
|
};
|
|
1214
1360
|
this._store = new QueryStore({
|
|
1215
1361
|
enableChangeLogging: _clientConfig.logging?.queryStateChanges,
|
|
1216
1362
|
enableGarbageCollectorLogging: _clientConfig.logging?.queryStateGarbageCollector,
|
|
1217
1363
|
});
|
|
1218
1364
|
}
|
|
1219
|
-
get config() {
|
|
1220
|
-
return this._clientConfig;
|
|
1221
|
-
}
|
|
1222
|
-
get authProvider() {
|
|
1223
|
-
return this._authProvider;
|
|
1224
|
-
}
|
|
1225
1365
|
}
|
|
1226
1366
|
|
|
1227
1367
|
class QueryField {
|
|
1368
|
+
get control() {
|
|
1369
|
+
return this.data.control;
|
|
1370
|
+
}
|
|
1228
1371
|
constructor(data) {
|
|
1229
1372
|
this.data = data;
|
|
1230
1373
|
this.changes$ = this._setupChangesObservable();
|
|
1231
1374
|
this._currentDebounceTimeout = null;
|
|
1232
1375
|
}
|
|
1233
|
-
get control() {
|
|
1234
|
-
return this.data.control;
|
|
1235
|
-
}
|
|
1236
1376
|
setValue(value) {
|
|
1237
1377
|
if (this._currentDebounceTimeout !== null) {
|
|
1238
1378
|
clearTimeout(this._currentDebounceTimeout);
|
|
@@ -1266,7 +1406,7 @@ class QueryForm {
|
|
|
1266
1406
|
this.form = this._setupFormGroup();
|
|
1267
1407
|
}
|
|
1268
1408
|
observe(options) {
|
|
1269
|
-
return combineLatest(Object.values(this._fields).map((field) => field.changes$)).pipe(map(() => this.form.getRawValue()), distinctUntilChanged((a, b) =>
|
|
1409
|
+
return combineLatest(Object.values(this._fields).map((field) => field.changes$)).pipe(map(() => this.form.getRawValue()), distinctUntilChanged((a, b) => equal(a, b)), tap((values) => {
|
|
1270
1410
|
if (options?.syncViaUrlQueryParams !== false) {
|
|
1271
1411
|
this._syncViaUrlQueryParams(values);
|
|
1272
1412
|
}
|
|
@@ -1279,10 +1419,11 @@ class QueryForm {
|
|
|
1279
1419
|
const queryParams = this._activatedRoute.snapshot.queryParams;
|
|
1280
1420
|
for (const [key, field] of Object.entries(this._fields)) {
|
|
1281
1421
|
const value = queryParams[key];
|
|
1282
|
-
|
|
1422
|
+
// We only check using == because the value types can be different (e.g. "1" and 1)
|
|
1423
|
+
if (value === undefined || value == field.control.value) {
|
|
1283
1424
|
continue;
|
|
1284
1425
|
}
|
|
1285
|
-
const deserializedValue = field.data.
|
|
1426
|
+
const deserializedValue = field.data.queryParamToValueTransformFn?.(value) ?? value;
|
|
1286
1427
|
field.setValue(deserializedValue);
|
|
1287
1428
|
}
|
|
1288
1429
|
}
|
|
@@ -1326,13 +1467,15 @@ class QueryForm {
|
|
|
1326
1467
|
if (!this._router || !this._activatedRoute) {
|
|
1327
1468
|
return;
|
|
1328
1469
|
}
|
|
1329
|
-
const queryParams =
|
|
1470
|
+
const queryParams = clone(this._activatedRoute.snapshot.queryParams);
|
|
1330
1471
|
for (const [key, value] of Object.entries(values)) {
|
|
1331
1472
|
if (this._isDefaultValue(key, value) || this._fields[key].data.appendToUrl === false) {
|
|
1332
1473
|
delete queryParams[key];
|
|
1333
1474
|
}
|
|
1334
1475
|
else {
|
|
1335
|
-
queryParams[key] =
|
|
1476
|
+
queryParams[key] = this._fields[key].data.valueToQueryParamTransformFn
|
|
1477
|
+
? this._fields[key].data.valueToQueryParamTransformFn?.(value)
|
|
1478
|
+
: value;
|
|
1336
1479
|
}
|
|
1337
1480
|
}
|
|
1338
1481
|
this._router.navigate([], {
|
|
@@ -1414,10 +1557,55 @@ const transformToDateArray = (value) => {
|
|
|
1414
1557
|
}
|
|
1415
1558
|
return null;
|
|
1416
1559
|
};
|
|
1560
|
+
const transformToSort = (value) => {
|
|
1561
|
+
if (typeof value === 'string') {
|
|
1562
|
+
const [active, direction] = value.split(':');
|
|
1563
|
+
return {
|
|
1564
|
+
active,
|
|
1565
|
+
direction: direction,
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
return null;
|
|
1569
|
+
};
|
|
1570
|
+
const transformToSortQueryParam = (value) => {
|
|
1571
|
+
if (typeof value === 'string') {
|
|
1572
|
+
return value;
|
|
1573
|
+
}
|
|
1574
|
+
if (value && typeof value === 'object' && 'active' in value && 'direction' in value) {
|
|
1575
|
+
const valAsSort = value;
|
|
1576
|
+
return valAsSort.direction ? `${valAsSort.active}:${valAsSort.direction}` : null;
|
|
1577
|
+
}
|
|
1578
|
+
return null;
|
|
1579
|
+
};
|
|
1580
|
+
|
|
1581
|
+
const deepFreeze = (object) => {
|
|
1582
|
+
// check if object is actually an object or frozen
|
|
1583
|
+
if (!object || typeof object !== 'object' || Object.isFrozen(object)) {
|
|
1584
|
+
return object;
|
|
1585
|
+
}
|
|
1586
|
+
// Retrieve the property names defined on object
|
|
1587
|
+
const propNames = Object.getOwnPropertyNames(object);
|
|
1588
|
+
// Freeze properties before freezing self
|
|
1589
|
+
for (const name of propNames) {
|
|
1590
|
+
const value = object[name];
|
|
1591
|
+
if (value && typeof value === 'object') {
|
|
1592
|
+
deepFreeze(value);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
return Object.freeze(object);
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
/**
|
|
1599
|
+
* Dummy function for providing types while not breaking inference.
|
|
1600
|
+
* **This function always returns null.**
|
|
1601
|
+
* @see https://github.com/microsoft/TypeScript/issues/26242
|
|
1602
|
+
* @returns null
|
|
1603
|
+
*/
|
|
1604
|
+
const def = () => null;
|
|
1417
1605
|
|
|
1418
1606
|
/**
|
|
1419
1607
|
* Generated bundle index. Do not edit.
|
|
1420
1608
|
*/
|
|
1421
1609
|
|
|
1422
|
-
export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryDirective, QueryError, QueryField, QueryForm, QueryStore, buildBody, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryString, buildRequestError, buildRoute, buildTimestampFromSeconds, createInfinityQueryConfig, decryptBearer, deepFreeze, def, extractExpiresInSeconds, filterFailure, filterInvalidParams, filterSuccess, gql, guessContentType, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAbortRequestError, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isFetchResponse, isGqlQueryConfig, isParamValid, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, mergeHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, shouldCacheQuery, skipPaginationPageParamCalculator, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToString, transformToStringArray };
|
|
1610
|
+
export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryDirective, QueryError, QueryField, QueryForm, QueryStore, buildBody, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryString, buildRequestError, buildRoute, buildTimestampFromSeconds, createInfinityQueryConfig, createQueryCollection, decryptBearer, deepFreeze, def, extractExpiresInSeconds, extractQuery, filterFailure, filterInvalidParams, filterNull, filterQueryStates, filterSuccess, gql, guessContentType, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAbortRequestError, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isFetchResponse, isGqlQueryConfig, isParamValid, isQuery, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, mergeHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, shouldCacheQuery, skipPaginationPageParamCalculator, switchQueryCollectionState, switchQueryState, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
|
|
1423
1611
|
//# sourceMappingURL=ethlete-query.mjs.map
|