@arsedizioni/ars-utils 22.5.51 → 22.5.53
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/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +15 -15
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +43 -43
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.date.mjs +9 -9
- package/fesm2022/arsedizioni-ars-utils-core.markdown.mjs +3 -3
- package/fesm2022/arsedizioni-ars-utils-core.mjs +48 -48
- package/fesm2022/arsedizioni-ars-utils-core.validators.mjs +42 -42
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +94 -24
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs +18 -9
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.controls.date.mjs +6 -6
- package/fesm2022/arsedizioni-ars-utils-ui.controls.mjs +9 -9
- package/fesm2022/arsedizioni-ars-utils-ui.controls.tree.mjs +3 -3
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.auth.mjs +18 -18
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.mjs +12 -12
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.prompt.mjs +9 -9
- package/fesm2022/arsedizioni-ars-utils-ui.dialogs.select.mjs +15 -15
- package/fesm2022/arsedizioni-ars-utils-ui.files.mjs +12 -12
- package/fesm2022/arsedizioni-ars-utils-ui.filters.mjs +3 -3
- package/fesm2022/arsedizioni-ars-utils-ui.help.mjs +9 -9
- package/fesm2022/arsedizioni-ars-utils-ui.mjs +61 -61
- package/fesm2022/arsedizioni-ars-utils-ui.navigation.mjs +3 -3
- package/fesm2022/arsedizioni-ars-utils-ui.notifications.mjs +6 -6
- package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs +6 -6
- package/fesm2022/arsedizioni-ars-utils-ui.paginator.mjs +3 -3
- package/fesm2022/arsedizioni-ars-utils-ui.shell.mjs +9 -9
- package/fesm2022/arsedizioni-ars-utils-ui.tinymce.mjs +9 -9
- package/package.json +1 -1
- package/types/arsedizioni-ars-utils-clipper.common.d.ts +5 -5
- package/types/arsedizioni-ars-utils-clipper.ui.d.ts +1 -1
- package/types/arsedizioni-ars-utils-core.d.ts +5 -5
- package/types/arsedizioni-ars-utils-core.date.d.ts +3 -3
- package/types/arsedizioni-ars-utils-evolution.common.d.ts +23 -7
- package/types/arsedizioni-ars-utils-support.common.d.ts +11 -2
- package/types/arsedizioni-ars-utils-ui.d.ts +2 -2
- package/types/arsedizioni-ars-utils-ui.dialogs.d.ts +1 -1
- package/types/arsedizioni-ars-utils-ui.dialogs.select.d.ts +1 -1
- package/types/arsedizioni-ars-utils-ui.help.d.ts +2 -2
- package/types/arsedizioni-ars-utils-ui.paginator.d.ts +1 -1
- package/types/arsedizioni-ars-utils-ui.shell.d.ts +1 -1
- package/types/arsedizioni-ars-utils-ui.tinymce.d.ts +1 -1
|
@@ -2,13 +2,23 @@ import { HttpResponse, HttpClient } from '@angular/common/http';
|
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { inject, signal, Service, DestroyRef } from '@angular/core';
|
|
4
4
|
import { BroadcastService, SystemUtils } from '@arsedizioni/ars-utils/core';
|
|
5
|
-
import {
|
|
5
|
+
import { retry, timer, throwError, tap, catchError, EMPTY, of } from 'rxjs';
|
|
6
6
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
7
7
|
import { catchError as catchError$1, map, finalize } from 'rxjs/operators';
|
|
8
8
|
|
|
9
9
|
const EvolutionMessages = {
|
|
10
10
|
// Error
|
|
11
11
|
ERROR: '§evo-error',
|
|
12
|
+
/**
|
|
13
|
+
* The API is not answering: the interceptor has already sent the request three times over ten
|
|
14
|
+
* seconds and none of them got an answer carrying an `ApiResult` envelope. Emitted once per
|
|
15
|
+
* outage, however many requests were in flight, and re-armed on the first good response.
|
|
16
|
+
*
|
|
17
|
+
* Deliberately not an `ERROR`: a server being replaced is neither a failed operation to report
|
|
18
|
+
* in a dialog nor an expired session to sign out of, and the host application usually answers it
|
|
19
|
+
* with a banner that clears itself.
|
|
20
|
+
*/
|
|
21
|
+
ERROR_UNAVAILABLE: '§evo-error-unavailable',
|
|
12
22
|
SUCCESS: '§evo-success',
|
|
13
23
|
SUCCESS_TOAST: '§evo-success-toast',
|
|
14
24
|
// Login
|
|
@@ -494,6 +504,33 @@ class EvolutionComplianceContextInfo {
|
|
|
494
504
|
|
|
495
505
|
/** Minimum milliseconds between consecutive generic error broadcasts (debounce guard). */
|
|
496
506
|
const ERROR_DEBOUNCE_MS = 5000;
|
|
507
|
+
/** How many more times a request is sent when the API is not there. */
|
|
508
|
+
const UNAVAILABLE_RETRIES = 2;
|
|
509
|
+
/** How long to wait before each of those retries, in milliseconds. */
|
|
510
|
+
const UNAVAILABLE_RETRY_DELAY = 5000;
|
|
511
|
+
/** The statuses a server that is being replaced answers with, plus the one it cannot answer at all. */
|
|
512
|
+
const UNAVAILABLE_STATUSES = [0, 500, 502, 503, 504];
|
|
513
|
+
/**
|
|
514
|
+
* Returns whether the failure means the API is not there, rather than the request being wrong.
|
|
515
|
+
*
|
|
516
|
+
* The discriminator is the body, not the status. An error raised INSIDE the application arrives
|
|
517
|
+
* wrapped in the usual `ApiResult` envelope, so it has been seen, parsed and acted upon: replaying
|
|
518
|
+
* it would run whatever it already ran a second time. A server that is being replaced answers with
|
|
519
|
+
* IIS's own HTML, or with nothing at all — no envelope — and that request never reached any
|
|
520
|
+
* handler. Only the second kind is retried, which is what makes it safe to retry a POST.
|
|
521
|
+
* @param error - The raw HTTP error object.
|
|
522
|
+
* @returns True when the request is worth sending again.
|
|
523
|
+
*/
|
|
524
|
+
function isServiceUnavailable(error) {
|
|
525
|
+
if (!UNAVAILABLE_STATUSES.includes(parseInt(error?.status ?? '0')))
|
|
526
|
+
return false;
|
|
527
|
+
const body = error?.error;
|
|
528
|
+
const isApiEnvelope = !!body
|
|
529
|
+
&& typeof body === 'object'
|
|
530
|
+
&& !(body instanceof Blob)
|
|
531
|
+
&& ('success' in body || 'problem' in body);
|
|
532
|
+
return !isApiEnvelope;
|
|
533
|
+
}
|
|
497
534
|
/**
|
|
498
535
|
* Returns whether the URL is an authentication endpoint, where a 401 is a normal outcome -- wrong
|
|
499
536
|
* credentials, a rejected code, a refused passkey -- rather than an expired or invalid session.
|
|
@@ -531,6 +568,10 @@ function isStatusProbe(url) {
|
|
|
531
568
|
}
|
|
532
569
|
/**
|
|
533
570
|
* Resolves the user-facing message for a failed request.
|
|
571
|
+
*
|
|
572
|
+
* There is no branch for status 0 any more, nor for the 5xx family: a request that got no answer,
|
|
573
|
+
* or an answer with no `ApiResult` envelope, never reaches here — it is retried and then reported
|
|
574
|
+
* as `ERROR_UNAVAILABLE`. What is left is the failures the API itself described.
|
|
534
575
|
* @param error - The raw HTTP error object.
|
|
535
576
|
* @param errorStatus - The numeric HTTP status code.
|
|
536
577
|
* @returns A localised message, ready to be rendered as HTML.
|
|
@@ -538,8 +579,6 @@ function isStatusProbe(url) {
|
|
|
538
579
|
function resolveErrorMessage(error, errorStatus) {
|
|
539
580
|
const message = error?.error?.message ?? error?.message;
|
|
540
581
|
switch (errorStatus) {
|
|
541
|
-
case 0:
|
|
542
|
-
return "In questo momento Evolution non è disponibile. Riprova tra qualche minuto.";
|
|
543
582
|
case 401:
|
|
544
583
|
// A 401 that reaches here comes from a sign-in attempt; anything else was classified as a
|
|
545
584
|
// dead session before this function was called.
|
|
@@ -574,9 +613,15 @@ function resolveErrorMessage(error, errorStatus) {
|
|
|
574
613
|
* broke, and those are three different things that used to be one. `invalidateSession` is
|
|
575
614
|
* therefore now, and only, a 401 outside the authentication endpoints.
|
|
576
615
|
*
|
|
577
|
-
*
|
|
578
|
-
* 5xx
|
|
579
|
-
*
|
|
616
|
+
* Between them sits a third case, which is neither: the API is being replaced. A deployment answers
|
|
617
|
+
* with a 5xx that has no `ApiResult` envelope, or does not answer at all, for the few seconds the
|
|
618
|
+
* process takes to come back. That is not worth a dialog and not worth a redirect either, so the
|
|
619
|
+
* request is simply sent again — twice, five seconds apart — and only if the third attempt fails
|
|
620
|
+
* too does it become `EvolutionMessages.ERROR_UNAVAILABLE`, once per outage.
|
|
621
|
+
*
|
|
622
|
+
* `EvolutionServiceFlags.NotifySystemErrors` therefore now governs one narrower case: a 5xx that
|
|
623
|
+
* DOES carry an envelope, i.e. a server error the API itself described. Without the flag it is
|
|
624
|
+
* swallowed, as it always was in this library.
|
|
580
625
|
*
|
|
581
626
|
* Errors are re-thrown rather than swallowed: call sites rely on their `error` callback firing, and
|
|
582
627
|
* on `finalize` clearing a busy dialog.
|
|
@@ -600,6 +645,11 @@ function evolutionAuthInterceptor(serviceUri, flags = EvolutionServiceFlags.None
|
|
|
600
645
|
* several in-flight requests fail at once; re-armed on the next successful response.
|
|
601
646
|
*/
|
|
602
647
|
let sessionExpiredNotified = false;
|
|
648
|
+
/**
|
|
649
|
+
* Whether the unavailable-API notification has already been sent. A deployment fails every
|
|
650
|
+
* request in flight, and one notification is enough. Re-armed on the next successful response.
|
|
651
|
+
*/
|
|
652
|
+
let unavailableNotified = false;
|
|
603
653
|
/**
|
|
604
654
|
* Broadcasts a generic, user-facing error for an Evolution HTTP failure, debounced.
|
|
605
655
|
* @param error - The raw error value thrown by the HTTP layer.
|
|
@@ -608,7 +658,7 @@ function evolutionAuthInterceptor(serviceUri, flags = EvolutionServiceFlags.None
|
|
|
608
658
|
* @returns void
|
|
609
659
|
*/
|
|
610
660
|
function notifyError(error, errorStatus, broadcastService) {
|
|
611
|
-
// A
|
|
661
|
+
// A 5xx the API described itself is the one case the flag still governs.
|
|
612
662
|
if (errorStatus >= 500 && (flags & EvolutionServiceFlags.NotifySystemErrors) === 0)
|
|
613
663
|
return;
|
|
614
664
|
const now = Date.now();
|
|
@@ -643,10 +693,20 @@ function evolutionAuthInterceptor(serviceUri, flags = EvolutionServiceFlags.None
|
|
|
643
693
|
'X-Evo-Account': sessionStorage.getItem(EVOLUTION_ACTIVE_ACCOUNT_KEY) ?? ''
|
|
644
694
|
}
|
|
645
695
|
});
|
|
646
|
-
return next(authenticatedRequest).pipe(
|
|
647
|
-
|
|
696
|
+
return next(authenticatedRequest).pipe(
|
|
697
|
+
// An API that is being replaced is not an error to show, it is a wait: two more attempts,
|
|
698
|
+
// five seconds apart. Anything else is rethrown on the spot, so a request that genuinely
|
|
699
|
+
// failed still fails immediately.
|
|
700
|
+
retry({
|
|
701
|
+
count: UNAVAILABLE_RETRIES,
|
|
702
|
+
delay: error => isServiceUnavailable(error)
|
|
703
|
+
? timer(UNAVAILABLE_RETRY_DELAY)
|
|
704
|
+
: throwError(() => error)
|
|
705
|
+
}), tap(event => {
|
|
706
|
+
// A response means the session is valid again, and the API is back: re-arm both notifiers.
|
|
648
707
|
if (event instanceof HttpResponse) {
|
|
649
708
|
sessionExpiredNotified = false;
|
|
709
|
+
unavailableNotified = false;
|
|
650
710
|
}
|
|
651
711
|
}), catchError((error) => {
|
|
652
712
|
// Which request this was is read from the request, not from `error.url`: a failure with no
|
|
@@ -658,6 +718,16 @@ function evolutionAuthInterceptor(serviceUri, flags = EvolutionServiceFlags.None
|
|
|
658
718
|
// The silent probe stays silent: its caller reads the outcome from the rethrown error,
|
|
659
719
|
// nobody else needs to hear about it.
|
|
660
720
|
}
|
|
721
|
+
else if (isServiceUnavailable(error)) {
|
|
722
|
+
// Three attempts over ten seconds and the API is still not answering. There is nothing
|
|
723
|
+
// left to retry, so the host application is told once, however many requests were in
|
|
724
|
+
// flight. Reported whatever the flags say: `NotifySystemErrors` governs a 5xx the API
|
|
725
|
+
// described itself, and a server that never answered described nothing.
|
|
726
|
+
if (!unavailableNotified) {
|
|
727
|
+
unavailableNotified = true;
|
|
728
|
+
broadcastService.sendMessage(EvolutionMessages.ERROR_UNAVAILABLE);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
661
731
|
else if (errorStatus === 401 && !isAuthEndpoint(authenticatedRequest.url)) {
|
|
662
732
|
// Expired or invalidated session on an authenticated request. Notified once: several
|
|
663
733
|
// in-flight requests failing together is how a single expiry becomes a wall of dialogs.
|
|
@@ -851,10 +921,10 @@ class CoreService {
|
|
|
851
921
|
sessionStorage.removeItem('evolution_client_id');
|
|
852
922
|
this.reset();
|
|
853
923
|
}
|
|
854
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
855
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
924
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: CoreService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
925
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: CoreService }); }
|
|
856
926
|
}
|
|
857
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
927
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: CoreService, decorators: [{
|
|
858
928
|
type: Service
|
|
859
929
|
}] });
|
|
860
930
|
|
|
@@ -1219,10 +1289,10 @@ class LoginService {
|
|
|
1219
1289
|
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_COMPLETED);
|
|
1220
1290
|
}
|
|
1221
1291
|
}
|
|
1222
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1223
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
1292
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: LoginService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
1293
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: LoginService }); }
|
|
1224
1294
|
}
|
|
1225
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1295
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: LoginService, decorators: [{
|
|
1226
1296
|
type: Service
|
|
1227
1297
|
}] });
|
|
1228
1298
|
|
|
@@ -1310,10 +1380,10 @@ class ComplianceService {
|
|
|
1310
1380
|
addActivities(params) {
|
|
1311
1381
|
return this.httpClient.post(this.core.serviceUri + '/compliance/activities/add', params);
|
|
1312
1382
|
}
|
|
1313
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1314
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
1383
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ComplianceService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
1384
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: ComplianceService }); }
|
|
1315
1385
|
}
|
|
1316
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1386
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ComplianceService, decorators: [{
|
|
1317
1387
|
type: Service
|
|
1318
1388
|
}] });
|
|
1319
1389
|
|
|
@@ -1383,10 +1453,10 @@ class AccountService {
|
|
|
1383
1453
|
refreshLicence() {
|
|
1384
1454
|
return this.httpClient.get(this.core.serviceUri + '/account/licenses/refresh/' + (this.core.user?.userId ?? -1));
|
|
1385
1455
|
}
|
|
1386
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1387
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
1456
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AccountService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
1457
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: AccountService }); }
|
|
1388
1458
|
}
|
|
1389
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1459
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AccountService, decorators: [{
|
|
1390
1460
|
type: Service
|
|
1391
1461
|
}] });
|
|
1392
1462
|
|
|
@@ -1460,10 +1530,10 @@ class EvolutionService {
|
|
|
1460
1530
|
* @returns void
|
|
1461
1531
|
*/
|
|
1462
1532
|
ping() { this.session.ping(); }
|
|
1463
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1464
|
-
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
1533
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: EvolutionService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
|
|
1534
|
+
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: EvolutionService }); }
|
|
1465
1535
|
}
|
|
1466
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1536
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: EvolutionService, decorators: [{
|
|
1467
1537
|
type: Service
|
|
1468
1538
|
}] });
|
|
1469
1539
|
|