synapse-storage 3.0.5 → 3.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.cjs CHANGED
@@ -1 +1,2420 @@
1
- 'use strict';var chunkVSIVOWZF_cjs=require('./chunk-VSIVOWZF.cjs');require('./chunk-635Q6YJZ.cjs');Object.defineProperty(exports,"IndexedDBStorage",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.e}});Object.defineProperty(exports,"LocalStorage",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.f}});Object.defineProperty(exports,"MemoryStorage",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.g}});Object.defineProperty(exports,"SelectorModule",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.a}});Object.defineProperty(exports,"StorageEvents",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.c}});Object.defineProperty(exports,"StoragePluginModule",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.b}});Object.defineProperty(exports,"broadcastMiddleware",{enumerable:true,get:function(){return chunkVSIVOWZF_cjs.d}});
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/core/index.ts
21
+ var core_exports = {};
22
+ __export(core_exports, {
23
+ IndexedDBStorage: () => IndexedDBStorage,
24
+ LocalStorage: () => LocalStorage,
25
+ MemoryStorage: () => MemoryStorage,
26
+ SelectorModule: () => SelectorModule,
27
+ StorageEvents: () => StorageEvents,
28
+ StoragePluginModule: () => StoragePluginModule,
29
+ broadcastMiddleware: () => broadcastMiddleware
30
+ });
31
+ module.exports = __toCommonJS(core_exports);
32
+
33
+ // src/core/selector/selector.module.ts
34
+ var DEBUG = false;
35
+ var GLOBAL_SELECTOR_CACHE = /* @__PURE__ */ new Map();
36
+ function getStringHash(str) {
37
+ let hash = 0;
38
+ if (str.length === 0) return hash.toString(36);
39
+ for (let i = 0; i < str.length; i++) {
40
+ const char = str.charCodeAt(i);
41
+ hash = (hash << 5) - hash + char;
42
+ hash = hash & hash;
43
+ }
44
+ return Math.abs(hash).toString(36).substring(0, 6);
45
+ }
46
+ function defaultEquals(a, b) {
47
+ if (a === b) return true;
48
+ if (a == null || b == null) return false;
49
+ if (typeof a !== "object" && typeof a !== "function" && typeof b !== "object" && typeof b !== "function") {
50
+ return a === b;
51
+ }
52
+ if (typeof a !== typeof b) return false;
53
+ if (a instanceof Date && b instanceof Date) {
54
+ return a.getTime() === b.getTime();
55
+ }
56
+ if (Array.isArray(a) && Array.isArray(b)) {
57
+ if (a.length !== b.length) return false;
58
+ for (let i = 0; i < a.length; i++) {
59
+ if (!defaultEquals(a[i], b[i])) return false;
60
+ }
61
+ return true;
62
+ }
63
+ if (typeof a === "object" && typeof b === "object") {
64
+ const keysA = Object.keys(a);
65
+ const keysB = Object.keys(b);
66
+ if (keysA.length !== keysB.length) return false;
67
+ return keysA.every((key) => {
68
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
69
+ return defaultEquals(a[key], b[key]);
70
+ });
71
+ }
72
+ return false;
73
+ }
74
+ function memoizeSelector(selectorFn, equals = defaultEquals) {
75
+ let lastState;
76
+ let lastResult;
77
+ let hasResult = false;
78
+ return function memoized(state) {
79
+ if (!hasResult || lastState !== state) {
80
+ const newResult = selectorFn(state);
81
+ if (!hasResult || !equals(newResult, lastResult)) {
82
+ lastResult = newResult;
83
+ }
84
+ lastState = state;
85
+ hasResult = true;
86
+ }
87
+ return lastResult;
88
+ };
89
+ }
90
+ var SelectorSubscription = class {
91
+ constructor(name, getState, equals = defaultEquals, logger) {
92
+ this.name = name;
93
+ this.equals = equals;
94
+ this.logger = logger;
95
+ this.id = name;
96
+ this.memoizedGetState = this.createMemoizedGetState(getState);
97
+ if (DEBUG) {
98
+ console.log(`[${this.id}] \u0421\u043E\u0437\u0434\u0430\u043D new SelectorSubscription`);
99
+ }
100
+ }
101
+ id;
102
+ subscribers = /* @__PURE__ */ new Set();
103
+ lastValue;
104
+ memoizedGetState;
105
+ // Создает мемоизированную версию getState с кешированием результата
106
+ createMemoizedGetState(getState) {
107
+ let lastPromise = null;
108
+ let isExecuting = false;
109
+ return async () => {
110
+ if (isExecuting && lastPromise) {
111
+ return lastPromise;
112
+ }
113
+ isExecuting = true;
114
+ try {
115
+ lastPromise = getState();
116
+ return await lastPromise;
117
+ } finally {
118
+ isExecuting = false;
119
+ }
120
+ };
121
+ }
122
+ async notify() {
123
+ try {
124
+ const newValue = await this.memoizedGetState();
125
+ if (this.lastValue === void 0 || !this.equals(newValue, this.lastValue)) {
126
+ if (DEBUG) {
127
+ console.log(`[${this.id}] \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C, notify()`, {
128
+ old: this.lastValue,
129
+ new: newValue
130
+ });
131
+ }
132
+ this.lastValue = newValue;
133
+ const promises = Array.from(this.subscribers).map(async (subscriber) => {
134
+ try {
135
+ await subscriber.notify(newValue);
136
+ } catch (error) {
137
+ this.logger?.error(`[${this.id}] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A\u0430`, { error });
138
+ }
139
+ });
140
+ await Promise.all(promises);
141
+ } else if (DEBUG) {
142
+ console.log(`[${this.id}] \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C in notify(), \u043F\u0440\u043E\u043F\u0443\u0441\u043A \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F`);
143
+ }
144
+ } catch (error) {
145
+ this.logger?.error(`[${this.id}] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432 notify()`, { error });
146
+ throw error;
147
+ }
148
+ }
149
+ subscribe(subscriber) {
150
+ if (DEBUG) {
151
+ console.log(`[${this.id}] \u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E \u043D\u043E\u0432\u044B\u0439 \u043F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A, \u0432\u0441\u0435\u0433\u043E: ${this.subscribers.size + 1}`);
152
+ }
153
+ this.subscribers.add(subscriber);
154
+ if (this.lastValue !== void 0) {
155
+ Promise.resolve().then(() => {
156
+ try {
157
+ subscriber.notify(this.lastValue);
158
+ } catch (error) {
159
+ this.logger?.error(`[${this.id}] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u0435\u0440\u0432\u043E\u043D\u0430\u0447\u0430\u043B\u044C\u043D\u043E\u043C \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0438`, { error });
160
+ }
161
+ });
162
+ } else {
163
+ this.notify().catch((error) => {
164
+ this.logger?.error(`[${this.id}] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u0435\u0440\u0432\u043E\u043D\u0430\u0447\u0430\u043B\u044C\u043D\u043E\u043C \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0438`, { error });
165
+ });
166
+ }
167
+ return () => {
168
+ if (DEBUG) {
169
+ console.log(`[${this.id}] \u041F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A \u0443\u0434\u0430\u043B\u0435\u043D, \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C: ${this.subscribers.size - 1}`);
170
+ }
171
+ this.subscribers.delete(subscriber);
172
+ };
173
+ }
174
+ cleanup() {
175
+ if (DEBUG) {
176
+ console.log(`[${this.id}] \u041E\u0447\u0438\u0441\u0442\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0438, \u0431\u044B\u043B\u043E ${this.subscribers.size} \u043F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A\u043E\u0432`);
177
+ }
178
+ this.subscribers.clear();
179
+ this.lastValue = void 0;
180
+ }
181
+ getId() {
182
+ return this.id;
183
+ }
184
+ };
185
+ var SelectorModule = class {
186
+ constructor(source, logger) {
187
+ this.source = source;
188
+ this.logger = logger;
189
+ this.storageName = source.name;
190
+ if (DEBUG) {
191
+ console.log(`\u0421\u043E\u0437\u0434\u0430\u043D SelectorModule \u0434\u043B\u044F \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430: ${this.storageName}`);
192
+ }
193
+ this.source.getState().then((state) => {
194
+ this.cachedState = state;
195
+ if (DEBUG) {
196
+ console.log(`\u041A\u044D\u0448\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0435 \u043D\u0430\u0447\u0430\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0434\u043B\u044F ${this.storageName}`);
197
+ }
198
+ });
199
+ }
200
+ storageName;
201
+ subscriptions = /* @__PURE__ */ new Map();
202
+ cachedState;
203
+ localSelectorCache = /* @__PURE__ */ new Map();
204
+ // Флаг для батчинга обновлений
205
+ batchUpdateInProgress = false;
206
+ pendingUpdates = /* @__PURE__ */ new Set();
207
+ /**
208
+ * Генерирует имя для селектора на основе его типа и функции
209
+ */
210
+ generateName(isSimpleSelector, selectorOrDeps, resultFnOrOptions) {
211
+ const type = isSimpleSelector ? "simple" : "combined";
212
+ let hash = "";
213
+ if (isSimpleSelector) {
214
+ const selectorStr = selectorOrDeps.toString();
215
+ hash = getStringHash(selectorStr);
216
+ } else {
217
+ const depsIds = selectorOrDeps.map((s) => s.getId()).join("_");
218
+ const resultFnStr = resultFnOrOptions.toString();
219
+ hash = getStringHash(depsIds + resultFnStr);
220
+ }
221
+ return `${this.storageName}_${type}_${hash}`;
222
+ }
223
+ /**
224
+ * Обрабатывает отложенные обновления, чтобы избежать каскадных уведомлений
225
+ */
226
+ processPendingUpdates() {
227
+ if (this.pendingUpdates.size === 0 || this.batchUpdateInProgress) return;
228
+ this.batchUpdateInProgress = true;
229
+ setTimeout(async () => {
230
+ try {
231
+ const subscriptionsToUpdate = Array.from(this.pendingUpdates);
232
+ this.pendingUpdates.clear();
233
+ this.cachedState = await this.source.getState();
234
+ const updatePromises = subscriptionsToUpdate.map(async (id) => {
235
+ const subscription = this.subscriptions.get(id);
236
+ if (subscription) {
237
+ try {
238
+ return await subscription.notify();
239
+ } catch (error) {
240
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A\u0430 ${id}`, { error });
241
+ }
242
+ }
243
+ return Promise.resolve();
244
+ });
245
+ await Promise.all(updatePromises);
246
+ } catch (error) {
247
+ this.logger?.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0438 \u043E\u0436\u0438\u0434\u0430\u044E\u0449\u0438\u0445 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439", { error });
248
+ } finally {
249
+ this.batchUpdateInProgress = false;
250
+ if (this.pendingUpdates.size > 0) {
251
+ this.processPendingUpdates();
252
+ }
253
+ }
254
+ }, 0);
255
+ }
256
+ createSelector(selectorOrDeps, resultFnOrOptions, optionsArg) {
257
+ const isSimpleSelector = !Array.isArray(selectorOrDeps);
258
+ const options = isSimpleSelector ? resultFnOrOptions || {} : optionsArg || {};
259
+ const selectorId = options.name || this.generateName(isSimpleSelector, selectorOrDeps, isSimpleSelector ? void 0 : resultFnOrOptions);
260
+ if (this.localSelectorCache.has(selectorId)) {
261
+ if (DEBUG) {
262
+ console.log(`[${this.storageName}] Reusing cached selector: ${selectorId}`);
263
+ }
264
+ return this.localSelectorCache.get(selectorId).api;
265
+ }
266
+ if (GLOBAL_SELECTOR_CACHE.has(selectorId)) {
267
+ const cached = GLOBAL_SELECTOR_CACHE.get(selectorId);
268
+ cached.refCount++;
269
+ if (DEBUG) {
270
+ console.log(`[${this.storageName}] \u041F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u043A\u044D\u0448\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440\u0430: ${selectorId}, refCount: ${cached.refCount}`);
271
+ }
272
+ return cached.api;
273
+ }
274
+ let result;
275
+ let dependencies;
276
+ let unsubscribeFunctions = [];
277
+ if (isSimpleSelector) {
278
+ const memoized = memoizeSelector(selectorOrDeps, options.equals || defaultEquals);
279
+ const created = this.createSimpleSelector(memoized, { ...options, name: selectorId, equals: options.equals || defaultEquals });
280
+ result = created.api;
281
+ unsubscribeFunctions = created.unsubscribeFunctions;
282
+ } else {
283
+ dependencies = selectorOrDeps;
284
+ const created = this.createCombinedSelector(dependencies, resultFnOrOptions, {
285
+ ...options,
286
+ name: selectorId,
287
+ equals: options.equals || defaultEquals
288
+ });
289
+ result = created.api;
290
+ unsubscribeFunctions = created.unsubscribeFunctions;
291
+ }
292
+ this.localSelectorCache.set(selectorId, {
293
+ api: result,
294
+ dependencies,
295
+ unsubscribeFunctions
296
+ });
297
+ GLOBAL_SELECTOR_CACHE.set(selectorId, {
298
+ api: result,
299
+ refCount: 1,
300
+ unsubscribeFunctions
301
+ });
302
+ if (DEBUG) {
303
+ console.log(`[${this.storageName}] \u0421\u043E\u0437\u0434\u0430\u043D \u043D\u043E\u0432\u044B\u0439 \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440: ${selectorId}`);
304
+ }
305
+ return result;
306
+ }
307
+ createSimpleSelector(selector, options) {
308
+ if (DEBUG) {
309
+ console.log(`[${this.storageName}] \u0421\u043E\u0437\u0434\u0430\u043D \u043F\u0440\u043E\u0441\u0442\u043E\u0439 \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440: ${options.name}`);
310
+ }
311
+ const getState = async () => {
312
+ if (this.cachedState) {
313
+ return selector(this.cachedState);
314
+ }
315
+ const state = await this.source.getState();
316
+ this.cachedState = state;
317
+ return selector(state);
318
+ };
319
+ const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger);
320
+ const id = subscription.getId();
321
+ this.subscriptions.set(id, subscription);
322
+ const unsubscribeFromStorage = this.source.subscribeToAll(async (event) => {
323
+ if (event?.type === "storage:update") {
324
+ if (DEBUG) {
325
+ console.log(`[${id}] \u041F\u043E\u043B\u0443\u0447\u0435\u043D\u043E \u0441\u043E\u0431\u044B\u0442\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430`);
326
+ }
327
+ this.pendingUpdates.add(id);
328
+ this.processPendingUpdates();
329
+ }
330
+ });
331
+ const unsubscribeFunctions = [unsubscribeFromStorage];
332
+ return {
333
+ api: {
334
+ select: () => getState(),
335
+ subscribe: (subscriber) => {
336
+ return subscription.subscribe(subscriber);
337
+ },
338
+ getId: () => id
339
+ },
340
+ unsubscribeFunctions
341
+ };
342
+ }
343
+ createCombinedSelector(selectors, resultFn, options) {
344
+ const memoizedResultFn = memoizeSelector((args) => resultFn(...args), options.equals || defaultEquals);
345
+ const getState = async () => {
346
+ const values = await Promise.all(selectors.map((s) => s.select()));
347
+ return memoizedResultFn(values);
348
+ };
349
+ const subscription = new SelectorSubscription(options.name, getState, options.equals || defaultEquals, this.logger);
350
+ const id = subscription.getId();
351
+ this.subscriptions.set(id, subscription);
352
+ let debounceTimer = null;
353
+ const triggerUpdate = () => {
354
+ if (debounceTimer !== null) {
355
+ clearTimeout(debounceTimer);
356
+ }
357
+ debounceTimer = setTimeout(() => {
358
+ debounceTimer = null;
359
+ subscription.notify().catch((error) => this.logger?.error(`[${id}] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u0435\u043D\u043D\u043E\u043C \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0438:`, { error }));
360
+ }, 10);
361
+ };
362
+ const unsubscribeFunctions = selectors.map(
363
+ (selector) => selector.subscribe({
364
+ notify: () => {
365
+ triggerUpdate();
366
+ }
367
+ })
368
+ );
369
+ return {
370
+ api: {
371
+ select: () => getState(),
372
+ subscribe: (subscriber) => {
373
+ return subscription.subscribe(subscriber);
374
+ },
375
+ getId: () => id
376
+ },
377
+ unsubscribeFunctions
378
+ };
379
+ }
380
+ destroy() {
381
+ if (DEBUG) {
382
+ console.log(`[${this.storageName}] \u041D\u0430\u0447\u0430\u043B\u043E\u0441\u044C \u0443\u043D\u0438\u0447\u0442\u043E\u0436\u0435\u043D\u0438\u0435 SelectorModule`);
383
+ }
384
+ this.subscriptions.forEach((sub) => sub.cleanup());
385
+ this.subscriptions.clear();
386
+ this.cachedState = void 0;
387
+ this.pendingUpdates.clear();
388
+ this.localSelectorCache.forEach((cached) => {
389
+ cached.unsubscribeFunctions.forEach((unsub) => unsub());
390
+ });
391
+ const keysToCheck = /* @__PURE__ */ new Set();
392
+ this.localSelectorCache.forEach((_, key) => {
393
+ keysToCheck.add(key);
394
+ });
395
+ this.localSelectorCache.clear();
396
+ keysToCheck.forEach((key) => {
397
+ const globalCached = GLOBAL_SELECTOR_CACHE.get(key);
398
+ if (globalCached) {
399
+ globalCached.refCount--;
400
+ if (globalCached.refCount <= 0) {
401
+ globalCached.unsubscribeFunctions.forEach((unsub) => unsub());
402
+ GLOBAL_SELECTOR_CACHE.delete(key);
403
+ if (DEBUG) {
404
+ console.log(`[${this.storageName}] \u0423\u0434\u0430\u043B\u0435\u043D \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440 \u0438\u0437 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u043E\u0433\u043E \u043A\u044D\u0448\u0430: ${key}`);
405
+ }
406
+ }
407
+ }
408
+ });
409
+ if (DEBUG) {
410
+ console.log(`[${this.storageName}] \u0423\u043D\u0438\u0447\u0442\u043E\u0436\u0435\u043D`);
411
+ }
412
+ }
413
+ };
414
+
415
+ // src/core/storage/modules/plugin/plugin.service.ts
416
+ var StoragePluginModule = class {
417
+ constructor(parentExecutor, logger, storageName = "default") {
418
+ this.parentExecutor = parentExecutor;
419
+ this.logger = logger;
420
+ this.storageName = storageName;
421
+ }
422
+ plugins = /* @__PURE__ */ new Map();
423
+ createContext(metadata) {
424
+ return {
425
+ storageName: this.storageName,
426
+ timestamp: Date.now(),
427
+ metadata
428
+ };
429
+ }
430
+ async add(plugin) {
431
+ if (this.plugins.has(plugin.name)) {
432
+ this.logger?.warn(`\u041F\u043B\u0430\u0433\u0438\u043D ${plugin.name} \u0443\u0436\u0435 \u0431\u044B\u043B \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D`);
433
+ return;
434
+ }
435
+ try {
436
+ await plugin.initialize?.();
437
+ this.plugins.set(plugin.name, plugin);
438
+ this.logger?.info("\u041F\u043B\u0430\u0433\u0438\u043D \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D", { name: plugin.name });
439
+ } catch (error) {
440
+ throw error;
441
+ }
442
+ }
443
+ async remove(name) {
444
+ const plugin = this.plugins.get(name);
445
+ if (plugin) {
446
+ await plugin.destroy?.();
447
+ this.plugins.delete(name);
448
+ this.logger?.info("\u041F\u043B\u0430\u0433\u0438\u043D \u0443\u0434\u0430\u043B\u0435\u043D", { name });
449
+ }
450
+ }
451
+ get(name) {
452
+ return this.plugins.get(name);
453
+ }
454
+ getAll() {
455
+ return Array.from(this.plugins.values());
456
+ }
457
+ async initialize() {
458
+ for (const plugin of this.plugins.values()) {
459
+ await plugin.initialize?.();
460
+ }
461
+ }
462
+ async destroy() {
463
+ await Promise.all(Array.from(this.plugins.values()).map((plugin) => plugin.destroy?.() ?? Promise.resolve()));
464
+ this.plugins.clear();
465
+ }
466
+ async executeBeforeSet(value, metadata) {
467
+ let result = value;
468
+ const context = this.createContext(metadata);
469
+ if (this.parentExecutor) {
470
+ result = await this.parentExecutor.executeBeforeSet(result, context);
471
+ }
472
+ for (const plugin of this.plugins.values()) {
473
+ if (plugin.onBeforeSet) {
474
+ try {
475
+ result = await plugin.onBeforeSet(result, context);
476
+ } catch (error) {
477
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onBeforeSet`, { error });
478
+ throw error;
479
+ }
480
+ }
481
+ }
482
+ return result;
483
+ }
484
+ async executeAfterSet(key, value, metadata) {
485
+ let result = value;
486
+ const context = this.createContext(metadata);
487
+ if (this.parentExecutor) {
488
+ result = await this.parentExecutor.executeAfterSet(key, result, context);
489
+ }
490
+ for (const plugin of this.plugins.values()) {
491
+ if (plugin.onAfterSet) {
492
+ try {
493
+ result = await plugin.onAfterSet(key, result, context);
494
+ } catch (error) {
495
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onAfterSet`, { key, error });
496
+ throw error;
497
+ }
498
+ }
499
+ }
500
+ return result;
501
+ }
502
+ async executeBeforeGet(key, metadata) {
503
+ let processedKey = key;
504
+ const context = this.createContext(metadata);
505
+ if (this.parentExecutor) {
506
+ processedKey = await this.parentExecutor.executeBeforeGet(processedKey, context);
507
+ }
508
+ for (const plugin of this.plugins.values()) {
509
+ if (plugin.onBeforeGet) {
510
+ try {
511
+ processedKey = await plugin.onBeforeGet(processedKey, context);
512
+ } catch (error) {
513
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onBeforeGet`, { key, error });
514
+ throw error;
515
+ }
516
+ }
517
+ }
518
+ return processedKey;
519
+ }
520
+ async executeAfterGet(key, value, metadata) {
521
+ let result = value;
522
+ const context = this.createContext(metadata);
523
+ if (this.parentExecutor) {
524
+ result = await this.parentExecutor.executeAfterGet(key, result, context);
525
+ }
526
+ console.log("executeAfterGet", key, value, metadata);
527
+ for (const plugin of this.plugins.values()) {
528
+ if (plugin.onAfterGet) {
529
+ try {
530
+ result = await plugin.onAfterGet(key, result, context);
531
+ } catch (error) {
532
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onAfterGet`, { key, error });
533
+ throw error;
534
+ }
535
+ }
536
+ }
537
+ return result;
538
+ }
539
+ async executeBeforeDelete(key, metadata) {
540
+ let canDelete = true;
541
+ const context = this.createContext(metadata);
542
+ if (this.parentExecutor) {
543
+ canDelete = await this.parentExecutor.executeBeforeDelete(key, context);
544
+ }
545
+ for (const plugin of this.plugins.values()) {
546
+ if (plugin.onBeforeDelete) {
547
+ try {
548
+ canDelete = await plugin.onBeforeDelete(key, context) && canDelete;
549
+ } catch (error) {
550
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onBeforeDelete`, { key, error });
551
+ throw error;
552
+ }
553
+ }
554
+ }
555
+ return canDelete;
556
+ }
557
+ async executeAfterDelete(key, metadata) {
558
+ const context = this.createContext(metadata);
559
+ if (this.parentExecutor) {
560
+ await this.parentExecutor.executeAfterDelete(key, context);
561
+ }
562
+ for (const plugin of this.plugins.values()) {
563
+ if (plugin.onAfterDelete) {
564
+ try {
565
+ await plugin.onAfterDelete(key, context);
566
+ } catch (error) {
567
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onAfterDelete`, { key, error });
568
+ throw error;
569
+ }
570
+ }
571
+ }
572
+ }
573
+ async executeOnClear(metadata) {
574
+ const context = this.createContext(metadata);
575
+ if (this.parentExecutor) {
576
+ await this.parentExecutor.executeOnClear(context);
577
+ }
578
+ for (const plugin of this.plugins.values()) {
579
+ if (plugin.onClear) {
580
+ try {
581
+ await plugin.onClear(context);
582
+ } catch (error) {
583
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043B\u0430\u0433\u0438\u043D\u0435 ${plugin.name} onClear`, { error });
584
+ throw error;
585
+ }
586
+ }
587
+ }
588
+ }
589
+ };
590
+
591
+ // src/core/storage/storage.interface.ts
592
+ var StorageEvents = /* @__PURE__ */ ((StorageEvents2) => {
593
+ StorageEvents2["STORAGE_UPDATE"] = "storage:update";
594
+ StorageEvents2["STORAGE_DELETE"] = "storage:delete";
595
+ StorageEvents2["STORAGE_PATCH"] = "storage:patch";
596
+ StorageEvents2["STORAGE_SELECT"] = "storage:select";
597
+ StorageEvents2["STORAGE_CLEAR"] = "storage:clear";
598
+ StorageEvents2["STORAGE_DESTROY"] = "storage:destroy";
599
+ return StorageEvents2;
600
+ })(StorageEvents || {});
601
+
602
+ // src/core/storage/utils/broadcast.util.ts
603
+ var SyncBroadcastChannel = class {
604
+ channel;
605
+ tabId;
606
+ messageHandlers;
607
+ syncHandler;
608
+ debug;
609
+ syncTimeoutMs = 1e3;
610
+ pendingSyncRequests;
611
+ constructor(channelName, options = {}) {
612
+ this.channel = new BroadcastChannel(channelName);
613
+ this.tabId = crypto.randomUUID();
614
+ this.messageHandlers = /* @__PURE__ */ new Set();
615
+ this.debug = options.debug ?? false;
616
+ this.pendingSyncRequests = /* @__PURE__ */ new Map();
617
+ this.channel.onmessage = this.handleMessage.bind(this);
618
+ this.channel.onmessageerror = this.handleError.bind(this);
619
+ }
620
+ log(...args) {
621
+ if (this.debug) {
622
+ console.log(`[SyncBroadcastChannel][${this.tabId}]`, ...args);
623
+ }
624
+ }
625
+ error(...args) {
626
+ console.error(`[SyncBroadcastChannel][${this.tabId}]`, ...args);
627
+ }
628
+ async handleMessage(event) {
629
+ const message = event.data;
630
+ if (message.senderId === this.tabId) {
631
+ return;
632
+ }
633
+ if (message.type === "SYNC_REQUEST") {
634
+ if (this.syncHandler) {
635
+ try {
636
+ const state = await this.syncHandler();
637
+ this.postMessage("SYNC_RESPONSE", state, message.senderId);
638
+ } catch (error) {
639
+ this.error("Error handling sync request:", error);
640
+ }
641
+ }
642
+ return;
643
+ }
644
+ if (message.type === "SYNC_RESPONSE") {
645
+ const request = this.pendingSyncRequests.get(this.tabId);
646
+ if (request) {
647
+ clearTimeout(request.timeout);
648
+ this.pendingSyncRequests.delete(this.tabId);
649
+ request.resolve(message.payload);
650
+ }
651
+ return;
652
+ }
653
+ for (const handler of this.messageHandlers) {
654
+ try {
655
+ await handler(message);
656
+ } catch (error) {
657
+ this.error("Error in message handler:", error);
658
+ }
659
+ }
660
+ }
661
+ handleError(event) {
662
+ this.error("Channel error:", event);
663
+ }
664
+ postMessage(type, payload, targetId) {
665
+ const message = {
666
+ type,
667
+ payload,
668
+ senderId: this.tabId,
669
+ timestamp: Date.now()
670
+ };
671
+ this.channel.postMessage(message);
672
+ }
673
+ /**
674
+ * Подписка на сообщения канала
675
+ */
676
+ subscribe(handler) {
677
+ this.messageHandlers.add(handler);
678
+ return () => this.messageHandlers.delete(handler);
679
+ }
680
+ /**
681
+ * Установка обработчика запросов на синхронизацию
682
+ */
683
+ setSyncHandler(handler) {
684
+ this.syncHandler = handler;
685
+ }
686
+ /**
687
+ * Отправка сообщения всем подписчикам
688
+ */
689
+ broadcast(type, payload) {
690
+ this.postMessage(type, payload);
691
+ }
692
+ /**
693
+ * Запрос синхронизации данных с других вкладок
694
+ */
695
+ async requestSync() {
696
+ return new Promise((resolve, reject) => {
697
+ const timeout = setTimeout(() => {
698
+ this.pendingSyncRequests.delete(this.tabId);
699
+ resolve(null);
700
+ }, this.syncTimeoutMs);
701
+ this.pendingSyncRequests.set(this.tabId, { resolve, reject, timeout });
702
+ this.postMessage("SYNC_REQUEST", { type: "sync" });
703
+ });
704
+ }
705
+ /**
706
+ * Закрытие канала
707
+ */
708
+ close() {
709
+ for (const [, request] of this.pendingSyncRequests) {
710
+ clearTimeout(request.timeout);
711
+ request.reject(new Error("Channel closed"));
712
+ }
713
+ this.pendingSyncRequests.clear();
714
+ this.messageHandlers.clear();
715
+ this.syncHandler = void 0;
716
+ this.channel.close();
717
+ }
718
+ };
719
+
720
+ // src/core/storage/middlewares/broadcast.middleware.ts
721
+ async function handleMemoryStorageMessage(api, type, payload) {
722
+ switch (type) {
723
+ case "set":
724
+ if (payload?.key !== void 0 && payload?.value !== void 0) {
725
+ await api.storage.doSet(payload.key, payload.value);
726
+ api.storage.notifySubscribers(payload.key, payload.value);
727
+ }
728
+ break;
729
+ case "update":
730
+ if (Array.isArray(payload?.value)) {
731
+ await api.storage.doUpdate(payload.value);
732
+ payload.value.forEach(({ key, value }) => {
733
+ api.storage.notifySubscribers(key, value);
734
+ });
735
+ }
736
+ break;
737
+ case "delete":
738
+ if (payload?.key !== void 0) {
739
+ await api.storage.doDelete(payload.key);
740
+ api.storage.notifySubscribers(payload.key, void 0);
741
+ }
742
+ break;
743
+ case "clear":
744
+ await api.storage.doClear();
745
+ api.storage.notifySubscribers("*", {
746
+ type: "storage:update" /* STORAGE_UPDATE */,
747
+ value: {},
748
+ source: "broadcast"
749
+ });
750
+ break;
751
+ }
752
+ api.storage.notifySubscribers("*", {
753
+ type: "storage:update" /* STORAGE_UPDATE */,
754
+ key: payload?.key,
755
+ value: payload?.value,
756
+ source: "broadcast"
757
+ });
758
+ }
759
+ async function handlePersistentStorageMessage(api, type, payload) {
760
+ switch (type) {
761
+ case "set":
762
+ if (payload?.key !== void 0) {
763
+ const currentValue = await api.storage.doGet(payload.key);
764
+ api.storage.notifySubscribers(payload.key, currentValue);
765
+ }
766
+ break;
767
+ case "update":
768
+ if (Array.isArray(payload?.value)) {
769
+ for (const { key } of payload.value) {
770
+ const currentValue = await api.storage.doGet(key);
771
+ api.storage.notifySubscribers(key, currentValue);
772
+ }
773
+ api.storage.notifySubscribers("*", {
774
+ type: "storage:update" /* STORAGE_UPDATE */,
775
+ //@ts-ignore
776
+ key: payload.value.map(({ key }) => key),
777
+ value: payload.value,
778
+ source: "broadcast"
779
+ });
780
+ }
781
+ break;
782
+ case "delete":
783
+ if (payload?.key !== void 0) {
784
+ api.storage.notifySubscribers(payload.key, void 0);
785
+ }
786
+ break;
787
+ case "clear":
788
+ api.storage.notifySubscribers("*", {
789
+ type: "storage:update" /* STORAGE_UPDATE */,
790
+ value: {},
791
+ source: "broadcast"
792
+ });
793
+ break;
794
+ }
795
+ if (type !== "update") {
796
+ api.storage.notifySubscribers("*", {
797
+ type: "storage:update" /* STORAGE_UPDATE */,
798
+ key: payload?.key,
799
+ value: type === "delete" ? void 0 : payload?.value,
800
+ source: "broadcast"
801
+ });
802
+ }
803
+ }
804
+ var broadcastMiddleware = (props) => {
805
+ const { storageName, storageType } = props;
806
+ const channelName = `${storageType}-${storageName}`;
807
+ const channel = new SyncBroadcastChannel(channelName, { debug: true });
808
+ return {
809
+ name: "broadcast",
810
+ setup: (api) => {
811
+ if (storageType === "memory") {
812
+ channel.setSyncHandler(async () => {
813
+ const state = await api.getState();
814
+ const updates = Object.entries(state).map(([key, value]) => ({
815
+ key,
816
+ value
817
+ }));
818
+ const action = {
819
+ type: "update",
820
+ key: "*",
821
+ value: updates,
822
+ metadata: {
823
+ batchUpdate: true,
824
+ timestamp: Date.now()
825
+ }
826
+ };
827
+ return action;
828
+ });
829
+ channel.requestSync().then(async (action) => {
830
+ if (action?.type === "update" && Array.isArray(action.value)) {
831
+ try {
832
+ const validUpdates = action.value.every((update) => update && typeof update === "object" && "key" in update && "value" in update);
833
+ if (!validUpdates) {
834
+ console.error("[Sync Response] Invalid updates structure:", action.value);
835
+ return;
836
+ }
837
+ await api.storage.doUpdate(action.value);
838
+ action.value.forEach(({ key, value }) => {
839
+ api.storage.notifySubscribers(key, value);
840
+ });
841
+ api.storage.notifySubscribers("*", {
842
+ type: "storage:update" /* STORAGE_UPDATE */,
843
+ value: action.value,
844
+ source: "broadcast"
845
+ });
846
+ } catch (error) {
847
+ console.error("[Sync Response] Error applying updates:", error);
848
+ }
849
+ }
850
+ });
851
+ }
852
+ return channel.subscribe(async (message) => {
853
+ const { type, payload } = message;
854
+ if (storageType === "memory") {
855
+ await handleMemoryStorageMessage(api, type, payload);
856
+ } else {
857
+ await handlePersistentStorageMessage(api, type, payload);
858
+ }
859
+ });
860
+ },
861
+ reducer: (api) => (next) => async (action) => {
862
+ const result = await next(action);
863
+ if (["set", "delete", "clear", "update"].includes(action.type)) {
864
+ channel.broadcast(action.type, action);
865
+ }
866
+ return result;
867
+ },
868
+ cleanup: () => {
869
+ channel.close();
870
+ }
871
+ };
872
+ };
873
+
874
+ // src/core/storage/utils/storage-key.ts
875
+ var StorageKey = class {
876
+ constructor(value, isRawKey = false) {
877
+ this.value = value;
878
+ this.isRawKey = isRawKey;
879
+ }
880
+ toString() {
881
+ return this.value;
882
+ }
883
+ toJSON() {
884
+ return this.value;
885
+ }
886
+ valueOf() {
887
+ return this.value;
888
+ }
889
+ isUnparseable() {
890
+ return this.isRawKey;
891
+ }
892
+ };
893
+
894
+ // src/core/storage/middlewares/storage-batching.middleware.ts
895
+ var batchingMiddleware = (options = {}) => {
896
+ const batchSize = options.batchSize ?? 10;
897
+ const batchDelay = options.batchDelay ?? 10;
898
+ const queues = /* @__PURE__ */ new Map();
899
+ const timeouts = /* @__PURE__ */ new Map();
900
+ const shouldBatch = (action) => {
901
+ return action.type === "set" || action.type === "update";
902
+ };
903
+ const getSegmentKey = (action) => {
904
+ return `${action.type}_${action.key?.toString() || "default"}`;
905
+ };
906
+ const mergeActions = (actions) => {
907
+ const merged = /* @__PURE__ */ new Map();
908
+ for (const action of actions) {
909
+ const key = `${action.type}_${action.key?.toString() || "default"}`;
910
+ merged.set(key, action);
911
+ }
912
+ return Array.from(merged.values());
913
+ };
914
+ const clearTimeout2 = (segment) => {
915
+ const timeout = timeouts.get(segment);
916
+ if (timeout) {
917
+ globalThis.clearTimeout(timeout);
918
+ timeouts.delete(segment);
919
+ }
920
+ };
921
+ const setTimeout2 = (segment, callback) => {
922
+ const timeout = globalThis.setTimeout(callback, batchDelay);
923
+ timeouts.set(segment, timeout);
924
+ };
925
+ const processBatch = async (segment, api, next) => {
926
+ const queue = queues.get(segment);
927
+ if (!queue || queue.length === 0) return;
928
+ queues.delete(segment);
929
+ clearTimeout2(segment);
930
+ try {
931
+ const actions = queue.map((item) => item.action);
932
+ const mergedActions = mergeActions(actions);
933
+ console.log(`\u{1F504} Batching ${segment}: ${queue.length} actions -> ${mergedActions.length} merged`, {
934
+ original: actions.map((a) => ({ type: a.type, key: a.key?.toString(), value: a.value })),
935
+ merged: mergedActions.map((a) => ({ type: a.type, key: a.key?.toString(), value: a.value }))
936
+ });
937
+ for (const mergedAction of mergedActions) {
938
+ try {
939
+ const result = await next(mergedAction);
940
+ const matchingItems = queue.filter((item) => item.action.type === mergedAction.type && item.action.key?.toString() === mergedAction.key?.toString());
941
+ matchingItems.forEach((item) => item.resolve(result));
942
+ } catch (error) {
943
+ const matchingItems = queue.filter((item) => item.action.type === mergedAction.type && item.action.key?.toString() === mergedAction.key?.toString());
944
+ matchingItems.forEach((item) => item.reject(error));
945
+ }
946
+ }
947
+ } catch (error) {
948
+ queue.forEach((item) => item.reject(error));
949
+ }
950
+ };
951
+ const addToQueue = async (action, api, next) => {
952
+ return new Promise((resolve, reject) => {
953
+ const segment = getSegmentKey(action);
954
+ let queue = queues.get(segment);
955
+ if (!queue) {
956
+ queue = [];
957
+ queues.set(segment, queue);
958
+ }
959
+ queue.push({
960
+ action,
961
+ resolve,
962
+ reject,
963
+ timestamp: Date.now()
964
+ });
965
+ clearTimeout2(segment);
966
+ if (queue.length >= batchSize) {
967
+ setImmediate(() => processBatch(segment, api, next));
968
+ } else {
969
+ setTimeout2(segment, () => processBatch(segment, api, next));
970
+ }
971
+ });
972
+ };
973
+ return {
974
+ name: "batching",
975
+ setup: () => {
976
+ },
977
+ cleanup: async () => {
978
+ timeouts.forEach((timeout) => globalThis.clearTimeout(timeout));
979
+ timeouts.clear();
980
+ queues.clear();
981
+ },
982
+ reducer: (api) => (next) => async (action) => {
983
+ if (!shouldBatch(action)) {
984
+ return next(action);
985
+ }
986
+ return addToQueue(action, api, next);
987
+ }
988
+ };
989
+ };
990
+
991
+ // src/core/storage/middlewares/storage-shallow-compare.middleware.ts
992
+ var shallowCompareMiddleware = (options = {}) => {
993
+ const {
994
+ comparator = (prev, next) => {
995
+ if (prev === next) return true;
996
+ if (typeof prev !== "object" || typeof next !== "object" || prev === null || next === null) {
997
+ return prev === next;
998
+ }
999
+ const keysA = Object.keys(prev);
1000
+ const keysB = Object.keys(next);
1001
+ if (keysA.length !== keysB.length) return false;
1002
+ return keysA.every((key) => Object.prototype.hasOwnProperty.call(next, key) && prev[key] === next[key]);
1003
+ },
1004
+ segments = []
1005
+ } = options;
1006
+ const valueCache = /* @__PURE__ */ new Map();
1007
+ return {
1008
+ name: "shallow-compare",
1009
+ setup: (api) => {
1010
+ },
1011
+ reducer: (api) => (next) => async (action) => {
1012
+ if (action.type !== "set" || segments.length && !segments.includes(action.metadata?.segment ?? "default")) {
1013
+ return next(action);
1014
+ }
1015
+ const cacheKey = action.key;
1016
+ const prevValue = valueCache.get(cacheKey);
1017
+ const nextValue = action.value;
1018
+ if (prevValue !== void 0 && comparator(prevValue, nextValue)) {
1019
+ console.log("ShallowCompare: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0438\u0434\u0435\u043D\u0442\u0438\u0447\u043D\u044B, \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u043C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044E", { key: cacheKey, value: nextValue });
1020
+ return {
1021
+ ...prevValue,
1022
+ __metadata: {
1023
+ valueNotChanged: true,
1024
+ // Этот флаг будет проверяться в BaseStorage перед notifySubscribers
1025
+ originalValue: prevValue
1026
+ }
1027
+ };
1028
+ }
1029
+ const result = await next(action);
1030
+ valueCache.set(cacheKey, nextValue);
1031
+ return result;
1032
+ }
1033
+ };
1034
+ };
1035
+
1036
+ // src/core/storage/utils/middleware-module.ts
1037
+ var MiddlewareModule = class {
1038
+ middlewares = [];
1039
+ api;
1040
+ initialized = false;
1041
+ dispatchFn;
1042
+ constructor(storage) {
1043
+ this.api = {
1044
+ dispatch: async (action) => this.dispatch(action),
1045
+ getState: () => storage.getState(),
1046
+ storage: {
1047
+ doGet: storage.doGet.bind(storage),
1048
+ doSet: storage.doSet.bind(storage),
1049
+ doUpdate: storage.doUpdate.bind(storage),
1050
+ doDelete: storage.doDelete.bind(storage),
1051
+ doClear: storage.doClear.bind(storage),
1052
+ doKeys: storage.doKeys.bind(storage),
1053
+ notifySubscribers: storage.notifySubscribers.bind(storage)
1054
+ }
1055
+ };
1056
+ }
1057
+ async baseOperation(action) {
1058
+ const { processed: _, ...metadata } = action.metadata || {};
1059
+ const cleanAction = { ...action, metadata };
1060
+ switch (cleanAction.type) {
1061
+ case "get": {
1062
+ return this.api.storage.doGet(cleanAction.key);
1063
+ }
1064
+ case "set": {
1065
+ await this.api.storage.doSet(cleanAction.key, cleanAction.value);
1066
+ return this.api.storage.doGet(cleanAction.key);
1067
+ }
1068
+ case "update": {
1069
+ if (Array.isArray(cleanAction.value)) {
1070
+ await this.api.storage.doUpdate(cleanAction.value);
1071
+ return this.api.storage.doGet("");
1072
+ }
1073
+ return cleanAction.value;
1074
+ }
1075
+ case "delete": {
1076
+ return this.api.storage.doDelete(cleanAction.key);
1077
+ }
1078
+ case "clear": {
1079
+ return this.api.storage.doClear();
1080
+ }
1081
+ case "init": {
1082
+ const currentState = await this.api.storage.doGet("");
1083
+ if (Object.keys(currentState || {}).length > 0) {
1084
+ return currentState;
1085
+ }
1086
+ if (cleanAction.value) {
1087
+ await this.api.storage.doSet("", cleanAction.value);
1088
+ return this.api.storage.doGet("");
1089
+ }
1090
+ return currentState;
1091
+ }
1092
+ case "keys": {
1093
+ return this.api.storage.doKeys();
1094
+ }
1095
+ default: {
1096
+ throw new Error(`Unknown action type: ${cleanAction.type}`);
1097
+ }
1098
+ }
1099
+ }
1100
+ initializeMiddlewares() {
1101
+ if (this.initialized) return;
1102
+ let chain = this.baseOperation.bind(this);
1103
+ for (const middleware of [...this.middlewares].reverse()) {
1104
+ const nextChain = chain;
1105
+ chain = async (action) => {
1106
+ if (action.metadata?.processed) {
1107
+ return nextChain(action);
1108
+ }
1109
+ const actionWithMeta = {
1110
+ ...action,
1111
+ metadata: {
1112
+ ...action.metadata,
1113
+ processed: true,
1114
+ timestamp: action.metadata?.timestamp || Date.now()
1115
+ }
1116
+ };
1117
+ return middleware.reducer(this.api)(nextChain)(actionWithMeta);
1118
+ };
1119
+ }
1120
+ this.dispatchFn = chain;
1121
+ this.initialized = true;
1122
+ }
1123
+ use(middleware) {
1124
+ if (middleware.setup) {
1125
+ middleware.setup(this.api);
1126
+ }
1127
+ this.middlewares.push(middleware);
1128
+ this.initialized = false;
1129
+ }
1130
+ async dispatch(action) {
1131
+ if (!this.initialized) {
1132
+ this.initializeMiddlewares();
1133
+ }
1134
+ try {
1135
+ return this.dispatchFn(action);
1136
+ } catch (error) {
1137
+ console.error("Error in middleware chain:", error);
1138
+ throw error;
1139
+ }
1140
+ }
1141
+ };
1142
+
1143
+ // src/core/storage/adapters/path.utils.ts
1144
+ function parsePath(path) {
1145
+ if (path instanceof StorageKey && path.isUnparseable()) {
1146
+ return [path.toString()];
1147
+ }
1148
+ const pathStr = path.toString();
1149
+ return pathStr.replace(/\[/g, ".").replace(/\]/g, "").split(".").filter(Boolean);
1150
+ }
1151
+ function getValueByPath(obj, path) {
1152
+ const parts = parsePath(path);
1153
+ return parts.reduce((curr, key) => curr === void 0 ? void 0 : curr[key], obj);
1154
+ }
1155
+ function setValueByPath(obj, path, value) {
1156
+ if (path === "") return value;
1157
+ const parts = parsePath(path);
1158
+ if (path instanceof StorageKey && path.isUnparseable()) {
1159
+ obj[path.toString()] = value;
1160
+ return obj;
1161
+ }
1162
+ const lastKey = parts.pop();
1163
+ const target = parts.reduce((curr, key) => {
1164
+ const nextKey = parts[parts.indexOf(key) + 1];
1165
+ const shouldBeArray = !Number.isNaN(Number(nextKey));
1166
+ if (!(key in curr)) {
1167
+ curr[key] = shouldBeArray ? [] : {};
1168
+ }
1169
+ return curr[key];
1170
+ }, obj);
1171
+ target[lastKey] = value;
1172
+ return obj;
1173
+ }
1174
+
1175
+ // src/core/storage/adapters/base-storage.service.ts
1176
+ var BaseStorage = class _BaseStorage {
1177
+ constructor(config, pluginExecutor, eventEmitter, logger) {
1178
+ this.config = config;
1179
+ this.pluginExecutor = pluginExecutor;
1180
+ this.eventEmitter = eventEmitter;
1181
+ this.logger = logger;
1182
+ this.name = config.name;
1183
+ this.middlewareModule = new MiddlewareModule({
1184
+ getState: this.getState.bind(this),
1185
+ // Предоставляем базовые операции хранилища
1186
+ doGet: this.doGet.bind(this),
1187
+ doSet: this.doSet.bind(this),
1188
+ doUpdate: this.doUpdate.bind(this),
1189
+ doDelete: this.doDelete.bind(this),
1190
+ doClear: this.doClear.bind(this),
1191
+ doKeys: this.doKeys.bind(this),
1192
+ // Предоставляем методы для работы с подписчиками
1193
+ notifySubscribers: this.notifySubscribers.bind(this),
1194
+ // Предоставляем плагины и эмиттер
1195
+ pluginExecutor: this.pluginExecutor,
1196
+ eventEmitter: this.eventEmitter,
1197
+ logger: this.logger
1198
+ });
1199
+ this.initializeMiddlewares();
1200
+ }
1201
+ // Константа для глобальной подписки
1202
+ static GLOBAL_SUBSCRIPTION_KEY = "*";
1203
+ name;
1204
+ selectorPathCache = /* @__PURE__ */ new WeakMap();
1205
+ middlewareModule;
1206
+ initializedMiddlewares = null;
1207
+ subscribers = /* @__PURE__ */ new Map();
1208
+ initializeMiddlewares() {
1209
+ if (this.config.middlewares && !this.initializedMiddlewares) {
1210
+ this.initializedMiddlewares = this.config.middlewares(() => this.getDefaultMiddleware());
1211
+ this.initializedMiddlewares.forEach((middleware) => this.middlewareModule.use(middleware));
1212
+ }
1213
+ }
1214
+ getDefaultMiddleware() {
1215
+ return {
1216
+ batching: (options = {}) => batchingMiddleware(options),
1217
+ shallowCompare: (options = {}) => shallowCompareMiddleware(options)
1218
+ };
1219
+ }
1220
+ async initializeWithMiddlewares() {
1221
+ try {
1222
+ const state = await this.getState();
1223
+ const hasExistingState = Object.keys(state).length > 0;
1224
+ if (!hasExistingState && this.config.initialState) {
1225
+ await this.middlewareModule.dispatch({
1226
+ type: "init",
1227
+ value: this.config.initialState
1228
+ });
1229
+ }
1230
+ } catch (error) {
1231
+ this.logger?.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430", { error });
1232
+ throw error;
1233
+ }
1234
+ }
1235
+ async get(key) {
1236
+ try {
1237
+ const metadata = { operation: "get", timestamp: Date.now(), key };
1238
+ const middlewareResult = await this.middlewareModule.dispatch({
1239
+ type: "get",
1240
+ key,
1241
+ metadata
1242
+ });
1243
+ const finalResult = await this.pluginExecutor?.executeAfterGet(key, middlewareResult, metadata) ?? middlewareResult;
1244
+ await this.emitEvent({
1245
+ type: "storage:select" /* STORAGE_SELECT */,
1246
+ payload: { key, value: finalResult }
1247
+ });
1248
+ return finalResult;
1249
+ } catch (error) {
1250
+ this.logger?.error("Error getting value", { key, error });
1251
+ throw error;
1252
+ }
1253
+ }
1254
+ async set(key, value) {
1255
+ try {
1256
+ const metadata = { operation: "set", timestamp: Date.now(), key };
1257
+ const processedValue = await this.pluginExecutor?.executeBeforeSet(value, metadata) ?? value;
1258
+ const middlewareResult = await this.middlewareModule.dispatch({
1259
+ type: "set",
1260
+ key,
1261
+ value: processedValue,
1262
+ metadata
1263
+ });
1264
+ const valueNotChanged = middlewareResult?.__metadata?.valueNotChanged === true;
1265
+ let finalResult;
1266
+ if (valueNotChanged && middlewareResult?.__metadata?.originalValue !== void 0) {
1267
+ finalResult = middlewareResult.__metadata.originalValue;
1268
+ } else {
1269
+ finalResult = await this.pluginExecutor?.executeAfterSet(key, middlewareResult, metadata) ?? middlewareResult;
1270
+ }
1271
+ if (!valueNotChanged) {
1272
+ const keyStr = key.toString();
1273
+ const changedPaths = [keyStr];
1274
+ this.notifySubscribers(key, finalResult);
1275
+ this.notifySubscribers(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY, {
1276
+ type: "storage:update" /* STORAGE_UPDATE */,
1277
+ key,
1278
+ value: finalResult,
1279
+ changedPaths
1280
+ });
1281
+ await this.emitEvent({
1282
+ type: "storage:update" /* STORAGE_UPDATE */,
1283
+ payload: {
1284
+ key,
1285
+ value: finalResult,
1286
+ changedPaths
1287
+ }
1288
+ });
1289
+ }
1290
+ } catch (error) {
1291
+ this.logger?.error("Error setting value", { key, error });
1292
+ throw error;
1293
+ }
1294
+ }
1295
+ async update(updater) {
1296
+ try {
1297
+ const metadata = { operation: "update", timestamp: Date.now() };
1298
+ const currentState = await this.getState();
1299
+ const newState = structuredClone(currentState);
1300
+ updater(newState);
1301
+ const changedPaths = this.findChangedPaths(currentState, newState);
1302
+ if (changedPaths.size === 0) {
1303
+ if (this.logger?.debug) {
1304
+ this.logger.debug("No changes detected in update");
1305
+ }
1306
+ return;
1307
+ }
1308
+ if (this.logger?.debug) {
1309
+ this.logger.debug("Changed paths:", { paths: Array.from(changedPaths) });
1310
+ }
1311
+ const changedTopLevelKeys = /* @__PURE__ */ new Set();
1312
+ for (const path of changedPaths) {
1313
+ const topLevelKey = path.split(".")[0];
1314
+ changedTopLevelKeys.add(topLevelKey);
1315
+ }
1316
+ const updates = await Promise.all(
1317
+ Array.from(changedTopLevelKeys).map(async (key) => {
1318
+ const keyMetadata = { ...metadata, key };
1319
+ const processedValue = await this.pluginExecutor?.executeBeforeSet(newState[key], keyMetadata) ?? newState[key];
1320
+ return { key, value: processedValue };
1321
+ })
1322
+ );
1323
+ const result = await this.middlewareModule.dispatch({
1324
+ type: "update",
1325
+ value: updates,
1326
+ metadata: {
1327
+ ...metadata,
1328
+ batchUpdate: true,
1329
+ changedPaths: Array.from(changedPaths)
1330
+ }
1331
+ });
1332
+ let updatedValues = {};
1333
+ if (Array.isArray(result)) {
1334
+ result.forEach((update) => {
1335
+ if (update && typeof update === "object" && "key" in update && "value" in update) {
1336
+ updatedValues[update.key] = update.value;
1337
+ }
1338
+ });
1339
+ } else if (result && typeof result === "object") {
1340
+ updatedValues = { ...result };
1341
+ }
1342
+ const actuallyChangedKeys = Object.keys(updatedValues).filter((key) => !this.isEqual(currentState[key], updatedValues[key]));
1343
+ if (actuallyChangedKeys.length === 0) {
1344
+ if (this.logger?.debug) {
1345
+ this.logger.debug("No actual changes after middleware processing");
1346
+ }
1347
+ return;
1348
+ }
1349
+ const finalUpdates = {};
1350
+ actuallyChangedKeys.forEach((key) => {
1351
+ finalUpdates[key] = updatedValues[key];
1352
+ });
1353
+ if (this.logger?.debug) {
1354
+ this.logger.debug("Notifying subscribers about changes:", { keys: actuallyChangedKeys });
1355
+ }
1356
+ this.notifySubscribers(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY, {
1357
+ type: "storage:update" /* STORAGE_UPDATE */,
1358
+ key: actuallyChangedKeys,
1359
+ value: finalUpdates,
1360
+ changedPaths: Array.from(changedPaths)
1361
+ // Добавляем информацию о всех изменившихся путях
1362
+ });
1363
+ for (const path of changedPaths) {
1364
+ try {
1365
+ const topLevelKey = path.split(".")[0];
1366
+ if (topLevelKey in finalUpdates) {
1367
+ let value;
1368
+ if (path === topLevelKey) {
1369
+ value = finalUpdates[topLevelKey];
1370
+ } else {
1371
+ const restPath = path.substring(topLevelKey.length + 1);
1372
+ value = getValueByPath(finalUpdates[topLevelKey], restPath);
1373
+ }
1374
+ if (value !== void 0) {
1375
+ this.notifySubscribers(path, value);
1376
+ }
1377
+ }
1378
+ } catch (error) {
1379
+ this.logger?.error("Error notifying path subscribers", { path, error });
1380
+ }
1381
+ }
1382
+ await this.emitEvent({
1383
+ type: "storage:update" /* STORAGE_UPDATE */,
1384
+ payload: {
1385
+ state: finalUpdates,
1386
+ key: actuallyChangedKeys,
1387
+ changedPaths: Array.from(changedPaths)
1388
+ }
1389
+ });
1390
+ } catch (error) {
1391
+ this.logger?.error("Error updating state", { error });
1392
+ throw error;
1393
+ }
1394
+ }
1395
+ async delete(key) {
1396
+ try {
1397
+ const metadata = { operation: "delete", timestamp: Date.now(), key };
1398
+ if (await this.pluginExecutor?.executeBeforeDelete(key, metadata)) {
1399
+ const middlewareResult = await this.middlewareModule.dispatch({
1400
+ type: "delete",
1401
+ key,
1402
+ metadata
1403
+ });
1404
+ await this.pluginExecutor?.executeAfterDelete(key, metadata);
1405
+ const keyStr = key.toString();
1406
+ const changedPaths = [keyStr];
1407
+ this.notifySubscribers(key, void 0);
1408
+ this.notifySubscribers(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY, {
1409
+ type: "storage:update" /* STORAGE_UPDATE */,
1410
+ key,
1411
+ value: void 0,
1412
+ result: middlewareResult,
1413
+ changedPaths
1414
+ });
1415
+ await this.emitEvent({
1416
+ type: "storage:update" /* STORAGE_UPDATE */,
1417
+ payload: {
1418
+ key,
1419
+ value: void 0,
1420
+ result: middlewareResult,
1421
+ changedPaths
1422
+ }
1423
+ });
1424
+ }
1425
+ } catch (error) {
1426
+ this.logger?.error("Error deleting value", { key, error });
1427
+ throw error;
1428
+ }
1429
+ }
1430
+ async clear() {
1431
+ try {
1432
+ this.pluginExecutor?.executeOnClear();
1433
+ await this.middlewareModule.dispatch({
1434
+ type: "clear"
1435
+ });
1436
+ } catch (error) {
1437
+ this.logger?.error("Error clearing storage", { error });
1438
+ throw error;
1439
+ }
1440
+ }
1441
+ async keys() {
1442
+ try {
1443
+ return await this.middlewareModule.dispatch({
1444
+ type: "keys"
1445
+ });
1446
+ } catch (error) {
1447
+ this.logger?.error("Error getting keys", { error });
1448
+ throw error;
1449
+ }
1450
+ }
1451
+ async has(key) {
1452
+ try {
1453
+ return await this.doHas(key);
1454
+ } catch (error) {
1455
+ this.logger?.error("Error checking value existence", { key, error });
1456
+ throw error;
1457
+ }
1458
+ }
1459
+ async getState() {
1460
+ try {
1461
+ const value = await this.doGet("");
1462
+ return value || {};
1463
+ } catch (error) {
1464
+ this.logger?.error("Error getting state", { error });
1465
+ throw error;
1466
+ }
1467
+ }
1468
+ // Вспомогательный метод для подписки на все изменения
1469
+ subscribeToAll(callback) {
1470
+ if (!this.subscribers.has(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY)) {
1471
+ this.subscribers.set(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY, /* @__PURE__ */ new Set());
1472
+ }
1473
+ this.subscribers.get(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY).add(callback);
1474
+ return () => {
1475
+ const subscribers = this.subscribers.get(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY);
1476
+ if (subscribers) {
1477
+ subscribers.delete(callback);
1478
+ if (subscribers.size === 0) {
1479
+ this.subscribers.delete(_BaseStorage.GLOBAL_SUBSCRIPTION_KEY);
1480
+ }
1481
+ }
1482
+ };
1483
+ }
1484
+ subscribe(keyOrSelector, callback) {
1485
+ if (typeof keyOrSelector === "string") {
1486
+ return this.subscribeByKey(keyOrSelector, callback);
1487
+ }
1488
+ return this.subscribeBySelector(keyOrSelector, callback);
1489
+ }
1490
+ async destroy() {
1491
+ try {
1492
+ await this.clear();
1493
+ await this.doDestroy();
1494
+ if (this.initializedMiddlewares) {
1495
+ await Promise.all(
1496
+ this.initializedMiddlewares.map(async (middleware) => {
1497
+ if ("cleanup" in middleware) {
1498
+ await middleware.cleanup?.();
1499
+ }
1500
+ })
1501
+ );
1502
+ this.initializedMiddlewares = null;
1503
+ }
1504
+ await this.emitEvent({
1505
+ type: "storage:destroy" /* STORAGE_DESTROY */
1506
+ });
1507
+ } catch (error) {
1508
+ this.logger?.error("Error destroying storage", { error });
1509
+ throw error;
1510
+ }
1511
+ }
1512
+ // Вспомогательные методы
1513
+ subscribeByKey(key, callback) {
1514
+ if (!this.subscribers.has(key)) {
1515
+ this.subscribers.set(key, /* @__PURE__ */ new Set());
1516
+ }
1517
+ let initialValueSent = false;
1518
+ this.subscribers.get(key).add(callback);
1519
+ this.get(key).then((value) => {
1520
+ try {
1521
+ if (!initialValueSent) {
1522
+ initialValueSent = true;
1523
+ callback(value);
1524
+ }
1525
+ } catch (error) {
1526
+ this.logger?.error("Error in initial callback", { key, error });
1527
+ }
1528
+ });
1529
+ return () => {
1530
+ const subscribers = this.subscribers.get(key);
1531
+ if (subscribers) {
1532
+ subscribers.delete(callback);
1533
+ if (subscribers.size === 0) {
1534
+ this.subscribers.delete(key);
1535
+ }
1536
+ }
1537
+ };
1538
+ }
1539
+ createDummyState() {
1540
+ const handler = {
1541
+ get: (target, prop) => {
1542
+ target[prop] = target[prop] || new Proxy({}, handler);
1543
+ return target[prop];
1544
+ }
1545
+ };
1546
+ return new Proxy({}, handler);
1547
+ }
1548
+ isEqual(a, b) {
1549
+ if (a === b) return true;
1550
+ if (a == null || b == null) return a === b;
1551
+ const typeA = typeof a;
1552
+ const typeB = typeof b;
1553
+ if (typeA !== typeB) return false;
1554
+ if (typeA !== "object") return a === b;
1555
+ if (a instanceof Date && b instanceof Date) {
1556
+ return a.getTime() === b.getTime();
1557
+ }
1558
+ if (Array.isArray(a) && Array.isArray(b)) {
1559
+ if (a.length !== b.length) return false;
1560
+ for (let i = 0; i < a.length; i++) {
1561
+ if (!this.isEqual(a[i], b[i])) return false;
1562
+ }
1563
+ return true;
1564
+ }
1565
+ const keysA = Object.keys(a);
1566
+ const keysB = Object.keys(b);
1567
+ if (keysA.length !== keysB.length) return false;
1568
+ return keysA.every((key) => Object.prototype.hasOwnProperty.call(b, key) && this.isEqual(a[key], b[key]));
1569
+ }
1570
+ /**
1571
+ * Возвращает полный путь, а не только корневой ключ
1572
+ */
1573
+ extractPath(selector, dummyState) {
1574
+ if (this.selectorPathCache.has(selector)) {
1575
+ return this.selectorPathCache.get(selector);
1576
+ }
1577
+ const accessedPaths = [];
1578
+ const createProxyHandler = (path = "") => ({
1579
+ get: (target, prop) => {
1580
+ if (typeof prop === "symbol") {
1581
+ return Reflect.get(target, prop);
1582
+ }
1583
+ const currentPath = path ? `${path}.${prop}` : prop;
1584
+ accessedPaths.push(currentPath);
1585
+ return new Proxy({}, createProxyHandler(currentPath));
1586
+ },
1587
+ // Обработка опциональной цепочки (?.)
1588
+ has: (target, prop) => {
1589
+ return true;
1590
+ },
1591
+ // Поддержка для Array.prototype.map и других операций над массивами
1592
+ ownKeys: () => [],
1593
+ getOwnPropertyDescriptor: () => ({
1594
+ configurable: true,
1595
+ enumerable: true
1596
+ }),
1597
+ apply: (target, thisArg, args) => {
1598
+ return new Proxy(() => {
1599
+ }, createProxyHandler(path));
1600
+ }
1601
+ });
1602
+ try {
1603
+ selector(new Proxy(dummyState, createProxyHandler()));
1604
+ } catch (error) {
1605
+ }
1606
+ if (accessedPaths.length === 0) return "";
1607
+ accessedPaths.sort((a, b) => b.length - a.length);
1608
+ this.selectorPathCache.set(selector, accessedPaths[0]);
1609
+ return accessedPaths[0];
1610
+ }
1611
+ notifySubscribers(key, value) {
1612
+ const keyStr = key.toString();
1613
+ const exactSubscribers = this.subscribers.get(keyStr);
1614
+ if (exactSubscribers?.size) {
1615
+ const subscribersCopy = new Set(exactSubscribers);
1616
+ subscribersCopy.forEach((callback) => {
1617
+ try {
1618
+ callback(value);
1619
+ } catch (error) {
1620
+ this.logger?.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u0432 \u043F\u043E\u0434\u043F\u0438\u0441\u0447\u0438\u043A\u0435 \u043D\u0430 \u043A\u043E\u043B\u0431\u044D\u043A", { key: keyStr, error });
1621
+ }
1622
+ });
1623
+ }
1624
+ }
1625
+ /**
1626
+ * Метод для определения изменившихся путей между двумя объектами
1627
+ */
1628
+ findChangedPaths(oldObj, newObj, prefix = "", changedPaths = /* @__PURE__ */ new Set(), visited = /* @__PURE__ */ new WeakMap()) {
1629
+ if (oldObj === newObj) return changedPaths;
1630
+ if (typeof oldObj !== "object" || typeof newObj !== "object" || oldObj === null || newObj === null) {
1631
+ if (oldObj !== newObj) {
1632
+ changedPaths.add(prefix || "");
1633
+ }
1634
+ return changedPaths;
1635
+ }
1636
+ if (visited.has(oldObj)) return changedPaths;
1637
+ visited.set(oldObj, true);
1638
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(oldObj || {}), ...Object.keys(newObj || {})]);
1639
+ for (const key of allKeys) {
1640
+ const oldValue = oldObj[key];
1641
+ const newValue = newObj[key];
1642
+ if (oldValue === newValue) continue;
1643
+ const path = prefix ? `${prefix}.${key}` : key;
1644
+ if (oldValue && newValue && typeof oldValue === "object" && typeof newValue === "object" && !Array.isArray(oldValue) && !Array.isArray(newValue)) {
1645
+ this.findChangedPaths(oldValue, newValue, path, changedPaths, visited);
1646
+ } else if (Array.isArray(oldValue) && Array.isArray(newValue)) {
1647
+ if (!this.isEqual(oldValue, newValue)) {
1648
+ changedPaths.add(path);
1649
+ }
1650
+ } else if (!this.isEqual(oldValue, newValue)) {
1651
+ changedPaths.add(path);
1652
+ }
1653
+ }
1654
+ return changedPaths;
1655
+ }
1656
+ subscribeBySelector(pathSelector, callback) {
1657
+ const dummyState = this.createDummyState();
1658
+ const fullPath = this.extractPath(pathSelector, dummyState);
1659
+ if (this.logger?.debug) {
1660
+ this.logger.debug("Subscribing to path:", { path: fullPath });
1661
+ }
1662
+ const wrappedCallback = async (value) => {
1663
+ try {
1664
+ if (value === void 0 || value === null) {
1665
+ const currentState2 = await this.getState();
1666
+ const selectedValue2 = pathSelector(currentState2);
1667
+ callback(selectedValue2);
1668
+ return;
1669
+ }
1670
+ if (typeof value !== "object" || value === null) {
1671
+ callback(value);
1672
+ return;
1673
+ }
1674
+ const currentState = await this.getState();
1675
+ const selectedValue = pathSelector(currentState);
1676
+ callback(selectedValue);
1677
+ } catch (error) {
1678
+ this.logger?.error("Error in selector callback", { path: fullPath, error });
1679
+ callback(value);
1680
+ }
1681
+ };
1682
+ if (!fullPath) {
1683
+ return this.subscribeToAll(() => {
1684
+ this.getState().then((state) => {
1685
+ callback(pathSelector(state));
1686
+ });
1687
+ });
1688
+ }
1689
+ return this.subscribeByKey(fullPath, wrappedCallback);
1690
+ }
1691
+ async emitEvent(event) {
1692
+ try {
1693
+ await this.eventEmitter?.emit({
1694
+ ...event,
1695
+ metadata: {
1696
+ ...event.metadata || {},
1697
+ timestamp: Date.now(),
1698
+ storageName: this.name
1699
+ }
1700
+ });
1701
+ } catch (error) {
1702
+ this.logger?.error("Error emitting event", { event, error });
1703
+ }
1704
+ }
1705
+ };
1706
+
1707
+ // src/core/storage/adapters/indexed-DB.service.ts
1708
+ var IndexedDBManager = class _IndexedDBManager {
1709
+ constructor(dbName, dbVersion, logger) {
1710
+ this.dbName = dbName;
1711
+ this.logger = logger;
1712
+ this.dbVersion = dbVersion;
1713
+ }
1714
+ static instances = /* @__PURE__ */ new Map();
1715
+ db = null;
1716
+ initPromise = null;
1717
+ storeNames = /* @__PURE__ */ new Set();
1718
+ dbVersion;
1719
+ static getInstance(dbName, dbVersion = 1, logger) {
1720
+ if (!_IndexedDBManager.instances.has(dbName)) {
1721
+ _IndexedDBManager.instances.set(dbName, new _IndexedDBManager(dbName, dbVersion, logger));
1722
+ }
1723
+ const instance = _IndexedDBManager.instances.get(dbName);
1724
+ if (dbVersion > instance.dbVersion) {
1725
+ instance.dbVersion = dbVersion;
1726
+ }
1727
+ return instance;
1728
+ }
1729
+ async initialize() {
1730
+ if (this.db) {
1731
+ return this.db;
1732
+ }
1733
+ if (!this.initPromise) {
1734
+ this.initPromise = this.openDatabase();
1735
+ }
1736
+ return this.initPromise;
1737
+ }
1738
+ async ensureStoreExists(storeName) {
1739
+ await this.initialize();
1740
+ if (this.db.objectStoreNames.contains(storeName)) {
1741
+ this.storeNames.add(storeName);
1742
+ return this.db;
1743
+ }
1744
+ this.logger?.debug(`Store "${storeName}" not found, upgrading database`, {
1745
+ dbName: this.dbName,
1746
+ currentStores: Array.from(this.db.objectStoreNames)
1747
+ });
1748
+ this.db.close();
1749
+ this.db = null;
1750
+ this.dbVersion++;
1751
+ this.initPromise = this.openDatabase([storeName]);
1752
+ const newDb = await this.initPromise;
1753
+ this.storeNames.add(storeName);
1754
+ return newDb;
1755
+ }
1756
+ async openDatabase(newStores = []) {
1757
+ return new Promise((resolve, reject) => {
1758
+ this.logger?.debug(`Opening database "${this.dbName}" with version ${this.dbVersion}`);
1759
+ const request = indexedDB.open(this.dbName, this.dbVersion);
1760
+ request.onerror = () => {
1761
+ this.logger?.error(`Failed to open database "${this.dbName}"`, { error: request.error });
1762
+ reject(request.error);
1763
+ };
1764
+ request.onsuccess = () => {
1765
+ this.db = request.result;
1766
+ for (let i = 0; i < this.db.objectStoreNames.length; i++) {
1767
+ this.storeNames.add(this.db.objectStoreNames[i]);
1768
+ }
1769
+ this.logger?.debug(`Database "${this.dbName}" opened successfully`, {
1770
+ version: this.db.version,
1771
+ stores: Array.from(this.db.objectStoreNames)
1772
+ });
1773
+ resolve(this.db);
1774
+ };
1775
+ request.onupgradeneeded = (event) => {
1776
+ const db = event.target.result;
1777
+ this.logger?.debug(`Upgrading database "${this.dbName}" to version ${this.dbVersion}`);
1778
+ for (const storeName of newStores) {
1779
+ if (!db.objectStoreNames.contains(storeName)) {
1780
+ this.logger?.debug(`Creating store "${storeName}"`);
1781
+ db.createObjectStore(storeName);
1782
+ }
1783
+ }
1784
+ };
1785
+ });
1786
+ }
1787
+ closeDatabase() {
1788
+ if (this.db) {
1789
+ this.db.close();
1790
+ this.db = null;
1791
+ this.initPromise = null;
1792
+ }
1793
+ }
1794
+ async deleteDatabase() {
1795
+ this.closeDatabase();
1796
+ return new Promise((resolve, reject) => {
1797
+ const request = indexedDB.deleteDatabase(this.dbName);
1798
+ request.onsuccess = () => {
1799
+ this.logger?.debug(`Database "${this.dbName}" deleted successfully`);
1800
+ _IndexedDBManager.instances.delete(this.dbName);
1801
+ this.storeNames.clear();
1802
+ resolve();
1803
+ };
1804
+ request.onerror = () => {
1805
+ this.logger?.error(`Failed to delete database "${this.dbName}"`, { error: request.error });
1806
+ reject(request.error);
1807
+ };
1808
+ });
1809
+ }
1810
+ async ensureStoresExist(storeNames) {
1811
+ await this.initialize();
1812
+ const missingStores = storeNames.filter((name) => !this.db.objectStoreNames.contains(name));
1813
+ if (missingStores.length === 0) {
1814
+ return this.db;
1815
+ }
1816
+ this.logger?.debug(`\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0438\u0445 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449: ${missingStores.join(", ")}`, {
1817
+ dbName: this.dbName,
1818
+ currentStores: Array.from(this.db.objectStoreNames)
1819
+ });
1820
+ this.db.close();
1821
+ this.db = null;
1822
+ this.dbVersion++;
1823
+ this.initPromise = this.openDatabase(missingStores);
1824
+ return this.initPromise;
1825
+ }
1826
+ // Метод для получения текущей версии
1827
+ getCurrentVersion() {
1828
+ return this.dbVersion;
1829
+ }
1830
+ };
1831
+ var DBVersionManager = class {
1832
+ constructor(dbName, initialVersion = 1, logger) {
1833
+ this.dbName = dbName;
1834
+ this.logger = logger;
1835
+ this.version = initialVersion;
1836
+ }
1837
+ db = null;
1838
+ version;
1839
+ /**
1840
+ * Получает текущую версию базы данных
1841
+ */
1842
+ getCurrentVersion() {
1843
+ return this.version;
1844
+ }
1845
+ /**
1846
+ * Открывает базу данных с заданной версией
1847
+ */
1848
+ openDatabase(version, newStores = []) {
1849
+ return new Promise((resolve, reject) => {
1850
+ this.logger?.debug(`\u041E\u0442\u043A\u0440\u044B\u0442\u0438\u0435 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445 "${this.dbName}" \u0441 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 ${version}`);
1851
+ const request = indexedDB.open(this.dbName, version);
1852
+ request.onerror = () => {
1853
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u0438\u0438 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445 "${this.dbName}"`, { error: request.error });
1854
+ reject(request.error);
1855
+ };
1856
+ request.onsuccess = () => {
1857
+ this.db = request.result;
1858
+ this.version = this.db.version;
1859
+ this.logger?.debug(`\u0411\u0430\u0437\u0430 \u0434\u0430\u043D\u043D\u044B\u0445 "${this.dbName}" \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u0430`, {
1860
+ version: this.db.version,
1861
+ stores: Array.from(this.db.objectStoreNames)
1862
+ });
1863
+ resolve(this.db);
1864
+ };
1865
+ request.onupgradeneeded = (event) => {
1866
+ const db = event.target.result;
1867
+ this.logger?.debug(`\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445 "${this.dbName}" \u0434\u043E \u0432\u0435\u0440\u0441\u0438\u0438 ${version}`);
1868
+ for (const storeName of newStores) {
1869
+ if (!db.objectStoreNames.contains(storeName)) {
1870
+ this.logger?.debug(`\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 "${storeName}"`);
1871
+ db.createObjectStore(storeName);
1872
+ }
1873
+ }
1874
+ };
1875
+ });
1876
+ }
1877
+ /**
1878
+ * Убеждается, что все указанные хранилища существуют в базе данных
1879
+ */
1880
+ async ensureStoresExist(storeNames) {
1881
+ if (!this.db) {
1882
+ this.db = await this.openDatabase(this.version);
1883
+ }
1884
+ const missingStores = storeNames.filter((name) => !this.db.objectStoreNames.contains(name));
1885
+ if (missingStores.length === 0) {
1886
+ return this.db;
1887
+ }
1888
+ this.logger?.debug(`\u041D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430: ${missingStores.join(", ")}`, {
1889
+ dbName: this.dbName,
1890
+ currentVersion: this.version
1891
+ });
1892
+ this.db.close();
1893
+ this.db = null;
1894
+ this.version++;
1895
+ this.db = await this.openDatabase(this.version, missingStores);
1896
+ return this.db;
1897
+ }
1898
+ /**
1899
+ * Закрывает соединение с базой данных
1900
+ */
1901
+ close() {
1902
+ if (this.db) {
1903
+ this.db.close();
1904
+ this.db = null;
1905
+ }
1906
+ }
1907
+ };
1908
+ var IndexedDBStorage = class _IndexedDBStorage extends BaseStorage {
1909
+ DB_NAME;
1910
+ STORE_NAME;
1911
+ DB_VERSION;
1912
+ dbManager;
1913
+ constructor(config, pluginExecutor, eventEmitter, logger) {
1914
+ super(config, pluginExecutor, eventEmitter, logger);
1915
+ const options = config.options;
1916
+ this.DB_NAME = options.dbName || "app_storage";
1917
+ this.STORE_NAME = config.name;
1918
+ this.DB_VERSION = options.dbVersion || 1;
1919
+ this.dbManager = IndexedDBManager.getInstance(this.DB_NAME, this.DB_VERSION, logger);
1920
+ }
1921
+ async initialize() {
1922
+ try {
1923
+ this.logger?.debug(`Initializing IndexedDB storage "${this.STORE_NAME}"`);
1924
+ await this.dbManager.ensureStoreExists(this.STORE_NAME);
1925
+ try {
1926
+ const db = await this.dbManager.initialize();
1927
+ if (!db.objectStoreNames.contains(this.STORE_NAME)) {
1928
+ throw new Error(`Store "${this.STORE_NAME}" not found after initialization`);
1929
+ }
1930
+ } catch (error) {
1931
+ this.logger?.error(`Error verifying store "${this.STORE_NAME}" exists:`, { error });
1932
+ throw error;
1933
+ }
1934
+ this.initializeMiddlewares();
1935
+ try {
1936
+ await this.initializeWithMiddlewares();
1937
+ this.logger?.debug(`IndexedDB storage "${this.STORE_NAME}" initialized successfully`);
1938
+ } catch (error) {
1939
+ this.logger?.error(`Failed to initialize middleware for store "${this.STORE_NAME}"`, { error });
1940
+ }
1941
+ return this;
1942
+ } catch (error) {
1943
+ this.logger?.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 IndexedDB "${this.name}"`, { error });
1944
+ throw error;
1945
+ }
1946
+ }
1947
+ static async getCurrentDBVersion(dbName) {
1948
+ return new Promise((resolve) => {
1949
+ try {
1950
+ const request = indexedDB.open(dbName);
1951
+ request.onsuccess = () => {
1952
+ const version = request.result.version;
1953
+ request.result.close();
1954
+ resolve(version);
1955
+ };
1956
+ request.onerror = () => {
1957
+ console.warn(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0438 \u0432\u0435\u0440\u0441\u0438\u0438 \u0411\u0414 ${dbName}`, request.error);
1958
+ resolve(0);
1959
+ };
1960
+ } catch (error) {
1961
+ console.warn(`\u0418\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u043F\u0440\u0438 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0438 \u0432\u0435\u0440\u0441\u0438\u0438 \u0411\u0414 ${dbName}`, error);
1962
+ resolve(0);
1963
+ }
1964
+ });
1965
+ }
1966
+ static async createStorages(dbName, configs, logger) {
1967
+ const currentVersion = await this.getCurrentDBVersion(dbName);
1968
+ const initialVersion = currentVersion || 1;
1969
+ const dbManager = new DBVersionManager(dbName, initialVersion, logger);
1970
+ const storeNames = Object.values(configs).map((config) => config.name);
1971
+ await dbManager.ensureStoresExist(storeNames);
1972
+ const result = {};
1973
+ for (const [key, config] of Object.entries(configs)) {
1974
+ const storage = new _IndexedDBStorage(
1975
+ {
1976
+ ...config,
1977
+ options: {
1978
+ dbName,
1979
+ dbVersion: dbManager.getCurrentVersion()
1980
+ }
1981
+ },
1982
+ config.pluginExecutor,
1983
+ config.eventEmitter,
1984
+ logger
1985
+ );
1986
+ result[key] = await storage.initialize();
1987
+ }
1988
+ return result;
1989
+ }
1990
+ async getTransaction(mode = "readonly") {
1991
+ try {
1992
+ const db = await this.dbManager.ensureStoreExists(this.STORE_NAME);
1993
+ if (!db.objectStoreNames.contains(this.STORE_NAME)) {
1994
+ this.logger?.warn(`Object store "${this.STORE_NAME}" not found, attempting to repair`);
1995
+ db.close();
1996
+ this.dbManager.closeDatabase();
1997
+ const newDb = await this.dbManager.ensureStoreExists(this.STORE_NAME);
1998
+ if (!newDb.objectStoreNames.contains(this.STORE_NAME)) {
1999
+ throw new Error(`Object store "${this.STORE_NAME}" still doesn't exist after repair attempt`);
2000
+ }
2001
+ return newDb.transaction(this.STORE_NAME, mode);
2002
+ }
2003
+ return db.transaction(this.STORE_NAME, mode);
2004
+ } catch (error) {
2005
+ this.logger?.error(`Failed to create transaction for store "${this.STORE_NAME}"`, { error });
2006
+ throw error;
2007
+ }
2008
+ }
2009
+ async getObjectStore(mode = "readonly") {
2010
+ const transaction = await this.getTransaction(mode);
2011
+ return transaction.objectStore(this.STORE_NAME);
2012
+ }
2013
+ async doGet(key) {
2014
+ const store = await this.getObjectStore();
2015
+ if (key === "") {
2016
+ return new Promise((resolve, reject) => {
2017
+ const request = store.getAll();
2018
+ request.onerror = () => reject(request.error);
2019
+ request.onsuccess = () => {
2020
+ const allValues = request.result;
2021
+ const allKeys = store.getAllKeys();
2022
+ allKeys.onsuccess = () => {
2023
+ const state = allKeys.result.reduce(
2024
+ (acc, k, index) => {
2025
+ if (k !== "root") {
2026
+ acc[k] = allValues[index];
2027
+ }
2028
+ return acc;
2029
+ },
2030
+ {}
2031
+ );
2032
+ resolve(state);
2033
+ };
2034
+ allKeys.onerror = () => reject(allKeys.error);
2035
+ };
2036
+ });
2037
+ }
2038
+ if (key instanceof StorageKey && key.isUnparseable()) {
2039
+ return new Promise((resolve, reject) => {
2040
+ const request = store.get(key.valueOf());
2041
+ request.onerror = () => reject(request.error);
2042
+ request.onsuccess = () => resolve(request.result);
2043
+ });
2044
+ }
2045
+ const parts = parsePath(key);
2046
+ if (parts.length > 1) {
2047
+ const rootKey = parts[0];
2048
+ return new Promise((resolve, reject) => {
2049
+ const request = store.get(rootKey);
2050
+ request.onerror = () => reject(request.error);
2051
+ request.onsuccess = () => {
2052
+ const rootValue = request.result;
2053
+ if (!rootValue) {
2054
+ resolve(void 0);
2055
+ return;
2056
+ }
2057
+ const value = getValueByPath(rootValue, parts.slice(1).join("."));
2058
+ resolve(value);
2059
+ };
2060
+ });
2061
+ }
2062
+ return new Promise((resolve, reject) => {
2063
+ const request = store.get(parts[0]);
2064
+ request.onerror = () => reject(request.error);
2065
+ request.onsuccess = () => resolve(request.result);
2066
+ });
2067
+ }
2068
+ async doSet(key, value) {
2069
+ if (key === "") {
2070
+ const store2 = await this.getObjectStore("readwrite");
2071
+ return new Promise((resolve, reject) => {
2072
+ const tx = store2.transaction;
2073
+ tx.oncomplete = () => {
2074
+ resolve();
2075
+ };
2076
+ tx.onerror = () => {
2077
+ reject(tx.error);
2078
+ };
2079
+ const clearRequest = store2.clear();
2080
+ clearRequest.onsuccess = () => {
2081
+ const entries = Object.entries(value);
2082
+ for (const [entryKey, entryValue] of entries) {
2083
+ store2.put(entryValue, entryKey);
2084
+ }
2085
+ };
2086
+ clearRequest.onerror = () => {
2087
+ reject(clearRequest.error);
2088
+ };
2089
+ });
2090
+ }
2091
+ const store = await this.getObjectStore("readwrite");
2092
+ if (key instanceof StorageKey && key.isUnparseable()) {
2093
+ await this.putValueInStore(store, key.valueOf(), value);
2094
+ return;
2095
+ }
2096
+ const parts = parsePath(key);
2097
+ if (parts.length > 1) {
2098
+ const rootKey = parts[0];
2099
+ return new Promise((resolve, reject) => {
2100
+ const request = store.get(rootKey);
2101
+ request.onerror = () => reject(request.error);
2102
+ request.onsuccess = () => {
2103
+ const rootValue = request.result || {};
2104
+ const updatedValue = setValueByPath(rootValue, parts.slice(1).join("."), value);
2105
+ const putRequest = store.put(updatedValue, rootKey);
2106
+ putRequest.onerror = () => reject(putRequest.error);
2107
+ putRequest.onsuccess = () => resolve();
2108
+ };
2109
+ });
2110
+ }
2111
+ await this.putValueInStore(store, parts[0], value);
2112
+ }
2113
+ async putValueInStore(store, key, value) {
2114
+ return new Promise((resolve, reject) => {
2115
+ const request = store.put(value, key.valueOf());
2116
+ request.onerror = () => reject(request.error);
2117
+ request.onsuccess = () => resolve();
2118
+ });
2119
+ }
2120
+ async doUpdate(updates) {
2121
+ const updatesByRoot = /* @__PURE__ */ new Map();
2122
+ const rawUpdates = [];
2123
+ for (const { key, value } of updates) {
2124
+ if (key instanceof StorageKey && key.isUnparseable()) {
2125
+ rawUpdates.push({ key: key.valueOf(), value });
2126
+ continue;
2127
+ }
2128
+ const parts = parsePath(key);
2129
+ const rootKey = parts[0];
2130
+ const path = parts.slice(1);
2131
+ if (!updatesByRoot.has(rootKey)) {
2132
+ updatesByRoot.set(rootKey, []);
2133
+ }
2134
+ updatesByRoot.get(rootKey).push({ path, value });
2135
+ }
2136
+ try {
2137
+ for (const { key, value } of rawUpdates) {
2138
+ const store = await this.getObjectStore("readwrite");
2139
+ await this.putValueInStore(store, key, value);
2140
+ }
2141
+ for (const [rootKey, pathUpdates] of updatesByRoot) {
2142
+ const rootValue = await this.doGet(rootKey) || {};
2143
+ let updatedValue = { ...rootValue };
2144
+ for (const { path, value } of pathUpdates) {
2145
+ if (path.length === 0) {
2146
+ updatedValue = value;
2147
+ } else {
2148
+ updatedValue = setValueByPath(updatedValue, path.join("."), value);
2149
+ }
2150
+ }
2151
+ const store = await this.getObjectStore("readwrite");
2152
+ await this.putValueInStore(store, rootKey, updatedValue);
2153
+ }
2154
+ } catch (error) {
2155
+ this.logger?.error("Error during update:", { error });
2156
+ throw error;
2157
+ }
2158
+ }
2159
+ async doDelete(key) {
2160
+ const store = await this.getObjectStore("readwrite");
2161
+ if (key instanceof StorageKey && key.isUnparseable()) {
2162
+ return new Promise((resolve, reject) => {
2163
+ const request = store.delete(key.valueOf());
2164
+ request.onerror = () => reject(request.error);
2165
+ request.onsuccess = () => resolve(true);
2166
+ });
2167
+ }
2168
+ const parts = parsePath(key);
2169
+ if (parts.length === 1) {
2170
+ return new Promise((resolve, reject) => {
2171
+ const request = store.delete(parts[0]);
2172
+ request.onerror = () => reject(request.error);
2173
+ request.onsuccess = () => resolve(true);
2174
+ });
2175
+ }
2176
+ const rootKey = parts[0];
2177
+ return new Promise((resolve, reject) => {
2178
+ const getRequest = store.get(rootKey);
2179
+ getRequest.onerror = () => reject(getRequest.error);
2180
+ getRequest.onsuccess = () => {
2181
+ const rootValue = getRequest.result;
2182
+ if (!rootValue) {
2183
+ resolve(false);
2184
+ return;
2185
+ }
2186
+ const parent = getValueByPath(rootValue, parts.slice(0, -1).join("."));
2187
+ const lastKey = parts[parts.length - 1];
2188
+ if (!parent || !(lastKey in parent)) {
2189
+ resolve(false);
2190
+ return;
2191
+ }
2192
+ if (Array.isArray(parent)) {
2193
+ const index = parseInt(lastKey, 10);
2194
+ if (!isNaN(index)) {
2195
+ parent.splice(index, 1);
2196
+ } else {
2197
+ delete parent[lastKey];
2198
+ }
2199
+ } else {
2200
+ delete parent[lastKey];
2201
+ }
2202
+ const putRequest = store.put(rootValue, rootKey);
2203
+ putRequest.onerror = () => reject(putRequest.error);
2204
+ putRequest.onsuccess = () => resolve(true);
2205
+ };
2206
+ });
2207
+ }
2208
+ async doClear() {
2209
+ const store = await this.getObjectStore("readwrite");
2210
+ return new Promise((resolve, reject) => {
2211
+ const request = store.clear();
2212
+ request.onsuccess = () => resolve();
2213
+ request.onerror = () => reject(request.error);
2214
+ });
2215
+ }
2216
+ async doKeys() {
2217
+ const store = await this.getObjectStore();
2218
+ const request = store.getAllKeys();
2219
+ return new Promise((resolve, reject) => {
2220
+ request.onsuccess = () => {
2221
+ resolve(request.result);
2222
+ };
2223
+ request.onerror = () => reject(request.error);
2224
+ });
2225
+ }
2226
+ async doHas(key) {
2227
+ const value = await this.doGet(key);
2228
+ return value !== void 0;
2229
+ }
2230
+ async doDestroy() {
2231
+ try {
2232
+ await this.doClear();
2233
+ } catch (error) {
2234
+ this.logger?.error(`Error destroying store "${this.STORE_NAME}"`, { error });
2235
+ throw error;
2236
+ }
2237
+ }
2238
+ };
2239
+
2240
+ // src/core/storage/adapters/local-storage.service.ts
2241
+ var LocalStorage = class extends BaseStorage {
2242
+ constructor(config, pluginExecutor, eventEmitter, logger) {
2243
+ super(config, pluginExecutor, eventEmitter, logger);
2244
+ }
2245
+ async initialize() {
2246
+ try {
2247
+ await this.initializeWithMiddlewares();
2248
+ return this;
2249
+ } catch (error) {
2250
+ this.logger?.error("Error initializing LocalStorage", { error });
2251
+ throw error;
2252
+ }
2253
+ }
2254
+ async doGet(key) {
2255
+ const storageData = localStorage.getItem(this.name);
2256
+ if (!storageData) return void 0;
2257
+ const state = JSON.parse(storageData);
2258
+ if (key instanceof StorageKey && key.isUnparseable()) {
2259
+ return state[key.valueOf()];
2260
+ }
2261
+ return getValueByPath(state, key);
2262
+ }
2263
+ async doSet(key, value) {
2264
+ const storageData = localStorage.getItem(this.name);
2265
+ const state = storageData ? JSON.parse(storageData) : {};
2266
+ if (key instanceof StorageKey && key.isUnparseable()) {
2267
+ state[key.valueOf()] = value;
2268
+ localStorage.setItem(this.name, JSON.stringify(state));
2269
+ return;
2270
+ }
2271
+ const newState = setValueByPath({ ...state }, key, value);
2272
+ localStorage.setItem(this.name, JSON.stringify(newState));
2273
+ }
2274
+ async doDelete(key) {
2275
+ const storageData = localStorage.getItem(this.name);
2276
+ if (!storageData) return false;
2277
+ const state = JSON.parse(storageData);
2278
+ if (key instanceof StorageKey && key.isUnparseable()) {
2279
+ const rawKey = key.valueOf();
2280
+ if (!(rawKey in state)) return false;
2281
+ delete state[rawKey];
2282
+ localStorage.setItem(this.name, JSON.stringify(state));
2283
+ return true;
2284
+ }
2285
+ const pathParts = parsePath(key);
2286
+ const parentPath = pathParts.slice(0, -1).join(".");
2287
+ const lastKey = pathParts[pathParts.length - 1];
2288
+ const parent = parentPath ? getValueByPath(state, parentPath) : state;
2289
+ if (!parent || !(lastKey in parent)) return false;
2290
+ delete parent[lastKey];
2291
+ localStorage.setItem(this.name, JSON.stringify(state));
2292
+ return true;
2293
+ }
2294
+ async doUpdate(updates) {
2295
+ const storageData = localStorage.getItem(this.name);
2296
+ const state = storageData ? JSON.parse(storageData) : {};
2297
+ for (const { key, value } of updates) {
2298
+ if (key instanceof StorageKey && key.isUnparseable()) {
2299
+ state[key.valueOf()] = value;
2300
+ } else {
2301
+ setValueByPath(state, key, value);
2302
+ }
2303
+ }
2304
+ localStorage.setItem(this.name, JSON.stringify(state));
2305
+ }
2306
+ async doClear() {
2307
+ localStorage.removeItem(this.name);
2308
+ }
2309
+ async doKeys() {
2310
+ const storageData = localStorage.getItem(this.name);
2311
+ if (!storageData) return [];
2312
+ const state = JSON.parse(storageData);
2313
+ return this.getAllKeys(state);
2314
+ }
2315
+ async doHas(key) {
2316
+ const value = await this.doGet(key);
2317
+ return value !== void 0;
2318
+ }
2319
+ getAllKeys(obj) {
2320
+ return Object.keys(obj);
2321
+ }
2322
+ async doDestroy() {
2323
+ await this.doClear();
2324
+ }
2325
+ };
2326
+
2327
+ // src/core/storage/adapters/memory-storage.service.ts
2328
+ var MemoryStorage = class extends BaseStorage {
2329
+ storage = /* @__PURE__ */ new Map();
2330
+ constructor(config, pluginExecutor, eventEmitter, logger) {
2331
+ super(config, pluginExecutor, eventEmitter, logger);
2332
+ }
2333
+ async initialize() {
2334
+ try {
2335
+ this.initializeMiddlewares();
2336
+ await this.initializeWithMiddlewares();
2337
+ return this;
2338
+ } catch (error) {
2339
+ this.logger?.error("Error initializing MemoryStorage", { error });
2340
+ throw error;
2341
+ }
2342
+ }
2343
+ async doGet(key) {
2344
+ const state = this.storage.get(this.name);
2345
+ if (!state) return void 0;
2346
+ if (key instanceof StorageKey && key.isUnparseable()) {
2347
+ return state[key.valueOf()];
2348
+ }
2349
+ return getValueByPath(state, key);
2350
+ }
2351
+ async doSet(key, value) {
2352
+ const state = this.storage.get(this.name) || {};
2353
+ if (key instanceof StorageKey && key.isUnparseable()) {
2354
+ state[key.valueOf()] = value;
2355
+ this.storage.set(this.name, state);
2356
+ return;
2357
+ }
2358
+ const newState = setValueByPath({ ...state }, key, value);
2359
+ this.storage.set(this.name, newState);
2360
+ }
2361
+ async doDelete(key) {
2362
+ const state = this.storage.get(this.name);
2363
+ if (!state) return false;
2364
+ if (key instanceof StorageKey && key.isUnparseable()) {
2365
+ const rawKey = key.valueOf();
2366
+ if (!(rawKey in state)) return false;
2367
+ delete state[rawKey];
2368
+ this.storage.set(this.name, state);
2369
+ return true;
2370
+ }
2371
+ const pathParts = parsePath(key);
2372
+ const parentPath = pathParts.slice(0, -1).join(".");
2373
+ const lastKey = pathParts[pathParts.length - 1];
2374
+ const parent = parentPath ? getValueByPath(state, parentPath) : state;
2375
+ if (!parent || !(lastKey in parent)) return false;
2376
+ delete parent[lastKey];
2377
+ this.storage.set(this.name, state);
2378
+ return true;
2379
+ }
2380
+ async doUpdate(updates) {
2381
+ const currentState = this.storage.get(this.name) || {};
2382
+ const newState = { ...currentState };
2383
+ for (const { key, value } of updates) {
2384
+ if (key instanceof StorageKey && key.isUnparseable()) {
2385
+ newState[key.valueOf()] = value;
2386
+ } else {
2387
+ setValueByPath(newState, key, value);
2388
+ }
2389
+ }
2390
+ this.storage.set(this.name, newState);
2391
+ }
2392
+ async doClear() {
2393
+ this.storage.delete(this.name);
2394
+ }
2395
+ async doKeys() {
2396
+ const state = this.storage.get(this.name);
2397
+ if (!state) return [];
2398
+ return this.getAllKeys(state);
2399
+ }
2400
+ async doHas(key) {
2401
+ const value = await this.doGet(key);
2402
+ return value !== void 0;
2403
+ }
2404
+ async doDestroy() {
2405
+ this.storage.delete(this.name);
2406
+ }
2407
+ getAllKeys(obj) {
2408
+ return Object.keys(obj);
2409
+ }
2410
+ };
2411
+ // Annotate the CommonJS export names for ESM import in node:
2412
+ 0 && (module.exports = {
2413
+ IndexedDBStorage,
2414
+ LocalStorage,
2415
+ MemoryStorage,
2416
+ SelectorModule,
2417
+ StorageEvents,
2418
+ StoragePluginModule,
2419
+ broadcastMiddleware
2420
+ });