ngrx-entity-crud 19.4.0-beta.6 → 19.4.0-beta.7
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.
|
@@ -8,6 +8,10 @@ import * as i0 from "@angular/core";
|
|
|
8
8
|
* pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy
|
|
9
9
|
* mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;
|
|
10
10
|
* polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.
|
|
11
|
+
*
|
|
12
|
+
* Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)
|
|
13
|
+
* anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular
|
|
14
|
+
* >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).
|
|
11
15
|
*/
|
|
12
16
|
export declare class NecDashboardComponent implements OnInit, OnDestroy {
|
|
13
17
|
private readonly localStorageProbe;
|
|
@@ -39,6 +43,14 @@ export declare class NecDashboardComponent implements OnInit, OnDestroy {
|
|
|
39
43
|
/** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */
|
|
40
44
|
reveal(key: string): void;
|
|
41
45
|
isSensitive(key: string): boolean;
|
|
46
|
+
/** trackBy per le righe identificate da `key` (entry localStorage, slice store). */
|
|
47
|
+
trackByKey(_: number, item: {
|
|
48
|
+
key: string;
|
|
49
|
+
}): string;
|
|
50
|
+
/** trackBy per le righe identificate da `name` (DB/object store IndexedDB, voci lazy). */
|
|
51
|
+
trackByName(_: number, item: {
|
|
52
|
+
name: string;
|
|
53
|
+
}): string;
|
|
42
54
|
formatBytes(n: number | undefined | null): string;
|
|
43
55
|
static ɵfac: i0.ɵɵFactoryDeclaration<NecDashboardComponent, never>;
|
|
44
56
|
static ɵcmp: i0.ɵɵComponentDeclaration<NecDashboardComponent, "nec-dashboard", never, { "blacklist": { "alias": "blacklist"; "required": false; }; "whitelist": { "alias": "whitelist"; "required": false; }; "lazyReportUrl": { "alias": "lazyReportUrl"; "required": false; }; "idbDatabaseNames": { "alias": "idbDatabaseNames"; "required": false; }; "pollingMs": { "alias": "pollingMs"; "required": false; }; "allowRevealValues": { "alias": "allowRevealValues"; "required": false; }; }, {}, never, never, true, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nec-dashboard.component.d.ts","sourceRoot":"","sources":["../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,SAAS,EACT,MAAM,EAEP,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"nec-dashboard.component.d.ts","sourceRoot":"","sources":["../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,SAAS,EACT,MAAM,EAEP,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,UAAU,CAAC;;AAM1F;;;;;;;;;;;GAWG;AACH,qBAyQa,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAC7D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IACzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,2DAA2D;IAClD,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,oFAAoF;IAC3E,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,wFAAwF;IAC/E,aAAa,EAAE,MAAM,GAAG,IAAI,CAA6B;IAClE,0FAA0F;IACjF,gBAAgB,EAAE,MAAM,EAAE,CAAM;IACzC,oEAAoE;IAC3D,SAAS,SAAK;IACvB,4FAA4F;IACnF,iBAAiB,UAAS;IAEnC,QAAQ,CAAC,IAAI,kDAAiB;IAC9B,QAAQ,CAAC,WAAW,iDAA+B;IACnD,QAAQ,CAAC,OAAO,2DAAyC;IACzD,QAAQ,CAAC,KAAK,2DAAyC;IACvD,QAAQ,CAAC,GAAG,uDAAqC;IACjD,QAAQ,CAAC,WAAW,yDAAuC;IAC3D,QAAQ,CAAC,QAAQ,iEAAsC;IAEvD,OAAO,CAAC,KAAK,CAA+C;IAE5D,QAAQ,IAAI,IAAI;IAOhB,WAAW,IAAI,IAAI;IAOb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB9B,yFAAyF;IACzF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIjC,oFAAoF;IACpF,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIlD,0FAA0F;IAC1F,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIpD,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM;yCArFtC,qBAAqB;2CAArB,qBAAqB;CAiGjC"}
|
|
@@ -2,6 +2,8 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { InjectionToken, Injectable, Optional, Inject, inject, signal, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { createSelector, Store } from '@ngrx/store';
|
|
4
4
|
import { take } from 'rxjs/operators';
|
|
5
|
+
import * as i1 from '@angular/common';
|
|
6
|
+
import { CommonModule } from '@angular/common';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Modelli dei report prodotti dai probe della dashboard (`ngrx-entity-crud/devtools`).
|
|
@@ -509,6 +511,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
509
511
|
* pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy
|
|
510
512
|
* mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;
|
|
511
513
|
* polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.
|
|
514
|
+
*
|
|
515
|
+
* Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)
|
|
516
|
+
* anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular
|
|
517
|
+
* >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).
|
|
512
518
|
*/
|
|
513
519
|
class NecDashboardComponent {
|
|
514
520
|
localStorageProbe = inject(NecLocalStorageProbeService);
|
|
@@ -577,6 +583,14 @@ class NecDashboardComponent {
|
|
|
577
583
|
isSensitive(key) {
|
|
578
584
|
return looksSensitiveKey(key);
|
|
579
585
|
}
|
|
586
|
+
/** trackBy per le righe identificate da `key` (entry localStorage, slice store). */
|
|
587
|
+
trackByKey(_, item) {
|
|
588
|
+
return item.key;
|
|
589
|
+
}
|
|
590
|
+
/** trackBy per le righe identificate da `name` (DB/object store IndexedDB, voci lazy). */
|
|
591
|
+
trackByName(_, item) {
|
|
592
|
+
return item.name;
|
|
593
|
+
}
|
|
580
594
|
formatBytes(n) {
|
|
581
595
|
if (n == null) {
|
|
582
596
|
return '–';
|
|
@@ -590,20 +604,18 @@ class NecDashboardComponent {
|
|
|
590
604
|
return `${(n / 1024 / 1024).toFixed(2)} MB`;
|
|
591
605
|
}
|
|
592
606
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: NecDashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
593
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
607
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: NecDashboardComponent, isStandalone: true, selector: "nec-dashboard", inputs: { blacklist: "blacklist", whitelist: "whitelist", lazyReportUrl: "lazyReportUrl", idbDatabaseNames: "idbDatabaseNames", pollingMs: "pollingMs", allowRevealValues: "allowRevealValues" }, ngImport: i0, template: `
|
|
594
608
|
<div class="nec-toolbar">
|
|
595
609
|
<button type="button" (click)="refresh()" [disabled]="busy()">
|
|
596
610
|
{{ busy() ? 'Aggiorno…' : 'Aggiorna' }}
|
|
597
611
|
</button>
|
|
598
|
-
|
|
599
|
-
<span class="nec-note">ultimo aggiornamento: {{ lastUpdated() }}</span>
|
|
600
|
-
}
|
|
612
|
+
<span class="nec-note" *ngIf="lastUpdated()">ultimo aggiornamento: {{ lastUpdated() }}</span>
|
|
601
613
|
</div>
|
|
602
614
|
|
|
603
615
|
<!-- Quota aggregata origine -->
|
|
604
616
|
<div class="nec-panel">
|
|
605
617
|
<h3>Quota origine (aggregata)</h3>
|
|
606
|
-
|
|
618
|
+
<ng-container *ngIf="quota()?.available; else noQuota">
|
|
607
619
|
<div>
|
|
608
620
|
uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /
|
|
609
621
|
quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>
|
|
@@ -611,112 +623,108 @@ class NecDashboardComponent {
|
|
|
611
623
|
<div class="nec-note">
|
|
612
624
|
Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.
|
|
613
625
|
</div>
|
|
614
|
-
|
|
626
|
+
</ng-container>
|
|
627
|
+
<ng-template #noQuota>
|
|
615
628
|
<div class="nec-note">Stima quota non disponibile (Safari o contesto non sicuro).</div>
|
|
616
|
-
|
|
629
|
+
</ng-template>
|
|
617
630
|
</div>
|
|
618
631
|
|
|
619
632
|
<!-- localStorage -->
|
|
620
633
|
<div class="nec-panel">
|
|
621
634
|
<h3>localStorage</h3>
|
|
622
|
-
|
|
635
|
+
<ng-container *ngIf="storage()?.available; else noLocalStorage">
|
|
623
636
|
<div>
|
|
624
637
|
{{ storage()?.count }} chiavi · totale
|
|
625
638
|
<strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /
|
|
626
639
|
{{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)
|
|
627
640
|
</div>
|
|
628
|
-
|
|
641
|
+
<ng-container *ngIf="storage()!.entries.length; else noLocalStorageEntries">
|
|
629
642
|
<table>
|
|
630
643
|
<thead>
|
|
631
644
|
<tr>
|
|
632
645
|
<th>chiave</th>
|
|
633
646
|
<th class="num">UTF-16</th>
|
|
634
647
|
<th class="num">UTF-8</th>
|
|
635
|
-
|
|
636
|
-
<th>valore</th>
|
|
637
|
-
}
|
|
648
|
+
<th *ngIf="allowRevealValues">valore</th>
|
|
638
649
|
</tr>
|
|
639
650
|
</thead>
|
|
640
651
|
<tbody>
|
|
641
|
-
|
|
642
|
-
<
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
652
|
+
<tr *ngFor="let e of storage()!.entries; trackBy: trackByKey">
|
|
653
|
+
<td>
|
|
654
|
+
{{ e.key }}
|
|
655
|
+
<span
|
|
656
|
+
class="nec-badge error"
|
|
657
|
+
title="chiave potenzialmente sensibile"
|
|
658
|
+
*ngIf="isSensitive(e.key)"
|
|
659
|
+
>⚠</span>
|
|
660
|
+
</td>
|
|
661
|
+
<td class="num">{{ formatBytes(e.bytesUtf16) }}</td>
|
|
662
|
+
<td class="num">{{ formatBytes(e.bytesUtf8) }}</td>
|
|
663
|
+
<td *ngIf="allowRevealValues">
|
|
664
|
+
<ng-container *ngIf="revealed()[e.key] !== undefined; else revealBtn">
|
|
665
|
+
<code>{{ revealed()[e.key] }}</code>
|
|
666
|
+
</ng-container>
|
|
667
|
+
<ng-template #revealBtn>
|
|
668
|
+
<button type="button" (click)="reveal(e.key)">mostra</button>
|
|
669
|
+
</ng-template>
|
|
670
|
+
</td>
|
|
671
|
+
</tr>
|
|
662
672
|
</tbody>
|
|
663
673
|
</table>
|
|
664
|
-
|
|
674
|
+
</ng-container>
|
|
675
|
+
<ng-template #noLocalStorageEntries>
|
|
665
676
|
<div class="nec-note">Nessuna chiave.</div>
|
|
666
|
-
|
|
667
|
-
|
|
677
|
+
</ng-template>
|
|
678
|
+
</ng-container>
|
|
679
|
+
<ng-template #noLocalStorage>
|
|
668
680
|
<div class="nec-note">localStorage non disponibile.</div>
|
|
669
|
-
|
|
681
|
+
</ng-template>
|
|
670
682
|
</div>
|
|
671
683
|
|
|
672
684
|
<!-- IndexedDB -->
|
|
673
685
|
<div class="nec-panel">
|
|
674
686
|
<h3>IndexedDB</h3>
|
|
675
|
-
|
|
687
|
+
<ng-container *ngIf="idb()?.available; else noIdb">
|
|
676
688
|
<div class="nec-note">adapter: {{ idb()?.adapter }}</div>
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
<
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
</tbody>
|
|
707
|
-
</table>
|
|
708
|
-
}
|
|
689
|
+
<div class="nec-note" *ngIf="idb()?.note">{{ idb()?.note }}</div>
|
|
690
|
+
<table *ngIf="idb()!.databases.length">
|
|
691
|
+
<thead>
|
|
692
|
+
<tr>
|
|
693
|
+
<th>database</th>
|
|
694
|
+
<th>object store</th>
|
|
695
|
+
<th class="num">record</th>
|
|
696
|
+
</tr>
|
|
697
|
+
</thead>
|
|
698
|
+
<tbody>
|
|
699
|
+
<ng-container *ngFor="let db of idb()!.databases; trackBy: trackByName">
|
|
700
|
+
<ng-container *ngIf="db.stores.length; else noStores">
|
|
701
|
+
<tr *ngFor="let st of db.stores; trackBy: trackByName">
|
|
702
|
+
<td>{{ db.name }} <span class="nec-note">v{{ db.version }}</span></td>
|
|
703
|
+
<td>{{ st.name }}</td>
|
|
704
|
+
<td class="num">{{ st.count ?? '–' }}</td>
|
|
705
|
+
</tr>
|
|
706
|
+
</ng-container>
|
|
707
|
+
<ng-template #noStores>
|
|
708
|
+
<tr>
|
|
709
|
+
<td>{{ db.name }} <span class="nec-note">v{{ db.version }}</span></td>
|
|
710
|
+
<td class="nec-note" colspan="2">{{ db.note ?? 'nessun object store' }}</td>
|
|
711
|
+
</tr>
|
|
712
|
+
</ng-template>
|
|
713
|
+
</ng-container>
|
|
714
|
+
</tbody>
|
|
715
|
+
</table>
|
|
709
716
|
<div class="nec-note">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>
|
|
710
|
-
|
|
717
|
+
</ng-container>
|
|
718
|
+
<ng-template #noIdb>
|
|
711
719
|
<div class="nec-note">IndexedDB non disponibile in questo contesto.</div>
|
|
712
|
-
|
|
720
|
+
</ng-template>
|
|
713
721
|
</div>
|
|
714
722
|
|
|
715
723
|
<!-- Store NgRx + lazy -->
|
|
716
724
|
<div class="nec-panel">
|
|
717
725
|
<h3>Store NgRx</h3>
|
|
718
|
-
|
|
719
|
-
|
|
726
|
+
<ng-container *ngIf="storeReport()">
|
|
727
|
+
<ng-container *ngIf="storeReport()!.slices.length; else noSlices">
|
|
720
728
|
<table>
|
|
721
729
|
<thead>
|
|
722
730
|
<tr>
|
|
@@ -728,39 +736,32 @@ class NecDashboardComponent {
|
|
|
728
736
|
</tr>
|
|
729
737
|
</thead>
|
|
730
738
|
<tbody>
|
|
731
|
-
|
|
732
|
-
<
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
<
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
@if (!s.isLoading && !s.error) {
|
|
745
|
-
<span class="nec-badge">{{ s.isLoaded ? 'caricato' : 'idle' }}</span>
|
|
746
|
-
}
|
|
747
|
-
</td>
|
|
748
|
-
</tr>
|
|
749
|
-
}
|
|
739
|
+
<tr *ngFor="let s of storeReport()!.slices; trackBy: trackByKey">
|
|
740
|
+
<td>{{ s.key }}</td>
|
|
741
|
+
<td>{{ s.kind }}</td>
|
|
742
|
+
<td class="num">{{ s.entityCount ?? '–' }}</td>
|
|
743
|
+
<td class="num">{{ s.responsesCount }}</td>
|
|
744
|
+
<td>
|
|
745
|
+
<span class="nec-badge loading" *ngIf="s.isLoading">loading</span>
|
|
746
|
+
<span class="nec-badge error" [title]="s.error" *ngIf="s.error">error</span>
|
|
747
|
+
<span class="nec-badge" *ngIf="!s.isLoading && !s.error">{{
|
|
748
|
+
s.isLoaded ? 'caricato' : 'idle'
|
|
749
|
+
}}</span>
|
|
750
|
+
</td>
|
|
751
|
+
</tr>
|
|
750
752
|
</tbody>
|
|
751
753
|
</table>
|
|
752
|
-
|
|
754
|
+
</ng-container>
|
|
755
|
+
<ng-template #noSlices>
|
|
753
756
|
<div class="nec-note">Nessuna slice CRUD montata.</div>
|
|
754
|
-
|
|
757
|
+
</ng-template>
|
|
755
758
|
|
|
756
|
-
|
|
759
|
+
<ng-container *ngIf="storeReport()!.lazy?.length; else noLazy">
|
|
757
760
|
<h3 style="margin-top:12px">Sezioni lazy (da lazy-report)</h3>
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
</div>
|
|
763
|
-
}
|
|
761
|
+
<div class="nec-note" *ngIf="storeReport()!.lazyReportGeneratedAt">
|
|
762
|
+
snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con
|
|
763
|
+
<code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.
|
|
764
|
+
</div>
|
|
764
765
|
<table>
|
|
765
766
|
<thead>
|
|
766
767
|
<tr>
|
|
@@ -771,47 +772,44 @@ class NecDashboardComponent {
|
|
|
771
772
|
</tr>
|
|
772
773
|
</thead>
|
|
773
774
|
<tbody>
|
|
774
|
-
|
|
775
|
-
<
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
<
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
</tr>
|
|
786
|
-
}
|
|
775
|
+
<tr *ngFor="let l of storeReport()!.lazy!; trackBy: trackByName">
|
|
776
|
+
<td>{{ l.name }}</td>
|
|
777
|
+
<td>{{ l.sections.join(', ') || '–' }}</td>
|
|
778
|
+
<td>{{ l.verdict }}</td>
|
|
779
|
+
<td>
|
|
780
|
+
<span
|
|
781
|
+
class="nec-badge"
|
|
782
|
+
[class.lazy]="l.runtimeStatus === 'lazy-not-loaded'"
|
|
783
|
+
>{{ l.runtimeStatus }}</span>
|
|
784
|
+
</td>
|
|
785
|
+
</tr>
|
|
787
786
|
</tbody>
|
|
788
787
|
</table>
|
|
789
|
-
|
|
788
|
+
</ng-container>
|
|
789
|
+
<ng-template #noLazy>
|
|
790
790
|
<div class="nec-note">
|
|
791
791
|
Nessun lazy-report caricato (genera src/assets/lazy-report.json con
|
|
792
792
|
<code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).
|
|
793
793
|
</div>
|
|
794
|
-
|
|
795
|
-
|
|
794
|
+
</ng-template>
|
|
795
|
+
</ng-container>
|
|
796
796
|
</div>
|
|
797
|
-
`, isInline: true, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
797
|
+
`, isInline: true, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
798
798
|
}
|
|
799
799
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: NecDashboardComponent, decorators: [{
|
|
800
800
|
type: Component,
|
|
801
|
-
args: [{ selector: 'nec-dashboard', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
801
|
+
args: [{ selector: 'nec-dashboard', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
802
802
|
<div class="nec-toolbar">
|
|
803
803
|
<button type="button" (click)="refresh()" [disabled]="busy()">
|
|
804
804
|
{{ busy() ? 'Aggiorno…' : 'Aggiorna' }}
|
|
805
805
|
</button>
|
|
806
|
-
|
|
807
|
-
<span class="nec-note">ultimo aggiornamento: {{ lastUpdated() }}</span>
|
|
808
|
-
}
|
|
806
|
+
<span class="nec-note" *ngIf="lastUpdated()">ultimo aggiornamento: {{ lastUpdated() }}</span>
|
|
809
807
|
</div>
|
|
810
808
|
|
|
811
809
|
<!-- Quota aggregata origine -->
|
|
812
810
|
<div class="nec-panel">
|
|
813
811
|
<h3>Quota origine (aggregata)</h3>
|
|
814
|
-
|
|
812
|
+
<ng-container *ngIf="quota()?.available; else noQuota">
|
|
815
813
|
<div>
|
|
816
814
|
uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /
|
|
817
815
|
quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>
|
|
@@ -819,112 +817,108 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
819
817
|
<div class="nec-note">
|
|
820
818
|
Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.
|
|
821
819
|
</div>
|
|
822
|
-
|
|
820
|
+
</ng-container>
|
|
821
|
+
<ng-template #noQuota>
|
|
823
822
|
<div class="nec-note">Stima quota non disponibile (Safari o contesto non sicuro).</div>
|
|
824
|
-
|
|
823
|
+
</ng-template>
|
|
825
824
|
</div>
|
|
826
825
|
|
|
827
826
|
<!-- localStorage -->
|
|
828
827
|
<div class="nec-panel">
|
|
829
828
|
<h3>localStorage</h3>
|
|
830
|
-
|
|
829
|
+
<ng-container *ngIf="storage()?.available; else noLocalStorage">
|
|
831
830
|
<div>
|
|
832
831
|
{{ storage()?.count }} chiavi · totale
|
|
833
832
|
<strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /
|
|
834
833
|
{{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)
|
|
835
834
|
</div>
|
|
836
|
-
|
|
835
|
+
<ng-container *ngIf="storage()!.entries.length; else noLocalStorageEntries">
|
|
837
836
|
<table>
|
|
838
837
|
<thead>
|
|
839
838
|
<tr>
|
|
840
839
|
<th>chiave</th>
|
|
841
840
|
<th class="num">UTF-16</th>
|
|
842
841
|
<th class="num">UTF-8</th>
|
|
843
|
-
|
|
844
|
-
<th>valore</th>
|
|
845
|
-
}
|
|
842
|
+
<th *ngIf="allowRevealValues">valore</th>
|
|
846
843
|
</tr>
|
|
847
844
|
</thead>
|
|
848
845
|
<tbody>
|
|
849
|
-
|
|
850
|
-
<
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
846
|
+
<tr *ngFor="let e of storage()!.entries; trackBy: trackByKey">
|
|
847
|
+
<td>
|
|
848
|
+
{{ e.key }}
|
|
849
|
+
<span
|
|
850
|
+
class="nec-badge error"
|
|
851
|
+
title="chiave potenzialmente sensibile"
|
|
852
|
+
*ngIf="isSensitive(e.key)"
|
|
853
|
+
>⚠</span>
|
|
854
|
+
</td>
|
|
855
|
+
<td class="num">{{ formatBytes(e.bytesUtf16) }}</td>
|
|
856
|
+
<td class="num">{{ formatBytes(e.bytesUtf8) }}</td>
|
|
857
|
+
<td *ngIf="allowRevealValues">
|
|
858
|
+
<ng-container *ngIf="revealed()[e.key] !== undefined; else revealBtn">
|
|
859
|
+
<code>{{ revealed()[e.key] }}</code>
|
|
860
|
+
</ng-container>
|
|
861
|
+
<ng-template #revealBtn>
|
|
862
|
+
<button type="button" (click)="reveal(e.key)">mostra</button>
|
|
863
|
+
</ng-template>
|
|
864
|
+
</td>
|
|
865
|
+
</tr>
|
|
870
866
|
</tbody>
|
|
871
867
|
</table>
|
|
872
|
-
|
|
868
|
+
</ng-container>
|
|
869
|
+
<ng-template #noLocalStorageEntries>
|
|
873
870
|
<div class="nec-note">Nessuna chiave.</div>
|
|
874
|
-
|
|
875
|
-
|
|
871
|
+
</ng-template>
|
|
872
|
+
</ng-container>
|
|
873
|
+
<ng-template #noLocalStorage>
|
|
876
874
|
<div class="nec-note">localStorage non disponibile.</div>
|
|
877
|
-
|
|
875
|
+
</ng-template>
|
|
878
876
|
</div>
|
|
879
877
|
|
|
880
878
|
<!-- IndexedDB -->
|
|
881
879
|
<div class="nec-panel">
|
|
882
880
|
<h3>IndexedDB</h3>
|
|
883
|
-
|
|
881
|
+
<ng-container *ngIf="idb()?.available; else noIdb">
|
|
884
882
|
<div class="nec-note">adapter: {{ idb()?.adapter }}</div>
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
<
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
</tbody>
|
|
915
|
-
</table>
|
|
916
|
-
}
|
|
883
|
+
<div class="nec-note" *ngIf="idb()?.note">{{ idb()?.note }}</div>
|
|
884
|
+
<table *ngIf="idb()!.databases.length">
|
|
885
|
+
<thead>
|
|
886
|
+
<tr>
|
|
887
|
+
<th>database</th>
|
|
888
|
+
<th>object store</th>
|
|
889
|
+
<th class="num">record</th>
|
|
890
|
+
</tr>
|
|
891
|
+
</thead>
|
|
892
|
+
<tbody>
|
|
893
|
+
<ng-container *ngFor="let db of idb()!.databases; trackBy: trackByName">
|
|
894
|
+
<ng-container *ngIf="db.stores.length; else noStores">
|
|
895
|
+
<tr *ngFor="let st of db.stores; trackBy: trackByName">
|
|
896
|
+
<td>{{ db.name }} <span class="nec-note">v{{ db.version }}</span></td>
|
|
897
|
+
<td>{{ st.name }}</td>
|
|
898
|
+
<td class="num">{{ st.count ?? '–' }}</td>
|
|
899
|
+
</tr>
|
|
900
|
+
</ng-container>
|
|
901
|
+
<ng-template #noStores>
|
|
902
|
+
<tr>
|
|
903
|
+
<td>{{ db.name }} <span class="nec-note">v{{ db.version }}</span></td>
|
|
904
|
+
<td class="nec-note" colspan="2">{{ db.note ?? 'nessun object store' }}</td>
|
|
905
|
+
</tr>
|
|
906
|
+
</ng-template>
|
|
907
|
+
</ng-container>
|
|
908
|
+
</tbody>
|
|
909
|
+
</table>
|
|
917
910
|
<div class="nec-note">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>
|
|
918
|
-
|
|
911
|
+
</ng-container>
|
|
912
|
+
<ng-template #noIdb>
|
|
919
913
|
<div class="nec-note">IndexedDB non disponibile in questo contesto.</div>
|
|
920
|
-
|
|
914
|
+
</ng-template>
|
|
921
915
|
</div>
|
|
922
916
|
|
|
923
917
|
<!-- Store NgRx + lazy -->
|
|
924
918
|
<div class="nec-panel">
|
|
925
919
|
<h3>Store NgRx</h3>
|
|
926
|
-
|
|
927
|
-
|
|
920
|
+
<ng-container *ngIf="storeReport()">
|
|
921
|
+
<ng-container *ngIf="storeReport()!.slices.length; else noSlices">
|
|
928
922
|
<table>
|
|
929
923
|
<thead>
|
|
930
924
|
<tr>
|
|
@@ -936,39 +930,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
936
930
|
</tr>
|
|
937
931
|
</thead>
|
|
938
932
|
<tbody>
|
|
939
|
-
|
|
940
|
-
<
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
<
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
@if (!s.isLoading && !s.error) {
|
|
953
|
-
<span class="nec-badge">{{ s.isLoaded ? 'caricato' : 'idle' }}</span>
|
|
954
|
-
}
|
|
955
|
-
</td>
|
|
956
|
-
</tr>
|
|
957
|
-
}
|
|
933
|
+
<tr *ngFor="let s of storeReport()!.slices; trackBy: trackByKey">
|
|
934
|
+
<td>{{ s.key }}</td>
|
|
935
|
+
<td>{{ s.kind }}</td>
|
|
936
|
+
<td class="num">{{ s.entityCount ?? '–' }}</td>
|
|
937
|
+
<td class="num">{{ s.responsesCount }}</td>
|
|
938
|
+
<td>
|
|
939
|
+
<span class="nec-badge loading" *ngIf="s.isLoading">loading</span>
|
|
940
|
+
<span class="nec-badge error" [title]="s.error" *ngIf="s.error">error</span>
|
|
941
|
+
<span class="nec-badge" *ngIf="!s.isLoading && !s.error">{{
|
|
942
|
+
s.isLoaded ? 'caricato' : 'idle'
|
|
943
|
+
}}</span>
|
|
944
|
+
</td>
|
|
945
|
+
</tr>
|
|
958
946
|
</tbody>
|
|
959
947
|
</table>
|
|
960
|
-
|
|
948
|
+
</ng-container>
|
|
949
|
+
<ng-template #noSlices>
|
|
961
950
|
<div class="nec-note">Nessuna slice CRUD montata.</div>
|
|
962
|
-
|
|
951
|
+
</ng-template>
|
|
963
952
|
|
|
964
|
-
|
|
953
|
+
<ng-container *ngIf="storeReport()!.lazy?.length; else noLazy">
|
|
965
954
|
<h3 style="margin-top:12px">Sezioni lazy (da lazy-report)</h3>
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
</div>
|
|
971
|
-
}
|
|
955
|
+
<div class="nec-note" *ngIf="storeReport()!.lazyReportGeneratedAt">
|
|
956
|
+
snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con
|
|
957
|
+
<code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.
|
|
958
|
+
</div>
|
|
972
959
|
<table>
|
|
973
960
|
<thead>
|
|
974
961
|
<tr>
|
|
@@ -979,28 +966,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
979
966
|
</tr>
|
|
980
967
|
</thead>
|
|
981
968
|
<tbody>
|
|
982
|
-
|
|
983
|
-
<
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
<
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
</tr>
|
|
994
|
-
}
|
|
969
|
+
<tr *ngFor="let l of storeReport()!.lazy!; trackBy: trackByName">
|
|
970
|
+
<td>{{ l.name }}</td>
|
|
971
|
+
<td>{{ l.sections.join(', ') || '–' }}</td>
|
|
972
|
+
<td>{{ l.verdict }}</td>
|
|
973
|
+
<td>
|
|
974
|
+
<span
|
|
975
|
+
class="nec-badge"
|
|
976
|
+
[class.lazy]="l.runtimeStatus === 'lazy-not-loaded'"
|
|
977
|
+
>{{ l.runtimeStatus }}</span>
|
|
978
|
+
</td>
|
|
979
|
+
</tr>
|
|
995
980
|
</tbody>
|
|
996
981
|
</table>
|
|
997
|
-
|
|
982
|
+
</ng-container>
|
|
983
|
+
<ng-template #noLazy>
|
|
998
984
|
<div class="nec-note">
|
|
999
985
|
Nessun lazy-report caricato (genera src/assets/lazy-report.json con
|
|
1000
986
|
<code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).
|
|
1001
987
|
</div>
|
|
1002
|
-
|
|
1003
|
-
|
|
988
|
+
</ng-template>
|
|
989
|
+
</ng-container>
|
|
1004
990
|
</div>
|
|
1005
991
|
`, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}\n"] }]
|
|
1006
992
|
}], propDecorators: { blacklist: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngrx-entity-crud-devtools.mjs","sources":["../../../libs/ngrx-entity-crud/devtools/models.ts","../../../libs/ngrx-entity-crud/devtools/idb-adapter.token.ts","../../../libs/ngrx-entity-crud/devtools/agnostic-selectors.ts","../../../libs/ngrx-entity-crud/devtools/mask.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-local-storage-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-indexeddb-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts","../../../libs/ngrx-entity-crud/devtools/public-api.ts","../../../libs/ngrx-entity-crud/devtools/ngrx-entity-crud-devtools.ts"],"sourcesContent":["/**\n * Modelli dei report prodotti dai probe della dashboard (`ngrx-entity-crud/devtools`).\n *\n * Sono volutamente indipendenti dai tipi del main entry-point: i probe leggono lo stato\n * per CONVENZIONE (vedi `EntityCrudBaseState` in `src/lib/models.ts`), non per tipo, così\n * il sotto-modulo `devtools` resta autonomo e agnostico rispetto alla persistenza usata.\n */\n\n// ---------------------------------------------------------------------------\n// localStorage / sessionStorage\n// ---------------------------------------------------------------------------\n\nexport interface NecStorageEntry {\n key: string;\n /** Byte verso la quota (UTF-16): `(key.length + value.length) * 2`. Metrica primaria. */\n bytesUtf16: number;\n /** Byte della serializzazione UTF-8 (`TextEncoder`/`Blob`). Metrica secondaria. */\n bytesUtf8: number;\n}\n\nexport interface NecStorageReport {\n available: boolean;\n type: 'local' | 'session';\n entries: NecStorageEntry[];\n count: number;\n totalBytesUtf16: number;\n totalBytesUtf8: number;\n}\n\n/** Stima quota AGGREGATA per-origine (localStorage + IndexedDB + Cache), non scorporabile. */\nexport interface NecQuotaEstimate {\n available: boolean;\n usage?: number;\n quota?: number;\n /** Non-standard (solo Chromium): byte per area. Assente su Firefox/Safari. */\n usageDetails?: Record<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// IndexedDB (agnostico)\n// ---------------------------------------------------------------------------\n\nexport interface NecIdbStoreReport {\n name: string;\n /** Numero record (`objectStore.count()`); `null` se non determinabile. */\n count: number | null;\n}\n\nexport interface NecIdbDbReport {\n name: string;\n version: number | null;\n stores: NecIdbStoreReport[];\n note?: string;\n}\n\nexport interface NecIdbReport {\n available: boolean;\n /** `false` se non è stato possibile elencare i database (es. Firefox senza nomi forniti). */\n enumerable: boolean;\n /** Nome dell'adapter usato: `'native'`, il nome di un `NecIdbAdapter`, o `null`. */\n adapter: string | null;\n databases: NecIdbDbReport[];\n note?: string;\n}\n\n/**\n * Punto di estensione agnostico: il consumer può fornire un adapter esplicito (via\n * `NEC_IDB_ADAPTER`) per conteggi accurati quando la sua libreria di persistenza nasconde\n * i nomi DB. Quando assente, il probe usa solo le API native.\n */\nexport interface NecIdbAdapter {\n name: string;\n isAvailable(): boolean;\n listDatabases(): Promise<NecIdbDbReport[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Store NgRx + lazy\n// ---------------------------------------------------------------------------\n\nexport type NecSliceKind = 'plural' | 'singular' | 'unknown';\n\nexport interface NecStoreSlice {\n key: string;\n kind: NecSliceKind;\n isLoading: boolean;\n isLoaded: boolean;\n error: string | null;\n /** Numero entità (solo slice `plural`). */\n entityCount?: number;\n responsesCount: number;\n}\n\nexport type NecRuntimeStatus = 'loaded' | 'lazy-not-loaded' | 'unknown';\n\nexport interface NecLazyEntry {\n name: string;\n clazz?: string;\n type?: string;\n verdict?: string;\n isLazyCandidate: boolean;\n lazyRoute?: boolean;\n sections: string[];\n usedByShell: boolean;\n runtimeStatus: NecRuntimeStatus;\n}\n\nexport interface NecStoreReport {\n slices: NecStoreSlice[];\n loadingNames: string[];\n errors: string[];\n /** Presente solo se è stato fornito un `lazyReportUrl` e il fetch è riuscito. */\n lazy?: NecLazyEntry[];\n /** Timestamp ISO di generazione del `lazy-report.json` (per segnalare snapshot stantii). */\n lazyReportGeneratedAt?: string;\n}\n","import {InjectionToken} from '@angular/core';\nimport {NecIdbAdapter} from './models';\n\n/**\n * Adapter IndexedDB OPZIONALE, agnostico rispetto alla libreria di persistenza.\n *\n * Fornendolo, il `NecIndexedDbProbeService` lo usa con priorità per enumerare i database\n * (utile quando la libreria del consumer nasconde i nomi DB o su browser senza\n * `indexedDB.databases()`, es. Firefox). Quando NON fornito, il probe usa solo le API native.\n */\nexport const NEC_IDB_ADAPTER = new InjectionToken<NecIdbAdapter>('NEC_IDB_ADAPTER');\n","import {createSelector, MemoizedSelector} from '@ngrx/store';\n\n/**\n * Versione FACTORY (parametrizzabile) dei selettori agnostici di loading/error che il\n * template `ng-add` installa in `root-store/selectors.ts`.\n *\n * Il template resta invariato (retro-compatibilità): qui la logica è IDENTICA ma con\n * `rootSelector`/`blacklist`/`whitelist` resi parametri invece che costanti hardcoded, così\n * è riutilizzabile dal pacchetto npm (entry-point `ngrx-entity-crud/devtools`).\n *\n * Scandisce lo stato sfruttando la convenzione `EntityCrudBaseState`: ogni slice CRUD espone\n * `isLoading: boolean` ed `error: string | null` al livello top.\n */\nexport interface AgnosticLoadingSelectorsOptions {\n /** Selettore della radice da scandire (default: l'intero stato root). */\n rootSelector?: (state: any) => Record<string, any>;\n /** Chiavi di slice da escludere dallo scan. */\n blacklist?: ReadonlyArray<string>;\n /** Se valorizzata, considera SOLO queste chiavi (precede la blacklist). */\n whitelist?: ReadonlyArray<string>;\n}\n\nexport interface AgnosticLoadingSelectors {\n /** Nomi delle slice attualmente in caricamento (`isLoading === true`). */\n selectLoadingNames: MemoizedSelector<any, string[]>;\n /** `true` se almeno una slice CRUD è in caricamento. */\n selectIsLoading: MemoizedSelector<any, boolean>;\n /** Elenco degli errori non vuoti presenti nelle slice CRUD. */\n selectErrors: MemoizedSelector<any, string[]>;\n /** Concatenazione degli errori non vuoti (stringa vuota se non ce ne sono). */\n selectError: MemoizedSelector<any, string>;\n}\n\ninterface LoadingSlice {\n isLoading?: boolean;\n error?: string | null;\n}\n\nexport function createAgnosticLoadingSelectors(\n options: AgnosticLoadingSelectorsOptions = {}\n): AgnosticLoadingSelectors {\n const rootSelector = options.rootSelector ?? ((state: any): Record<string, any> => state);\n const blacklist = options.blacklist ?? [];\n const whitelist = options.whitelist ?? [];\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const isLoadingSlice = (value: any): value is LoadingSlice =>\n !!value && typeof value === 'object' && typeof value.isLoading === 'boolean';\n\n const crudEntries = (state: Record<string, any>): Array<[string, LoadingSlice]> =>\n Object.entries(state || {})\n .filter(([key]) => isEligible(key))\n .filter((entry): entry is [string, LoadingSlice] => isLoadingSlice(entry[1]));\n\n const selectLoadingNames = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .filter(([, slice]) => slice.isLoading === true)\n .map(([key]) => key)\n );\n\n const selectIsLoading = createSelector(\n selectLoadingNames,\n (names): boolean => names.length > 0\n );\n\n const selectErrors = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .map(([, slice]) => slice.error)\n .filter((error): error is string => typeof error === 'string' && error.length > 0)\n );\n\n const selectError = createSelector(selectErrors, (errors): string => errors.join('\\n'));\n\n return {selectLoadingNames, selectIsLoading, selectErrors, selectError};\n}\n","/**\n * Utility di privacy per la dashboard: poiché può girare anche in PRODUZIONE, i valori non\n * vengono mai mostrati di default e — quando il consumer abilita esplicitamente il reveal —\n * vengono comunque mascherati i pattern sensibili (token/JWT/email/segreti).\n */\n\nconst SENSITIVE_KEY =\n /(token|secret|password|passwd|pwd|auth(orization)?|credential|api[-_]?key|jwt|session|cookie|bearer)/i;\n\n/** `true` se il nome chiave suggerisce un contenuto sensibile (token, password, ecc.). */\nexport function looksSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY.test(key || '');\n}\n\n/** Redige nel testo i pattern sensibili comuni (JWT, email, token/hex lunghi). */\nexport function redactSensitive(value: string): string {\n return (value || '')\n .replace(/eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '«jwt-redatto»')\n .replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g, '«email-redatta»')\n .replace(/\\b[A-Fa-f0-9]{32,}\\b/g, '«hex-redatto»')\n .replace(/\\b[A-Za-z0-9_-]{40,}\\b/g, '«token-redatto»');\n}\n\n/**\n * Valore \"sicuro da mostrare\": se la chiave è sensibile, nasconde tutto (mostra solo la\n * lunghezza); altrimenti redige i pattern sensibili e tronca a `maxLength`.\n */\nexport function maskValue(key: string, value: string, maxLength = 200): string {\n if (looksSensitiveKey(key)) {\n return `«nascosto» (${(value || '').length} caratteri)`;\n }\n let out = redactSensitive(value);\n if (out.length > maxLength) {\n out = out.slice(0, maxLength) + '… (troncato)';\n }\n return out;\n}\n","import {Injectable} from '@angular/core';\nimport {NecQuotaEstimate, NecStorageEntry, NecStorageReport} from '../models';\n\n/**\n * Riepilogo di `localStorage` / `sessionStorage`.\n *\n * Sincrono per la lettura delle chiavi. NON espone i valori: solo chiavi e dimensioni\n * (privacy). La metrica primaria verso la quota è UTF-16 `(key.length + value.length) * 2`,\n * perché è ciò che conta verso il limite ~5-10MB; la metrica UTF-8 è secondaria.\n */\n@Injectable({providedIn: 'root'})\nexport class NecLocalStorageProbeService {\n read(type: 'local' | 'session' = 'local'): NecStorageReport {\n const empty: NecStorageReport = {\n available: false,\n type,\n entries: [],\n count: 0,\n totalBytesUtf16: 0,\n totalBytesUtf8: 0,\n };\n\n if (typeof window === 'undefined') {\n return empty;\n }\n\n let storage: Storage | null = null;\n try {\n storage = type === 'local' ? window.localStorage : window.sessionStorage;\n } catch {\n // accesso negato (sandbox/incognito/policy)\n return empty;\n }\n if (!storage) {\n return empty;\n }\n\n const entries: NecStorageEntry[] = [];\n let totalBytesUtf16 = 0;\n let totalBytesUtf8 = 0;\n\n try {\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (key == null) {\n continue;\n }\n const value = storage.getItem(key) ?? '';\n const bytesUtf16 = (key.length + value.length) * 2;\n const bytesUtf8 = this.utf8Bytes(key + value);\n totalBytesUtf16 += bytesUtf16;\n totalBytesUtf8 += bytesUtf8;\n entries.push({key, bytesUtf16, bytesUtf8});\n }\n } catch {\n // accesso parziale negato: ritorna ciò che è stato raccolto finora\n }\n\n entries.sort((a, b) => b.bytesUtf16 - a.bytesUtf16);\n\n return {\n available: true,\n type,\n entries,\n count: entries.length,\n totalBytesUtf16,\n totalBytesUtf8,\n };\n }\n\n /**\n * Legge ON-DEMAND il valore grezzo di una singola chiave (per il reveal esplicito in UI).\n * Non viene mai incluso nel report: la dashboard lo richiede solo su azione dell'utente e lo\n * maschera tramite `maskValue`.\n */\n readValue(key: string, type: 'local' | 'session' = 'local'): string | null {\n if (typeof window === 'undefined') {\n return null;\n }\n try {\n const storage = type === 'local' ? window.localStorage : window.sessionStorage;\n return storage ? storage.getItem(key) : null;\n } catch {\n return null;\n }\n }\n\n /**\n * Stima quota AGGREGATA per-origine (include anche IndexedDB e Cache): NON è scorporabile\n * per area. Può essere assente (Safari/contesto non sicuro) o arrotondata (anti-fingerprint).\n */\n async estimate(): Promise<NecQuotaEstimate> {\n const empty: NecQuotaEstimate = {available: false};\n if (\n typeof navigator === 'undefined' ||\n !navigator.storage ||\n typeof navigator.storage.estimate !== 'function'\n ) {\n return empty;\n }\n try {\n const est = await navigator.storage.estimate();\n return {\n available: true,\n usage: est.usage,\n quota: est.quota,\n usageDetails: (est as {usageDetails?: Record<string, number>}).usageDetails,\n };\n } catch {\n return empty;\n }\n }\n\n private utf8Bytes(s: string): number {\n try {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(s).length;\n }\n } catch {\n /* noop */\n }\n try {\n if (typeof Blob !== 'undefined') {\n return new Blob([s]).size;\n }\n } catch {\n /* noop */\n }\n return s.length;\n }\n}\n","import {Inject, Injectable, Optional} from '@angular/core';\nimport {NecIdbAdapter, NecIdbDbReport, NecIdbReport, NecIdbStoreReport} from '../models';\nimport {NEC_IDB_ADAPTER} from '../idb-adapter.token';\n\n/**\n * Riepilogo IndexedDB AGNOSTICO rispetto alla libreria di persistenza.\n *\n * Priorità reale: (1) `NEC_IDB_ADAPTER` esplicito, (2) API native\n * (`indexedDB.databases()` + `open()` + `count()`). NESSUN import di librerie di\n * persistenza. Mostra il numero di record per object store; i byte per-store NON sono\n * misurabili e non vengono promessi (solo la quota aggregata, altrove).\n */\n@Injectable({providedIn: 'root'})\nexport class NecIndexedDbProbeService {\n constructor(@Optional() @Inject(NEC_IDB_ADAPTER) private readonly adapter: NecIdbAdapter | null) {}\n\n /**\n * @param fallbackDatabaseNames nomi DB da ispezionare quando `indexedDB.databases()` non\n * è supportato (Firefox / Safari vecchi). Passa qui i nomi noti della tua persistenza.\n * @param openTimeoutMs timeout per ogni `open()` (default 3000ms).\n */\n async read(fallbackDatabaseNames: string[] = [], openTimeoutMs = 3000): Promise<NecIdbReport> {\n // 1) adapter esplicito: path prioritario e agnostico, indipendente dalle API native\n // (il consumer può fornire conteggi anche dove l'introspezione nativa non basta).\n if (this.adapter && this.adapter.isAvailable()) {\n try {\n const databases = await this.adapter.listDatabases();\n return {available: true, enumerable: true, adapter: this.adapter.name, databases};\n } catch {\n // degrada al path nativo\n }\n }\n\n // 2) path nativo: richiede l'API IndexedDB del browser\n if (typeof indexedDB === 'undefined') {\n return {\n available: false,\n enumerable: false,\n adapter: null,\n databases: [],\n note: 'IndexedDB non disponibile in questo contesto',\n };\n }\n\n const names = await this.listDatabaseNames(fallbackDatabaseNames);\n if (!names.length) {\n return {\n available: true,\n enumerable: false,\n adapter: 'native',\n databases: [],\n note:\n 'Impossibile elencare i database: indexedDB.databases() non supportato (es. Firefox) ' +\n 'e nessun nome fornito. Passa i nomi DB noti via input \"idbDatabaseNames\".',\n };\n }\n\n const databases: NecIdbDbReport[] = [];\n for (const name of names) {\n databases.push(await this.inspectDatabase(name, openTimeoutMs));\n }\n return {available: true, enumerable: true, adapter: 'native', databases};\n }\n\n private async listDatabaseNames(fallback: string[]): Promise<string[]> {\n const idbAny = indexedDB as unknown as {\n databases?: () => Promise<Array<{name?: string}>>;\n };\n if (typeof idbAny.databases === 'function') {\n try {\n const list = await idbAny.databases();\n const names = list.map((d) => d.name).filter((n): n is string => !!n);\n if (names.length) {\n return names;\n }\n } catch {\n // ignora: usa il fallback\n }\n }\n return Array.from(new Set(fallback.filter(Boolean)));\n }\n\n private inspectDatabase(name: string, timeoutMs: number): Promise<NecIdbDbReport> {\n return new Promise<NecIdbDbReport>((resolve) => {\n let settled = false;\n const done = (report: NecIdbDbReport): void => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(report);\n };\n\n const timer = setTimeout(\n () => done({name, version: null, stores: [], note: 'timeout apertura DB'}),\n timeoutMs\n );\n\n let request: IDBOpenDBRequest;\n try {\n request = indexedDB.open(name);\n } catch {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'open() fallita'});\n return;\n }\n\n request.onblocked = () => {\n clearTimeout(timer);\n done({\n name,\n version: null,\n stores: [],\n note: 'apertura bloccata (versionchange in un\\'altra scheda)',\n });\n };\n\n request.onerror = () => {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'errore apertura DB (o DB inesistente)'});\n };\n\n request.onupgradeneeded = (event) => {\n // Il DB non esisteva: NON crearne lo schema. Annulla la transazione di upgrade\n // (provoca onerror e rollback della creazione) per non sporcare l'origine.\n try {\n (event.target as IDBOpenDBRequest).transaction?.abort();\n } catch {\n /* noop */\n }\n };\n\n request.onsuccess = () => {\n const db = request.result;\n const version = db.version;\n const storeNames = Array.from(db.objectStoreNames);\n\n if (!storeNames.length) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores: []});\n return;\n }\n\n let tx: IDBTransaction;\n try {\n tx = db.transaction(storeNames, 'readonly');\n } catch {\n clearTimeout(timer);\n db.close();\n done({\n name,\n version,\n stores: storeNames.map((s): NecIdbStoreReport => ({name: s, count: null})),\n });\n return;\n }\n\n const stores: NecIdbStoreReport[] = storeNames.map((s) => ({name: s, count: null}));\n let pending = storeNames.length;\n const finalize = (): void => {\n if (--pending === 0) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores});\n }\n };\n\n storeNames.forEach((s, idx) => {\n try {\n const countReq = tx.objectStore(s).count();\n countReq.onsuccess = () => {\n stores[idx].count = countReq.result;\n finalize();\n };\n countReq.onerror = () => finalize();\n } catch {\n finalize();\n }\n });\n };\n });\n }\n}\n","import {inject, Injectable} from '@angular/core';\nimport {Store} from '@ngrx/store';\nimport {take} from 'rxjs/operators';\nimport {NecLazyEntry, NecSliceKind, NecStoreReport, NecStoreSlice} from '../models';\n\ninterface ProbeOptions {\n blacklist?: string[];\n whitelist?: string[];\n}\n\n/**\n * Riepilogo degli store NgRx a runtime.\n *\n * Enumera le slice CRUD montate per CONVENZIONE (`typeof value.isLoading === 'boolean'`,\n * vedi `EntityCrudBaseState`), senza dipendere dai selettori per-dominio. Una slice lazy non\n * ancora caricata semplicemente non ha la chiave nello stato root.\n */\n@Injectable({providedIn: 'root'})\nexport class NecStoreProbeService {\n private readonly store = inject(Store);\n\n /** Lettura sincrona dello stato root (NgRx emette il valore corrente all'iscrizione). */\n read(opts: ProbeOptions = {}): NecStoreReport {\n const blacklist = opts.blacklist ?? [];\n const whitelist = opts.whitelist ?? [];\n\n let root: Record<string, any> = {};\n this.store\n .select((s) => s as Record<string, any>)\n .pipe(take(1))\n .subscribe((s) => (root = s ?? {}));\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const slices: NecStoreSlice[] = [];\n const loadingNames: string[] = [];\n const errors: string[] = [];\n\n for (const [key, value] of Object.entries(root)) {\n if (!isEligible(key)) {\n continue;\n }\n if (!value || typeof value !== 'object' || typeof value.isLoading !== 'boolean') {\n continue;\n }\n const v = value as Record<string, any>;\n const kind: NecSliceKind = Array.isArray(v['ids'])\n ? 'plural'\n : 'item' in v\n ? 'singular'\n : 'unknown';\n const error =\n typeof v['error'] === 'string' && v['error'].length > 0 ? (v['error'] as string) : null;\n\n const slice: NecStoreSlice = {\n key,\n kind,\n isLoading: v['isLoading'] === true,\n isLoaded: v['isLoaded'] === true,\n error,\n entityCount:\n kind === 'plural'\n ? Array.isArray(v['ids'])\n ? v['ids'].length\n : Object.keys(v['entities'] ?? {}).length\n : undefined,\n responsesCount: Array.isArray(v['responses']) ? v['responses'].length : 0,\n };\n slices.push(slice);\n if (slice.isLoading) {\n loadingNames.push(key);\n }\n if (slice.error) {\n errors.push(`${key}: ${slice.error}`);\n }\n }\n\n slices.sort((a, b) => a.key.localeCompare(b.key));\n return {slices, loadingNames, errors};\n }\n\n /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */\n async readWithLazyReport(url: string, opts: ProbeOptions = {}): Promise<NecStoreReport> {\n const report = this.read(opts);\n const fetched = await this.fetchLazyReport(url, report);\n if (!fetched) {\n return report;\n }\n return {...report, lazy: fetched.entries, lazyReportGeneratedAt: fetched.generatedAt};\n }\n\n private async fetchLazyReport(\n url: string,\n report: NecStoreReport\n ): Promise<{entries: NecLazyEntry[]; generatedAt?: string} | undefined> {\n if (typeof fetch !== 'function') {\n return undefined;\n }\n let json: any;\n try {\n const res = await fetch(url, {headers: {Accept: 'application/json'}});\n if (!res.ok) {\n return undefined;\n }\n json = await res.json();\n } catch {\n return undefined;\n }\n\n const stores: any[] = Array.isArray(json?.stores) ? json.stores : [];\n const mounted = new Set(report.slices.map((s) => s.key));\n const generatedAt = typeof json?.generatedAt === 'string' ? json.generatedAt : undefined;\n\n const entries = stores.map((st): NecLazyEntry => {\n const sliceKey = this.toSliceKey(st?.name);\n const isLoaded = mounted.has(sliceKey) || mounted.has(st?.name);\n const isLazyCandidate =\n typeof st?.isLazyCandidate === 'boolean'\n ? st.isLazyCandidate\n : /candidato lazy/i.test(st?.verdict ?? '');\n return {\n name: st?.name,\n clazz: st?.clazz,\n type: st?.type,\n verdict: st?.verdict,\n isLazyCandidate,\n lazyRoute: typeof st?.lazyRoute === 'boolean' ? st.lazyRoute : undefined,\n sections: Array.isArray(st?.sections) ? st.sections : [],\n usedByShell: !!st?.usedByShell,\n runtimeStatus: isLoaded ? 'loaded' : isLazyCandidate ? 'lazy-not-loaded' : 'unknown',\n };\n });\n\n return {entries, generatedAt};\n }\n\n /**\n * Best-effort: il root state usa `strings.underscore(name)` come chiave di slice, mentre il\n * report usa il nome dasherizzato. (Fase 1: far emettere a `lazy-report` la feature key reale.)\n */\n private toSliceKey(name: string): string {\n return (name ?? '').replace(/-/g, '_');\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n inject,\n Input,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport {NecIdbReport, NecQuotaEstimate, NecStorageReport, NecStoreReport} from './models';\nimport {NecLocalStorageProbeService} from './probes/nec-local-storage-probe.service';\nimport {NecIndexedDbProbeService} from './probes/nec-indexeddb-probe.service';\nimport {NecStoreProbeService} from './probes/nec-store-probe.service';\nimport {looksSensitiveKey, maskValue} from './mask';\n\n/**\n * `<nec-dashboard>` — dashboard di gestione progetto plug-and-play.\n *\n * Standalone, OnPush, template HTML inline (nessun PrimeNG → importabile ovunque). Tre\n * pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy\n * mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;\n * polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.\n */\n@Component({\n selector: 'nec-dashboard',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [\n `\n :host {\n display: block;\n font-family: system-ui, sans-serif;\n font-size: 13px;\n color: #1f2933;\n }\n .nec-toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .nec-panel {\n border: 1px solid #d7dce2;\n border-radius: 6px;\n padding: 12px 16px;\n margin-bottom: 16px;\n }\n .nec-panel h3 {\n margin: 0 0 8px;\n font-size: 14px;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid #eceff3;\n }\n th {\n font-weight: 600;\n color: #52606d;\n }\n td.num,\n th.num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n .nec-note {\n color: #7b8794;\n font-style: italic;\n }\n .nec-badge {\n display: inline-block;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 11px;\n background: #e4e7eb;\n }\n .nec-badge.loading {\n background: #fde68a;\n }\n .nec-badge.error {\n background: #fca5a5;\n }\n .nec-badge.lazy {\n background: #bfdbfe;\n }\n button {\n cursor: pointer;\n }\n `,\n ],\n template: `\n <div class=\"nec-toolbar\">\n <button type=\"button\" (click)=\"refresh()\" [disabled]=\"busy()\">\n {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}\n </button>\n @if (lastUpdated()) {\n <span class=\"nec-note\">ultimo aggiornamento: {{ lastUpdated() }}</span>\n }\n </div>\n\n <!-- Quota aggregata origine -->\n <div class=\"nec-panel\">\n <h3>Quota origine (aggregata)</h3>\n @if (quota()?.available) {\n <div>\n uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /\n quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>\n </div>\n <div class=\"nec-note\">\n Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.\n </div>\n } @else {\n <div class=\"nec-note\">Stima quota non disponibile (Safari o contesto non sicuro).</div>\n }\n </div>\n\n <!-- localStorage -->\n <div class=\"nec-panel\">\n <h3>localStorage</h3>\n @if (storage()?.available) {\n <div>\n {{ storage()?.count }} chiavi · totale\n <strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /\n {{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)\n </div>\n @if (storage()!.entries.length) {\n <table>\n <thead>\n <tr>\n <th>chiave</th>\n <th class=\"num\">UTF-16</th>\n <th class=\"num\">UTF-8</th>\n @if (allowRevealValues) {\n <th>valore</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (e of storage()!.entries; track e.key) {\n <tr>\n <td>\n {{ e.key }}\n @if (isSensitive(e.key)) {\n <span class=\"nec-badge error\" title=\"chiave potenzialmente sensibile\">⚠</span>\n }\n </td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf16) }}</td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf8) }}</td>\n @if (allowRevealValues) {\n <td>\n @if (revealed()[e.key] !== undefined) {\n <code>{{ revealed()[e.key] }}</code>\n } @else {\n <button type=\"button\" (click)=\"reveal(e.key)\">mostra</button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"nec-note\">Nessuna chiave.</div>\n }\n } @else {\n <div class=\"nec-note\">localStorage non disponibile.</div>\n }\n </div>\n\n <!-- IndexedDB -->\n <div class=\"nec-panel\">\n <h3>IndexedDB</h3>\n @if (idb()?.available) {\n <div class=\"nec-note\">adapter: {{ idb()?.adapter }}</div>\n @if (idb()?.note) {\n <div class=\"nec-note\">{{ idb()?.note }}</div>\n }\n @if (idb()!.databases.length) {\n <table>\n <thead>\n <tr>\n <th>database</th>\n <th>object store</th>\n <th class=\"num\">record</th>\n </tr>\n </thead>\n <tbody>\n @for (db of idb()!.databases; track db.name) {\n @if (db.stores.length) {\n @for (st of db.stores; track st.name) {\n <tr>\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td>{{ st.name }}</td>\n <td class=\"num\">{{ st.count ?? '–' }}</td>\n </tr>\n }\n } @else {\n <tr>\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td class=\"nec-note\" colspan=\"2\">{{ db.note ?? 'nessun object store' }}</td>\n </tr>\n }\n }\n </tbody>\n </table>\n }\n <div class=\"nec-note\">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>\n } @else {\n <div class=\"nec-note\">IndexedDB non disponibile in questo contesto.</div>\n }\n </div>\n\n <!-- Store NgRx + lazy -->\n <div class=\"nec-panel\">\n <h3>Store NgRx</h3>\n @if (storeReport()) {\n @if (storeReport()!.slices.length) {\n <table>\n <thead>\n <tr>\n <th>slice</th>\n <th>tipo</th>\n <th class=\"num\">entità</th>\n <th class=\"num\">responses</th>\n <th>stato</th>\n </tr>\n </thead>\n <tbody>\n @for (s of storeReport()!.slices; track s.key) {\n <tr>\n <td>{{ s.key }}</td>\n <td>{{ s.kind }}</td>\n <td class=\"num\">{{ s.entityCount ?? '–' }}</td>\n <td class=\"num\">{{ s.responsesCount }}</td>\n <td>\n @if (s.isLoading) {\n <span class=\"nec-badge loading\">loading</span>\n }\n @if (s.error) {\n <span class=\"nec-badge error\" [title]=\"s.error\">error</span>\n }\n @if (!s.isLoading && !s.error) {\n <span class=\"nec-badge\">{{ s.isLoaded ? 'caricato' : 'idle' }}</span>\n }\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"nec-note\">Nessuna slice CRUD montata.</div>\n }\n\n @if (storeReport()!.lazy?.length) {\n <h3 style=\"margin-top:12px\">Sezioni lazy (da lazy-report)</h3>\n @if (storeReport()!.lazyReportGeneratedAt) {\n <div class=\"nec-note\">\n snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.\n </div>\n }\n <table>\n <thead>\n <tr>\n <th>store</th>\n <th>sezioni</th>\n <th>verdetto</th>\n <th>runtime</th>\n </tr>\n </thead>\n <tbody>\n @for (l of storeReport()!.lazy!; track l.name) {\n <tr>\n <td>{{ l.name }}</td>\n <td>{{ l.sections.join(', ') || '–' }}</td>\n <td>{{ l.verdict }}</td>\n <td>\n <span\n class=\"nec-badge\"\n [class.lazy]=\"l.runtimeStatus === 'lazy-not-loaded'\"\n >{{ l.runtimeStatus }}</span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n } @else {\n <div class=\"nec-note\">\n Nessun lazy-report caricato (genera src/assets/lazy-report.json con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).\n </div>\n }\n }\n </div>\n `,\n})\nexport class NecDashboardComponent implements OnInit, OnDestroy {\n private readonly localStorageProbe = inject(NecLocalStorageProbeService);\n private readonly indexedDbProbe = inject(NecIndexedDbProbeService);\n private readonly storeProbe = inject(NecStoreProbeService);\n\n /** Chiavi di slice da escludere dallo scan dello store. */\n @Input() blacklist: string[] = [];\n /** Se valorizzata, considera SOLO queste chiavi di slice (precede la blacklist). */\n @Input() whitelist: string[] = [];\n /** URL del report statico (`lazy-report --format=json`); `null`/'' per disattivarlo. */\n @Input() lazyReportUrl: string | null = 'assets/lazy-report.json';\n /** Nomi DB IndexedDB da ispezionare dove `databases()` non è supportato (es. Firefox). */\n @Input() idbDatabaseNames: string[] = [];\n /** Intervallo di auto-refresh in ms; 0 = solo manuale (default). */\n @Input() pollingMs = 0;\n /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */\n @Input() allowRevealValues = false;\n\n readonly busy = signal(false);\n readonly lastUpdated = signal<string | null>(null);\n readonly storage = signal<NecStorageReport | null>(null);\n readonly quota = signal<NecQuotaEstimate | null>(null);\n readonly idb = signal<NecIdbReport | null>(null);\n readonly storeReport = signal<NecStoreReport | null>(null);\n readonly revealed = signal<Record<string, string>>({});\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n ngOnInit(): void {\n void this.refresh();\n if (this.pollingMs > 0) {\n this.timer = setInterval(() => void this.refresh(), this.pollingMs);\n }\n }\n\n ngOnDestroy(): void {\n if (this.timer != null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async refresh(): Promise<void> {\n if (this.busy()) {\n return;\n }\n this.busy.set(true);\n this.revealed.set({}); // i valori rivelati non sopravvivono a un refresh\n try {\n this.storage.set(this.localStorageProbe.read('local'));\n this.quota.set(await this.localStorageProbe.estimate());\n this.idb.set(await this.indexedDbProbe.read(this.idbDatabaseNames));\n\n const opts = {blacklist: this.blacklist, whitelist: this.whitelist};\n if (this.lazyReportUrl) {\n this.storeReport.set(await this.storeProbe.readWithLazyReport(this.lazyReportUrl, opts));\n } else {\n this.storeReport.set(this.storeProbe.read(opts));\n }\n this.lastUpdated.set(new Date().toLocaleTimeString());\n } finally {\n this.busy.set(false);\n }\n }\n\n /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */\n reveal(key: string): void {\n const value = this.localStorageProbe.readValue(key) ?? '';\n this.revealed.update((m) => ({...m, [key]: maskValue(key, value)}));\n }\n\n isSensitive(key: string): boolean {\n return looksSensitiveKey(key);\n }\n\n formatBytes(n: number | undefined | null): string {\n if (n == null) {\n return '–';\n }\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n }\n}\n","/**\n * Secondary entry-point `ngrx-entity-crud/devtools`.\n *\n * Dashboard di gestione progetto: riepiloghi runtime di localStorage, IndexedDB (agnostico)\n * e store NgRx + sezioni promovibili al lazy loading. Tree-shakable: chi non lo importa non\n * lo paga nel bundle. Vedi `ngrx-entity-crud-dashboard-plan.md`.\n */\n\nexport * from './models';\nexport * from './idb-adapter.token';\nexport * from './agnostic-selectors';\nexport * from './mask';\nexport * from './probes/nec-local-storage-probe.service';\nexport * from './probes/nec-indexeddb-probe.service';\nexport * from './probes/nec-store-probe.service';\nexport * from './nec-dashboard.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngrx-entity-crud-devtools.mjs","sources":["../../../libs/ngrx-entity-crud/devtools/models.ts","../../../libs/ngrx-entity-crud/devtools/idb-adapter.token.ts","../../../libs/ngrx-entity-crud/devtools/agnostic-selectors.ts","../../../libs/ngrx-entity-crud/devtools/mask.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-local-storage-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-indexeddb-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts","../../../libs/ngrx-entity-crud/devtools/public-api.ts","../../../libs/ngrx-entity-crud/devtools/ngrx-entity-crud-devtools.ts"],"sourcesContent":["/**\n * Modelli dei report prodotti dai probe della dashboard (`ngrx-entity-crud/devtools`).\n *\n * Sono volutamente indipendenti dai tipi del main entry-point: i probe leggono lo stato\n * per CONVENZIONE (vedi `EntityCrudBaseState` in `src/lib/models.ts`), non per tipo, così\n * il sotto-modulo `devtools` resta autonomo e agnostico rispetto alla persistenza usata.\n */\n\n// ---------------------------------------------------------------------------\n// localStorage / sessionStorage\n// ---------------------------------------------------------------------------\n\nexport interface NecStorageEntry {\n key: string;\n /** Byte verso la quota (UTF-16): `(key.length + value.length) * 2`. Metrica primaria. */\n bytesUtf16: number;\n /** Byte della serializzazione UTF-8 (`TextEncoder`/`Blob`). Metrica secondaria. */\n bytesUtf8: number;\n}\n\nexport interface NecStorageReport {\n available: boolean;\n type: 'local' | 'session';\n entries: NecStorageEntry[];\n count: number;\n totalBytesUtf16: number;\n totalBytesUtf8: number;\n}\n\n/** Stima quota AGGREGATA per-origine (localStorage + IndexedDB + Cache), non scorporabile. */\nexport interface NecQuotaEstimate {\n available: boolean;\n usage?: number;\n quota?: number;\n /** Non-standard (solo Chromium): byte per area. Assente su Firefox/Safari. */\n usageDetails?: Record<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// IndexedDB (agnostico)\n// ---------------------------------------------------------------------------\n\nexport interface NecIdbStoreReport {\n name: string;\n /** Numero record (`objectStore.count()`); `null` se non determinabile. */\n count: number | null;\n}\n\nexport interface NecIdbDbReport {\n name: string;\n version: number | null;\n stores: NecIdbStoreReport[];\n note?: string;\n}\n\nexport interface NecIdbReport {\n available: boolean;\n /** `false` se non è stato possibile elencare i database (es. Firefox senza nomi forniti). */\n enumerable: boolean;\n /** Nome dell'adapter usato: `'native'`, il nome di un `NecIdbAdapter`, o `null`. */\n adapter: string | null;\n databases: NecIdbDbReport[];\n note?: string;\n}\n\n/**\n * Punto di estensione agnostico: il consumer può fornire un adapter esplicito (via\n * `NEC_IDB_ADAPTER`) per conteggi accurati quando la sua libreria di persistenza nasconde\n * i nomi DB. Quando assente, il probe usa solo le API native.\n */\nexport interface NecIdbAdapter {\n name: string;\n isAvailable(): boolean;\n listDatabases(): Promise<NecIdbDbReport[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Store NgRx + lazy\n// ---------------------------------------------------------------------------\n\nexport type NecSliceKind = 'plural' | 'singular' | 'unknown';\n\nexport interface NecStoreSlice {\n key: string;\n kind: NecSliceKind;\n isLoading: boolean;\n isLoaded: boolean;\n error: string | null;\n /** Numero entità (solo slice `plural`). */\n entityCount?: number;\n responsesCount: number;\n}\n\nexport type NecRuntimeStatus = 'loaded' | 'lazy-not-loaded' | 'unknown';\n\nexport interface NecLazyEntry {\n name: string;\n clazz?: string;\n type?: string;\n verdict?: string;\n isLazyCandidate: boolean;\n lazyRoute?: boolean;\n sections: string[];\n usedByShell: boolean;\n runtimeStatus: NecRuntimeStatus;\n}\n\nexport interface NecStoreReport {\n slices: NecStoreSlice[];\n loadingNames: string[];\n errors: string[];\n /** Presente solo se è stato fornito un `lazyReportUrl` e il fetch è riuscito. */\n lazy?: NecLazyEntry[];\n /** Timestamp ISO di generazione del `lazy-report.json` (per segnalare snapshot stantii). */\n lazyReportGeneratedAt?: string;\n}\n","import {InjectionToken} from '@angular/core';\nimport {NecIdbAdapter} from './models';\n\n/**\n * Adapter IndexedDB OPZIONALE, agnostico rispetto alla libreria di persistenza.\n *\n * Fornendolo, il `NecIndexedDbProbeService` lo usa con priorità per enumerare i database\n * (utile quando la libreria del consumer nasconde i nomi DB o su browser senza\n * `indexedDB.databases()`, es. Firefox). Quando NON fornito, il probe usa solo le API native.\n */\nexport const NEC_IDB_ADAPTER = new InjectionToken<NecIdbAdapter>('NEC_IDB_ADAPTER');\n","import {createSelector, MemoizedSelector} from '@ngrx/store';\n\n/**\n * Versione FACTORY (parametrizzabile) dei selettori agnostici di loading/error che il\n * template `ng-add` installa in `root-store/selectors.ts`.\n *\n * Il template resta invariato (retro-compatibilità): qui la logica è IDENTICA ma con\n * `rootSelector`/`blacklist`/`whitelist` resi parametri invece che costanti hardcoded, così\n * è riutilizzabile dal pacchetto npm (entry-point `ngrx-entity-crud/devtools`).\n *\n * Scandisce lo stato sfruttando la convenzione `EntityCrudBaseState`: ogni slice CRUD espone\n * `isLoading: boolean` ed `error: string | null` al livello top.\n */\nexport interface AgnosticLoadingSelectorsOptions {\n /** Selettore della radice da scandire (default: l'intero stato root). */\n rootSelector?: (state: any) => Record<string, any>;\n /** Chiavi di slice da escludere dallo scan. */\n blacklist?: ReadonlyArray<string>;\n /** Se valorizzata, considera SOLO queste chiavi (precede la blacklist). */\n whitelist?: ReadonlyArray<string>;\n}\n\nexport interface AgnosticLoadingSelectors {\n /** Nomi delle slice attualmente in caricamento (`isLoading === true`). */\n selectLoadingNames: MemoizedSelector<any, string[]>;\n /** `true` se almeno una slice CRUD è in caricamento. */\n selectIsLoading: MemoizedSelector<any, boolean>;\n /** Elenco degli errori non vuoti presenti nelle slice CRUD. */\n selectErrors: MemoizedSelector<any, string[]>;\n /** Concatenazione degli errori non vuoti (stringa vuota se non ce ne sono). */\n selectError: MemoizedSelector<any, string>;\n}\n\ninterface LoadingSlice {\n isLoading?: boolean;\n error?: string | null;\n}\n\nexport function createAgnosticLoadingSelectors(\n options: AgnosticLoadingSelectorsOptions = {}\n): AgnosticLoadingSelectors {\n const rootSelector = options.rootSelector ?? ((state: any): Record<string, any> => state);\n const blacklist = options.blacklist ?? [];\n const whitelist = options.whitelist ?? [];\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const isLoadingSlice = (value: any): value is LoadingSlice =>\n !!value && typeof value === 'object' && typeof value.isLoading === 'boolean';\n\n const crudEntries = (state: Record<string, any>): Array<[string, LoadingSlice]> =>\n Object.entries(state || {})\n .filter(([key]) => isEligible(key))\n .filter((entry): entry is [string, LoadingSlice] => isLoadingSlice(entry[1]));\n\n const selectLoadingNames = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .filter(([, slice]) => slice.isLoading === true)\n .map(([key]) => key)\n );\n\n const selectIsLoading = createSelector(\n selectLoadingNames,\n (names): boolean => names.length > 0\n );\n\n const selectErrors = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .map(([, slice]) => slice.error)\n .filter((error): error is string => typeof error === 'string' && error.length > 0)\n );\n\n const selectError = createSelector(selectErrors, (errors): string => errors.join('\\n'));\n\n return {selectLoadingNames, selectIsLoading, selectErrors, selectError};\n}\n","/**\n * Utility di privacy per la dashboard: poiché può girare anche in PRODUZIONE, i valori non\n * vengono mai mostrati di default e — quando il consumer abilita esplicitamente il reveal —\n * vengono comunque mascherati i pattern sensibili (token/JWT/email/segreti).\n */\n\nconst SENSITIVE_KEY =\n /(token|secret|password|passwd|pwd|auth(orization)?|credential|api[-_]?key|jwt|session|cookie|bearer)/i;\n\n/** `true` se il nome chiave suggerisce un contenuto sensibile (token, password, ecc.). */\nexport function looksSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY.test(key || '');\n}\n\n/** Redige nel testo i pattern sensibili comuni (JWT, email, token/hex lunghi). */\nexport function redactSensitive(value: string): string {\n return (value || '')\n .replace(/eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '«jwt-redatto»')\n .replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g, '«email-redatta»')\n .replace(/\\b[A-Fa-f0-9]{32,}\\b/g, '«hex-redatto»')\n .replace(/\\b[A-Za-z0-9_-]{40,}\\b/g, '«token-redatto»');\n}\n\n/**\n * Valore \"sicuro da mostrare\": se la chiave è sensibile, nasconde tutto (mostra solo la\n * lunghezza); altrimenti redige i pattern sensibili e tronca a `maxLength`.\n */\nexport function maskValue(key: string, value: string, maxLength = 200): string {\n if (looksSensitiveKey(key)) {\n return `«nascosto» (${(value || '').length} caratteri)`;\n }\n let out = redactSensitive(value);\n if (out.length > maxLength) {\n out = out.slice(0, maxLength) + '… (troncato)';\n }\n return out;\n}\n","import {Injectable} from '@angular/core';\nimport {NecQuotaEstimate, NecStorageEntry, NecStorageReport} from '../models';\n\n/**\n * Riepilogo di `localStorage` / `sessionStorage`.\n *\n * Sincrono per la lettura delle chiavi. NON espone i valori: solo chiavi e dimensioni\n * (privacy). La metrica primaria verso la quota è UTF-16 `(key.length + value.length) * 2`,\n * perché è ciò che conta verso il limite ~5-10MB; la metrica UTF-8 è secondaria.\n */\n@Injectable({providedIn: 'root'})\nexport class NecLocalStorageProbeService {\n read(type: 'local' | 'session' = 'local'): NecStorageReport {\n const empty: NecStorageReport = {\n available: false,\n type,\n entries: [],\n count: 0,\n totalBytesUtf16: 0,\n totalBytesUtf8: 0,\n };\n\n if (typeof window === 'undefined') {\n return empty;\n }\n\n let storage: Storage | null = null;\n try {\n storage = type === 'local' ? window.localStorage : window.sessionStorage;\n } catch {\n // accesso negato (sandbox/incognito/policy)\n return empty;\n }\n if (!storage) {\n return empty;\n }\n\n const entries: NecStorageEntry[] = [];\n let totalBytesUtf16 = 0;\n let totalBytesUtf8 = 0;\n\n try {\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (key == null) {\n continue;\n }\n const value = storage.getItem(key) ?? '';\n const bytesUtf16 = (key.length + value.length) * 2;\n const bytesUtf8 = this.utf8Bytes(key + value);\n totalBytesUtf16 += bytesUtf16;\n totalBytesUtf8 += bytesUtf8;\n entries.push({key, bytesUtf16, bytesUtf8});\n }\n } catch {\n // accesso parziale negato: ritorna ciò che è stato raccolto finora\n }\n\n entries.sort((a, b) => b.bytesUtf16 - a.bytesUtf16);\n\n return {\n available: true,\n type,\n entries,\n count: entries.length,\n totalBytesUtf16,\n totalBytesUtf8,\n };\n }\n\n /**\n * Legge ON-DEMAND il valore grezzo di una singola chiave (per il reveal esplicito in UI).\n * Non viene mai incluso nel report: la dashboard lo richiede solo su azione dell'utente e lo\n * maschera tramite `maskValue`.\n */\n readValue(key: string, type: 'local' | 'session' = 'local'): string | null {\n if (typeof window === 'undefined') {\n return null;\n }\n try {\n const storage = type === 'local' ? window.localStorage : window.sessionStorage;\n return storage ? storage.getItem(key) : null;\n } catch {\n return null;\n }\n }\n\n /**\n * Stima quota AGGREGATA per-origine (include anche IndexedDB e Cache): NON è scorporabile\n * per area. Può essere assente (Safari/contesto non sicuro) o arrotondata (anti-fingerprint).\n */\n async estimate(): Promise<NecQuotaEstimate> {\n const empty: NecQuotaEstimate = {available: false};\n if (\n typeof navigator === 'undefined' ||\n !navigator.storage ||\n typeof navigator.storage.estimate !== 'function'\n ) {\n return empty;\n }\n try {\n const est = await navigator.storage.estimate();\n return {\n available: true,\n usage: est.usage,\n quota: est.quota,\n usageDetails: (est as {usageDetails?: Record<string, number>}).usageDetails,\n };\n } catch {\n return empty;\n }\n }\n\n private utf8Bytes(s: string): number {\n try {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(s).length;\n }\n } catch {\n /* noop */\n }\n try {\n if (typeof Blob !== 'undefined') {\n return new Blob([s]).size;\n }\n } catch {\n /* noop */\n }\n return s.length;\n }\n}\n","import {Inject, Injectable, Optional} from '@angular/core';\nimport {NecIdbAdapter, NecIdbDbReport, NecIdbReport, NecIdbStoreReport} from '../models';\nimport {NEC_IDB_ADAPTER} from '../idb-adapter.token';\n\n/**\n * Riepilogo IndexedDB AGNOSTICO rispetto alla libreria di persistenza.\n *\n * Priorità reale: (1) `NEC_IDB_ADAPTER` esplicito, (2) API native\n * (`indexedDB.databases()` + `open()` + `count()`). NESSUN import di librerie di\n * persistenza. Mostra il numero di record per object store; i byte per-store NON sono\n * misurabili e non vengono promessi (solo la quota aggregata, altrove).\n */\n@Injectable({providedIn: 'root'})\nexport class NecIndexedDbProbeService {\n constructor(@Optional() @Inject(NEC_IDB_ADAPTER) private readonly adapter: NecIdbAdapter | null) {}\n\n /**\n * @param fallbackDatabaseNames nomi DB da ispezionare quando `indexedDB.databases()` non\n * è supportato (Firefox / Safari vecchi). Passa qui i nomi noti della tua persistenza.\n * @param openTimeoutMs timeout per ogni `open()` (default 3000ms).\n */\n async read(fallbackDatabaseNames: string[] = [], openTimeoutMs = 3000): Promise<NecIdbReport> {\n // 1) adapter esplicito: path prioritario e agnostico, indipendente dalle API native\n // (il consumer può fornire conteggi anche dove l'introspezione nativa non basta).\n if (this.adapter && this.adapter.isAvailable()) {\n try {\n const databases = await this.adapter.listDatabases();\n return {available: true, enumerable: true, adapter: this.adapter.name, databases};\n } catch {\n // degrada al path nativo\n }\n }\n\n // 2) path nativo: richiede l'API IndexedDB del browser\n if (typeof indexedDB === 'undefined') {\n return {\n available: false,\n enumerable: false,\n adapter: null,\n databases: [],\n note: 'IndexedDB non disponibile in questo contesto',\n };\n }\n\n const names = await this.listDatabaseNames(fallbackDatabaseNames);\n if (!names.length) {\n return {\n available: true,\n enumerable: false,\n adapter: 'native',\n databases: [],\n note:\n 'Impossibile elencare i database: indexedDB.databases() non supportato (es. Firefox) ' +\n 'e nessun nome fornito. Passa i nomi DB noti via input \"idbDatabaseNames\".',\n };\n }\n\n const databases: NecIdbDbReport[] = [];\n for (const name of names) {\n databases.push(await this.inspectDatabase(name, openTimeoutMs));\n }\n return {available: true, enumerable: true, adapter: 'native', databases};\n }\n\n private async listDatabaseNames(fallback: string[]): Promise<string[]> {\n const idbAny = indexedDB as unknown as {\n databases?: () => Promise<Array<{name?: string}>>;\n };\n if (typeof idbAny.databases === 'function') {\n try {\n const list = await idbAny.databases();\n const names = list.map((d) => d.name).filter((n): n is string => !!n);\n if (names.length) {\n return names;\n }\n } catch {\n // ignora: usa il fallback\n }\n }\n return Array.from(new Set(fallback.filter(Boolean)));\n }\n\n private inspectDatabase(name: string, timeoutMs: number): Promise<NecIdbDbReport> {\n return new Promise<NecIdbDbReport>((resolve) => {\n let settled = false;\n const done = (report: NecIdbDbReport): void => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(report);\n };\n\n const timer = setTimeout(\n () => done({name, version: null, stores: [], note: 'timeout apertura DB'}),\n timeoutMs\n );\n\n let request: IDBOpenDBRequest;\n try {\n request = indexedDB.open(name);\n } catch {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'open() fallita'});\n return;\n }\n\n request.onblocked = () => {\n clearTimeout(timer);\n done({\n name,\n version: null,\n stores: [],\n note: 'apertura bloccata (versionchange in un\\'altra scheda)',\n });\n };\n\n request.onerror = () => {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'errore apertura DB (o DB inesistente)'});\n };\n\n request.onupgradeneeded = (event) => {\n // Il DB non esisteva: NON crearne lo schema. Annulla la transazione di upgrade\n // (provoca onerror e rollback della creazione) per non sporcare l'origine.\n try {\n (event.target as IDBOpenDBRequest).transaction?.abort();\n } catch {\n /* noop */\n }\n };\n\n request.onsuccess = () => {\n const db = request.result;\n const version = db.version;\n const storeNames = Array.from(db.objectStoreNames);\n\n if (!storeNames.length) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores: []});\n return;\n }\n\n let tx: IDBTransaction;\n try {\n tx = db.transaction(storeNames, 'readonly');\n } catch {\n clearTimeout(timer);\n db.close();\n done({\n name,\n version,\n stores: storeNames.map((s): NecIdbStoreReport => ({name: s, count: null})),\n });\n return;\n }\n\n const stores: NecIdbStoreReport[] = storeNames.map((s) => ({name: s, count: null}));\n let pending = storeNames.length;\n const finalize = (): void => {\n if (--pending === 0) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores});\n }\n };\n\n storeNames.forEach((s, idx) => {\n try {\n const countReq = tx.objectStore(s).count();\n countReq.onsuccess = () => {\n stores[idx].count = countReq.result;\n finalize();\n };\n countReq.onerror = () => finalize();\n } catch {\n finalize();\n }\n });\n };\n });\n }\n}\n","import {inject, Injectable} from '@angular/core';\nimport {Store} from '@ngrx/store';\nimport {take} from 'rxjs/operators';\nimport {NecLazyEntry, NecSliceKind, NecStoreReport, NecStoreSlice} from '../models';\n\ninterface ProbeOptions {\n blacklist?: string[];\n whitelist?: string[];\n}\n\n/**\n * Riepilogo degli store NgRx a runtime.\n *\n * Enumera le slice CRUD montate per CONVENZIONE (`typeof value.isLoading === 'boolean'`,\n * vedi `EntityCrudBaseState`), senza dipendere dai selettori per-dominio. Una slice lazy non\n * ancora caricata semplicemente non ha la chiave nello stato root.\n */\n@Injectable({providedIn: 'root'})\nexport class NecStoreProbeService {\n private readonly store = inject(Store);\n\n /** Lettura sincrona dello stato root (NgRx emette il valore corrente all'iscrizione). */\n read(opts: ProbeOptions = {}): NecStoreReport {\n const blacklist = opts.blacklist ?? [];\n const whitelist = opts.whitelist ?? [];\n\n let root: Record<string, any> = {};\n this.store\n .select((s) => s as Record<string, any>)\n .pipe(take(1))\n .subscribe((s) => (root = s ?? {}));\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const slices: NecStoreSlice[] = [];\n const loadingNames: string[] = [];\n const errors: string[] = [];\n\n for (const [key, value] of Object.entries(root)) {\n if (!isEligible(key)) {\n continue;\n }\n if (!value || typeof value !== 'object' || typeof value.isLoading !== 'boolean') {\n continue;\n }\n const v = value as Record<string, any>;\n const kind: NecSliceKind = Array.isArray(v['ids'])\n ? 'plural'\n : 'item' in v\n ? 'singular'\n : 'unknown';\n const error =\n typeof v['error'] === 'string' && v['error'].length > 0 ? (v['error'] as string) : null;\n\n const slice: NecStoreSlice = {\n key,\n kind,\n isLoading: v['isLoading'] === true,\n isLoaded: v['isLoaded'] === true,\n error,\n entityCount:\n kind === 'plural'\n ? Array.isArray(v['ids'])\n ? v['ids'].length\n : Object.keys(v['entities'] ?? {}).length\n : undefined,\n responsesCount: Array.isArray(v['responses']) ? v['responses'].length : 0,\n };\n slices.push(slice);\n if (slice.isLoading) {\n loadingNames.push(key);\n }\n if (slice.error) {\n errors.push(`${key}: ${slice.error}`);\n }\n }\n\n slices.sort((a, b) => a.key.localeCompare(b.key));\n return {slices, loadingNames, errors};\n }\n\n /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */\n async readWithLazyReport(url: string, opts: ProbeOptions = {}): Promise<NecStoreReport> {\n const report = this.read(opts);\n const fetched = await this.fetchLazyReport(url, report);\n if (!fetched) {\n return report;\n }\n return {...report, lazy: fetched.entries, lazyReportGeneratedAt: fetched.generatedAt};\n }\n\n private async fetchLazyReport(\n url: string,\n report: NecStoreReport\n ): Promise<{entries: NecLazyEntry[]; generatedAt?: string} | undefined> {\n if (typeof fetch !== 'function') {\n return undefined;\n }\n let json: any;\n try {\n const res = await fetch(url, {headers: {Accept: 'application/json'}});\n if (!res.ok) {\n return undefined;\n }\n json = await res.json();\n } catch {\n return undefined;\n }\n\n const stores: any[] = Array.isArray(json?.stores) ? json.stores : [];\n const mounted = new Set(report.slices.map((s) => s.key));\n const generatedAt = typeof json?.generatedAt === 'string' ? json.generatedAt : undefined;\n\n const entries = stores.map((st): NecLazyEntry => {\n const sliceKey = this.toSliceKey(st?.name);\n const isLoaded = mounted.has(sliceKey) || mounted.has(st?.name);\n const isLazyCandidate =\n typeof st?.isLazyCandidate === 'boolean'\n ? st.isLazyCandidate\n : /candidato lazy/i.test(st?.verdict ?? '');\n return {\n name: st?.name,\n clazz: st?.clazz,\n type: st?.type,\n verdict: st?.verdict,\n isLazyCandidate,\n lazyRoute: typeof st?.lazyRoute === 'boolean' ? st.lazyRoute : undefined,\n sections: Array.isArray(st?.sections) ? st.sections : [],\n usedByShell: !!st?.usedByShell,\n runtimeStatus: isLoaded ? 'loaded' : isLazyCandidate ? 'lazy-not-loaded' : 'unknown',\n };\n });\n\n return {entries, generatedAt};\n }\n\n /**\n * Best-effort: il root state usa `strings.underscore(name)` come chiave di slice, mentre il\n * report usa il nome dasherizzato. (Fase 1: far emettere a `lazy-report` la feature key reale.)\n */\n private toSliceKey(name: string): string {\n return (name ?? '').replace(/-/g, '_');\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n inject,\n Input,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport {CommonModule} from '@angular/common';\nimport {NecIdbReport, NecQuotaEstimate, NecStorageReport, NecStoreReport} from './models';\nimport {NecLocalStorageProbeService} from './probes/nec-local-storage-probe.service';\nimport {NecIndexedDbProbeService} from './probes/nec-indexeddb-probe.service';\nimport {NecStoreProbeService} from './probes/nec-store-probe.service';\nimport {looksSensitiveKey, maskValue} from './mask';\n\n/**\n * `<nec-dashboard>` — dashboard di gestione progetto plug-and-play.\n *\n * Standalone, OnPush, template HTML inline (nessun PrimeNG → importabile ovunque). Tre\n * pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy\n * mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;\n * polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.\n *\n * Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)\n * anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular\n * >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).\n */\n@Component({\n selector: 'nec-dashboard',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [\n `\n :host {\n display: block;\n font-family: system-ui, sans-serif;\n font-size: 13px;\n color: #1f2933;\n }\n .nec-toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .nec-panel {\n border: 1px solid #d7dce2;\n border-radius: 6px;\n padding: 12px 16px;\n margin-bottom: 16px;\n }\n .nec-panel h3 {\n margin: 0 0 8px;\n font-size: 14px;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid #eceff3;\n }\n th {\n font-weight: 600;\n color: #52606d;\n }\n td.num,\n th.num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n .nec-note {\n color: #7b8794;\n font-style: italic;\n }\n .nec-badge {\n display: inline-block;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 11px;\n background: #e4e7eb;\n }\n .nec-badge.loading {\n background: #fde68a;\n }\n .nec-badge.error {\n background: #fca5a5;\n }\n .nec-badge.lazy {\n background: #bfdbfe;\n }\n button {\n cursor: pointer;\n }\n `,\n ],\n template: `\n <div class=\"nec-toolbar\">\n <button type=\"button\" (click)=\"refresh()\" [disabled]=\"busy()\">\n {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}\n </button>\n <span class=\"nec-note\" *ngIf=\"lastUpdated()\">ultimo aggiornamento: {{ lastUpdated() }}</span>\n </div>\n\n <!-- Quota aggregata origine -->\n <div class=\"nec-panel\">\n <h3>Quota origine (aggregata)</h3>\n <ng-container *ngIf=\"quota()?.available; else noQuota\">\n <div>\n uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /\n quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>\n </div>\n <div class=\"nec-note\">\n Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.\n </div>\n </ng-container>\n <ng-template #noQuota>\n <div class=\"nec-note\">Stima quota non disponibile (Safari o contesto non sicuro).</div>\n </ng-template>\n </div>\n\n <!-- localStorage -->\n <div class=\"nec-panel\">\n <h3>localStorage</h3>\n <ng-container *ngIf=\"storage()?.available; else noLocalStorage\">\n <div>\n {{ storage()?.count }} chiavi · totale\n <strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /\n {{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)\n </div>\n <ng-container *ngIf=\"storage()!.entries.length; else noLocalStorageEntries\">\n <table>\n <thead>\n <tr>\n <th>chiave</th>\n <th class=\"num\">UTF-16</th>\n <th class=\"num\">UTF-8</th>\n <th *ngIf=\"allowRevealValues\">valore</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let e of storage()!.entries; trackBy: trackByKey\">\n <td>\n {{ e.key }}\n <span\n class=\"nec-badge error\"\n title=\"chiave potenzialmente sensibile\"\n *ngIf=\"isSensitive(e.key)\"\n >⚠</span>\n </td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf16) }}</td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf8) }}</td>\n <td *ngIf=\"allowRevealValues\">\n <ng-container *ngIf=\"revealed()[e.key] !== undefined; else revealBtn\">\n <code>{{ revealed()[e.key] }}</code>\n </ng-container>\n <ng-template #revealBtn>\n <button type=\"button\" (click)=\"reveal(e.key)\">mostra</button>\n </ng-template>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLocalStorageEntries>\n <div class=\"nec-note\">Nessuna chiave.</div>\n </ng-template>\n </ng-container>\n <ng-template #noLocalStorage>\n <div class=\"nec-note\">localStorage non disponibile.</div>\n </ng-template>\n </div>\n\n <!-- IndexedDB -->\n <div class=\"nec-panel\">\n <h3>IndexedDB</h3>\n <ng-container *ngIf=\"idb()?.available; else noIdb\">\n <div class=\"nec-note\">adapter: {{ idb()?.adapter }}</div>\n <div class=\"nec-note\" *ngIf=\"idb()?.note\">{{ idb()?.note }}</div>\n <table *ngIf=\"idb()!.databases.length\">\n <thead>\n <tr>\n <th>database</th>\n <th>object store</th>\n <th class=\"num\">record</th>\n </tr>\n </thead>\n <tbody>\n <ng-container *ngFor=\"let db of idb()!.databases; trackBy: trackByName\">\n <ng-container *ngIf=\"db.stores.length; else noStores\">\n <tr *ngFor=\"let st of db.stores; trackBy: trackByName\">\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td>{{ st.name }}</td>\n <td class=\"num\">{{ st.count ?? '–' }}</td>\n </tr>\n </ng-container>\n <ng-template #noStores>\n <tr>\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td class=\"nec-note\" colspan=\"2\">{{ db.note ?? 'nessun object store' }}</td>\n </tr>\n </ng-template>\n </ng-container>\n </tbody>\n </table>\n <div class=\"nec-note\">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>\n </ng-container>\n <ng-template #noIdb>\n <div class=\"nec-note\">IndexedDB non disponibile in questo contesto.</div>\n </ng-template>\n </div>\n\n <!-- Store NgRx + lazy -->\n <div class=\"nec-panel\">\n <h3>Store NgRx</h3>\n <ng-container *ngIf=\"storeReport()\">\n <ng-container *ngIf=\"storeReport()!.slices.length; else noSlices\">\n <table>\n <thead>\n <tr>\n <th>slice</th>\n <th>tipo</th>\n <th class=\"num\">entità</th>\n <th class=\"num\">responses</th>\n <th>stato</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of storeReport()!.slices; trackBy: trackByKey\">\n <td>{{ s.key }}</td>\n <td>{{ s.kind }}</td>\n <td class=\"num\">{{ s.entityCount ?? '–' }}</td>\n <td class=\"num\">{{ s.responsesCount }}</td>\n <td>\n <span class=\"nec-badge loading\" *ngIf=\"s.isLoading\">loading</span>\n <span class=\"nec-badge error\" [title]=\"s.error\" *ngIf=\"s.error\">error</span>\n <span class=\"nec-badge\" *ngIf=\"!s.isLoading && !s.error\">{{\n s.isLoaded ? 'caricato' : 'idle'\n }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noSlices>\n <div class=\"nec-note\">Nessuna slice CRUD montata.</div>\n </ng-template>\n\n <ng-container *ngIf=\"storeReport()!.lazy?.length; else noLazy\">\n <h3 style=\"margin-top:12px\">Sezioni lazy (da lazy-report)</h3>\n <div class=\"nec-note\" *ngIf=\"storeReport()!.lazyReportGeneratedAt\">\n snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.\n </div>\n <table>\n <thead>\n <tr>\n <th>store</th>\n <th>sezioni</th>\n <th>verdetto</th>\n <th>runtime</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let l of storeReport()!.lazy!; trackBy: trackByName\">\n <td>{{ l.name }}</td>\n <td>{{ l.sections.join(', ') || '–' }}</td>\n <td>{{ l.verdict }}</td>\n <td>\n <span\n class=\"nec-badge\"\n [class.lazy]=\"l.runtimeStatus === 'lazy-not-loaded'\"\n >{{ l.runtimeStatus }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLazy>\n <div class=\"nec-note\">\n Nessun lazy-report caricato (genera src/assets/lazy-report.json con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).\n </div>\n </ng-template>\n </ng-container>\n </div>\n `,\n})\nexport class NecDashboardComponent implements OnInit, OnDestroy {\n private readonly localStorageProbe = inject(NecLocalStorageProbeService);\n private readonly indexedDbProbe = inject(NecIndexedDbProbeService);\n private readonly storeProbe = inject(NecStoreProbeService);\n\n /** Chiavi di slice da escludere dallo scan dello store. */\n @Input() blacklist: string[] = [];\n /** Se valorizzata, considera SOLO queste chiavi di slice (precede la blacklist). */\n @Input() whitelist: string[] = [];\n /** URL del report statico (`lazy-report --format=json`); `null`/'' per disattivarlo. */\n @Input() lazyReportUrl: string | null = 'assets/lazy-report.json';\n /** Nomi DB IndexedDB da ispezionare dove `databases()` non è supportato (es. Firefox). */\n @Input() idbDatabaseNames: string[] = [];\n /** Intervallo di auto-refresh in ms; 0 = solo manuale (default). */\n @Input() pollingMs = 0;\n /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */\n @Input() allowRevealValues = false;\n\n readonly busy = signal(false);\n readonly lastUpdated = signal<string | null>(null);\n readonly storage = signal<NecStorageReport | null>(null);\n readonly quota = signal<NecQuotaEstimate | null>(null);\n readonly idb = signal<NecIdbReport | null>(null);\n readonly storeReport = signal<NecStoreReport | null>(null);\n readonly revealed = signal<Record<string, string>>({});\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n ngOnInit(): void {\n void this.refresh();\n if (this.pollingMs > 0) {\n this.timer = setInterval(() => void this.refresh(), this.pollingMs);\n }\n }\n\n ngOnDestroy(): void {\n if (this.timer != null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async refresh(): Promise<void> {\n if (this.busy()) {\n return;\n }\n this.busy.set(true);\n this.revealed.set({}); // i valori rivelati non sopravvivono a un refresh\n try {\n this.storage.set(this.localStorageProbe.read('local'));\n this.quota.set(await this.localStorageProbe.estimate());\n this.idb.set(await this.indexedDbProbe.read(this.idbDatabaseNames));\n\n const opts = {blacklist: this.blacklist, whitelist: this.whitelist};\n if (this.lazyReportUrl) {\n this.storeReport.set(await this.storeProbe.readWithLazyReport(this.lazyReportUrl, opts));\n } else {\n this.storeReport.set(this.storeProbe.read(opts));\n }\n this.lastUpdated.set(new Date().toLocaleTimeString());\n } finally {\n this.busy.set(false);\n }\n }\n\n /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */\n reveal(key: string): void {\n const value = this.localStorageProbe.readValue(key) ?? '';\n this.revealed.update((m) => ({...m, [key]: maskValue(key, value)}));\n }\n\n isSensitive(key: string): boolean {\n return looksSensitiveKey(key);\n }\n\n /** trackBy per le righe identificate da `key` (entry localStorage, slice store). */\n trackByKey(_: number, item: {key: string}): string {\n return item.key;\n }\n\n /** trackBy per le righe identificate da `name` (DB/object store IndexedDB, voci lazy). */\n trackByName(_: number, item: {name: string}): string {\n return item.name;\n }\n\n formatBytes(n: number | undefined | null): string {\n if (n == null) {\n return '–';\n }\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n }\n}\n","/**\n * Secondary entry-point `ngrx-entity-crud/devtools`.\n *\n * Dashboard di gestione progetto: riepiloghi runtime di localStorage, IndexedDB (agnostico)\n * e store NgRx + sezioni promovibili al lazy loading. Tree-shakable: chi non lo importa non\n * lo paga nel bundle. Vedi `ngrx-entity-crud-dashboard-plan.md`.\n */\n\nexport * from './models';\nexport * from './idb-adapter.token';\nexport * from './agnostic-selectors';\nexport * from './mask';\nexport * from './probes/nec-local-storage-probe.service';\nexport * from './probes/nec-indexeddb-probe.service';\nexport * from './probes/nec-store-probe.service';\nexport * from './nec-dashboard.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|