@asaidimu/utils-persistence 6.1.11 → 6.1.13

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/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ //#region src/persistence/types.d.ts
1
2
  /**
2
3
  * configuration object for initializing a persistence store.
3
4
  *
@@ -11,215 +12,218 @@
11
12
  * @template T the type of data being persisted.
12
13
  */
13
14
  interface StoreConfig<T> {
14
- /**
15
- * the semantic version string (e.g., "1.0.0") of the data schema or application.
16
- *
17
- * this is used for version control and data migrations.
18
- * when the persisted state’s version does not match the current version,
19
- * the `onUpgrade` function will be invoked (if provided).
20
- */
15
+ /**
16
+ * the semantic version string (e.g., "1.0.0") of the data schema or application.
17
+ *
18
+ * this is used for version control and data migrations.
19
+ * when the persisted state’s version does not match the current version,
20
+ * the `onUpgrade` function will be invoked (if provided).
21
+ */
22
+ version: string;
23
+ /**
24
+ * a unique application identifier (e.g., "chat-app" or "my-dashboard").
25
+ *
26
+ * this prevents collisions between different apps or modules
27
+ * that might share the same persistence backend (e.g., localstorage).
28
+ *
29
+ * example: if two apps both persist under the key "user", the `app`
30
+ * value ensures they can be distinguished.
31
+ */
32
+ app: string;
33
+ /**
34
+ * optional handler for upgrading persisted state across versions.
35
+ *
36
+ * this function will be called when the persisted state’s `version`
37
+ * does not match the `version` specified in this config.
38
+ *
39
+ * @param state the existing state object, including:
40
+ * - `data`: the current persisted data (or null if none exists).
41
+ * - `version`: the version string stored with the data.
42
+ * - `app`: the application identifier stored with the data.
43
+ *
44
+ * @returns a new state object with:
45
+ * - `state`: the migrated data (or null if clearing/resetting).
46
+ * - `version`: the new version string (must match `config.version`).
47
+ *
48
+ * example:
49
+ * ```ts
50
+ * onupgrade: async ({ data, version, app }) => {
51
+ * if (version === "1.0.0") {
52
+ * // migrate from 1.0.0 to 2.0.0
53
+ * return { state: { ...data, newfield: "default" }, version: "2.0.0" };
54
+ * }
55
+ * return { state: data, version: "2.0.0" };
56
+ * }
57
+ * ```
58
+ */
59
+ onUpgrade?: (state: {
60
+ data: T | null;
21
61
  version: string;
22
- /**
23
- * a unique application identifier (e.g., "chat-app" or "my-dashboard").
24
- *
25
- * this prevents collisions between different apps or modules
26
- * that might share the same persistence backend (e.g., localstorage).
27
- *
28
- * example: if two apps both persist under the key "user", the `app`
29
- * value ensures they can be distinguished.
30
- */
31
62
  app: string;
32
- /**
33
- * optional handler for upgrading persisted state across versions.
34
- *
35
- * this function will be called when the persisted state’s `version`
36
- * does not match the `version` specified in this config.
37
- *
38
- * @param state the existing state object, including:
39
- * - `data`: the current persisted data (or null if none exists).
40
- * - `version`: the version string stored with the data.
41
- * - `app`: the application identifier stored with the data.
42
- *
43
- * @returns a new state object with:
44
- * - `state`: the migrated data (or null if clearing/resetting).
45
- * - `version`: the new version string (must match `config.version`).
46
- *
47
- * example:
48
- * ```ts
49
- * onupgrade: async ({ data, version, app }) => {
50
- * if (version === "1.0.0") {
51
- * // migrate from 1.0.0 to 2.0.0
52
- * return { state: { ...data, newfield: "default" }, version: "2.0.0" };
53
- * }
54
- * return { state: data, version: "2.0.0" };
55
- * }
56
- * ```
57
- */
58
- onUpgrade?: (state: {
59
- data: T | null;
60
- version: string;
61
- app: string;
62
- }) => Promise<{
63
- state: T | null;
64
- version: string;
65
- }>;
66
- /**
67
- * enables or disables developer mode for the persistence store.
68
- *
69
- * when set to `true`, the store may provide additional logging,
70
- * verbose error reporting, or bypass certain production constraints
71
- * (such as strict cache validation) to aid in debugging.
72
- *
73
- * @default false
74
- */
75
- dev?: boolean;
63
+ }) => Promise<{
64
+ state: T | null;
65
+ version: string;
66
+ }>;
67
+ /**
68
+ * enables or disables developer mode for the persistence store.
69
+ *
70
+ * when set to `true`, the store may provide additional logging,
71
+ * verbose error reporting, or bypass certain production constraints
72
+ * (such as strict cache validation) to aid in debugging.
73
+ *
74
+ * @default false
75
+ */
76
+ dev?: boolean;
76
77
  }
77
78
  interface SimplePersistence<T> {
78
- /**
79
- * Persists data to storage.
80
- *
81
- * @param id The **unique identifier of the *consumer instance*** making the change. This is NOT the ID of the data (`T`) itself.
82
- * Think of it as the ID of the specific browser tab, component, or module that's currently interacting with the persistence layer.
83
- * It should typically be a **UUID** generated once at the consumer instance's instantiation.
84
- * This `id` is crucial for the `subscribe` method, helping to differentiate updates originating from the current instance versus other instances/tabs, thereby preventing self-triggered notification loops.
85
- * @param state The state (of type T) to persist. This state is generally considered the **global or shared state** that all instances interact with.
86
- * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations (like `IndexedDBPersistence`), this returns a `Promise<boolean>`.
87
- */
88
- set(id: string, state: T): boolean | Promise<boolean>;
89
- /**
90
- * Retrieves the global persisted data from storage.
91
- *
92
- * @returns The retrieved state of type `T`, or `null` if no data is found or if an error occurs during retrieval/parsing.
93
- * For asynchronous implementations, this returns a `Promise<T | null>`.
94
- */
95
- get(): (T | null) | Promise<T | null>;
96
- /**
97
- * Subscribes to changes in the global persisted data that originate from *other* instances of your application (e.g., other tabs or independent components using the same persistence layer).
98
- *
99
- * @param id The **unique identifier of the *consumer instance* subscribing**. This allows the persistence implementation to filter out notifications that were initiated by the subscribing instance itself.
100
- * @param callback The function to call when the global persisted data changes from *another* source. The new state (`T`) is passed as an argument to this callback.
101
- * @returns A function that, when called, will unsubscribe the provided callback from future updates. Call this when your component or instance is no longer active to prevent memory leaks.
102
- */
103
- subscribe(id: string, callback: (state: T) => void): () => void;
104
- /**
105
- * Clears (removes) the entire global persisted data from storage.
106
- *
107
- * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations, this returns a `Promise<boolean>`.
108
- */
109
- clear(): boolean | Promise<boolean>;
110
- /**
111
- * Returns metadata about the persistence layer.
112
- *
113
- * This is useful for distinguishing between multiple apps running on the same host
114
- * (e.g., several apps served at `localhost:3000` that share the same storage key).
115
- *
116
- * @returns An object containing:
117
- * - `version`: The semantic version string of the persistence schema or application.
118
- * - `id`: A unique identifier for the application using this persistence instance.
119
- */
120
- stats(): {
121
- version: string;
122
- id: string;
123
- };
79
+ /**
80
+ * Persists data to storage.
81
+ *
82
+ * @param id The **unique identifier of the *consumer instance*** making the change. This is NOT the ID of the data (`T`) itself.
83
+ * Think of it as the ID of the specific browser tab, component, or module that's currently interacting with the persistence layer.
84
+ * It should typically be a **UUID** generated once at the consumer instance's instantiation.
85
+ * This `id` is crucial for the `subscribe` method, helping to differentiate updates originating from the current instance versus other instances/tabs, thereby preventing self-triggered notification loops.
86
+ * @param state The state (of type T) to persist. This state is generally considered the **global or shared state** that all instances interact with.
87
+ * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations (like `IndexedDBPersistence`), this returns a `Promise<boolean>`.
88
+ */
89
+ set(id: string, state: T): boolean | Promise<boolean>;
90
+ /**
91
+ * Retrieves the global persisted data from storage.
92
+ *
93
+ * @returns The retrieved state of type `T`, or `null` if no data is found or if an error occurs during retrieval/parsing.
94
+ * For asynchronous implementations, this returns a `Promise<T | null>`.
95
+ */
96
+ get(): (T | null) | Promise<T | null>;
97
+ /**
98
+ * Subscribes to changes in the global persisted data that originate from *other* instances of your application (e.g., other tabs or independent components using the same persistence layer).
99
+ *
100
+ * @param id The **unique identifier of the *consumer instance* subscribing**. This allows the persistence implementation to filter out notifications that were initiated by the subscribing instance itself.
101
+ * @param callback The function to call when the global persisted data changes from *another* source. The new state (`T`) is passed as an argument to this callback.
102
+ * @returns A function that, when called, will unsubscribe the provided callback from future updates. Call this when your component or instance is no longer active to prevent memory leaks.
103
+ */
104
+ subscribe(id: string, callback: (state: T) => void): () => void;
105
+ /**
106
+ * Clears (removes) the entire global persisted data from storage.
107
+ *
108
+ * @returns `true` if the operation was successful, `false` if an error occurred. For asynchronous implementations, this returns a `Promise<boolean>`.
109
+ */
110
+ clear(): boolean | Promise<boolean>;
111
+ /**
112
+ * Returns metadata about the persistence layer.
113
+ *
114
+ * This is useful for distinguishing between multiple apps running on the same host
115
+ * (e.g., several apps served at `localhost:3000` that share the same storage key).
116
+ *
117
+ * @returns An object containing:
118
+ * - `version`: The semantic version string of the persistence schema or application.
119
+ * - `id`: A unique identifier for the application using this persistence instance.
120
+ */
121
+ stats(): {
122
+ version: string;
123
+ id: string;
124
+ };
124
125
  }
125
126
  interface StorageEvents {
126
- "store:updated": {
127
- storageKey: string;
128
- instanceId: string;
129
- state: any;
130
- timestamp?: number;
131
- version: string;
132
- app: string;
133
- };
127
+ "store:updated": {
128
+ storageKey: string;
129
+ instanceId: string;
130
+ state: any;
131
+ timestamp?: number;
132
+ version: string;
133
+ app: string;
134
+ };
134
135
  }
135
-
136
+ //#endregion
137
+ //#region src/persistence/webstorage.d.ts
136
138
  /**
137
139
  * Configuration options specific to the WebStoragePersistence adapter.
138
140
  */
139
141
  interface WebStoragePersistenceConfig {
140
- /**
141
- * The key under which data is stored in web storage (e.g., 'user-profile').
142
- */
143
- storageKey: string;
144
- /**
145
- * If true, uses sessionStorage instead of localStorage. Defaults to false.
146
- */
147
- session?: boolean;
142
+ /**
143
+ * The key under which data is stored in web storage (e.g., 'user-profile').
144
+ */
145
+ storageKey: string;
146
+ /**
147
+ * If true, uses sessionStorage instead of localStorage. Defaults to false.
148
+ */
149
+ session?: boolean;
148
150
  }
149
151
  /**
150
152
  * Implements SimplePersistence using web storage (localStorage or sessionStorage).
151
153
  * Supports cross-tab synchronization and data versioning with upgrade handlers.
152
154
  */
153
155
  declare class WebStoragePersistence<T> implements SimplePersistence<T> {
154
- private readonly eventBus;
155
- private readonly storage;
156
- private readonly config;
157
- private initialized;
158
- private initializationCallbacks;
159
- constructor(config: StoreConfig<T> & WebStoragePersistenceConfig);
160
- private initialize;
161
- private _onInitialized;
162
- private initializeEventBus;
163
- private getStoreName;
164
- private setupStorageEventListener;
165
- set(instanceId: string, state: T): boolean;
166
- private _get;
167
- get(): Promise<T | null>;
168
- subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
169
- clear(): boolean;
170
- stats(): {
171
- version: string;
172
- id: string;
173
- };
156
+ private readonly eventBus;
157
+ private readonly storage;
158
+ private readonly config;
159
+ private initialized;
160
+ private initializationCallbacks;
161
+ constructor(config: StoreConfig<T> & WebStoragePersistenceConfig);
162
+ private initialize;
163
+ private _onInitialized;
164
+ private initializeEventBus;
165
+ private getStoreName;
166
+ private setupStorageEventListener;
167
+ set(instanceId: string, state: T): boolean;
168
+ private _get;
169
+ get(): Promise<T | null>;
170
+ subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
171
+ clear(): boolean;
172
+ stats(): {
173
+ version: string;
174
+ id: string;
175
+ };
174
176
  }
175
-
177
+ //#endregion
178
+ //#region src/persistence/indexedb.d.ts
176
179
  interface IndexedDBPersistenceConfig {
177
- store: string;
178
- database: string;
179
- collection: string;
180
- enableTelemetry?: boolean;
180
+ store: string;
181
+ database: string;
182
+ collection: string;
183
+ enableTelemetry?: boolean;
181
184
  }
182
185
  declare class IndexedDBPersistence<T> implements SimplePersistence<T> {
183
- private collection;
184
- private collectionPromise;
185
- private config;
186
- private eventBus;
187
- private initialized;
188
- private _initializing;
189
- private initializationCallbacks;
190
- private doc;
191
- private getStoreName;
192
- constructor(config: StoreConfig<T> & IndexedDBPersistenceConfig);
193
- private initialize;
194
- private _onInitialized;
195
- private getCollection;
196
- /**
197
- * Writes state. Waits for initialisation (migration) to complete first.
198
- */
199
- set(id: string, state: T): Promise<boolean>;
200
- private _read;
201
- /**
202
- * Returns the stored document data (after ensuring it has been
203
- * fully read from the underlying store). The `document.read()`
204
- * call populates internal state and we then return the document
205
- * itself which has all fields available.
206
- */
207
- private _get;
208
- get(): Promise<T | null>;
209
- subscribe(id: string, callback: (state: T) => void): () => void;
210
- clear(): Promise<boolean>;
211
- stats(): {
212
- version: string;
213
- id: string;
214
- };
215
- /**
216
- * Closes this persistence instance, releasing our reference on the
217
- * shared database. The actual database connection is closed only
218
- * when every active store has been released.
219
- */
220
- close(): Promise<void>;
186
+ private collection;
187
+ private collectionPromise;
188
+ private config;
189
+ private eventBus;
190
+ private initialized;
191
+ private _initializing;
192
+ private initializationCallbacks;
193
+ private doc;
194
+ private getStoreName;
195
+ constructor(config: StoreConfig<T> & IndexedDBPersistenceConfig);
196
+ private initialize;
197
+ private _onInitialized;
198
+ private getCollection;
199
+ /**
200
+ * Writes state. Waits for initialisation (migration) to complete first.
201
+ */
202
+ set(id: string, state: T): Promise<boolean>;
203
+ private _read;
204
+ /**
205
+ * Returns the stored document data (after ensuring it has been
206
+ * fully read from the underlying store). The `document.read()`
207
+ * call populates internal state and we then return the document
208
+ * itself which has all fields available.
209
+ */
210
+ private _get;
211
+ get(): Promise<T | null>;
212
+ subscribe(id: string, callback: (state: T) => void): () => void;
213
+ clear(): Promise<boolean>;
214
+ stats(): {
215
+ version: string;
216
+ id: string;
217
+ };
218
+ /**
219
+ * Closes this persistence instance, releasing our reference on the
220
+ * shared database. The actual database connection is closed only
221
+ * when every active store has been released.
222
+ */
223
+ close(): Promise<void>;
221
224
  }
222
-
225
+ //#endregion
226
+ //#region src/persistence/ephemeral.d.ts
223
227
  /**
224
228
  * Implements SimplePersistence using an in-memory store.
225
229
  * Data is NOT persisted across page loads or application restarts.
@@ -236,65 +240,65 @@ declare class IndexedDBPersistence<T> implements SimplePersistence<T> {
236
240
  * SimplePersistence is required.
237
241
  */
238
242
  declare class EphemeralPersistence<T> implements SimplePersistence<T> {
239
- private readonly eventBus;
240
- private inMemoryState;
241
- private readonly config;
242
- /**
243
- * Initializes a new instance of EphemeralPersistence.
244
- * @param config Configuration object for the persistence adapter.
245
- */
246
- constructor(config: StoreConfig<T> & {
247
- storageKey: string;
248
- });
249
- /**
250
- * Initializes the event bus with configured settings for cross-tab communication.
251
- * @returns Configured event bus instance.
252
- */
253
- private initializeEventBus;
254
- /**
255
- * Sets up an internal listener to synchronize the in-memory state
256
- * using the Last Write Wins (LWW) strategy.
257
- */
258
- private setupLwwSynchronizationListener;
259
- /**
260
- * Persists the provided state to in-memory storage and notifies all subscribers
261
- * across tabs. The state is synchronized using LWW.
262
- * @param instanceId Unique identifier of the instance making the update.
263
- * @param state The state to persist.
264
- * @returns True if successful, false if an error occurs.
265
- */
266
- set(instanceId: string, state: T): boolean;
267
- /**
268
- * Retrieves the current synchronized state from in-memory storage.
269
- * @returns The synchronized state, or null if not set or if cleared.
270
- */
271
- get(): T | null;
272
- /**
273
- * Subscribes to updates in the in-memory state.
274
- * The callback is invoked when the state is updated by any instance
275
- * (including other tabs) *excluding the subscribing instance's own 'set' or 'clear' calls*.
276
- * @param instanceId Unique identifier of the subscribing instance.
277
- * @param onStateChange Callback to invoke with the updated state.
278
- * @returns Function to unsubscribe from updates.
279
- */
280
- subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
281
- /**
282
- * Clears the in-memory state of this instance and synchronizes this clear
283
- * across all tabs using the LWW strategy.
284
- * @returns True if successful, false if an error occurs.
285
- */
286
- clear(): boolean;
287
- /**
288
- * Returns metadata about the persistence layer.
289
- *
290
- * @returns An object containing:
291
- * - `version`: The semantic version string of the persistence schema or application.
292
- * - `id`: A unique identifier for the application using this persistence instance.
293
- */
294
- stats(): {
295
- version: string;
296
- id: string;
297
- };
243
+ private readonly eventBus;
244
+ private inMemoryState;
245
+ private readonly config;
246
+ /**
247
+ * Initializes a new instance of EphemeralPersistence.
248
+ * @param config Configuration object for the persistence adapter.
249
+ */
250
+ constructor(config: StoreConfig<T> & {
251
+ storageKey: string;
252
+ });
253
+ /**
254
+ * Initializes the event bus with configured settings for cross-tab communication.
255
+ * @returns Configured event bus instance.
256
+ */
257
+ private initializeEventBus;
258
+ /**
259
+ * Sets up an internal listener to synchronize the in-memory state
260
+ * using the Last Write Wins (LWW) strategy.
261
+ */
262
+ private setupLwwSynchronizationListener;
263
+ /**
264
+ * Persists the provided state to in-memory storage and notifies all subscribers
265
+ * across tabs. The state is synchronized using LWW.
266
+ * @param instanceId Unique identifier of the instance making the update.
267
+ * @param state The state to persist.
268
+ * @returns True if successful, false if an error occurs.
269
+ */
270
+ set(instanceId: string, state: T): boolean;
271
+ /**
272
+ * Retrieves the current synchronized state from in-memory storage.
273
+ * @returns The synchronized state, or null if not set or if cleared.
274
+ */
275
+ get(): T | null;
276
+ /**
277
+ * Subscribes to updates in the in-memory state.
278
+ * The callback is invoked when the state is updated by any instance
279
+ * (including other tabs) *excluding the subscribing instance's own 'set' or 'clear' calls*.
280
+ * @param instanceId Unique identifier of the subscribing instance.
281
+ * @param onStateChange Callback to invoke with the updated state.
282
+ * @returns Function to unsubscribe from updates.
283
+ */
284
+ subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
285
+ /**
286
+ * Clears the in-memory state of this instance and synchronizes this clear
287
+ * across all tabs using the LWW strategy.
288
+ * @returns True if successful, false if an error occurs.
289
+ */
290
+ clear(): boolean;
291
+ /**
292
+ * Returns metadata about the persistence layer.
293
+ *
294
+ * @returns An object containing:
295
+ * - `version`: The semantic version string of the persistence schema or application.
296
+ * - `id`: A unique identifier for the application using this persistence instance.
297
+ */
298
+ stats(): {
299
+ version: string;
300
+ id: string;
301
+ };
298
302
  }
299
-
300
- export { EphemeralPersistence, IndexedDBPersistence, type IndexedDBPersistenceConfig, type SimplePersistence, type StorageEvents, type StoreConfig, WebStoragePersistence, type WebStoragePersistenceConfig };
303
+ //#endregion
304
+ export { EphemeralPersistence, IndexedDBPersistence, IndexedDBPersistenceConfig, SimplePersistence, StorageEvents, StoreConfig, WebStoragePersistence, WebStoragePersistenceConfig };
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e,t,i=require("@asaidimu/utils-events"),r=require("@asaidimu/utils-database"),s=require("@asaidimu/utils-error"),n=Object.create,o=Object.defineProperty,a=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,u=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,h=(e={"node_modules/.bun/@asaidimu+query@1.1.2/node_modules/@asaidimu/query/index.js"(e,t){var i,r=Object.defineProperty,s=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,o=Object.prototype.hasOwnProperty,a={};((e,t)=>{for(var i in t)r(e,i,{get:t[i],enumerable:!0})})(a,{QueryBuilder:()=>c,createJoiner:()=>g,createMatcher:()=>l,createPaginator:()=>q,createProjector:()=>E,createSorter:()=>b}),t.exports=(i=a,((e,t,i,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let c of n(t))!o.call(e,c)&&c!==i&&r(e,c,{get:()=>t[c],enumerable:!(a=s(t,c))||a.enumerable});return e})(r({},"__esModule",{value:!0}),i));var c=class{query;constructor(){this.query={}}where(e){return this.query.filters=e,this}orderBy(e,t){return this.query.sort||(this.query.sort=[]),this.query.sort.push({field:e,direction:t}),this}offset(e,t){return this.query.pagination={type:"offset",offset:e,limit:t},this}cursor(e,t,i){return this.query.pagination={type:"cursor",cursor:e,limit:t,direction:i},this}include(e){return this.query.projection||(this.query.projection={}),this.query.projection.include=e,this}exclude(e){return this.query.projection||(this.query.projection={}),this.query.projection.exclude=e,this}computed(e,t){return this.query.projection||(this.query.projection={}),this.query.projection.computed||(this.query.projection.computed=[]),this.query.projection.computed.push({type:"computed",expression:e,alias:t}),this}case(e,t,i){return this.query.projection||(this.query.projection={}),this.query.projection.computed||(this.query.projection.computed=[]),this.query.projection.computed.push({type:"case",conditions:e,else:t,alias:i}),this}join(e,t,i){return this.query.joins||(this.query.joins=[]),this.query.joins.push({relation:e,alias:i,query:t}),this}aggregate(e,t){return this.query.aggregations={groupBy:e,metrics:t},this}window(e){return this.query.window||(this.query.window=[]),this.query.window.push(e),this}hint(e){return this.query.hints||(this.query.hints=[]),this.query.hints.push(e),this}build(){return this.query}};function u(e){function t(e,t){return function(e){return"field"===e?.type}(t)?e[t.field]:function(e){return"value"===e?.type}(t)?t.value:function(e){return"function"===e?.type}(t)?r(t,e):function(e){return"computed"===e?.type}(t)?r(t.expression,e):function(e){return"case"===e?.type}(t)?function(e,t){for(let i of t.conditions)if(s(e,i.when))return i.then;return t.else}(e,t):t}let i=new Map([["and",(e,t)=>t.every(t=>s(e,t))],["or",(e,t)=>t.some(t=>s(e,t))],["not",(e,t)=>!t.every(t=>s(e,t))],["nor",(e,t)=>!t.some(t=>s(e,t))],["xor",(e,t)=>1===t.filter(t=>s(e,t)).length]]);function r(i,r){let s=i.arguments.map(e=>t(r,e));if(e[i.function])return e[i.function](...s);throw new Error(`Function ${i.function} not found!`)}function s(r,s){if(function(e){return!!e&&void 0!==e.conditions}(s))return function(e,t){let{operator:r,conditions:s}=t,n=i.get(r);if(n)return n(e,s);throw new Error(`Unsupported logical operator: ${r}`)}(r,s);if(!s||!s.field)return!1;let{field:n,operator:o,value:a}=s,c=r[n],u=t(r,a),l=new Map([["eq",(e,t)=>e===t],["neq",(e,t)=>e!==t],["lt",(e,t)=>e<t],["lte",(e,t)=>e<=t],["gt",(e,t)=>e>t],["gte",(e,t)=>e>=t],["in",(e,t)=>Array.isArray(t)&&t.includes(e)],["nin",(e,t)=>Array.isArray(t)&&!t.includes(e)],["contains",(e,t)=>"string"==typeof e?e.includes(t):!!Array.isArray(e)&&e.includes(a)],["ncontains",(e,t)=>"string"==typeof e&&!e.includes(t)],["startswith",(e,t)=>"string"==typeof e&&e.startsWith(t)],["endswith",(e,t)=>"string"==typeof e&&e.endsWith(t)],["exists",e=>null!=e],["nexists",e=>null==e]]),h=e[o]||l.get(o);if(h)return h(c,u);throw new Error(`Unsupported comparison operator: ${o}`)}return{resolve:t,evaluate:s}}function l(e){let{evaluate:t}=u(e),i=new WeakMap;function r(e,r){let s=i.get(e);s||(s=new Map,i.set(e,s));let n=JSON.stringify(r);if(s.has(n))return s.get(n);let o=t(e,r);return s.set(n,o),o}return{matcher:r,match:r}}var h=class extends Error{constructor(e,t){super(e),this.code=t,this.name="JoinError"}},p=e=>e&&"field"in e&&"operator"in e&&"value"in e,d=(e,t)=>{if(e){if(p(e)&&e){let i=(e=>"object"==typeof e&&null!==e&&"type"in e&&"field"===e.type)(e.value)?((e,t)=>t.split(".").reduce((e,t)=>e?.[t],e))(t,e.value.field):e.value;return{...e,value:i}}if((e=>"operator"in e&&"conditions"in e)(e)){let i={...e};return e.conditions&&(i.conditions=e.conditions.map(e=>d(e,t))),i}return e}},f=async(e,t,i,r)=>{try{if(((e,t)=>{if(!e.relation)throw new h("Join configuration must specify a relation","INVALID_CONFIG");if(!t[e.relation])throw new h(`Collection "${e.relation}" not found in database`,"COLLECTION_NOT_FOUND");if(e.alias&&"string"!=typeof e.alias)throw new h("Join alias must be a string","INVALID_ALIAS")})(i,e),!Array.isArray(t))throw new h("Source data must be an array","INVALID_SOURCE_DATA");let s,n=e[i.relation];return i.query?.filters&&p(i.query.filters)&&(s=((e,t)=>{let i=new Map;return e.forEach(e=>{let r=e[t];i.has(r)||i.set(r,[]),i.get(r).push(e)}),i})(n,i.query.filters.field)),(await Promise.all(t.map(async e=>{let t,o=((e,t)=>{if(!e)return{};let i=d(e.filters,t);return{...e,filters:i}})(i.query,e);return t=o.filters&&p(o.filters)&&s?.has(o.filters.value)?s.get(o.filters.value)||[]:n.filter(e=>r.matcher(e,o.filters)),((e,t,i)=>{let r=i.alias||i.relation;return[{...e,[r]:t}]})(e,await[e=>o.sort?r.sorter(e,o.sort):e,e=>o.projection?r.projector(e,o.projection):e,async e=>o.pagination?await r.paginator(e,o.pagination):e].reduce(async(e,t)=>t(await e),Promise.resolve(t)),i)}))).flat()}catch(e){throw e instanceof h?e:new h(`Join operation failed: ${e.message}`,"JOIN_EXECUTION_ERROR")}},y=async(e,t,i,r)=>i.reduce(async(t,i)=>f(e,await t,i,r),Promise.resolve(t));function g(){return{join:y}}var m=class extends Error{constructor(e,t){super(`Unsupported comparison between ${typeof e} and ${typeof t}`),this.name="UnsupportedComparisonError"}},w=class extends Error{constructor(e){super(`Unsupported sort direction: ${e}`),this.name="InvalidSortDirectionError"}};function v(e,t,i){if(e===t)return 0;if(null==e||null==t)return null==e?"asc"===i?-1:1:"asc"===i?1:-1;if("string"==typeof e&&"string"==typeof t)return"asc"===i?e.localeCompare(t):t.localeCompare(e);if("number"==typeof e&&"number"==typeof t)return"asc"===i?e-t:t-e;throw new m(e,t)}function _(e,t){let i=Array.from(e);return 0===t.length?i:i.sort((e,i)=>{for(let r of t){let{field:t,direction:s}=r,n=e[t],o=i[t];try{if("asc"!==s&&"desc"!==s)throw new w(s);let e=v(n,o,s);if(0!==e)return e}catch(e){throw e instanceof m||e instanceof w?e:new Error(`Error comparing field '${t}': ${e.message}`)}}return 0})}function b(){return{sort:_}}function E(e){let{resolve:t}=u(e);function i(e,r){let s={};return r.include?.length&&function(e,t,r){for(let s of t){if("string"==typeof s){let t=s;r[t]=e[t];continue}for(let[t,n]of Object.entries(s))if(Object.prototype.hasOwnProperty.call(e,t)){let s=i(e[t],n);r[t]=s}}}(e,r.include,s),r.exclude?.length&&function(e,t,r){0===Object.keys(r).length&&Object.assign(r,e);for(let e of t)if("string"!=typeof e)for(let[t,s]of Object.entries(e)){if(!Object.prototype.hasOwnProperty.call(r,t))continue;let e=r[t];e&&"object"==typeof e?r[t]=i(e,s):delete r[t]}else delete r[e]}(e,r.exclude,s),r.computed?.length&&function(e,i,r){for(let s of i)r[s.alias]=t(e,s)}(e,r.computed,s),s}return{project:i}}async function*S(e,t,i=e=>String(e)){"offset"===t.type?yield*async function*(e,t){let{offset:i,limit:r}=t,s=0,n=r,o=[];for await(let t of e)n<=0&&(yield o,o=[],n=r),s<i?s++:(o.push(t),n--);o.length>0&&(yield o)}(e,t):yield*async function*(e,t,i){let{cursor:r,limit:s,direction:n}=t,o=s,a=void 0===r,c=[];if("forward"===n)for await(let t of e)o<=0&&(yield c,c=[],o=s),a?(c.push(t),o--):a=i(t)===r;else{let t=[];for await(let i of e)t.push(i);for(let e=t.length-1;e>=0;e--){let n=t[e];a?(c.push(n),o--,o<=0&&(yield c,c=[],o=s)):a=i(n)===r}}c.length>0&&(yield c)}(e,t,i)}function q(){return{paginate:S}}}},function(){return t||(0,e[c(e)[0]])((t={exports:{}}).exports,t),t.exports}),p=((e,t,i)=>(i=null!=e?n(u(e)):{},((e,t,i,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let s of c(t))l.call(e,s)||s===i||o(e,s,{get:()=>t[s],enumerable:!(r=a(t,s))||r.enumerable});return e})(e&&e.__esModule?i:o(i,"default",{value:e,enumerable:!0}),e)))(h()),d=class e extends s.SystemError{constructor(t,i){super({code:"SYNC_ERROR",message:t,cause:i}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},f=class e extends d{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},y=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const i=new Promise(e=>t=e);if(this.waiters.push(t),null==e)return void await i;let r;await Promise.race([i.then(()=>clearTimeout(r)),new Promise((i,s)=>{r=setTimeout(()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),s(new f("Mutex lock timed out"))},e)})])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},g=class{mutex=new y({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,i="Operation timed out"){if(null==t)return e;let r;return Promise.race([e.then(e=>(clearTimeout(r),e)),new Promise((e,s)=>{r=setTimeout(()=>s(new f(i)),t)})])}},m=class{constructor(e,t,i={}){this.factory=e,this.onCleanup=t,this.options=i}_count=0;init=new g({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask(()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())})):void(this.cleanupTimer=setTimeout(()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()},e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}},w=class e{static dbResources=new Map;static eventBusMap=new Map;static createDatabaseFactory(e){return async()=>{const{database:t,enableTelemetry:i=!1,collection:s="stores"}=e,n=await r.DatabaseConnection({database:t,enableTelemetry:i},r.createIndexedDbStore);try{await n.createCollection({name:s,version:"1.0.0",nestedSchemas:{},fields:{store:{name:"store",type:"string",required:!0},data:{name:"data",type:"object",required:!0},version:{name:"version",type:"string",required:!0},app:{name:"app",type:"string",required:!0}}})}catch(e){if(e instanceof r.DatabaseError&&"SCHEMA_ALREADY_EXISTS"!==e.type)throw e}return n}}static createDatabaseCleanup(t){return i=>{i?.close();const r=[];e.eventBusMap.forEach((e,i)=>{i.startsWith(`${t}_store_`)&&(e.clear(),r.push(i))}),r.forEach(t=>e.eventBusMap.delete(t))}}static async acquireDatabase(t){const i=t.database;if(!e.dbResources.has(i)){const r=new m(e.createDatabaseFactory(t),e.createDatabaseCleanup(i),{gracePeriod:"microtask"});e.dbResources.set(i,r)}return e.dbResources.get(i).acquire()}static releaseDatabase(t){const i=e.dbResources.get(t);i&&i.release()}static async getCollection(t){const i=await e.acquireDatabase(t),r=t.collection??"stores";return i.collection(r)}static getEventBus(t,r){const s=`${t}_store_${r}`;return e.eventBusMap.has(s)||e.eventBusMap.set(s,i.createEventBus({errorHandler:e=>console.error(`Event bus error for ${t}:${r}:`,e),broadcast:{channel:s}})),e.eventBusMap.get(s)}};exports.EphemeralPersistence=class{eventBus;inMemoryState=null;config;constructor(e){this.config=e,this.eventBus=this.initializeEventBus(),this.setupLwwSynchronizationListener()}initializeEventBus(){const e={errorHandler:e=>console.error(`Event bus error for ${this.config.storageKey} (Ephemeral LWW):`,e)};return"undefined"!=typeof process&&"test"===process.env.NODE_ENV||(e.broadcast={channel:`ephemeral_lww_${this.config.storageKey}`}),i.createEventBus(e)}setupLwwSynchronizationListener(){this.eventBus.subscribe("store:updated",({storageKey:e,instanceId:t,state:i,timestamp:r,version:s})=>{e===this.config.storageKey&&(!this.inMemoryState||r&&r>this.inMemoryState.timestamp)&&(this.inMemoryState={data:i,timestamp:r,instanceId:t,version:s})})}set(e,t){try{const i=Date.now();return this.inMemoryState={data:structuredClone(t),timestamp:i,instanceId:e,version:this.config.version},this.eventBus.emit({name:"store:updated",payload:{storageKey:this.config.storageKey,instanceId:e,state:t,timestamp:i,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to set state in EphemeralPersistence (LWW) for ${this.config.storageKey}:`,e),!1}}get(){return this.inMemoryState?.data??null}subscribe(e,t){return this.eventBus.subscribe("store:updated",({storageKey:i,instanceId:r,state:s})=>{i===this.config.storageKey&&r!==e&&t(s)})}clear(){try{const e=Date.now(),t="clear-initiator";return this.inMemoryState={data:null,timestamp:e,instanceId:t,version:this.config.version},this.eventBus.emit({name:"store:updated",payload:{storageKey:this.config.storageKey,instanceId:t,state:null,timestamp:e,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to clear state in EphemeralPersistence (LWW) for ${this.config.storageKey}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}},exports.IndexedDBPersistence=class{collection=null;collectionPromise;config;eventBus;initialized=!1;_initializing=!1;initializationCallbacks=[];doc=null;getStoreName(){return`_${this.config.app}_${this.config.store}_`}constructor(e){this.config=e,this.collectionPromise=w.getCollection(this.config),this.collectionPromise.then(e=>{this.collection=e,this.initialize()}).catch(e=>{console.error(`Failed to initialize collection for store ${this.getStoreName()}:`,e)}),this.eventBus=w.getEventBus(this.config.database,this.getStoreName()),this.eventBus.subscribe("store:updated",({storageKey:e})=>{e===this.getStoreName()&&(this.doc=null)})}async initialize(){this._initializing=!0;try{const e=await this._get();if(e&&e.version!==this.config.version&&this.config.onUpgrade){const{state:t}=await this.config.onUpgrade({data:e.data,version:e.version,app:e.app});await this.set("migration",t)}this.initialized=!0,this.initializationCallbacks.forEach(e=>e()),this.initializationCallbacks=[]}catch(e){console.error(`Failed to initialize and upgrade store ${this.getStoreName()}:`,e)}finally{this._initializing=!1}}_onInitialized(e){this.initialized?e():this.initializationCallbacks.push(e)}async getCollection(){return this.collection??this.collectionPromise}async set(e,t){this.initialized||this._initializing||await new Promise(e=>this._onInitialized(e));try{const i=await this.getCollection(),r=await this._read(),s={store:this.getStoreName(),data:t,version:this.config.version,app:this.config.app};let n;return r?n=await r.update(s):(this.doc=await i.create(s),n=!0),n&&this.eventBus.emit({name:"store:updated",payload:{storageKey:this.getStoreName(),instanceId:e,state:t,version:this.config.version,app:this.config.app}}),n}catch(t){return console.error(`Failed to set state for store ${this.getStoreName()} in database ${this.config.database} by instance ${e}:`,t),!1}}async _read(){if(this.doc)return this.doc;const e=await this.getCollection(),t=(new p.QueryBuilder).where({field:"store",operator:"eq",value:this.getStoreName()}).build();return this.doc=await e.find(t.filters),this.doc}async _get(){try{const e=await this._read();return e?e.read().then(()=>e):null}catch(e){return console.error(`Failed to get state for store ${this.getStoreName()} in database ${this.config.database}:`,e),null}}async get(){this.initialized||await new Promise(e=>this._onInitialized(e));const e=await this._get();return e?e.data:null}subscribe(e,t){return this.eventBus.subscribe("store:updated",({storageKey:i,instanceId:r,state:s})=>{i===this.getStoreName()&&r!==e&&t(s)})}async clear(){this.initialized||await new Promise(e=>this._onInitialized(e));try{const e=await this._read();return!e||!await e.delete()||(this.doc=null,this.eventBus.emit({name:"store:updated",payload:{storageKey:this.getStoreName(),instanceId:"",state:null,version:this.config.version,app:this.config.app}}),!0)}catch(e){return console.error(`Failed to clear state for store ${this.getStoreName()} in database ${this.config.database}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}async close(){w.releaseDatabase(this.config.database)}},exports.WebStoragePersistence=class{eventBus;storage;config;initialized=!1;initializationCallbacks=[];constructor(e){this.config=e,this.storage=e.session?sessionStorage:localStorage,this.eventBus=this.initializeEventBus(),this.initialize(),e.session||this.setupStorageEventListener()}async initialize(){try{const e=this.storage.getItem(this.getStoreName());if(e){const t=JSON.parse(e);if(t.version!==this.config.version&&this.config.onUpgrade){const{state:e}=await this.config.onUpgrade({data:t.state,version:t.version,app:t.app});this.set("migration",e)}}this.initialized=!0,this.initializationCallbacks.forEach(e=>e()),this.initializationCallbacks=[]}catch(e){console.error(`Failed to initialize WebStoragePersistence for ${this.config.storageKey}:`,e)}}_onInitialized(e){this.initialized?e():this.initializationCallbacks.push(e)}initializeEventBus(){const e={batch:{size:0,delay:0},errorHandler:e=>console.error(`Event bus error for ${this.config.storageKey}:`,e)};return"undefined"!=typeof process&&"test"===process.env.NODE_ENV||(e.broadcast={channel:`storage_${this.getStoreName()}`}),i.createEventBus(e)}getStoreName(){return`_${this.config.app}_${this.config.storageKey}_`}setupStorageEventListener(){window.addEventListener("storage",e=>{if(e.key===this.getStoreName()&&e.newValue)try{const t=JSON.parse(e.newValue);t&&this.eventBus.emit({name:"store:updated",payload:{storageKey:this.config.storageKey,instanceId:"external",state:t.state,version:t.version,app:t.app}})}catch(e){console.error("Failed to parse storage event data:",e)}})}set(e,t){try{const i={state:structuredClone(t),version:this.config.version,app:this.config.app},r=JSON.stringify(i);return this.storage.setItem(this.getStoreName(),r),this.eventBus.emit({name:"store:updated",payload:{storageKey:this.config.storageKey,instanceId:e,state:t,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to persist state to web storage for ${this.config.storageKey}:`,e),!1}}_get(){try{const e=this.storage.getItem(this.getStoreName());if(!e)return null;return JSON.parse(e).state}catch(e){return console.error(`Failed to retrieve state from web storage for ${this.config.storageKey}:`,e),null}}async get(){return this.initialized||await new Promise(e=>{this._onInitialized(e)}),this._get()}subscribe(e,t){return this.eventBus.subscribe("store:updated",({storageKey:i,instanceId:r,state:s})=>{i===this.config.storageKey&&r!==e&&t(s)})}clear(){try{return this.storage.removeItem(this.getStoreName()),this.eventBus.emit({name:"store:updated",payload:{storageKey:this.config.storageKey,instanceId:"clear-initiator",state:null,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.config.storageKey}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}};
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);let t=require("@asaidimu/utils-events"),n=require("@asaidimu/utils-database"),r=require("@asaidimu/utils-sync");var i=class{eventBus;storage;config;initialized=!1;initializationCallbacks=[];constructor(e){this.config=e,this.storage=e.session?sessionStorage:localStorage,this.eventBus=this.initializeEventBus(),this.initialize(),e.session||this.setupStorageEventListener()}async initialize(){try{let e=this.storage.getItem(this.getStoreName());if(e){let t=JSON.parse(e);if(t.version!==this.config.version&&this.config.onUpgrade){let{state:e}=await this.config.onUpgrade({data:t.state,version:t.version,app:t.app});this.set(`migration`,e)}}this.initialized=!0,this.initializationCallbacks.forEach(e=>e()),this.initializationCallbacks=[]}catch(e){console.error(`Failed to initialize WebStoragePersistence for ${this.config.storageKey}:`,e)}}_onInitialized(e){this.initialized?e():this.initializationCallbacks.push(e)}initializeEventBus(){let e={batch:{size:0,delay:0},errorHandler:e=>console.error(`Event bus error for ${this.config.storageKey}:`,e)};return(typeof process>`u`||process.env.NODE_ENV!==`test`)&&(e.broadcast={channel:`storage_${this.getStoreName()}`}),(0,t.createEventBus)(e)}getStoreName(){return`_${this.config.app}_${this.config.storageKey}_`}setupStorageEventListener(){window.addEventListener(`storage`,e=>{if(!(e.key!==this.getStoreName()||!e.newValue))try{let t=JSON.parse(e.newValue);t&&this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.config.storageKey,instanceId:`external`,state:t.state,version:t.version,app:t.app}})}catch(e){console.error(`Failed to parse storage event data:`,e)}})}set(e,t){try{let n={state:structuredClone(t),version:this.config.version,app:this.config.app},r=JSON.stringify(n);return this.storage.setItem(this.getStoreName(),r),this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.config.storageKey,instanceId:e,state:t,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to persist state to web storage for ${this.config.storageKey}:`,e),!1}}_get(){try{let e=this.storage.getItem(this.getStoreName());return e?JSON.parse(e).state:null}catch(e){return console.error(`Failed to retrieve state from web storage for ${this.config.storageKey}:`,e),null}}async get(){return this.initialized||await new Promise(e=>{this._onInitialized(e)}),this._get()}subscribe(e,t){return this.eventBus.subscribe(`store:updated`,({storageKey:n,instanceId:r,state:i})=>{n===this.config.storageKey&&r!==e&&t(i)})}clear(){try{return this.storage.removeItem(this.getStoreName()),this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.config.storageKey,instanceId:`clear-initiator`,state:null,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to clear persisted state for ${this.config.storageKey}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}},a=e(((e,t)=>{var n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,o=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},s=(e,t,o,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(let c of i(t))!a.call(e,c)&&c!==o&&n(e,c,{get:()=>t[c],enumerable:!(s=r(t,c))||s.enumerable});return e},c=e=>s(n({},`__esModule`,{value:!0}),e),l={};o(l,{QueryBuilder:()=>u,createJoiner:()=>j,createMatcher:()=>v,createPaginator:()=>z,createProjector:()=>L,createSorter:()=>I}),t.exports=c(l);var u=class{query;constructor(){this.query={}}where(e){return this.query.filters=e,this}orderBy(e,t){return this.query.sort||(this.query.sort=[]),this.query.sort.push({field:e,direction:t}),this}offset(e,t){return this.query.pagination={type:`offset`,offset:e,limit:t},this}cursor(e,t,n){return this.query.pagination={type:`cursor`,cursor:e,limit:t,direction:n},this}include(e){return this.query.projection||(this.query.projection={}),this.query.projection.include=e,this}exclude(e){return this.query.projection||(this.query.projection={}),this.query.projection.exclude=e,this}computed(e,t){return this.query.projection||(this.query.projection={}),this.query.projection.computed||(this.query.projection.computed=[]),this.query.projection.computed.push({type:`computed`,expression:e,alias:t}),this}case(e,t,n){return this.query.projection||(this.query.projection={}),this.query.projection.computed||(this.query.projection.computed=[]),this.query.projection.computed.push({type:`case`,conditions:e,else:t,alias:n}),this}join(e,t,n){return this.query.joins||(this.query.joins=[]),this.query.joins.push({relation:e,alias:n,query:t}),this}aggregate(e,t){return this.query.aggregations={groupBy:e,metrics:t},this}window(e){return this.query.window||(this.query.window=[]),this.query.window.push(e),this}hint(e){return this.query.hints||(this.query.hints=[]),this.query.hints.push(e),this}build(){return this.query}};function d(e){function t(e,t){return f(t)?e[t.field]:p(t)?t.value:g(t)?i(t,e):m(t)?i(t.expression,e):h(t)?a(e,t):t}let n=new Map([[`and`,(e,t)=>t.every(t=>o(e,t))],[`or`,(e,t)=>t.some(t=>o(e,t))],[`not`,(e,t)=>!t.every(t=>o(e,t))],[`nor`,(e,t)=>!t.some(t=>o(e,t))],[`xor`,(e,t)=>t.filter(t=>o(e,t)).length===1]]);function r(e,t){let{operator:r,conditions:i}=t,a=n.get(r);if(a)return a(e,i);throw Error(`Unsupported logical operator: ${r}`)}function i(n,r){let i=n.arguments.map(e=>t(r,e));if(e[n.function])return e[n.function](...i);throw Error(`Function ${n.function} not found!`)}function a(e,t){for(let n of t.conditions)if(o(e,n.when))return n.then;return t.else}function o(n,i){if(_(i))return r(n,i);if(!i||!i.field)return!1;let{field:a,operator:o,value:s}=i,c=n[a],l=t(n,s),u=new Map([[`eq`,(e,t)=>e===t],[`neq`,(e,t)=>e!==t],[`lt`,(e,t)=>e<t],[`lte`,(e,t)=>e<=t],[`gt`,(e,t)=>e>t],[`gte`,(e,t)=>e>=t],[`in`,(e,t)=>Array.isArray(t)&&t.includes(e)],[`nin`,(e,t)=>Array.isArray(t)&&!t.includes(e)],[`contains`,(e,t)=>typeof e==`string`?e.includes(t):Array.isArray(e)?e.includes(s):!1],[`ncontains`,(e,t)=>typeof e==`string`&&!e.includes(t)],[`startswith`,(e,t)=>typeof e==`string`&&e.startsWith(t)],[`endswith`,(e,t)=>typeof e==`string`&&e.endsWith(t)],[`exists`,e=>e!=null],[`nexists`,e=>e==null]]),d=e[o]||u.get(o);if(d)return d(c,l);throw Error(`Unsupported comparison operator: ${o}`)}return{resolve:t,evaluate:o}}function f(e){return e?.type===`field`}function p(e){return e?.type===`value`}function m(e){return e?.type===`computed`}function h(e){return e?.type===`case`}function g(e){return e?.type===`function`}function _(e){return e?e.conditions!==void 0:!1}function v(e){let{evaluate:t}=d(e),n=new WeakMap;function r(e,r){let i=n.get(e);i||(i=new Map,n.set(e,i));let a=JSON.stringify(r);if(i.has(a))return i.get(a);let o=t(e,r);return i.set(a,o),o}return{matcher:r,match:r}}var y=class extends Error{constructor(e,t){super(e),this.code=t,this.name=`JoinError`}},b=e=>e&&`field`in e&&`operator`in e&&`value`in e,x=e=>`operator`in e&&`conditions`in e,S=e=>typeof e==`object`&&!!e&&`type`in e&&e.type===`field`,C=(e,t)=>{if(!e.relation)throw new y(`Join configuration must specify a relation`,`INVALID_CONFIG`);if(!t[e.relation])throw new y(`Collection "${e.relation}" not found in database`,`COLLECTION_NOT_FOUND`);if(e.alias&&typeof e.alias!=`string`)throw new y(`Join alias must be a string`,`INVALID_ALIAS`)},w=(e,t)=>t.split(`.`).reduce((e,t)=>e?.[t],e),T=(e,t)=>{if(e){if(b(e)&&e){let n=S(e.value)?w(t,e.value.field):e.value;return{...e,value:n}}if(x(e)){let n={...e};return e.conditions&&(n.conditions=e.conditions.map(e=>T(e,t))),n}return e}},E=(e,t)=>{if(!e)return{};let n=T(e.filters,t);return{...e,filters:n}},D=(e,t,n)=>{let r=n.alias||n.relation;return[{...e,[r]:t}]},O=(e,t)=>{let n=new Map;return e.forEach(e=>{let r=e[t];n.has(r)||n.set(r,[]),n.get(r).push(e)}),n},k=async(e,t,n,r)=>{try{if(C(n,e),!Array.isArray(t))throw new y(`Source data must be an array`,`INVALID_SOURCE_DATA`);let i=e[n.relation],a;return n.query?.filters&&b(n.query.filters)&&(a=O(i,n.query.filters.field)),(await Promise.all(t.map(async e=>{let t=E(n.query,e),o;return o=t.filters&&b(t.filters)&&a?.has(t.filters.value)?a.get(t.filters.value)||[]:i.filter(e=>r.matcher(e,t.filters)),D(e,await[e=>t.sort?r.sorter(e,t.sort):e,e=>t.projection?r.projector(e,t.projection):e,async e=>t.pagination?await r.paginator(e,t.pagination):e].reduce(async(e,t)=>t(await e),Promise.resolve(o)),n)}))).flat()}catch(e){throw e instanceof y?e:new y(`Join operation failed: ${e.message}`,`JOIN_EXECUTION_ERROR`)}},A=async(e,t,n,r)=>n.reduce(async(t,n)=>k(e,await t,n,r),Promise.resolve(t));function j(){return{join:A}}var M=class extends Error{constructor(e,t){super(`Unsupported comparison between ${typeof e} and ${typeof t}`),this.name=`UnsupportedComparisonError`}},N=class extends Error{constructor(e){super(`Unsupported sort direction: ${e}`),this.name=`InvalidSortDirectionError`}};function P(e,t,n){if(e===t)return 0;if(e==null||t==null)return e==null?n===`asc`?-1:1:n===`asc`?1:-1;if(typeof e==`string`&&typeof t==`string`)return n===`asc`?e.localeCompare(t):t.localeCompare(e);if(typeof e==`number`&&typeof t==`number`)return n===`asc`?e-t:t-e;throw new M(e,t)}function F(e,t){let n=Array.from(e);return t.length===0?n:n.sort((e,n)=>{for(let r of t){let{field:t,direction:i}=r,a=e[t],o=n[t];try{if(i!==`asc`&&i!==`desc`)throw new N(i);let e=P(a,o,i);if(e!==0)return e}catch(e){throw e instanceof M||e instanceof N?e:Error(`Error comparing field '${t}': ${e.message}`)}}return 0})}function I(){return{sort:F}}function L(e){let{resolve:t}=d(e);function n(e,t,n){for(let r of t){if(typeof r==`string`){let t=r;n[t]=e[t];continue}for(let[t,i]of Object.entries(r))Object.prototype.hasOwnProperty.call(e,t)&&(n[t]=a(e[t],i))}}function r(e,t,n){Object.keys(n).length===0&&Object.assign(n,e);for(let e of t){if(typeof e==`string`){let t=e;delete n[t];continue}for(let[t,r]of Object.entries(e)){if(!Object.prototype.hasOwnProperty.call(n,t))continue;let e=n[t];e&&typeof e==`object`?n[t]=a(e,r):delete n[t]}}}function i(e,n,r){for(let i of n)r[i.alias]=t(e,i)}function a(e,t){let a={};return t.include?.length&&n(e,t.include,a),t.exclude?.length&&r(e,t.exclude,a),t.computed?.length&&i(e,t.computed,a),a}return{project:a}}async function*R(e,t,n=e=>String(e)){t.type===`offset`?yield*B(e,t):yield*V(e,t,n)}function z(){return{paginate:R}}async function*B(e,t){let{offset:n,limit:r}=t,i=0,a=r,o=[];for await(let t of e){if(a<=0&&(yield o,o=[],a=r),i<n){i++;continue}o.push(t),a--}o.length>0&&(yield o)}async function*V(e,t,n){let{cursor:r,limit:i,direction:a}=t,o=i,s=r===void 0,c=[];if(a===`forward`)for await(let t of e){if(o<=0&&(yield c,c=[],o=i),!s){s=n(t)===r;continue}c.push(t),o--}else{let t=[];for await(let n of e)t.push(n);for(let e=t.length-1;e>=0;e--){let a=t[e];if(!s){s=n(a)===r;continue}c.push(a),o--,o<=0&&(yield c,c=[],o=i)}}c.length>0&&(yield c)}0&&(t.exports={QueryBuilder,createJoiner,createMatcher,createPaginator,createProjector,createSorter})}))(),o=class e{static dbResources=new Map;static eventBusMap=new Map;static createDatabaseFactory(e){return async()=>{let{database:t,enableTelemetry:r=!1,collection:i=`stores`}=e,a=await(0,n.DatabaseConnection)({database:t,enableTelemetry:r},n.createIndexedDbStore);try{await a.createCollection({name:i,version:`1.0.0`,nestedSchemas:{},fields:{store:{name:`store`,type:`string`,required:!0},data:{name:`data`,type:`object`,required:!0},version:{name:`version`,type:`string`,required:!0},app:{name:`app`,type:`string`,required:!0}}})}catch(e){if(e instanceof n.DatabaseError&&e.type!==`SCHEMA_ALREADY_EXISTS`)throw e}return a}}static createDatabaseCleanup(t){return n=>{n?.close();let r=[];e.eventBusMap.forEach((e,n)=>{n.startsWith(`${t}_store_`)&&(e.clear(),r.push(n))}),r.forEach(t=>e.eventBusMap.delete(t))}}static async acquireDatabase(t){let n=t.database;if(!e.dbResources.has(n)){let i=new r.SharedResource(e.createDatabaseFactory(t),e.createDatabaseCleanup(n),{gracePeriod:`microtask`});e.dbResources.set(n,i)}return e.dbResources.get(n).acquire()}static releaseDatabase(t){let n=e.dbResources.get(t);n&&n.release()}static async getCollection(t){let n=await e.acquireDatabase(t),r=t.collection??`stores`;return n.collection(r)}static getEventBus(n,r){let i=`${n}_store_${r}`;return e.eventBusMap.has(i)||e.eventBusMap.set(i,(0,t.createEventBus)({errorHandler:e=>console.error(`Event bus error for ${n}:${r}:`,e),broadcast:{channel:i}})),e.eventBusMap.get(i)}},s=class{collection=null;collectionPromise;config;eventBus;initialized=!1;_initializing=!1;initializationCallbacks=[];doc=null;getStoreName(){return`_${this.config.app}_${this.config.store}_`}constructor(e){this.config=e,this.collectionPromise=o.getCollection(this.config),this.collectionPromise.then(e=>{this.collection=e,this.initialize()}).catch(e=>{console.error(`Failed to initialize collection for store ${this.getStoreName()}:`,e)}),this.eventBus=o.getEventBus(this.config.database,this.getStoreName()),this.eventBus.subscribe(`store:updated`,({storageKey:e})=>{e===this.getStoreName()&&(this.doc=null)})}async initialize(){this._initializing=!0;try{let e=await this._get();if(e&&e.version!==this.config.version&&this.config.onUpgrade){let{state:t}=await this.config.onUpgrade({data:e.data,version:e.version,app:e.app});await this.set(`migration`,t)}this.initialized=!0,this.initializationCallbacks.forEach(e=>e()),this.initializationCallbacks=[]}catch(e){console.error(`Failed to initialize and upgrade store ${this.getStoreName()}:`,e)}finally{this._initializing=!1}}_onInitialized(e){this.initialized?e():this.initializationCallbacks.push(e)}async getCollection(){return this.collection??this.collectionPromise}async set(e,t){!this.initialized&&!this._initializing&&await new Promise(e=>this._onInitialized(e));try{let n=await this.getCollection(),r=await this._read(),i={store:this.getStoreName(),data:t,version:this.config.version,app:this.config.app},a;return r?a=await r.update(i):(this.doc=await n.create(i),a=!0),a&&this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.getStoreName(),instanceId:e,state:t,version:this.config.version,app:this.config.app}}),a}catch(t){return console.error(`Failed to set state for store ${this.getStoreName()} in database ${this.config.database} by instance ${e}:`,t),!1}}async _read(){if(this.doc)return this.doc;let e=await this.getCollection(),t=new a.QueryBuilder().where({field:`store`,operator:`eq`,value:this.getStoreName()}).build();return this.doc=await e.find(t.filters),this.doc}async _get(){try{let e=await this._read();return e?e.read().then(()=>e):null}catch(e){return console.error(`Failed to get state for store ${this.getStoreName()} in database ${this.config.database}:`,e),null}}async get(){this.initialized||await new Promise(e=>this._onInitialized(e));let e=await this._get();return e?e.data:null}subscribe(e,t){return this.eventBus.subscribe(`store:updated`,({storageKey:n,instanceId:r,state:i})=>{n===this.getStoreName()&&r!==e&&t(i)})}async clear(){this.initialized||await new Promise(e=>this._onInitialized(e));try{let e=await this._read();return e&&await e.delete()?(this.doc=null,this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.getStoreName(),instanceId:``,state:null,version:this.config.version,app:this.config.app}}),!0):!0}catch(e){return console.error(`Failed to clear state for store ${this.getStoreName()} in database ${this.config.database}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}async close(){o.releaseDatabase(this.config.database)}},c=class{eventBus;inMemoryState=null;config;constructor(e){this.config=e,this.eventBus=this.initializeEventBus(),this.setupLwwSynchronizationListener()}initializeEventBus(){let e={errorHandler:e=>console.error(`Event bus error for ${this.config.storageKey} (Ephemeral LWW):`,e)};return(typeof process>`u`||process.env.NODE_ENV!==`test`)&&(e.broadcast={channel:`ephemeral_lww_${this.config.storageKey}`}),(0,t.createEventBus)(e)}setupLwwSynchronizationListener(){this.eventBus.subscribe(`store:updated`,({storageKey:e,instanceId:t,state:n,timestamp:r,version:i})=>{e===this.config.storageKey&&(!this.inMemoryState||r&&r>this.inMemoryState.timestamp)&&(this.inMemoryState={data:n,timestamp:r,instanceId:t,version:i})})}set(e,t){try{let n=Date.now();return this.inMemoryState={data:structuredClone(t),timestamp:n,instanceId:e,version:this.config.version},this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.config.storageKey,instanceId:e,state:t,timestamp:n,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to set state in EphemeralPersistence (LWW) for ${this.config.storageKey}:`,e),!1}}get(){return this.inMemoryState?.data??null}subscribe(e,t){return this.eventBus.subscribe(`store:updated`,({storageKey:n,instanceId:r,state:i})=>{n===this.config.storageKey&&r!==e&&t(i)})}clear(){try{let e=Date.now(),t=`clear-initiator`;return this.inMemoryState={data:null,timestamp:e,instanceId:t,version:this.config.version},this.eventBus.emit({name:`store:updated`,payload:{storageKey:this.config.storageKey,instanceId:t,state:null,timestamp:e,version:this.config.version,app:this.config.app}}),!0}catch(e){return console.error(`Failed to clear state in EphemeralPersistence (LWW) for ${this.config.storageKey}:`,e),!1}}stats(){return{version:this.config.version,id:this.config.app}}};exports.EphemeralPersistence=c,exports.IndexedDBPersistence=s,exports.WebStoragePersistence=i;