@tstdl/base 0.93.144 → 0.93.145
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/authentication/authentication.api.d.ts +9 -0
- package/authentication/authentication.api.js +3 -0
- package/authentication/client/authentication.service.js +5 -5
- package/authentication/client/http-client.middleware.js +6 -2
- package/authentication/tests/authentication.client-middleware.test.js +35 -0
- package/authentication/tests/authentication.client-service-refresh.test.js +7 -0
- package/package.json +1 -1
|
@@ -126,6 +126,9 @@ export declare const authenticationApiDefinition: {
|
|
|
126
126
|
timestamp: {
|
|
127
127
|
resource: string;
|
|
128
128
|
result: import("../schema/index.js").NumberSchema;
|
|
129
|
+
data: {
|
|
130
|
+
[dontWaitForValidToken]: boolean;
|
|
131
|
+
};
|
|
129
132
|
};
|
|
130
133
|
};
|
|
131
134
|
};
|
|
@@ -248,6 +251,9 @@ export declare function getAuthenticationApiDefinition<AdditionalTokenPayload ex
|
|
|
248
251
|
timestamp: {
|
|
249
252
|
resource: string;
|
|
250
253
|
result: import("../schema/index.js").NumberSchema;
|
|
254
|
+
data: {
|
|
255
|
+
[dontWaitForValidToken]: boolean;
|
|
256
|
+
};
|
|
251
257
|
};
|
|
252
258
|
};
|
|
253
259
|
};
|
|
@@ -365,6 +371,9 @@ export declare function getAuthenticationApiEndpointsDefinition<AdditionalTokenP
|
|
|
365
371
|
timestamp: {
|
|
366
372
|
resource: string;
|
|
367
373
|
result: import("../schema/index.js").NumberSchema;
|
|
374
|
+
data: {
|
|
375
|
+
[dontWaitForValidToken]: boolean;
|
|
376
|
+
};
|
|
368
377
|
};
|
|
369
378
|
};
|
|
370
379
|
export {};
|
|
@@ -420,7 +420,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
420
420
|
if (stillNeedsRefresh) {
|
|
421
421
|
await this.refresh();
|
|
422
422
|
}
|
|
423
|
-
if (this.forceRefreshRequested() && (this.token() != currentToken)) {
|
|
423
|
+
if (this.forceRefreshRequested() && (this.token()?.jti != currentToken?.jti)) {
|
|
424
424
|
this.forceRefreshRequested.set(false);
|
|
425
425
|
}
|
|
426
426
|
});
|
|
@@ -428,7 +428,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
428
428
|
// Lock held by another instance, wait 5 seconds or until token changes (Passive Sync)
|
|
429
429
|
const changeReason = await firstValueFrom(race([
|
|
430
430
|
timer(5000).pipe(map(() => 'timer')),
|
|
431
|
-
this.token$.pipe(filter((t) => t != token), map(() => 'token')),
|
|
431
|
+
this.token$.pipe(filter((t) => t?.jti != token.jti), map(() => 'token')),
|
|
432
432
|
from(this.disposeSignal),
|
|
433
433
|
]), { defaultValue: undefined });
|
|
434
434
|
if (changeReason == 'token') {
|
|
@@ -442,7 +442,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
442
442
|
const delay = Math.min(maxRefreshDelay, ((currentToken?.exp ?? 0) - this.estimatedServerTimestampSeconds() - currentRefreshBufferSeconds) * millisecondsPerSecond);
|
|
443
443
|
const wakeUpSignals = [
|
|
444
444
|
from(this.disposeSignal),
|
|
445
|
-
this.token$.pipe(filter((t) => t != currentToken)),
|
|
445
|
+
this.token$.pipe(filter((t) => t?.jti != currentToken?.jti)),
|
|
446
446
|
];
|
|
447
447
|
if (!forceRefresh) {
|
|
448
448
|
wakeUpSignals.push(this.forceRefreshRequested$.pipe(filter((requested) => requested)));
|
|
@@ -451,7 +451,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
451
451
|
await firstValueFrom(race([timer(delay), ...wakeUpSignals]), { defaultValue: undefined });
|
|
452
452
|
}
|
|
453
453
|
else {
|
|
454
|
-
await firstValueFrom(race([timer(
|
|
454
|
+
await firstValueFrom(race([timer(2500), ...wakeUpSignals]), { defaultValue: undefined });
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
457
|
catch (error) {
|
|
@@ -460,7 +460,7 @@ let AuthenticationClientService = class AuthenticationClientService {
|
|
|
460
460
|
await firstValueFrom(race([
|
|
461
461
|
timer(2500),
|
|
462
462
|
from(this.disposeSignal),
|
|
463
|
-
this.token$.pipe(filter((t) => t != currentToken)),
|
|
463
|
+
this.token$.pipe(filter((t) => t?.jti != currentToken?.jti)),
|
|
464
464
|
this.forceRefreshRequested$.pipe(filter((requested) => requested), skip(this.forceRefreshRequested() ? 1 : 0)),
|
|
465
465
|
]), { defaultValue: undefined });
|
|
466
466
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { firstValueFrom, race, timeout } from 'rxjs';
|
|
1
|
+
import { firstValueFrom, race, timeout as rxjsTimeout } from 'rxjs';
|
|
2
2
|
import { HttpError } from '../../http/index.js';
|
|
3
|
+
import { timeout } from '../../utils/timing.js';
|
|
3
4
|
import { isDefined } from '../../utils/type-guards.js';
|
|
4
5
|
import { cacheValueOrAsyncProvider } from '../../utils/value-or-provider.js';
|
|
5
6
|
import { dontWaitForValidToken } from '../authentication.api.js';
|
|
@@ -19,10 +20,13 @@ export function waitForAuthenticationCredentialsMiddleware(authenticationService
|
|
|
19
20
|
authenticationService.validToken$,
|
|
20
21
|
request.cancellationSignal,
|
|
21
22
|
]);
|
|
22
|
-
await firstValueFrom(race$.pipe(
|
|
23
|
+
await firstValueFrom(race$.pipe(rxjsTimeout(30000))).catch(() => undefined);
|
|
23
24
|
if (request.cancellationSignal.isSet) {
|
|
24
25
|
break;
|
|
25
26
|
}
|
|
27
|
+
if (!authenticationService.hasValidToken && authenticationService.isLoggedIn()) {
|
|
28
|
+
await timeout(100);
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
31
|
}
|
|
28
32
|
await next();
|
|
@@ -21,6 +21,41 @@ describe('waitForAuthenticationCredentialsMiddleware', () => {
|
|
|
21
21
|
await middleware({ request }, next);
|
|
22
22
|
expect(next).toHaveBeenCalled();
|
|
23
23
|
});
|
|
24
|
+
test('should NOT wait if endpoint has dontWaitForValidToken', async () => {
|
|
25
|
+
const authenticationServiceMock = {
|
|
26
|
+
isLoggedIn: vi.fn().mockReturnValue(true),
|
|
27
|
+
hasValidToken: false,
|
|
28
|
+
};
|
|
29
|
+
const middleware = waitForAuthenticationCredentialsMiddleware(authenticationServiceMock);
|
|
30
|
+
const request = new HttpClientRequest('http://localhost');
|
|
31
|
+
request.context = {
|
|
32
|
+
endpoint: {
|
|
33
|
+
credentials: true,
|
|
34
|
+
data: {
|
|
35
|
+
[dontWaitForValidToken]: true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const next = vi.fn().mockResolvedValue(undefined);
|
|
40
|
+
await middleware({ request }, next);
|
|
41
|
+
expect(next).toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
test('should NOT wait if credentials is NOT true', async () => {
|
|
44
|
+
const authenticationServiceMock = {
|
|
45
|
+
isLoggedIn: vi.fn().mockReturnValue(true),
|
|
46
|
+
hasValidToken: false,
|
|
47
|
+
};
|
|
48
|
+
const middleware = waitForAuthenticationCredentialsMiddleware(authenticationServiceMock);
|
|
49
|
+
const request = new HttpClientRequest('http://localhost');
|
|
50
|
+
request.context = {
|
|
51
|
+
endpoint: {
|
|
52
|
+
credentials: false,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const next = vi.fn().mockResolvedValue(undefined);
|
|
56
|
+
await middleware({ request }, next);
|
|
57
|
+
expect(next).toHaveBeenCalled();
|
|
58
|
+
});
|
|
24
59
|
});
|
|
25
60
|
describe('logoutOnUnauthorizedMiddleware', () => {
|
|
26
61
|
test('should call logout on 401 error', async () => {
|
|
@@ -123,4 +123,11 @@ describe('AuthenticationClientService Refresh Loop Reproduction', () => {
|
|
|
123
123
|
// If it busy loops, this will be much higher than 1.
|
|
124
124
|
expect(mockLock.tryUse.mock.calls.length).toBeLessThan(5);
|
|
125
125
|
});
|
|
126
|
+
test('refresh() should call timestamp() to sync clock', async () => {
|
|
127
|
+
service = injector.resolve(AuthenticationClientService);
|
|
128
|
+
const newToken = { iat: 1000, exp: 2000, jti: 'new' };
|
|
129
|
+
mockApiClient.refresh.mockResolvedValue(newToken);
|
|
130
|
+
await service.refresh();
|
|
131
|
+
expect(mockApiClient.timestamp).toHaveBeenCalled();
|
|
132
|
+
});
|
|
126
133
|
});
|