@sdcorejs/angular 20.1.3 → 20.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -14
- package/components/audit-diff/index.d.ts +74 -0
- package/components/badge/index.d.ts +1 -1
- package/components/breadcrumb/index.d.ts +53 -0
- package/components/data-state/index.d.ts +44 -0
- package/components/document-builder/index.d.ts +5 -5
- package/components/form-generic/index.d.ts +67 -104
- package/components/import-excel/index.d.ts +4 -14
- package/components/index.d.ts +4 -0
- package/components/job-progress/index.d.ts +38 -0
- package/components/mini-editor/index.d.ts +9 -9
- package/components/modal/index.d.ts +7 -1
- package/components/preview/index.d.ts +181 -28
- package/components/side-drawer/index.d.ts +7 -1
- package/components/tab/index.d.ts +9 -2
- package/components/table/index.d.ts +8 -7
- package/components/tree/index.d.ts +24 -2
- package/components/upload-file/index.d.ts +5 -4
- package/directives/index.d.ts +10 -8
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +14 -14
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-audit-diff.mjs +332 -0
- package/fesm2022/sdcorejs-angular-components-audit-diff.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs +1 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs +121 -0
- package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-data-state.mjs +68 -0
- package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +18 -23
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +6 -4
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +495 -838
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +24 -34
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-job-progress.mjs +97 -0
- package/fesm2022/sdcorejs-angular-components-job-progress.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +10 -20
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +61 -4
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +1438 -218
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +39 -2
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +16 -22
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab.mjs +48 -4
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +96 -63
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +186 -17
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +15 -22
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components.mjs +4 -0
- package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +29 -41
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +7 -7
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +20 -83
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +6 -3
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +6 -3
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +16 -13
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +42 -65
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +51 -66
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +384 -0
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +7 -5
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +290 -56
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-models.mjs +155 -2
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +44 -78
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +6 -20
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +19 -76
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +6 -5
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs +280 -0
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-time.mjs +310 -0
- package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +210 -0
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms.mjs +73 -4
- package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-i18n.mjs +355 -10
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-interceptors.mjs +12 -17
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +861 -80
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-pipes.mjs +5 -7
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +407 -137
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +515 -105
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +5 -7
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +7 -10
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-loading.mjs +339 -74
- package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-notify.mjs +7 -10
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-persistence.mjs +899 -0
- package/fesm2022/sdcorejs-angular-services-persistence.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-storage.mjs +324 -122
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-task.mjs +389 -0
- package/fesm2022/sdcorejs-angular-services-task.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs +255 -0
- package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-viewport.mjs +76 -0
- package/fesm2022/sdcorejs-angular-services-viewport.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services.mjs +4 -0
- package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
- package/forms/autocomplete/index.d.ts +3 -4
- package/forms/checkbox/index.d.ts +4 -8
- package/forms/date/index.d.ts +2 -2
- package/forms/date-range/index.d.ts +6 -7
- package/forms/datetime/index.d.ts +2 -2
- package/forms/entity-picker/index.d.ts +128 -0
- package/forms/index.d.ts +15 -5
- package/forms/input/index.d.ts +74 -11
- package/forms/input-number/index.d.ts +1 -1
- package/forms/models/index.d.ts +86 -3
- package/forms/radio/index.d.ts +12 -8
- package/forms/switch/index.d.ts +4 -7
- package/forms/time/index.d.ts +117 -0
- package/forms/time-range/index.d.ts +98 -0
- package/forms/tree-select/index.d.ts +76 -0
- package/i18n/index.d.ts +68 -2
- package/interceptors/index.d.ts +5 -6
- package/modules/layout/index.d.ts +288 -15
- package/package.json +49 -1
- package/pipes/index.d.ts +2 -2
- package/services/api/index.d.ts +68 -24
- package/services/cache/index.d.ts +52 -16
- package/services/confirm/index.d.ts +3 -2
- package/services/docx/index.d.ts +2 -3
- package/services/index.d.ts +4 -0
- package/services/loading/index.d.ts +16 -8
- package/services/persistence/index.d.ts +159 -0
- package/services/storage/index.d.ts +26 -8
- package/services/task/index.d.ts +104 -0
- package/services/unsaved-changes/index.d.ts +83 -0
- package/services/viewport/index.d.ts +42 -0
|
@@ -1,161 +1,363 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, DestroyRef, Injectable } from '@angular/core';
|
|
3
|
+
import { SD_PERSISTENCE_STORAGE_ADAPTER, SdGraphSerializer, SdGraphIdentityCanonicalizer, canonicalizeSdPersistenceValue, buildSdPersistenceKey, digestSdPersistenceKey, readSdPersistenceStorageItem, parseSdPersistenceEnvelope, stringifySdPersistenceValueEnvelope, stringifySdPersistenceTombstoneEnvelope } from '@sdcorejs/angular/services/persistence';
|
|
3
4
|
import { Utilities } from '@sdcorejs/utils/fns';
|
|
4
5
|
import { BehaviorSubject } from 'rxjs';
|
|
5
|
-
import { map } from 'rxjs/operators';
|
|
6
6
|
|
|
7
7
|
const SD_STORAGE_CONFIG = new InjectionToken('storage.configuration');
|
|
8
8
|
|
|
9
9
|
class SdStorageService {
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
#configuration = inject(SD_STORAGE_CONFIG, { optional: true });
|
|
11
|
+
#adapter = inject(SD_PERSISTENCE_STORAGE_ADAPTER);
|
|
12
|
+
#destroyRef = inject(DestroyRef);
|
|
13
|
+
#defaultSerializer = new SdGraphSerializer();
|
|
14
|
+
#defaultIdentityCanonicalizer = new SdGraphIdentityCanonicalizer();
|
|
15
|
+
#states = new Map();
|
|
16
|
+
#failedOwners = new Map();
|
|
17
|
+
#maxFailedOwners = 256;
|
|
18
|
+
#destroyed = false;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.#destroyRef.onDestroy(() => {
|
|
21
|
+
this.#destroyed = true;
|
|
22
|
+
for (const state of this.#states.values()) {
|
|
23
|
+
state.disposed = true;
|
|
24
|
+
state.entry = undefined;
|
|
25
|
+
for (const handle of state.handles)
|
|
26
|
+
handle.complete();
|
|
27
|
+
state.handles.clear();
|
|
28
|
+
}
|
|
29
|
+
this.#states.clear();
|
|
30
|
+
this.#failedOwners.clear();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
create(key, option = {}) {
|
|
34
|
+
if (this.#destroyed)
|
|
35
|
+
throw new Error('Storage service has been destroyed');
|
|
15
36
|
if (!key)
|
|
16
37
|
throw new Error('Key is required');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
else if (typeof key === 'object') {
|
|
23
|
-
hashKey = Utilities.hash(key);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
throw new Error('Invalid key type');
|
|
27
|
-
}
|
|
28
|
-
if (this.configuration?.key) {
|
|
29
|
-
hashKey = this.configuration.key(hashKey);
|
|
38
|
+
const normalized = this.#normalize(key, option);
|
|
39
|
+
const state = this.#getOrCreateState(normalized);
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(option, 'default')) {
|
|
41
|
+
return this.#createDefaultHandle(state, normalized, this.#cloneAs(normalized.serializer, option.default));
|
|
30
42
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return (val ?? option?.default);
|
|
43
|
+
return this.#createOptionalHandle(state, normalized);
|
|
44
|
+
}
|
|
45
|
+
#getOrCreateState(normalized) {
|
|
46
|
+
const existing = this.#states.get(normalized.ownerDigest);
|
|
47
|
+
if (existing)
|
|
48
|
+
return existing;
|
|
49
|
+
const state = {
|
|
50
|
+
hydrated: false,
|
|
51
|
+
handles: new Set(),
|
|
52
|
+
disposed: false,
|
|
42
53
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
this.#states.set(normalized.ownerDigest, state);
|
|
55
|
+
this.#hydrateState(state, normalized);
|
|
56
|
+
return state;
|
|
57
|
+
}
|
|
58
|
+
#createOptionalHandle(state, normalized) {
|
|
59
|
+
const read = () => this.#readOptional(state, normalized);
|
|
60
|
+
const subject = new BehaviorSubject(read());
|
|
61
|
+
const facade = {
|
|
62
|
+
emit: (present, value) => subject.next(present ? this.#cloneAs(normalized.serializer, value) : undefined),
|
|
63
|
+
complete: () => subject.complete(),
|
|
46
64
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
65
|
+
const operations = this.#attachHandle(state, normalized, facade, read);
|
|
66
|
+
return { ...operations, subject, observer: subject.asObservable() };
|
|
67
|
+
}
|
|
68
|
+
#createDefaultHandle(state, normalized, defaultSnapshot) {
|
|
69
|
+
const read = () => this.#readWithDefault(state, normalized, defaultSnapshot);
|
|
70
|
+
const subject = new BehaviorSubject(read());
|
|
71
|
+
const facade = {
|
|
72
|
+
emit: (present, value) => {
|
|
73
|
+
const next = present ? this.#cloneAs(normalized.serializer, value) : this.#cloneAs(normalized.serializer, defaultSnapshot);
|
|
74
|
+
subject.next(this.#cloneAs(normalized.serializer, next));
|
|
75
|
+
},
|
|
76
|
+
complete: () => subject.complete(),
|
|
77
|
+
};
|
|
78
|
+
const operations = this.#attachHandle(state, normalized, facade, read);
|
|
79
|
+
return { ...operations, get: read, subject, observer: subject.asObservable() };
|
|
80
|
+
}
|
|
81
|
+
#attachHandle(state, normalized, facade, read) {
|
|
82
|
+
state.handles.add(facade);
|
|
83
|
+
let active = true;
|
|
84
|
+
const assertActive = () => {
|
|
85
|
+
if (!active || state.disposed || this.#destroyed)
|
|
86
|
+
throw new Error('Storage handle has been destroyed');
|
|
87
|
+
};
|
|
88
|
+
const get = () => {
|
|
89
|
+
assertActive();
|
|
90
|
+
return read();
|
|
91
|
+
};
|
|
92
|
+
const write = (data, emit) => {
|
|
93
|
+
assertActive();
|
|
94
|
+
const entry = { data: normalized.serializer.clone(data), createdOn: new Date() };
|
|
95
|
+
state.entry = entry;
|
|
96
|
+
state.hydrated = true;
|
|
97
|
+
this.#writePersistent(normalized, entry);
|
|
98
|
+
if (emit)
|
|
99
|
+
this.#broadcast(state);
|
|
50
100
|
};
|
|
101
|
+
const set = (data) => write(data, true);
|
|
102
|
+
const setSilent = (data) => write(data, false);
|
|
51
103
|
const has = () => {
|
|
52
|
-
|
|
104
|
+
assertActive();
|
|
105
|
+
return this.#ensureEntry(state, normalized) !== undefined;
|
|
53
106
|
};
|
|
54
107
|
const remove = () => {
|
|
55
|
-
|
|
56
|
-
|
|
108
|
+
assertActive();
|
|
109
|
+
state.entry = undefined;
|
|
110
|
+
state.hydrated = true;
|
|
111
|
+
this.#writeTombstone(normalized);
|
|
112
|
+
this.#broadcast(state);
|
|
57
113
|
};
|
|
58
|
-
// Hàm dọn dẹp bộ nhớ (quan trọng)
|
|
59
114
|
const destroy = () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
115
|
+
if (!active)
|
|
116
|
+
return;
|
|
117
|
+
active = false;
|
|
118
|
+
state.handles.delete(facade);
|
|
119
|
+
facade.complete();
|
|
120
|
+
if (state.handles.size > 0)
|
|
121
|
+
return;
|
|
122
|
+
state.disposed = true;
|
|
123
|
+
state.entry = undefined;
|
|
124
|
+
this.#states.delete(normalized.ownerDigest);
|
|
63
125
|
};
|
|
126
|
+
return { get, set, setSilent, has, remove, destroy };
|
|
127
|
+
}
|
|
128
|
+
#normalize(key, option) {
|
|
129
|
+
const serializer = option.serializer ?? this.#configuration?.serializer ?? this.#defaultSerializer;
|
|
130
|
+
const identityCanonicalizer = option.identityCanonicalizer ?? this.#configuration?.identityCanonicalizer ?? this.#defaultIdentityCanonicalizer;
|
|
131
|
+
const canonicalKey = canonicalizeSdPersistenceValue(identityCanonicalizer, key, 'storage key');
|
|
132
|
+
const legacyStorageKey = this.#legacyStorageKey(key);
|
|
133
|
+
const namespace = option.namespace ?? this.#configuration?.namespace;
|
|
134
|
+
const version = option.version ?? this.#configuration?.version;
|
|
135
|
+
const area = option.type ?? 'local';
|
|
136
|
+
const serializerFormat = this.#serializerFormat(serializer);
|
|
137
|
+
const hasArgs = Object.prototype.hasOwnProperty.call(option, 'args');
|
|
138
|
+
const hasDefault = Object.prototype.hasOwnProperty.call(option, 'default');
|
|
139
|
+
const fields = [
|
|
140
|
+
{ tag: 'area', value: canonicalizeSdPersistenceValue(identityCanonicalizer, area, 'storage area') },
|
|
141
|
+
{ tag: 'namespace', value: this.#optionalIdentity(identityCanonicalizer, namespace !== undefined, namespace, 'storage namespace') },
|
|
142
|
+
{ tag: 'version', value: this.#optionalIdentity(identityCanonicalizer, version !== undefined, version, 'storage version') },
|
|
143
|
+
{ tag: 'args', value: this.#optionalIdentity(identityCanonicalizer, hasArgs, option.args, 'storage args') },
|
|
144
|
+
{ tag: 'default', value: this.#optionalIdentity(identityCanonicalizer, hasDefault, option.default, 'storage default') },
|
|
145
|
+
{ tag: 'serializer', value: serializerFormat },
|
|
146
|
+
{ tag: 'identityCanonicalizer', value: this.#identityCanonicalizerFormat(identityCanonicalizer) },
|
|
147
|
+
];
|
|
148
|
+
const identity = buildSdPersistenceKey(canonicalKey, fields);
|
|
149
|
+
const identityDigest = digestSdPersistenceKey(identity);
|
|
150
|
+
const storageKey = this.#convertKey(`sdcorejs.storage@1:${identityDigest}`);
|
|
151
|
+
const ownerDigest = digestSdPersistenceKey(buildSdPersistenceKey(storageKey, [{ tag: 'area', value: area }]));
|
|
64
152
|
return {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
destroy,
|
|
72
|
-
subject: subject,
|
|
73
|
-
observer: subject.asObservable().pipe(map(() => get())),
|
|
153
|
+
area,
|
|
154
|
+
storageKey,
|
|
155
|
+
legacyStorageKey,
|
|
156
|
+
ownerDigest,
|
|
157
|
+
identityDigest,
|
|
158
|
+
serializer,
|
|
74
159
|
};
|
|
75
160
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
161
|
+
#convertKey(baseKey) {
|
|
162
|
+
try {
|
|
163
|
+
return this.#configuration?.key?.(baseKey) ?? baseKey;
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return baseKey;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
#legacyStorageKey(key) {
|
|
170
|
+
try {
|
|
171
|
+
return this.#convertKey(typeof key === 'string' ? key : Utilities.hash(key));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
#optionalIdentity(canonicalizer, present, value, label) {
|
|
178
|
+
return present ? `1${canonicalizeSdPersistenceValue(canonicalizer, value, label)}` : '0';
|
|
179
|
+
}
|
|
180
|
+
#identityCanonicalizerFormat(canonicalizer) {
|
|
181
|
+
if (typeof canonicalizer.format !== 'string' || canonicalizer.format.length === 0) {
|
|
182
|
+
throw new Error('Persistence identity canonicalizer format must be a non-empty string');
|
|
183
|
+
}
|
|
184
|
+
return canonicalizer.format;
|
|
185
|
+
}
|
|
186
|
+
#serializerFormat(serializer) {
|
|
187
|
+
if (typeof serializer.format !== 'string' || serializer.format.length === 0) {
|
|
188
|
+
throw new Error('Persistence serializer format must be a non-empty string');
|
|
189
|
+
}
|
|
190
|
+
return serializer.format;
|
|
191
|
+
}
|
|
192
|
+
#readOptional(state, normalized) {
|
|
193
|
+
const entry = this.#ensureEntry(state, normalized);
|
|
194
|
+
return entry ? this.#cloneAs(normalized.serializer, entry.data) : undefined;
|
|
195
|
+
}
|
|
196
|
+
#readWithDefault(state, normalized, defaultSnapshot) {
|
|
197
|
+
const entry = this.#ensureEntry(state, normalized);
|
|
198
|
+
return entry ? this.#cloneAs(normalized.serializer, entry.data) : this.#cloneAs(normalized.serializer, defaultSnapshot);
|
|
199
|
+
}
|
|
200
|
+
#ensureEntry(state, normalized) {
|
|
201
|
+
if (!state.hydrated) {
|
|
202
|
+
this.#hydrateState(state, normalized);
|
|
203
|
+
}
|
|
204
|
+
return state.entry;
|
|
205
|
+
}
|
|
206
|
+
#hydrateState(state, normalized) {
|
|
207
|
+
const read = this.#readEntry(normalized);
|
|
208
|
+
state.entry = read.status === 'found' ? read.entry : undefined;
|
|
209
|
+
state.hydrated = read.status !== 'unavailable';
|
|
210
|
+
}
|
|
211
|
+
#broadcast(state) {
|
|
212
|
+
const present = state.entry !== undefined;
|
|
213
|
+
const value = state.entry?.data;
|
|
214
|
+
for (const handle of state.handles)
|
|
215
|
+
handle.emit(present, value);
|
|
216
|
+
}
|
|
217
|
+
#readEntry(normalized) {
|
|
218
|
+
if (this.#failedOwners.has(normalized.ownerDigest))
|
|
219
|
+
return { status: 'unavailable' };
|
|
220
|
+
const primary = readSdPersistenceStorageItem(this.#adapter, normalized.area, normalized.storageKey);
|
|
221
|
+
if (primary.status === 'found') {
|
|
222
|
+
let envelope;
|
|
223
|
+
try {
|
|
224
|
+
envelope = parseSdPersistenceEnvelope(primary.value, normalized.identityDigest, normalized.serializer.format);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
this.#writeTombstone(normalized);
|
|
228
|
+
return { status: 'absent' };
|
|
108
229
|
}
|
|
230
|
+
if (envelope?.kind === 'tombstone')
|
|
231
|
+
return { status: 'absent' };
|
|
232
|
+
const entry = envelope?.kind === 'value' ? this.#parseCurrentEntry(envelope.payload, normalized.serializer) : undefined;
|
|
233
|
+
if (entry)
|
|
234
|
+
return { status: 'found', entry };
|
|
235
|
+
this.#writeTombstone(normalized);
|
|
236
|
+
return { status: 'absent' };
|
|
109
237
|
}
|
|
110
|
-
if (
|
|
238
|
+
if (primary.status === 'unavailable')
|
|
239
|
+
return { status: 'unavailable' };
|
|
240
|
+
if (normalized.legacyStorageKey === undefined)
|
|
241
|
+
return { status: 'absent' };
|
|
242
|
+
const legacyRead = readSdPersistenceStorageItem(this.#adapter, normalized.area, normalized.legacyStorageKey);
|
|
243
|
+
if (legacyRead.status === 'unavailable')
|
|
244
|
+
return { status: 'unavailable' };
|
|
245
|
+
if (legacyRead.status === 'absent')
|
|
246
|
+
return { status: 'absent' };
|
|
247
|
+
const legacy = this.#parseLegacy(legacyRead.value);
|
|
248
|
+
if (!legacy) {
|
|
249
|
+
this.#writeTombstone(normalized);
|
|
250
|
+
return { status: 'absent' };
|
|
251
|
+
}
|
|
252
|
+
this.#writePersistent(normalized, legacy);
|
|
253
|
+
return { status: 'found', entry: legacy };
|
|
254
|
+
}
|
|
255
|
+
#parseCurrentEntry(payload, serializer) {
|
|
256
|
+
try {
|
|
257
|
+
return this.#validateEntry(serializer.parse(payload));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
111
260
|
return undefined;
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
* Ghi dữ liệu: Memory -> Storage
|
|
116
|
-
*/
|
|
117
|
-
#internalSet(key, data, option) {
|
|
118
|
-
const clonedData = this.#deepClone(data);
|
|
119
|
-
const entry = {
|
|
120
|
-
data: clonedData,
|
|
121
|
-
createdOn: new Date(),
|
|
122
|
-
};
|
|
123
|
-
// 1. Lưu Memory
|
|
124
|
-
this.#memoryCache.set(key, entry);
|
|
125
|
-
// 2. Lưu Storage
|
|
126
|
-
const storage = this.#getStorage(option);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
#parseLegacy(raw) {
|
|
127
264
|
try {
|
|
128
|
-
|
|
265
|
+
const parsed = JSON.parse(raw);
|
|
266
|
+
if (!this.#hasExactEntryKeys(parsed))
|
|
267
|
+
return undefined;
|
|
268
|
+
const createdOn = this.#toValidDate(parsed['createdOn']);
|
|
269
|
+
return createdOn ? { data: parsed['data'], createdOn } : undefined;
|
|
129
270
|
}
|
|
130
|
-
catch
|
|
131
|
-
|
|
271
|
+
catch {
|
|
272
|
+
return undefined;
|
|
132
273
|
}
|
|
133
274
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
275
|
+
#validateEntry(value) {
|
|
276
|
+
if (!this.#hasExactEntryKeys(value))
|
|
277
|
+
return undefined;
|
|
278
|
+
const createdOn = this.#toValidDate(value['createdOn']);
|
|
279
|
+
return createdOn ? { data: value['data'], createdOn } : undefined;
|
|
280
|
+
}
|
|
281
|
+
#toValidDate(value) {
|
|
282
|
+
const date = value instanceof Date ? value : typeof value === 'string' || typeof value === 'number' ? new Date(value) : undefined;
|
|
283
|
+
return date && Number.isFinite(date.getTime()) ? date : undefined;
|
|
284
|
+
}
|
|
285
|
+
#writePersistent(normalized, entry) {
|
|
286
|
+
try {
|
|
287
|
+
const payload = normalized.serializer.stringify(entry);
|
|
288
|
+
if (this.#adapter.setItem(normalized.area, normalized.storageKey, stringifySdPersistenceValueEnvelope(normalized.identityDigest, normalized.serializer.format, payload))) {
|
|
289
|
+
this.#clearFailedOwner(normalized.ownerDigest);
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// Fall through to canonical quarantine.
|
|
295
|
+
}
|
|
296
|
+
this.#safeRemove(normalized.area, normalized.storageKey);
|
|
297
|
+
if (this.#tryPersistTombstone(normalized)) {
|
|
298
|
+
this.#clearFailedOwner(normalized.ownerDigest);
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
this.#recordFailedOwner(normalized.ownerDigest);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
#safeRemove(area, key) {
|
|
305
|
+
try {
|
|
306
|
+
return this.#adapter.removeItem(area, key);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
#writeTombstone(normalized) {
|
|
313
|
+
if (this.#tryPersistTombstone(normalized)) {
|
|
314
|
+
this.#clearFailedOwner(normalized.ownerDigest);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
this.#safeRemove(normalized.area, normalized.storageKey);
|
|
318
|
+
this.#recordFailedOwner(normalized.ownerDigest);
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
#tryPersistTombstone(normalized) {
|
|
322
|
+
try {
|
|
323
|
+
return this.#adapter.setItem(normalized.area, normalized.storageKey, stringifySdPersistenceTombstoneEnvelope(normalized.identityDigest, normalized.serializer.format));
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
#clearFailedOwner(ownerDigest) {
|
|
330
|
+
this.#failedOwners.delete(ownerDigest);
|
|
331
|
+
}
|
|
332
|
+
#recordFailedOwner(ownerDigest) {
|
|
333
|
+
this.#failedOwners.delete(ownerDigest);
|
|
334
|
+
this.#failedOwners.set(ownerDigest, true);
|
|
335
|
+
if (this.#failedOwners.size <= this.#maxFailedOwners)
|
|
336
|
+
return;
|
|
337
|
+
const oldest = this.#failedOwners.keys().next().value;
|
|
338
|
+
if (oldest !== undefined)
|
|
339
|
+
this.#failedOwners.delete(oldest);
|
|
340
|
+
}
|
|
341
|
+
#cloneAs(serializer, value) {
|
|
342
|
+
const entry = serializer.parse(serializer.stringify({ data: value, createdOn: new Date(0) }));
|
|
343
|
+
return entry.data;
|
|
344
|
+
}
|
|
345
|
+
#isRecord(value) {
|
|
346
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
141
347
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return val;
|
|
148
|
-
return JSON.parse(JSON.stringify(val));
|
|
348
|
+
#hasExactEntryKeys(value) {
|
|
349
|
+
return (this.#isRecord(value) &&
|
|
350
|
+
Reflect.ownKeys(value).length === 2 &&
|
|
351
|
+
Object.prototype.hasOwnProperty.call(value, 'data') &&
|
|
352
|
+
Object.prototype.hasOwnProperty.call(value, 'createdOn'));
|
|
149
353
|
}
|
|
150
354
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
151
355
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdStorageService, providedIn: 'root' });
|
|
152
356
|
}
|
|
153
357
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdStorageService, decorators: [{
|
|
154
358
|
type: Injectable,
|
|
155
|
-
args: [{
|
|
156
|
-
|
|
157
|
-
}]
|
|
158
|
-
}] });
|
|
359
|
+
args: [{ providedIn: 'root' }]
|
|
360
|
+
}], ctorParameters: () => [] });
|
|
159
361
|
|
|
160
362
|
/**
|
|
161
363
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdcorejs-angular-services-storage.mjs","sources":["../../../projects/sdcorejs-angular/services/storage/src/storage.model.ts","../../../projects/sdcorejs-angular/services/storage/src/storage.service.ts","../../../projects/sdcorejs-angular/services/storage/sdcorejs-angular-services-storage.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nexport interface SdStorageOption<T = any> {\n type?: 'session';\n default?: T;\n args?: Record<string, any>;\n}\n\nexport interface SdStorage<T = any> {\n get: () => T;\n set: (data: T) => void;\n // Ghi vào storage nhưng KHÔNG emit subject. Dùng cho thay đổi UI-only\n // (vd: column width) để tránh re-trigger các subscriber gây reload data.\n setSilent: (data: T) => void;\n has: () => boolean;\n remove: () => void;\n subject: BehaviorSubject<T>;\n observer: Observable<T>;\n}\n\nexport interface ISdStorageConfiguration {\n key?: (key: string) => string;\n}\n\nexport const SD_STORAGE_CONFIG = new InjectionToken<ISdStorageConfiguration>('storage.configuration');\n","import { inject, Injectable } from '@angular/core';\nimport { Utilities } from '@sdcorejs/utils/fns';\nimport { BehaviorSubject } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { ISdStorageConfiguration, SD_STORAGE_CONFIG, SdStorage, SdStorageOption } from './storage.model';\n\ninterface StorageCacheEntry<T> {\n data: T;\n createdOn: Date;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SdStorageService {\n // Dùng Map để quản lý bộ nhớ tốt hơn Record\n #memoryCache = new Map<string, StorageCacheEntry<any>>();\n #subjects = new Map<string, BehaviorSubject<any>>();\n private readonly configuration: ISdStorageConfiguration | null = inject(SD_STORAGE_CONFIG, { optional: true });\n\n create<T = any>(key: string | object, option?: SdStorageOption<T>): SdStorage<T> {\n if (!key) throw new Error('Key is required');\n\n // 1. Xử lý Key\n let hashKey: string;\n if (typeof key === 'string') {\n hashKey = key;\n } else if (typeof key === 'object') {\n hashKey = Utilities.hash(key);\n } else {\n throw new Error('Invalid key type');\n }\n\n if (this.configuration?.key) {\n hashKey = this.configuration.key(hashKey);\n }\n\n // 2. Init Subject: Đọc dữ liệu từ Storage ngay lập tức để Subject có giá trị đúng\n if (!this.#subjects.has(hashKey)) {\n const existingData = this.#internalGet<T>(hashKey, option);\n // Fix Type: as T | undefined\n this.#subjects.set(hashKey, new BehaviorSubject<T | undefined>(existingData ?? option?.default));\n }\n\n const subject = this.#subjects.get(hashKey)!;\n\n // 3. Define Helpers\n const get = () => {\n const val = this.#internalGet<T>(hashKey, option);\n return (val ?? option?.default) as T;\n };\n\n const set = (data: T) => {\n this.#internalSet(hashKey, data, option);\n subject.next(data);\n };\n\n const setSilent = (data: T) => {\n this.#internalSet(hashKey, data, option);\n // Cố tình KHÔNG gọi subject.next — consumer dùng kênh riêng để thông báo\n };\n\n const has = () => {\n return this.#internalGet<T>(hashKey, option) !== undefined;\n };\n\n const remove = () => {\n this.#internalRemove(hashKey, option);\n subject.next(undefined);\n };\n\n // Hàm dọn dẹp bộ nhớ (quan trọng)\n const destroy = () => {\n subject.complete();\n this.#subjects.delete(hashKey);\n this.#memoryCache.delete(hashKey);\n };\n\n return {\n get,\n set,\n setSilent,\n has,\n remove,\n // @ts-expect-error: Bổ sung vào interface nếu cần\n destroy,\n subject: subject,\n observer: subject.asObservable().pipe(map(() => get())),\n };\n }\n\n // --- PRIVATE CORE LOGIC ---\n\n /**\n * Helper xác định loại Storage đang dùng\n */\n #getStorage(option?: SdStorageOption<any>): Storage {\n return option?.type === 'session' ? sessionStorage : localStorage;\n }\n\n /**\n * Đọc dữ liệu: Memory -> Storage -> Parse\n */\n #internalGet<T>(key: string, option?: SdStorageOption<T>): T | undefined {\n // 1. Check Memory (Nhanh nhất)\n let entry = this.#memoryCache.get(key);\n\n // 2. Check Storage (Nếu memory chưa có hoặc mới F5)\n if (!entry) {\n const storage = this.#getStorage(option);\n const raw = storage.getItem(key);\n if (raw) {\n try {\n const parsed = JSON.parse(raw);\n // Convert string date back to Date object nếu cần\n entry = {\n data: parsed.data,\n createdOn: new Date(parsed.createdOn),\n };\n // Sync ngược vào RAM\n this.#memoryCache.set(key, entry);\n } catch (e) {\n console.warn('Storage parse error', e);\n this.#internalRemove(key, option); // Dữ liệu lỗi -> Xóa\n }\n }\n }\n\n if (!entry) return undefined;\n\n return this.#deepClone(entry.data);\n }\n\n /**\n * Ghi dữ liệu: Memory -> Storage\n */\n #internalSet<T>(key: string, data: T, option?: SdStorageOption<T>): void {\n const clonedData = this.#deepClone(data);\n\n const entry: StorageCacheEntry<T> = {\n data: clonedData,\n createdOn: new Date(),\n };\n\n // 1. Lưu Memory\n this.#memoryCache.set(key, entry);\n\n // 2. Lưu Storage\n const storage = this.#getStorage(option);\n try {\n storage.setItem(key, JSON.stringify(entry));\n } catch (e) {\n console.error('Storage quota exceeded', e);\n }\n }\n\n /**\n * Xóa dữ liệu\n */\n #internalRemove(key: string, option?: SdStorageOption<any>): void {\n this.#memoryCache.delete(key);\n const storage = this.#getStorage(option);\n storage.removeItem(key);\n }\n\n /**\n * Deep Clone an toàn\n */\n #deepClone<T>(val: T): T {\n if (val === undefined || val === null) return val;\n return JSON.parse(JSON.stringify(val));\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdcorejs-angular-services-storage.mjs","sources":["../../../projects/sdcorejs-angular/services/storage/src/storage.model.ts","../../../projects/sdcorejs-angular/services/storage/src/storage.service.ts","../../../projects/sdcorejs-angular/services/storage/sdcorejs-angular-services-storage.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { SdPersistenceIdentityCanonicalizer, SdPersistenceSerializer } from '@sdcorejs/angular/services/persistence';\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nexport interface SdStorageOption<T = unknown> {\n type?: 'local' | 'session';\n default?: T;\n args?: Readonly<Record<string, unknown>>;\n namespace?: string;\n version?: string | number;\n serializer?: SdPersistenceSerializer;\n identityCanonicalizer?: SdPersistenceIdentityCanonicalizer;\n}\n\nexport interface SdStorage<T = unknown> {\n get: () => T | undefined;\n set: (data: T) => void;\n setSilent: (data: T) => void;\n has: () => boolean;\n remove: () => void;\n destroy: () => void;\n subject: BehaviorSubject<T | undefined>;\n observer: Observable<T | undefined>;\n}\n\nexport interface SdStorageWithDefault<T> extends Omit<SdStorage<T>, 'get' | 'subject' | 'observer'> {\n get: () => T;\n subject: BehaviorSubject<T>;\n observer: Observable<T>;\n}\n\nexport interface ISdStorageConfiguration {\n key?: (key: string) => string;\n namespace?: string;\n version?: string | number;\n serializer?: SdPersistenceSerializer;\n identityCanonicalizer?: SdPersistenceIdentityCanonicalizer;\n}\n\nexport const SD_STORAGE_CONFIG = new InjectionToken<ISdStorageConfiguration>('storage.configuration');\n","import { DestroyRef, inject, Injectable } from '@angular/core';\nimport {\n SD_PERSISTENCE_STORAGE_ADAPTER,\n SdGraphIdentityCanonicalizer,\n SdGraphSerializer,\n SdPersistenceIdentityCanonicalizer,\n SdPersistenceSerializer,\n SdPersistenceStorageArea,\n buildSdPersistenceKey,\n canonicalizeSdPersistenceValue,\n digestSdPersistenceKey,\n parseSdPersistenceEnvelope,\n readSdPersistenceStorageItem,\n stringifySdPersistenceTombstoneEnvelope,\n stringifySdPersistenceValueEnvelope,\n} from '@sdcorejs/angular/services/persistence';\nimport { Utilities } from '@sdcorejs/utils/fns';\nimport { BehaviorSubject } from 'rxjs';\nimport { SD_STORAGE_CONFIG, SdStorage, SdStorageOption, SdStorageWithDefault } from './storage.model';\n\ninterface StorageEntry {\n data: unknown;\n createdOn: Date;\n}\n\ntype StorageEntryRead = { status: 'found'; entry: StorageEntry } | { status: 'absent' } | { status: 'unavailable' };\n\ninterface StorageHandleFacade {\n emit: (present: boolean, value: unknown) => void;\n complete: () => void;\n}\n\ninterface StorageState {\n entry?: StorageEntry;\n hydrated: boolean;\n handles: Set<StorageHandleFacade>;\n disposed: boolean;\n}\n\ninterface NormalizedStorageOption {\n area: SdPersistenceStorageArea;\n storageKey: string;\n legacyStorageKey?: string;\n ownerDigest: string;\n identityDigest: string;\n serializer: SdPersistenceSerializer;\n}\n\ninterface StorageHandleOperations<T> {\n get: () => T | undefined;\n set: (data: T) => void;\n setSilent: (data: T) => void;\n has: () => boolean;\n remove: () => void;\n destroy: () => void;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SdStorageService {\n readonly #configuration = inject(SD_STORAGE_CONFIG, { optional: true });\n readonly #adapter = inject(SD_PERSISTENCE_STORAGE_ADAPTER);\n readonly #destroyRef = inject(DestroyRef);\n readonly #defaultSerializer = new SdGraphSerializer();\n readonly #defaultIdentityCanonicalizer = new SdGraphIdentityCanonicalizer();\n readonly #states = new Map<string, StorageState>();\n readonly #failedOwners = new Map<string, true>();\n readonly #maxFailedOwners = 256;\n #destroyed = false;\n\n constructor() {\n this.#destroyRef.onDestroy(() => {\n this.#destroyed = true;\n for (const state of this.#states.values()) {\n state.disposed = true;\n state.entry = undefined;\n for (const handle of state.handles) handle.complete();\n state.handles.clear();\n }\n this.#states.clear();\n this.#failedOwners.clear();\n });\n }\n\n create<T>(key: string | object, option: SdStorageOption<T> & { default: T }): SdStorageWithDefault<T>;\n create<T = unknown>(key: string | object, option?: SdStorageOption<unknown>): SdStorage<T>;\n create<T = unknown>(key: string | object, option: SdStorageOption<T> = {}): SdStorage<T> | SdStorageWithDefault<T> {\n if (this.#destroyed) throw new Error('Storage service has been destroyed');\n if (!key) throw new Error('Key is required');\n const normalized = this.#normalize(key, option);\n const state = this.#getOrCreateState(normalized);\n if (Object.prototype.hasOwnProperty.call(option, 'default')) {\n return this.#createDefaultHandle(state, normalized, this.#cloneAs<T>(normalized.serializer, option.default));\n }\n return this.#createOptionalHandle<T>(state, normalized);\n }\n\n #getOrCreateState(normalized: NormalizedStorageOption): StorageState {\n const existing = this.#states.get(normalized.ownerDigest);\n if (existing) return existing;\n const state: StorageState = {\n hydrated: false,\n handles: new Set<StorageHandleFacade>(),\n disposed: false,\n };\n this.#states.set(normalized.ownerDigest, state);\n this.#hydrateState(state, normalized);\n return state;\n }\n\n #createOptionalHandle<T>(state: StorageState, normalized: NormalizedStorageOption): SdStorage<T> {\n const read = (): T | undefined => this.#readOptional<T>(state, normalized);\n const subject = new BehaviorSubject<T | undefined>(read());\n const facade: StorageHandleFacade = {\n emit: (present, value) => subject.next(present ? this.#cloneAs<T>(normalized.serializer, value) : undefined),\n complete: () => subject.complete(),\n };\n const operations = this.#attachHandle(state, normalized, facade, read);\n return { ...operations, subject, observer: subject.asObservable() };\n }\n\n #createDefaultHandle<T>(state: StorageState, normalized: NormalizedStorageOption, defaultSnapshot: T): SdStorageWithDefault<T> {\n const read = (): T => this.#readWithDefault(state, normalized, defaultSnapshot);\n const subject = new BehaviorSubject<T>(read());\n const facade: StorageHandleFacade = {\n emit: (present, value) => {\n const next = present ? this.#cloneAs<T>(normalized.serializer, value) : this.#cloneAs<T>(normalized.serializer, defaultSnapshot);\n subject.next(this.#cloneAs<T>(normalized.serializer, next));\n },\n complete: () => subject.complete(),\n };\n const operations = this.#attachHandle(state, normalized, facade, read);\n return { ...operations, get: read, subject, observer: subject.asObservable() };\n }\n\n #attachHandle<T>(\n state: StorageState,\n normalized: NormalizedStorageOption,\n facade: StorageHandleFacade,\n read: () => T | undefined\n ): StorageHandleOperations<T> {\n state.handles.add(facade);\n let active = true;\n const assertActive = (): void => {\n if (!active || state.disposed || this.#destroyed) throw new Error('Storage handle has been destroyed');\n };\n const get = (): T | undefined => {\n assertActive();\n return read();\n };\n const write = (data: T, emit: boolean): void => {\n assertActive();\n const entry: StorageEntry = { data: normalized.serializer.clone(data), createdOn: new Date() };\n state.entry = entry;\n state.hydrated = true;\n this.#writePersistent(normalized, entry);\n if (emit) this.#broadcast(state);\n };\n const set = (data: T): void => write(data, true);\n const setSilent = (data: T): void => write(data, false);\n const has = (): boolean => {\n assertActive();\n return this.#ensureEntry(state, normalized) !== undefined;\n };\n const remove = (): void => {\n assertActive();\n state.entry = undefined;\n state.hydrated = true;\n this.#writeTombstone(normalized);\n this.#broadcast(state);\n };\n const destroy = (): void => {\n if (!active) return;\n active = false;\n state.handles.delete(facade);\n facade.complete();\n if (state.handles.size > 0) return;\n state.disposed = true;\n state.entry = undefined;\n this.#states.delete(normalized.ownerDigest);\n };\n return { get, set, setSilent, has, remove, destroy };\n }\n\n #normalize<T>(key: string | object, option: SdStorageOption<T>): NormalizedStorageOption {\n const serializer = option.serializer ?? this.#configuration?.serializer ?? this.#defaultSerializer;\n const identityCanonicalizer =\n option.identityCanonicalizer ?? this.#configuration?.identityCanonicalizer ?? this.#defaultIdentityCanonicalizer;\n const canonicalKey = canonicalizeSdPersistenceValue(identityCanonicalizer, key, 'storage key');\n const legacyStorageKey = this.#legacyStorageKey(key);\n const namespace = option.namespace ?? this.#configuration?.namespace;\n const version = option.version ?? this.#configuration?.version;\n const area = option.type ?? 'local';\n const serializerFormat = this.#serializerFormat(serializer);\n const hasArgs = Object.prototype.hasOwnProperty.call(option, 'args');\n const hasDefault = Object.prototype.hasOwnProperty.call(option, 'default');\n const fields = [\n { tag: 'area', value: canonicalizeSdPersistenceValue(identityCanonicalizer, area, 'storage area') },\n { tag: 'namespace', value: this.#optionalIdentity(identityCanonicalizer, namespace !== undefined, namespace, 'storage namespace') },\n { tag: 'version', value: this.#optionalIdentity(identityCanonicalizer, version !== undefined, version, 'storage version') },\n { tag: 'args', value: this.#optionalIdentity(identityCanonicalizer, hasArgs, option.args, 'storage args') },\n { tag: 'default', value: this.#optionalIdentity(identityCanonicalizer, hasDefault, option.default, 'storage default') },\n { tag: 'serializer', value: serializerFormat },\n { tag: 'identityCanonicalizer', value: this.#identityCanonicalizerFormat(identityCanonicalizer) },\n ];\n const identity = buildSdPersistenceKey(canonicalKey, fields);\n const identityDigest = digestSdPersistenceKey(identity);\n const storageKey = this.#convertKey(`sdcorejs.storage@1:${identityDigest}`);\n const ownerDigest = digestSdPersistenceKey(buildSdPersistenceKey(storageKey, [{ tag: 'area', value: area }]));\n return {\n area,\n storageKey,\n legacyStorageKey,\n ownerDigest,\n identityDigest,\n serializer,\n };\n }\n\n #convertKey(baseKey: string): string {\n try {\n return this.#configuration?.key?.(baseKey) ?? baseKey;\n } catch {\n return baseKey;\n }\n }\n\n #legacyStorageKey(key: string | object): string | undefined {\n try {\n return this.#convertKey(typeof key === 'string' ? key : Utilities.hash(key));\n } catch {\n return undefined;\n }\n }\n\n #optionalIdentity(canonicalizer: SdPersistenceIdentityCanonicalizer, present: boolean, value: unknown, label: string): string {\n return present ? `1${canonicalizeSdPersistenceValue(canonicalizer, value, label)}` : '0';\n }\n\n #identityCanonicalizerFormat(canonicalizer: SdPersistenceIdentityCanonicalizer): string {\n if (typeof canonicalizer.format !== 'string' || canonicalizer.format.length === 0) {\n throw new Error('Persistence identity canonicalizer format must be a non-empty string');\n }\n return canonicalizer.format;\n }\n\n #serializerFormat(serializer: SdPersistenceSerializer): string {\n if (typeof serializer.format !== 'string' || serializer.format.length === 0) {\n throw new Error('Persistence serializer format must be a non-empty string');\n }\n return serializer.format;\n }\n\n #readOptional<T>(state: StorageState, normalized: NormalizedStorageOption): T | undefined {\n const entry = this.#ensureEntry(state, normalized);\n return entry ? this.#cloneAs<T>(normalized.serializer, entry.data) : undefined;\n }\n\n #readWithDefault<T>(state: StorageState, normalized: NormalizedStorageOption, defaultSnapshot: T): T {\n const entry = this.#ensureEntry(state, normalized);\n return entry ? this.#cloneAs<T>(normalized.serializer, entry.data) : this.#cloneAs<T>(normalized.serializer, defaultSnapshot);\n }\n\n #ensureEntry(state: StorageState, normalized: NormalizedStorageOption): StorageEntry | undefined {\n if (!state.hydrated) {\n this.#hydrateState(state, normalized);\n }\n return state.entry;\n }\n\n #hydrateState(state: StorageState, normalized: NormalizedStorageOption): void {\n const read = this.#readEntry(normalized);\n state.entry = read.status === 'found' ? read.entry : undefined;\n state.hydrated = read.status !== 'unavailable';\n }\n\n #broadcast(state: StorageState): void {\n const present = state.entry !== undefined;\n const value = state.entry?.data;\n for (const handle of state.handles) handle.emit(present, value);\n }\n\n #readEntry(normalized: NormalizedStorageOption): StorageEntryRead {\n if (this.#failedOwners.has(normalized.ownerDigest)) return { status: 'unavailable' };\n const primary = readSdPersistenceStorageItem(this.#adapter, normalized.area, normalized.storageKey);\n if (primary.status === 'found') {\n let envelope: ReturnType<typeof parseSdPersistenceEnvelope>;\n try {\n envelope = parseSdPersistenceEnvelope(primary.value, normalized.identityDigest, normalized.serializer.format);\n } catch {\n this.#writeTombstone(normalized);\n return { status: 'absent' };\n }\n if (envelope?.kind === 'tombstone') return { status: 'absent' };\n const entry = envelope?.kind === 'value' ? this.#parseCurrentEntry(envelope.payload, normalized.serializer) : undefined;\n if (entry) return { status: 'found', entry };\n this.#writeTombstone(normalized);\n return { status: 'absent' };\n }\n if (primary.status === 'unavailable') return { status: 'unavailable' };\n if (normalized.legacyStorageKey === undefined) return { status: 'absent' };\n const legacyRead = readSdPersistenceStorageItem(this.#adapter, normalized.area, normalized.legacyStorageKey);\n if (legacyRead.status === 'unavailable') return { status: 'unavailable' };\n if (legacyRead.status === 'absent') return { status: 'absent' };\n const legacy = this.#parseLegacy(legacyRead.value);\n if (!legacy) {\n this.#writeTombstone(normalized);\n return { status: 'absent' };\n }\n this.#writePersistent(normalized, legacy);\n return { status: 'found', entry: legacy };\n }\n\n #parseCurrentEntry(payload: string, serializer: SdPersistenceSerializer): StorageEntry | undefined {\n try {\n return this.#validateEntry(serializer.parse<unknown>(payload));\n } catch {\n return undefined;\n }\n }\n\n #parseLegacy(raw: string): StorageEntry | undefined {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!this.#hasExactEntryKeys(parsed)) return undefined;\n const createdOn = this.#toValidDate(parsed['createdOn']);\n return createdOn ? { data: parsed['data'], createdOn } : undefined;\n } catch {\n return undefined;\n }\n }\n\n #validateEntry(value: unknown): StorageEntry | undefined {\n if (!this.#hasExactEntryKeys(value)) return undefined;\n const createdOn = this.#toValidDate(value['createdOn']);\n return createdOn ? { data: value['data'], createdOn } : undefined;\n }\n\n #toValidDate(value: unknown): Date | undefined {\n const date = value instanceof Date ? value : typeof value === 'string' || typeof value === 'number' ? new Date(value) : undefined;\n return date && Number.isFinite(date.getTime()) ? date : undefined;\n }\n\n #writePersistent(normalized: NormalizedStorageOption, entry: StorageEntry): boolean {\n try {\n const payload = normalized.serializer.stringify(entry);\n if (\n this.#adapter.setItem(\n normalized.area,\n normalized.storageKey,\n stringifySdPersistenceValueEnvelope(normalized.identityDigest, normalized.serializer.format, payload)\n )\n ) {\n this.#clearFailedOwner(normalized.ownerDigest);\n return true;\n }\n } catch {\n // Fall through to canonical quarantine.\n }\n this.#safeRemove(normalized.area, normalized.storageKey);\n if (this.#tryPersistTombstone(normalized)) {\n this.#clearFailedOwner(normalized.ownerDigest);\n return false;\n }\n this.#recordFailedOwner(normalized.ownerDigest);\n return false;\n }\n\n #safeRemove(area: SdPersistenceStorageArea, key: string): boolean {\n try {\n return this.#adapter.removeItem(area, key);\n } catch {\n return false;\n }\n }\n\n #writeTombstone(normalized: NormalizedStorageOption): boolean {\n if (this.#tryPersistTombstone(normalized)) {\n this.#clearFailedOwner(normalized.ownerDigest);\n return true;\n }\n this.#safeRemove(normalized.area, normalized.storageKey);\n this.#recordFailedOwner(normalized.ownerDigest);\n return false;\n }\n\n #tryPersistTombstone(normalized: NormalizedStorageOption): boolean {\n try {\n return this.#adapter.setItem(\n normalized.area,\n normalized.storageKey,\n stringifySdPersistenceTombstoneEnvelope(normalized.identityDigest, normalized.serializer.format)\n );\n } catch {\n return false;\n }\n }\n\n #clearFailedOwner(ownerDigest: string): void {\n this.#failedOwners.delete(ownerDigest);\n }\n\n #recordFailedOwner(ownerDigest: string): void {\n this.#failedOwners.delete(ownerDigest);\n this.#failedOwners.set(ownerDigest, true);\n if (this.#failedOwners.size <= this.#maxFailedOwners) return;\n const oldest = this.#failedOwners.keys().next().value;\n if (oldest !== undefined) this.#failedOwners.delete(oldest);\n }\n\n #cloneAs<T>(serializer: SdPersistenceSerializer, value: unknown): T {\n const entry = serializer.parse<{ data: T; createdOn: Date }>(serializer.stringify({ data: value, createdOn: new Date(0) }));\n return entry.data;\n }\n\n #isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n\n #hasExactEntryKeys(value: unknown): value is Record<string, unknown> {\n return (\n this.#isRecord(value) &&\n Reflect.ownKeys(value).length === 2 &&\n Object.prototype.hasOwnProperty.call(value, 'data') &&\n Object.prototype.hasOwnProperty.call(value, 'createdOn')\n );\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|