@sdcorejs/angular 20.1.2 → 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.
Files changed (177) hide show
  1. package/README.md +127 -807
  2. package/components/audit-diff/index.d.ts +74 -0
  3. package/components/badge/index.d.ts +1 -1
  4. package/components/breadcrumb/index.d.ts +53 -0
  5. package/components/data-state/index.d.ts +44 -0
  6. package/components/document-builder/index.d.ts +5 -5
  7. package/components/form-generic/index.d.ts +89 -103
  8. package/components/import-excel/index.d.ts +4 -14
  9. package/components/index.d.ts +4 -0
  10. package/components/job-progress/index.d.ts +38 -0
  11. package/components/mini-editor/index.d.ts +9 -9
  12. package/components/modal/index.d.ts +7 -1
  13. package/components/preview/index.d.ts +181 -28
  14. package/components/side-drawer/index.d.ts +7 -1
  15. package/components/tab/index.d.ts +9 -2
  16. package/components/table/index.d.ts +8 -7
  17. package/components/tree/index.d.ts +24 -2
  18. package/components/upload-file/index.d.ts +5 -4
  19. package/directives/index.d.ts +10 -8
  20. package/fesm2022/sdcorejs-angular-components-anchor.mjs +14 -14
  21. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  22. package/fesm2022/sdcorejs-angular-components-audit-diff.mjs +332 -0
  23. package/fesm2022/sdcorejs-angular-components-audit-diff.mjs.map +1 -0
  24. package/fesm2022/sdcorejs-angular-components-badge.mjs +1 -0
  25. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs +121 -0
  27. package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs.map +1 -0
  28. package/fesm2022/sdcorejs-angular-components-data-state.mjs +68 -0
  29. package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -0
  30. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +18 -23
  31. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-editor.mjs +6 -4
  33. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +633 -886
  35. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +26 -41
  37. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-job-progress.mjs +97 -0
  39. package/fesm2022/sdcorejs-angular-components-job-progress.mjs.map +1 -0
  40. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +10 -20
  41. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-modal.mjs +61 -4
  43. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-preview.mjs +1438 -218
  45. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +9 -17
  47. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +1 -1
  49. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +39 -2
  51. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +76 -52
  53. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components-tab.mjs +48 -4
  55. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-components-table.mjs +123 -89
  57. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-components-tree.mjs +188 -18
  59. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +17 -23
  61. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-components.mjs +4 -0
  63. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  64. package/fesm2022/sdcorejs-angular-directives.mjs +29 -41
  65. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +9 -8
  67. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +20 -83
  69. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +8 -4
  71. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-chip.mjs +8 -4
  73. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +18 -14
  75. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-date.mjs +48 -70
  77. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +62 -528
  79. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +384 -0
  81. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -0
  82. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +5 -3
  83. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  84. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +16 -11
  85. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  86. package/fesm2022/sdcorejs-angular-forms-input.mjs +297 -59
  87. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-forms-models.mjs +155 -2
  89. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  90. package/fesm2022/sdcorejs-angular-forms-radio.mjs +44 -78
  91. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  92. package/fesm2022/sdcorejs-angular-forms-select.mjs +8 -21
  93. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  94. package/fesm2022/sdcorejs-angular-forms-switch.mjs +19 -76
  95. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  96. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +8 -6
  97. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  98. package/fesm2022/sdcorejs-angular-forms-time-range.mjs +280 -0
  99. package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -0
  100. package/fesm2022/sdcorejs-angular-forms-time.mjs +310 -0
  101. package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -0
  102. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +210 -0
  103. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -0
  104. package/fesm2022/sdcorejs-angular-forms.mjs +73 -4
  105. package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
  106. package/fesm2022/sdcorejs-angular-i18n.mjs +355 -10
  107. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  108. package/fesm2022/sdcorejs-angular-interceptors.mjs +12 -17
  109. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  110. package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
  111. package/fesm2022/sdcorejs-angular-modules-layout.mjs +861 -80
  112. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  113. package/fesm2022/sdcorejs-angular-modules.mjs +0 -1
  114. package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -1
  115. package/fesm2022/sdcorejs-angular-pipes.mjs +5 -7
  116. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  117. package/fesm2022/sdcorejs-angular-services-api.mjs +407 -137
  118. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  119. package/fesm2022/sdcorejs-angular-services-cache.mjs +515 -105
  120. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  121. package/fesm2022/sdcorejs-angular-services-confirm.mjs +5 -7
  122. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  123. package/fesm2022/sdcorejs-angular-services-docx.mjs +7 -10
  124. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
  125. package/fesm2022/sdcorejs-angular-services-loading.mjs +340 -66
  126. package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
  127. package/fesm2022/sdcorejs-angular-services-notify.mjs +7 -10
  128. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  129. package/fesm2022/sdcorejs-angular-services-persistence.mjs +899 -0
  130. package/fesm2022/sdcorejs-angular-services-persistence.mjs.map +1 -0
  131. package/fesm2022/sdcorejs-angular-services-storage.mjs +324 -122
  132. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  133. package/fesm2022/sdcorejs-angular-services-task.mjs +389 -0
  134. package/fesm2022/sdcorejs-angular-services-task.mjs.map +1 -0
  135. package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs +255 -0
  136. package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs.map +1 -0
  137. package/fesm2022/sdcorejs-angular-services-viewport.mjs +76 -0
  138. package/fesm2022/sdcorejs-angular-services-viewport.mjs.map +1 -0
  139. package/fesm2022/sdcorejs-angular-services.mjs +4 -0
  140. package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
  141. package/forms/autocomplete/index.d.ts +3 -4
  142. package/forms/checkbox/index.d.ts +4 -8
  143. package/forms/date/index.d.ts +3 -3
  144. package/forms/date-range/index.d.ts +6 -7
  145. package/forms/datetime/index.d.ts +3 -3
  146. package/forms/entity-picker/index.d.ts +128 -0
  147. package/forms/index.d.ts +15 -5
  148. package/forms/input/index.d.ts +76 -11
  149. package/forms/input-color/index.d.ts +3 -1
  150. package/forms/input-number/index.d.ts +4 -2
  151. package/forms/models/index.d.ts +86 -3
  152. package/forms/radio/index.d.ts +12 -8
  153. package/forms/switch/index.d.ts +4 -7
  154. package/forms/time/index.d.ts +117 -0
  155. package/forms/time-range/index.d.ts +98 -0
  156. package/forms/tree-select/index.d.ts +76 -0
  157. package/i18n/index.d.ts +68 -2
  158. package/interceptors/index.d.ts +5 -6
  159. package/modules/icon/index.d.ts +2 -3
  160. package/modules/index.d.ts +0 -1
  161. package/modules/layout/index.d.ts +288 -15
  162. package/package.json +50 -5
  163. package/pipes/index.d.ts +2 -2
  164. package/services/api/index.d.ts +68 -24
  165. package/services/cache/index.d.ts +52 -16
  166. package/services/confirm/index.d.ts +3 -2
  167. package/services/docx/index.d.ts +2 -3
  168. package/services/index.d.ts +4 -0
  169. package/services/loading/index.d.ts +16 -8
  170. package/services/persistence/index.d.ts +159 -0
  171. package/services/storage/index.d.ts +26 -8
  172. package/services/task/index.d.ts +104 -0
  173. package/services/unsaved-changes/index.d.ts +83 -0
  174. package/services/viewport/index.d.ts +42 -0
  175. package/fesm2022/sdcorejs-angular-modules-authom.mjs +0 -360
  176. package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +0 -1
  177. package/modules/authom/index.d.ts +0 -70
@@ -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
- // Dùng Map để quản bộ nhớ tốt hơn Record
11
- #memoryCache = new Map();
12
- #subjects = new Map();
13
- configuration = inject(SD_STORAGE_CONFIG, { optional: true });
14
- create(key, option) {
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
- // 1. Xử Key
18
- let hashKey;
19
- if (typeof key === 'string') {
20
- hashKey = key;
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
- // 2. Init Subject: Đọc dữ liệu từ Storage ngay lập tức để Subject có giá trị đúng
32
- if (!this.#subjects.has(hashKey)) {
33
- const existingData = this.#internalGet(hashKey, option);
34
- // Fix Type: as T | undefined
35
- this.#subjects.set(hashKey, new BehaviorSubject(existingData ?? option?.default));
36
- }
37
- const subject = this.#subjects.get(hashKey);
38
- // 3. Define Helpers
39
- const get = () => {
40
- const val = this.#internalGet(hashKey, option);
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
- const set = (data) => {
44
- this.#internalSet(hashKey, data, option);
45
- subject.next(data);
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 setSilent = (data) => {
48
- this.#internalSet(hashKey, data, option);
49
- // Cố tình KHÔNG gọi subject.next — consumer dùng kênh riêng để thông báo
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
- return this.#internalGet(hashKey, option) !== undefined;
104
+ assertActive();
105
+ return this.#ensureEntry(state, normalized) !== undefined;
53
106
  };
54
107
  const remove = () => {
55
- this.#internalRemove(hashKey, option);
56
- subject.next(undefined);
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
- subject.complete();
61
- this.#subjects.delete(hashKey);
62
- this.#memoryCache.delete(hashKey);
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
- get,
66
- set,
67
- setSilent,
68
- has,
69
- remove,
70
- // @ts-expect-error: Bổ sung vào interface nếu cần
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
- // --- PRIVATE CORE LOGIC ---
77
- /**
78
- * Helper xác định loại Storage đang dùng
79
- */
80
- #getStorage(option) {
81
- return option?.type === 'session' ? sessionStorage : localStorage;
82
- }
83
- /**
84
- * Đọc dữ liệu: Memory -> Storage -> Parse
85
- */
86
- #internalGet(key, option) {
87
- // 1. Check Memory (Nhanh nhất)
88
- let entry = this.#memoryCache.get(key);
89
- // 2. Check Storage (Nếu memory chưa có hoặc mới F5)
90
- if (!entry) {
91
- const storage = this.#getStorage(option);
92
- const raw = storage.getItem(key);
93
- if (raw) {
94
- try {
95
- const parsed = JSON.parse(raw);
96
- // Convert string date back to Date object nếu cần
97
- entry = {
98
- data: parsed.data,
99
- createdOn: new Date(parsed.createdOn),
100
- };
101
- // Sync ngược vào RAM
102
- this.#memoryCache.set(key, entry);
103
- }
104
- catch (e) {
105
- console.warn('Storage parse error', e);
106
- this.#internalRemove(key, option); // Dữ liệu lỗi -> Xóa
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 (!entry)
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
- return this.#deepClone(entry.data);
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
- storage.setItem(key, JSON.stringify(entry));
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 (e) {
131
- console.error('Storage quota exceeded', e);
271
+ catch {
272
+ return undefined;
132
273
  }
133
274
  }
134
- /**
135
- * Xóa dữ liệu
136
- */
137
- #internalRemove(key, option) {
138
- this.#memoryCache.delete(key);
139
- const storage = this.#getStorage(option);
140
- storage.removeItem(key);
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
- * Deep Clone an toàn
144
- */
145
- #deepClone(val) {
146
- if (val === undefined || val === null)
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
- providedIn: 'root',
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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"}