localspace 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +85 -8
  2. package/dist/core/plugin-manager.d.ts +48 -0
  3. package/dist/core/plugin-manager.d.ts.map +1 -0
  4. package/dist/core/plugin-manager.js +334 -0
  5. package/dist/drivers/indexeddb.d.ts.map +1 -1
  6. package/dist/drivers/indexeddb.js +312 -284
  7. package/dist/drivers/localstorage.js +44 -45
  8. package/dist/errors.js +19 -4
  9. package/dist/index.cjs.js +1 -1
  10. package/dist/index.cjs.js.map +1 -1
  11. package/dist/index.d.ts +8 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.esm.js +1 -1
  14. package/dist/index.esm.js.map +1 -1
  15. package/dist/index.js +8 -1
  16. package/dist/index.umd.js +1 -1
  17. package/dist/index.umd.js.map +1 -1
  18. package/dist/localspace.d.ts +16 -3
  19. package/dist/localspace.d.ts.map +1 -1
  20. package/dist/localspace.js +541 -242
  21. package/dist/plugins/compression.d.ts +16 -0
  22. package/dist/plugins/compression.d.ts.map +1 -0
  23. package/dist/plugins/compression.js +59 -0
  24. package/dist/plugins/encryption.d.ts +26 -0
  25. package/dist/plugins/encryption.d.ts.map +1 -0
  26. package/dist/plugins/encryption.js +136 -0
  27. package/dist/plugins/quota.d.ts +22 -0
  28. package/dist/plugins/quota.d.ts.map +1 -0
  29. package/dist/plugins/quota.js +162 -0
  30. package/dist/plugins/sync.d.ts +16 -0
  31. package/dist/plugins/sync.d.ts.map +1 -0
  32. package/dist/plugins/sync.js +182 -0
  33. package/dist/plugins/ttl.d.ts +14 -0
  34. package/dist/plugins/ttl.d.ts.map +1 -0
  35. package/dist/plugins/ttl.js +94 -0
  36. package/dist/types.d.ts +71 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js +1 -1
  39. package/dist/utils/helpers.js +3 -3
  40. package/dist/utils/serializer.d.ts.map +1 -1
  41. package/dist/utils/serializer.js +33 -34
  42. package/package.json +9 -1
  43. package/src/core/plugin-manager.ts +522 -0
  44. package/src/drivers/indexeddb.ts +118 -65
  45. package/src/drivers/localstorage.ts +1 -1
  46. package/src/index.ts +25 -0
  47. package/src/localspace.ts +384 -4
  48. package/src/plugins/compression.ts +97 -0
  49. package/src/plugins/encryption.ts +254 -0
  50. package/src/plugins/quota.ts +244 -0
  51. package/src/plugins/sync.ts +267 -0
  52. package/src/plugins/ttl.ts +146 -0
  53. package/src/types.ts +122 -1
  54. package/src/utils/serializer.ts +6 -2
package/README.md CHANGED
@@ -57,20 +57,18 @@ localspace is built on a foundation designed for growth. Here's what's planned:
57
57
  - [x] **Improved error handling** - Structured error types with detailed context
58
58
 
59
59
  ### TODO
60
- - [ ] **Plugin system** - Middleware architecture for cross-cutting concerns
61
- - [ ] **Cache API driver** - Native browser caching with automatic HTTP semantics
60
+ - [x] **Plugin system** - Middleware architecture for cross-cutting concerns
62
61
  - [ ] **OPFS driver** - Origin Private File System for high-performance file storage
63
- - [ ] **Memory driver** - In-memory storage for testing and SSR
64
62
  - [ ] **Custom driver templates** - Documentation and examples for third-party drivers
65
63
  - [ ] **Node.js** - File system and SQLite adapters
66
64
  - [ ] **React Native** - AsyncStorage and SQLite drivers
67
65
  - [ ] **Electron** - Main and renderer process coordination
68
66
  - [ ] **Deno** - Native KV store integration
69
- - [ ] **TTL plugin** - Time-to-live expiration with automatic cleanup
70
- - [ ] **Encryption plugin** - Transparent encryption/decryption with Web Crypto API
71
- - [ ] **Compression plugin** - LZ-string or Brotli compression for large values
72
- - [ ] **Sync plugin** - Multi-tab synchronization with BroadcastChannel
73
- - [ ] **Quota plugin** - Automatic quota management and cleanup strategies
67
+ - [x] **TTL plugin** - Time-to-live expiration with automatic cleanup
68
+ - [x] **Encryption plugin** - Transparent encryption/decryption with Web Crypto API
69
+ - [x] **Compression plugin** - LZ-string or Brotli compression for large values
70
+ - [x] **Sync plugin** - Multi-tab synchronization with BroadcastChannel
71
+ - [x] **Quota plugin** - Automatic quota management and cleanup strategies
74
72
 
75
73
  ### 📊 Community Priorities
76
74
 
@@ -283,6 +281,82 @@ await localspace.setItem('file', file);
283
281
  const restored = await localspace.getItem<Blob>('file');
284
282
  ```
285
283
 
284
+ ## Plugin System
285
+
286
+ localspace now ships with a first-class plugin engine. Attach middleware when creating an instance or call `use()` later; plugins can mutate payloads, observe driver context, and run async interceptors around every storage call.
287
+
288
+ ```ts
289
+ const store = localspace.createInstance({
290
+ name: 'secure-store',
291
+ storeName: 'primary',
292
+ plugins: [
293
+ ttlPlugin({ defaultTTL: 60_000 }),
294
+ encryptionPlugin({ key: '0123456789abcdef0123456789abcdef' }),
295
+ compressionPlugin({ threshold: 1024 }),
296
+ syncPlugin({ channelName: 'localspace-sync' }),
297
+ quotaPlugin({ maxSize: 5 * 1024 * 1024, evictionPolicy: 'lru' }),
298
+ ],
299
+ });
300
+ ```
301
+
302
+ ### Lifecycle and hooks
303
+
304
+ - **Registration** – supply `plugins` when calling `createInstance()` or chain `instance.use(plugin)` later. Each plugin can also expose `enabled` (boolean or function) and `priority` to control execution order.
305
+ - **Lifecycle events** – `onInit(context)` is invoked after `ready()`, and `onDestroy` lets you tear down timers or channels. Call `await instance.destroy()` when disposing of an instance to run every `onDestroy` hook (executed in reverse priority order). Context exposes the active driver, db info, config, and a shared `metadata` bag for cross-plugin coordination.
306
+ - **Interceptors** – hook into `beforeSet/afterSet`, `beforeGet/afterGet`, `beforeRemove/afterRemove`, plus batch-specific methods such as `beforeSetItems` or `beforeGetItems`. Hooks run sequentially: `before*` hooks execute from highest to lowest priority, while `after*` hooks unwind in reverse order so layered transformations (compression → encryption → TTL) remain invertible. Returning a value passes it to the next plugin, while throwing a `LocalSpaceError` aborts the operation.
307
+ - **Per-call state** – plugins can stash data on `context.operationState` (e.g., capture the original value in `beforeSet` and reuse it in `afterSet`). For batch operations, `context.operationState.isBatch` is `true` and `context.operationState.batchSize` provides the total count.
308
+ - **Error handling & init policy** – unexpected exceptions are reported through `plugin.onError`. Throw a `LocalSpaceError` if you need to stop the pipeline (quota violations, failed decryptions, etc.). If a plugin `onInit` throws, the default policy is fail-fast (propagate and abort init). Set `pluginInitPolicy: 'disable-and-continue'` in config to log and skip the failing plugin instead (use with care for critical plugins like encryption).
309
+
310
+ ### Plugin execution order
311
+
312
+ Plugins are sorted by `priority` (higher runs first in `before*`, last in `after*`). Default priorities:
313
+
314
+ | Plugin | Priority | Notes |
315
+ |--------|----------|-------|
316
+ | sync | -100 | Runs last in `afterSet` to broadcast original (untransformed) values |
317
+ | quota | -10 | Runs late so it measures final payload sizes |
318
+ | ttl, encryption, compression | 0 | Default; chain in registration order |
319
+
320
+ **Recommended order**: `[ttlPlugin, encryptionPlugin, compressionPlugin, syncPlugin, quotaPlugin]`
321
+
322
+ ### Built-in plugins
323
+
324
+ #### TTL plugin
325
+ Wraps values as `{ data, expiresAt }`, invalidates stale reads, and optionally runs background cleanup. Options:
326
+
327
+ - `defaultTTL` (ms) and `keyTTL` overrides
328
+ - `cleanupInterval` to periodically scan `iterate()` output
329
+ - `onExpire(key, value)` callback before removal
330
+
331
+ #### Encryption plugin
332
+ Encrypts serialized payloads using the Web Crypto API (AES-GCM by default) and decrypts transparently on reads.
333
+
334
+ - Provide a `key` (CryptoKey/ArrayBuffer/string) or `keyDerivation` block (PBKDF2)
335
+ - Customize `algorithm`, `ivLength`, `ivGenerator`, or `randomSource`
336
+ - Works in browsers and modern Node runtimes (pass your own `subtle` when needed)
337
+
338
+ #### Compression plugin
339
+ Runs LZ-string compression (or a custom codec) when payloads exceed a `threshold` and restores them on read.
340
+
341
+ - `threshold` (bytes) controls when compression kicks in
342
+ - Supply a custom `{ compress, decompress }` codec if you prefer pako/Brotli
343
+
344
+ #### Sync plugin
345
+ Keeps multiple tabs/processes in sync via `BroadcastChannel` (with `storage`-event fallback).
346
+
347
+ - `channelName` separates logical buses
348
+ - `syncKeys` lets you scope which keys broadcast
349
+ - `conflictStrategy` defaults to `last-write-wins`; provide `onConflict` (return `false` to drop remote writes) for merge logic
350
+
351
+ #### Quota plugin
352
+ Tracks approximate storage usage after every mutation and enforces limits.
353
+
354
+ - `maxSize` (bytes) and optional `useNavigatorEstimate` to read the browser’s quota
355
+ - `evictionPolicy: 'error' | 'lru'` (LRU removes least-recently-used keys automatically)
356
+ - `onQuotaExceeded(info)` fires before throwing so you can log/alert users
357
+
358
+ > Tip: place quota plugins last so they see the final payload size after other transformations (TTL, encryption, compression, etc.).
359
+
286
360
  ## Migration Guide
287
361
 
288
362
  ### Note differences from localForage before upgrading
@@ -325,6 +399,7 @@ localspace.setItem('key', 'value', (err, value) => {
325
399
 
326
400
  ## Performance notes
327
401
  - **Automatic write coalescing (enabled by default):** localspace automatically merges rapid single writes (`setItem`/`removeItem`) within an 8ms window into one transaction, giving you 3-10x performance improvement with zero code changes. This is enabled by default for IndexedDB. Set `coalesceWrites: false` if you need strict per-operation durability.
402
+ - **Read-your-writes consistency with coalescing:** Pending coalesced writes are flushed before reads (`getItem`, `getItems`, `iterate`, `keys`, `length`, `key`) and destructive ops (`clear`, `dropInstance`), so immediate reads always observe the latest value. If you need eventual reads for speed, you can switch `coalesceReadConsistency` to `'eventual'`.
328
403
  - **Batch APIs outperform loops:** Playwright benchmark (`test/playwright/benchmark.spec.ts`) on 500 items x 256B showed `setItems()` ~6x faster and `getItems()` ~7.7x faster than per-item loops, with `removeItems()` ~2.8x faster (Chromium, relaxed durability).
329
404
  - **Transaction helpers:** `runTransaction()` lets you co-locate reads/writes in a single transaction for atomic migrations and to shorten lock time.
330
405
  - **Batch sizing:** Use `maxBatchSize` to split very large batch operations (`setItems`/`removeItems`/`getItems`) and keep transaction size in check. This works independently from `coalesceWrites`, which optimizes single-item operations.
@@ -342,6 +417,8 @@ When `compatibilityMode` is off, driver setup methods also use Node-style callba
342
417
  - **Read structured errors:** Rejections surface as `LocalSpaceError` with a `code`, contextual `details` (driver, operation, key, attemptedDrivers), and the original `cause`. Branch on `error.code` instead of parsing strings.
343
418
  - **Handle quota errors:** Check for `error.code === 'QUOTA_EXCEEDED'` (or inspect `error.cause`) from `setItem` to inform users about storage limits.
344
419
  - **Run unit tests:** The project ships with Vitest and Playwright suites covering API behavior; run `yarn test` to verify changes.
420
+ - **Collect Playwright coverage:** Run `yarn test:e2e:coverage` to re-build the bundle, execute the Playwright suite with Chromium V8 coverage enabled, and emit both text + HTML reports via `nyc` (open `coverage/index.html` after the run; raw JSON sits in `.nyc_output`).
421
+ - **Collect combined Vitest + Playwright coverage:** Run `yarn coverage:full` to clean previous artifacts, run `vitest --coverage`, stash its Istanbul JSON into `.nyc_output`, then execute the coverage-enabled Playwright suite and emit merged `nyc` reports.
345
422
 
346
423
  ## License
347
424
  [MIT](./LICENSE)
@@ -0,0 +1,48 @@
1
+ import type { BatchItems, BatchResponse, DbInfo, LocalSpaceConfig, LocalSpaceInstance, LocalSpacePlugin, PluginContext, PluginOperation } from '../types';
2
+ export declare class PluginAbortError extends Error {
3
+ constructor(message?: string);
4
+ }
5
+ type PluginHost = LocalSpaceInstance & {
6
+ _config: LocalSpaceConfig;
7
+ _dbInfo: DbInfo | null;
8
+ };
9
+ export declare class PluginManager {
10
+ private readonly host;
11
+ private readonly sharedMetadata;
12
+ private readonly pluginRegistry;
13
+ private readonly initialized;
14
+ private readonly initPromises;
15
+ private readonly destroyed;
16
+ private readonly disabled;
17
+ private orderCounter;
18
+ constructor(host: PluginHost, initialPlugins?: LocalSpacePlugin[]);
19
+ hasPlugins(): boolean;
20
+ registerPlugins(plugins: LocalSpacePlugin[]): void;
21
+ private sortPlugins;
22
+ private getActivePlugins;
23
+ ensureInitialized(): Promise<void>;
24
+ createContext(operation: PluginOperation | null): PluginContext;
25
+ beforeSet<T>(key: string, value: T, context: PluginContext): Promise<T>;
26
+ afterSet<T>(key: string, value: T, context: PluginContext): Promise<void>;
27
+ beforeGet(key: string, context: PluginContext): Promise<string>;
28
+ afterGet<T>(key: string, value: T | null, context: PluginContext): Promise<T | null>;
29
+ beforeRemove(key: string, context: PluginContext): Promise<string>;
30
+ afterRemove(key: string, context: PluginContext): Promise<void>;
31
+ beforeSetItems<T>(entries: BatchItems<T>, context: PluginContext): Promise<BatchItems<T>>;
32
+ afterSetItems<T>(entries: BatchResponse<T>, context: PluginContext): Promise<BatchResponse<T>>;
33
+ beforeGetItems(keys: string[], context: PluginContext): Promise<string[]>;
34
+ afterGetItems<T>(entries: BatchResponse<T>, context: PluginContext): Promise<BatchResponse<T>>;
35
+ beforeRemoveItems(keys: string[], context: PluginContext): Promise<string[]>;
36
+ afterRemoveItems(keys: string[], context: PluginContext): Promise<void>;
37
+ destroy(): Promise<void>;
38
+ normalizeBatch<T>(items: BatchItems<T>): Array<{
39
+ key: string;
40
+ value: T;
41
+ }>;
42
+ private shouldPropagate;
43
+ private dispatchPluginError;
44
+ private invokeValueHook;
45
+ private invokeVoidHook;
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=plugin-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-manager.d.ts","sourceRoot":"","sources":["../../src/core/plugin-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,334 @@
1
+ import { LocalSpaceError } from '../errors';
2
+ import { normalizeBatchEntries } from '../utils/helpers';
3
+ export class PluginAbortError extends Error {
4
+ constructor(message = 'Plugin aborted the operation') {
5
+ super(message);
6
+ this.name = 'PluginAbortError';
7
+ }
8
+ }
9
+ const sharedMetadataFor = () => Object.create(null);
10
+ export class PluginManager {
11
+ constructor(host, initialPlugins = []) {
12
+ Object.defineProperty(this, "host", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: void 0
17
+ });
18
+ Object.defineProperty(this, "sharedMetadata", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: sharedMetadataFor()
23
+ });
24
+ Object.defineProperty(this, "pluginRegistry", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: []
29
+ });
30
+ Object.defineProperty(this, "initialized", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: new WeakSet()
35
+ });
36
+ Object.defineProperty(this, "initPromises", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: new WeakMap()
41
+ });
42
+ Object.defineProperty(this, "destroyed", {
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true,
46
+ value: new WeakSet()
47
+ });
48
+ Object.defineProperty(this, "disabled", {
49
+ enumerable: true,
50
+ configurable: true,
51
+ writable: true,
52
+ value: new WeakSet()
53
+ });
54
+ Object.defineProperty(this, "orderCounter", {
55
+ enumerable: true,
56
+ configurable: true,
57
+ writable: true,
58
+ value: 0
59
+ });
60
+ this.host = host;
61
+ if (initialPlugins.length) {
62
+ this.registerPlugins(initialPlugins);
63
+ }
64
+ }
65
+ hasPlugins() {
66
+ return this.pluginRegistry.length > 0;
67
+ }
68
+ registerPlugins(plugins) {
69
+ for (const plugin of plugins) {
70
+ if (!plugin)
71
+ continue;
72
+ this.pluginRegistry.push({ plugin, order: this.orderCounter++ });
73
+ }
74
+ this.sortPlugins();
75
+ }
76
+ sortPlugins() {
77
+ this.pluginRegistry.sort((a, b) => {
78
+ const priorityA = a.plugin.priority ?? 0;
79
+ const priorityB = b.plugin.priority ?? 0;
80
+ if (priorityA === priorityB) {
81
+ return a.order - b.order;
82
+ }
83
+ return priorityB - priorityA;
84
+ });
85
+ }
86
+ getActivePlugins(options) {
87
+ const reverse = options?.reverse ?? false;
88
+ const plugins = this.pluginRegistry
89
+ .map((entry) => entry.plugin)
90
+ .filter((plugin) => {
91
+ if (this.disabled.has(plugin)) {
92
+ return false;
93
+ }
94
+ const enabled = plugin.enabled;
95
+ if (typeof enabled === 'function') {
96
+ try {
97
+ return !!enabled();
98
+ }
99
+ catch (error) {
100
+ console.warn(`Plugin "${plugin.name}" enabled() check failed`, error);
101
+ return false;
102
+ }
103
+ }
104
+ return enabled !== false;
105
+ });
106
+ return reverse ? plugins.slice().reverse() : plugins;
107
+ }
108
+ async ensureInitialized() {
109
+ for (const plugin of this.getActivePlugins()) {
110
+ if (this.initialized.has(plugin)) {
111
+ continue;
112
+ }
113
+ if (typeof plugin.onInit !== 'function') {
114
+ this.initialized.add(plugin);
115
+ continue;
116
+ }
117
+ const pendingInit = this.initPromises.get(plugin);
118
+ if (pendingInit) {
119
+ await pendingInit;
120
+ continue;
121
+ }
122
+ const context = this.createContext(null);
123
+ const initPromise = (async () => {
124
+ try {
125
+ await plugin.onInit(context);
126
+ this.initialized.add(plugin);
127
+ }
128
+ catch (error) {
129
+ await this.dispatchPluginError(plugin, error, 'init', 'lifecycle', undefined, context);
130
+ const policy = this.host._config.pluginInitPolicy ?? 'fail';
131
+ if (policy === 'disable-and-continue') {
132
+ this.disabled.add(plugin);
133
+ return;
134
+ }
135
+ throw error;
136
+ }
137
+ finally {
138
+ this.initPromises.delete(plugin);
139
+ }
140
+ })();
141
+ this.initPromises.set(plugin, initPromise);
142
+ await initPromise;
143
+ }
144
+ }
145
+ createContext(operation) {
146
+ return {
147
+ instance: this.host,
148
+ driver: this.host.driver ? this.host.driver() : null,
149
+ dbInfo: this.host._dbInfo ?? null,
150
+ config: this.host._config,
151
+ metadata: this.sharedMetadata,
152
+ operation,
153
+ operationState: Object.create(null),
154
+ };
155
+ }
156
+ async beforeSet(key, value, context) {
157
+ let current = value;
158
+ for (const plugin of this.getActivePlugins()) {
159
+ if (!plugin.beforeSet)
160
+ continue;
161
+ current = await this.invokeValueHook(plugin, () => plugin.beforeSet(key, current, context), 'before', 'setItem', key, context, current);
162
+ }
163
+ return current;
164
+ }
165
+ async afterSet(key, value, context) {
166
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
167
+ if (!plugin.afterSet)
168
+ continue;
169
+ await this.invokeVoidHook(plugin, () => plugin.afterSet(key, value, context), 'after', 'setItem', key, context);
170
+ }
171
+ }
172
+ async beforeGet(key, context) {
173
+ let currentKey = key;
174
+ for (const plugin of this.getActivePlugins()) {
175
+ if (!plugin.beforeGet)
176
+ continue;
177
+ currentKey = await this.invokeValueHook(plugin, () => plugin.beforeGet(currentKey, context), 'before', 'getItem', currentKey, context, currentKey);
178
+ }
179
+ return currentKey;
180
+ }
181
+ async afterGet(key, value, context) {
182
+ let currentValue = value;
183
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
184
+ if (!plugin.afterGet)
185
+ continue;
186
+ currentValue = await this.invokeValueHook(plugin, () => plugin.afterGet(key, currentValue, context), 'after', 'getItem', key, context, currentValue);
187
+ }
188
+ return currentValue;
189
+ }
190
+ async beforeRemove(key, context) {
191
+ let currentKey = key;
192
+ for (const plugin of this.getActivePlugins()) {
193
+ if (!plugin.beforeRemove)
194
+ continue;
195
+ currentKey = await this.invokeValueHook(plugin, () => plugin.beforeRemove(currentKey, context), 'before', 'removeItem', currentKey, context, currentKey);
196
+ }
197
+ return currentKey;
198
+ }
199
+ async afterRemove(key, context) {
200
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
201
+ if (!plugin.afterRemove)
202
+ continue;
203
+ await this.invokeVoidHook(plugin, () => plugin.afterRemove(key, context), 'after', 'removeItem', key, context);
204
+ }
205
+ }
206
+ async beforeSetItems(entries, context) {
207
+ let current = entries;
208
+ for (const plugin of this.getActivePlugins()) {
209
+ if (!plugin.beforeSetItems)
210
+ continue;
211
+ current = await this.invokeValueHook(plugin, () => plugin.beforeSetItems(current, context), 'before', 'setItems', undefined, context, current);
212
+ }
213
+ return current;
214
+ }
215
+ async afterSetItems(entries, context) {
216
+ let current = entries;
217
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
218
+ if (!plugin.afterSetItems)
219
+ continue;
220
+ current = await this.invokeValueHook(plugin, () => plugin.afterSetItems(current, context), 'after', 'setItems', undefined, context, current);
221
+ }
222
+ return current;
223
+ }
224
+ async beforeGetItems(keys, context) {
225
+ let currentKeys = keys;
226
+ for (const plugin of this.getActivePlugins()) {
227
+ if (!plugin.beforeGetItems)
228
+ continue;
229
+ currentKeys = await this.invokeValueHook(plugin, () => plugin.beforeGetItems(currentKeys, context), 'before', 'getItems', undefined, context, currentKeys);
230
+ }
231
+ return currentKeys;
232
+ }
233
+ async afterGetItems(entries, context) {
234
+ let current = entries;
235
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
236
+ if (!plugin.afterGetItems)
237
+ continue;
238
+ current = await this.invokeValueHook(plugin, () => plugin.afterGetItems(current, context), 'after', 'getItems', undefined, context, current);
239
+ }
240
+ return current;
241
+ }
242
+ async beforeRemoveItems(keys, context) {
243
+ let currentKeys = keys;
244
+ for (const plugin of this.getActivePlugins()) {
245
+ if (!plugin.beforeRemoveItems)
246
+ continue;
247
+ currentKeys = await this.invokeValueHook(plugin, () => plugin.beforeRemoveItems(currentKeys, context), 'before', 'removeItems', undefined, context, currentKeys);
248
+ }
249
+ return currentKeys;
250
+ }
251
+ async afterRemoveItems(keys, context) {
252
+ for (const plugin of this.getActivePlugins({ reverse: true })) {
253
+ if (!plugin.afterRemoveItems)
254
+ continue;
255
+ await this.invokeVoidHook(plugin, () => plugin.afterRemoveItems(keys, context), 'after', 'removeItems', undefined, context);
256
+ }
257
+ }
258
+ async destroy() {
259
+ const plugins = this.pluginRegistry
260
+ .map((entry) => entry.plugin)
261
+ .slice()
262
+ .reverse();
263
+ for (const plugin of plugins) {
264
+ if (this.destroyed.has(plugin) || this.disabled.has(plugin)) {
265
+ continue;
266
+ }
267
+ if (typeof plugin.onDestroy !== 'function') {
268
+ this.destroyed.add(plugin);
269
+ continue;
270
+ }
271
+ const context = this.createContext(null);
272
+ try {
273
+ await plugin.onDestroy(context);
274
+ }
275
+ catch (error) {
276
+ await this.dispatchPluginError(plugin, error, 'destroy', 'lifecycle', undefined, context);
277
+ }
278
+ finally {
279
+ this.destroyed.add(plugin);
280
+ }
281
+ }
282
+ }
283
+ normalizeBatch(items) {
284
+ return normalizeBatchEntries(items);
285
+ }
286
+ shouldPropagate(error) {
287
+ return (error instanceof LocalSpaceError || error instanceof PluginAbortError);
288
+ }
289
+ async dispatchPluginError(plugin, error, stage, operation, key, context) {
290
+ const info = {
291
+ plugin: plugin.name,
292
+ operation,
293
+ stage,
294
+ key,
295
+ context,
296
+ error,
297
+ };
298
+ if (typeof plugin.onError === 'function') {
299
+ try {
300
+ await plugin.onError(error, info);
301
+ return;
302
+ }
303
+ catch (hookError) {
304
+ console.error(`Plugin onError handler failed for "${plugin.name}"`, hookError);
305
+ }
306
+ }
307
+ console.warn(`Plugin "${plugin.name}" error during ${operation}`, error);
308
+ }
309
+ async invokeValueHook(plugin, executor, stage, operation, key, context, fallback) {
310
+ try {
311
+ const result = await executor();
312
+ return (typeof result === 'undefined' ? fallback : result);
313
+ }
314
+ catch (error) {
315
+ if (this.shouldPropagate(error)) {
316
+ throw error;
317
+ }
318
+ await this.dispatchPluginError(plugin, error, stage, operation, key, context);
319
+ return fallback;
320
+ }
321
+ }
322
+ async invokeVoidHook(plugin, executor, stage, operation, key, context) {
323
+ try {
324
+ await executor();
325
+ }
326
+ catch (error) {
327
+ if (this.shouldPropagate(error)) {
328
+ throw error;
329
+ }
330
+ await this.dispatchPluginError(plugin, error, stage, operation, key, context);
331
+ }
332
+ }
333
+ }
334
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29yZS9wbHVnaW4tbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFZQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzVDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXpELE1BQU0sT0FBTyxnQkFBaUIsU0FBUSxLQUFLO0lBQ3pDLFlBQVksT0FBTyxHQUFHLDhCQUE4QjtRQUNsRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLGtCQUFrQixDQUFDO0lBQ2pDLENBQUM7Q0FDRjtBQVlELE1BQU0saUJBQWlCLEdBQUcsR0FBNEIsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFN0UsTUFBTSxPQUFPLGFBQWE7SUFxQnhCLFlBQVksSUFBZ0IsRUFBRSxpQkFBcUMsRUFBRTtRQXBCcEQ7Ozs7O1dBQWlCO1FBRWpCOzs7O21CQUNmLGlCQUFpQixFQUFFO1dBQUM7UUFFTDs7OzttQkFBcUMsRUFBRTtXQUFDO1FBRXhDOzs7O21CQUFjLElBQUksT0FBTyxFQUFvQjtXQUFDO1FBRTlDOzs7O21CQUFlLElBQUksT0FBTyxFQUd4QztXQUFDO1FBRWE7Ozs7bUJBQVksSUFBSSxPQUFPLEVBQW9CO1dBQUM7UUFFNUM7Ozs7bUJBQVcsSUFBSSxPQUFPLEVBQW9CO1dBQUM7UUFFcEQ7Ozs7bUJBQWUsQ0FBQztXQUFDO1FBR3ZCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzFCLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDdkMsQ0FBQztJQUNILENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFD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R0FBRyxFQUNILE9BQU8sQ0FDUixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHtcbiAgQmF0Y2hJdGVtcyxcbiAgQmF0Y2hSZXNwb25zZSxcbiAgRGJJbmZvLFxuICBMb2NhbFNwYWNlQ29uZmlnLFxuICBMb2NhbFNwYWNlSW5zdGFuY2UsXG4gIExvY2FsU3BhY2VQbHVnaW4sXG4gIFBsdWdpbkNvbnRleHQsXG4gIFBsdWdpbkVycm9ySW5mbyxcbiAgUGx1Z2luT3BlcmF0aW9uLFxuICBQbHVnaW5TdGFnZSxcbn0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgTG9jYWxTcGFjZUVycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcbmltcG9ydCB7IG5vcm1hbGl6ZUJhdGNoRW50cmllcyB9IGZyb20gJy4uL3V0aWxzL2hlbHBlcnMnO1xuXG5leHBvcnQgY2xhc3MgUGx1Z2luQWJvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSA9ICdQbHVnaW4gYWJvcnRlZCB0aGUgb3BlcmF0aW9uJykge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdQbHVnaW5BYm9ydEVycm9yJztcbiAgfVxufVxuXG50eXBlIFBsdWdpbkhvc3QgPSBMb2NhbFNwYWNlSW5zdGFuY2UgJiB7XG4gIF9jb25maWc6IExvY2FsU3BhY2VDb25maWc7XG4gIF9kYkluZm86IERiSW5mbyB8IG51bGw7XG59O1xuXG50eXBlIFJlZ2lzdGVyZWRQbHVnaW4gPSB7XG4gIHBsdWdpbjogTG9jYWxTcGFjZVBsdWdpbjtcbiAgb3JkZXI6IG51bWJlcjtcbn07XG5cbmNvbnN0IHNoYXJlZE1ldGFkYXRhRm9yID0gKCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbmV4cG9ydCBjbGFzcyBQbHVnaW5NYW5hZ2VyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBob3N0OiBQbHVnaW5Ib3N0O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgc2hhcmVkTWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID1cbiAgICBzaGFyZWRNZXRhZGF0YUZvcigpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGx1Z2luUmVnaXN0cnk6IFJlZ2lzdGVyZWRQbHVnaW5bXSA9IFtdO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgaW5pdGlhbGl6ZWQgPSBuZXcgV2Vha1NldDxMb2NhbFNwYWNlUGx1Z2luPigpO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgaW5pdFByb21pc2VzID0gbmV3IFdlYWtNYXA8XG4gICAgTG9jYWxTcGFjZVBsdWdpbixcbiAgICBQcm9taXNlPHZvaWQ+XG4gID4oKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3llZCA9IG5ldyBXZWFrU2V0PExvY2FsU3BhY2VQbHVnaW4+KCk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBkaXNhYmxlZCA9IG5ldyBXZWFrU2V0PExvY2FsU3BhY2VQbHVnaW4+KCk7XG5cbiAgcHJpdmF0ZSBvcmRlckNvdW50ZXIgPSAwO1xuXG4gIGNvbnN0cnVjdG9yKGhvc3Q6IFBsdWdpbkhvc3QsIGluaXRpYWxQbHVnaW5zOiBMb2NhbFNwYWNlUGx1Z2luW10gPSBbXSkge1xuICAgIHRoaXMuaG9zdCA9IGhvc3Q7XG4gICAgaWYgKGluaXRpYWxQbHVnaW5zLmxlbmd0aCkge1xuICAgICAgdGhpcy5yZWdpc3RlclBsdWdpbnMoaW5pdGlhbFBsdWdpbnMpO1xuICAgIH1cbiAgfVxuXG4gIGhhc1BsdWdpbnMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucGx1Z2luUmVnaXN0cnkubGVuZ3RoID4gMDtcbiAgfVxuXG4gIHJlZ2lzdGVyUGx1Z2lucyhwbHVnaW5zOiBMb2NhbFNwYWNlUGx1Z2luW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiBwbHVnaW5zKSB7XG4gICAgICBpZiAoIXBsdWdpbikgY29udGludWU7XG4gICAgICB0aGlzLnBsdWdpblJlZ2lzdHJ5LnB1c2goeyBwbHVnaW4sIG9yZGVyOiB0aGlzLm9yZGVyQ291bnRlcisrIH0pO1xuICAgIH1cbiAgICB0aGlzLnNvcnRQbHVnaW5zKCk7XG4gIH1cblxuICBwcml2YXRlIHNvcnRQbHVnaW5zKCk6IHZvaWQge1xuICAgIHRoaXMucGx1Z2luUmVnaXN0cnkuc29ydCgoYSwgYikgPT4ge1xuICAgICAgY29uc3QgcHJpb3JpdHlBID0gYS5wbHVnaW4ucHJpb3JpdHkgPz8gMDtcbiAgICAgIGNvbnN0IHByaW9yaXR5QiA9IGIucGx1Z2luLnByaW9yaXR5ID8/IDA7XG4gICAgICBpZiAocHJpb3JpdHlBID09PSBwcmlvcml0eUIpIHtcbiAgICAgICAgcmV0dXJuIGEub3JkZXIgLSBiLm9yZGVyO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHByaW9yaXR5QiAtIHByaW9yaXR5QTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QWN0aXZlUGx1Z2lucyhvcHRpb25zPzoge1xuICAgIHJldmVyc2U/OiBib29sZWFuO1xuICB9KTogTG9jYWxTcGFjZVBsdWdpbltdIHtcbiAgICBjb25zdCByZXZlcnNlID0gb3B0aW9ucz8ucmV2ZXJzZSA/PyBmYWxzZTtcbiAgICBjb25zdCBwbHVnaW5zID0gdGhpcy5wbHVnaW5SZWdpc3RyeVxuICAgICAgLm1hcCgoZW50cnkpID0+IGVudHJ5LnBsdWdpbilcbiAgICAgIC5maWx0ZXIoKHBsdWdpbikgPT4ge1xuICAgICAgICBpZiAodGhpcy5kaXNhYmxlZC5oYXMocGx1Z2luKSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlbmFibGVkID0gcGx1Z2luLmVuYWJsZWQ7XG4gICAgICAgIGlmICh0eXBlb2YgZW5hYmxlZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gISFlbmFibGVkKCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgYFBsdWdpbiBcIiR7cGx1Z2luLm5hbWV9XCIgZW5hYmxlZCgpIGNoZWNrIGZhaWxlZGAsXG4gICAgICAgICAgICAgIGVycm9yXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZW5hYmxlZCAhPT0gZmFsc2U7XG4gICAgICB9KTtcbiAgICByZXR1cm4gcmV2ZXJzZSA/IHBsdWdpbnMuc2xpY2UoKS5yZXZlcnNlKCkgOiBwbHVnaW5zO1xuICB9XG5cbiAgYXN5bmMgZW5zdXJlSW5pdGlhbGl6ZWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBwbHVnaW4gb2YgdGhpcy5nZXRBY3RpdmVQbHVnaW5zKCkpIHtcbiAgICAgIGlmICh0aGlzLmluaXRpYWxpemVkLmhhcyhwbHVnaW4pKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIHBsdWdpbi5vbkluaXQgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdGhpcy5pbml0aWFsaXplZC5hZGQocGx1Z2luKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBlbmRpbmdJbml0ID0gdGhpcy5pbml0UHJvbWlzZXMuZ2V0KHBsdWdpbik7XG4gICAgICBpZiAocGVuZGluZ0luaXQpIHtcbiAgICAgICAgYXdhaXQgcGVuZGluZ0luaXQ7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KG51bGwpO1xuICAgICAgY29uc3QgaW5pdFByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHBsdWdpbi5vbkluaXQhKGNvbnRleHQpO1xuICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZWQuYWRkKHBsdWdpbik7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5kaXNwYXRjaFBsdWdpbkVycm9yKFxuICAgICAgICAgICAgcGx1Z2luLFxuICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICAnaW5pdCcsXG4gICAgICAgICAgICAnbGlmZWN5Y2xlJyxcbiAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGNvbnRleHRcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IHBvbGljeSA9IHRoaXMuaG9zdC5fY29uZmlnLnBsdWdpbkluaXRQb2xpY3kgPz8gJ2ZhaWwnO1xuICAgICAgICAgIGlmIChwb2xpY3kgPT09ICdkaXNhYmxlLWFuZC1jb250aW51ZScpIHtcbiAgICAgICAgICAgIHRoaXMuZGlzYWJsZWQuYWRkKHBsdWdpbik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHRoaXMuaW5pdFByb21pc2VzLmRlbGV0ZShwbHVnaW4pO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuXG4gICAgICB0aGlzLmluaXRQcm9taXNlcy5zZXQocGx1Z2luLCBpbml0UHJvbWlzZSk7XG4gICAgICBhd2FpdCBpbml0UHJvbWlzZTtcbiAgICB9XG4gIH1cblxuICBjcmVhdGVDb250ZXh0KG9wZXJhdGlvbjogUGx1Z2luT3BlcmF0aW9uIHwgbnVsbCk6IFBsdWdpbkNvbnRleHQge1xuICAgIHJldHVybiB7XG4gICAgICBpbnN0YW5jZTogdGhpcy5ob3N0LFxuICAgICAgZHJpdmVyOiB0aGlzLmhvc3QuZHJpdmVyID8gdGhpcy5ob3N0LmRyaXZlcigpIDogbnVsbCxcbiAgICAgIGRiSW5mbzogdGhpcy5ob3N0Ll9kYkluZm8gPz8gbnVsbCxcbiAgICAgIGNvbmZpZzogdGhpcy5ob3N0Ll9jb25maWcsXG4gICAgICBtZXRhZGF0YTogdGhpcy5zaGFyZWRNZXRhZGF0YSxcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIG9wZXJhdGlvblN0YXRlOiBPYmplY3QuY3JlYXRlKG51bGwpLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBiZWZvcmVTZXQ8VD4oXG4gICAga2V5OiBzdHJpbmcsXG4gICAgdmFsdWU6IFQsXG4gICAgY29udGV4dDogUGx1Z2luQ29udGV4dFxuICApOiBQcm9taXNlPFQ+IHtcbiAgICBsZXQgY3VycmVudCA9IHZhbHVlO1xuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHRoaXMuZ2V0QWN0aXZlUGx1Z2lucygpKSB7XG4gICAgICBpZiAoIXBsdWdpbi5iZWZvcmVTZXQpIGNvbnRpbnVlO1xuICAgICAgY3VycmVudCA9IGF3YWl0IHRoaXMuaW52b2tlVmFsdWVIb29rKFxuICAgICAgICBwbHVnaW4sXG4gICAgICAgICgpID0+IHBsdWdpbi5iZWZvcmVTZXQhKGtleSwgY3VycmVudCwgY29udGV4dCksXG4gICAgICAgICdiZWZvcmUnLFxuICAgICAgICAnc2V0SXRlbScsXG4gICAgICAgIGtleSxcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgY3VycmVudFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnJlbnQ7XG4gIH1cblxuICBhc3luYyBhZnRlclNldDxUPihcbiAgICBrZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogVCxcbiAgICBjb250ZXh0OiBQbHVnaW5Db250ZXh0XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHRoaXMuZ2V0QWN0aXZlUGx1Z2lucyh7IHJldmVyc2U6IHRydWUgfSkpIHtcbiAgICAgIGlmICghcGx1Z2luLmFmdGVyU2V0KSBjb250aW51ZTtcbiAgICAgIGF3YWl0IHRoaXMuaW52b2tlVm9pZEhvb2soXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgKCkgPT4gcGx1Z2luLmFmdGVyU2V0IShrZXksIHZhbHVlLCBjb250ZXh0KSxcbiAgICAgICAgJ2FmdGVyJyxcbiAgICAgICAgJ3NldEl0ZW0nLFxuICAgICAgICBrZXksXG4gICAgICAgIGNvbnRleHRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgYmVmb3JlR2V0KGtleTogc3RyaW5nLCBjb250ZXh0OiBQbHVnaW5Db250ZXh0KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgY3VycmVudEtleSA9IGtleTtcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoKSkge1xuICAgICAgaWYgKCFwbHVnaW4uYmVmb3JlR2V0KSBjb250aW51ZTtcbiAgICAgIGN1cnJlbnRLZXkgPSBhd2FpdCB0aGlzLmludm9rZVZhbHVlSG9vayhcbiAgICAgICAgcGx1Z2luLFxuICAgICAgICAoKSA9PiBwbHVnaW4uYmVmb3JlR2V0IShjdXJyZW50S2V5LCBjb250ZXh0KSxcbiAgICAgICAgJ2JlZm9yZScsXG4gICAgICAgICdnZXRJdGVtJyxcbiAgICAgICAgY3VycmVudEtleSxcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgY3VycmVudEtleVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnJlbnRLZXk7XG4gIH1cblxuICBhc3luYyBhZnRlckdldDxUPihcbiAgICBrZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogVCB8IG51bGwsXG4gICAgY29udGV4dDogUGx1Z2luQ29udGV4dFxuICApOiBQcm9taXNlPFQgfCBudWxsPiB7XG4gICAgbGV0IGN1cnJlbnRWYWx1ZTogVCB8IG51bGwgPSB2YWx1ZTtcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoeyByZXZlcnNlOiB0cnVlIH0pKSB7XG4gICAgICBpZiAoIXBsdWdpbi5hZnRlckdldCkgY29udGludWU7XG4gICAgICBjdXJyZW50VmFsdWUgPSBhd2FpdCB0aGlzLmludm9rZVZhbHVlSG9vayhcbiAgICAgICAgcGx1Z2luLFxuICAgICAgICAoKSA9PiBwbHVnaW4uYWZ0ZXJHZXQhKGtleSwgY3VycmVudFZhbHVlLCBjb250ZXh0KSxcbiAgICAgICAgJ2FmdGVyJyxcbiAgICAgICAgJ2dldEl0ZW0nLFxuICAgICAgICBrZXksXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIGN1cnJlbnRWYWx1ZVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnJlbnRWYWx1ZTtcbiAgfVxuXG4gIGFzeW5jIGJlZm9yZVJlbW92ZShrZXk6IHN0cmluZywgY29udGV4dDogUGx1Z2luQ29udGV4dCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgbGV0IGN1cnJlbnRLZXkgPSBrZXk7XG4gICAgZm9yIChjb25zdCBwbHVnaW4gb2YgdGhpcy5nZXRBY3RpdmVQbHVnaW5zKCkpIHtcbiAgICAgIGlmICghcGx1Z2luLmJlZm9yZVJlbW92ZSkgY29udGludWU7XG4gICAgICBjdXJyZW50S2V5ID0gYXdhaXQgdGhpcy5pbnZva2VWYWx1ZUhvb2soXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgKCkgPT4gcGx1Z2luLmJlZm9yZVJlbW92ZSEoY3VycmVudEtleSwgY29udGV4dCksXG4gICAgICAgICdiZWZvcmUnLFxuICAgICAgICAncmVtb3ZlSXRlbScsXG4gICAgICAgIGN1cnJlbnRLZXksXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIGN1cnJlbnRLZXlcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjdXJyZW50S2V5O1xuICB9XG5cbiAgYXN5bmMgYWZ0ZXJSZW1vdmUoa2V5OiBzdHJpbmcsIGNvbnRleHQ6IFBsdWdpbkNvbnRleHQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoeyByZXZlcnNlOiB0cnVlIH0pKSB7XG4gICAgICBpZiAoIXBsdWdpbi5hZnRlclJlbW92ZSkgY29udGludWU7XG4gICAgICBhd2FpdCB0aGlzLmludm9rZVZvaWRIb29rKFxuICAgICAgICBwbHVnaW4sXG4gICAgICAgICgpID0+IHBsdWdpbi5hZnRlclJlbW92ZSEoa2V5LCBjb250ZXh0KSxcbiAgICAgICAgJ2FmdGVyJyxcbiAgICAgICAgJ3JlbW92ZUl0ZW0nLFxuICAgICAgICBrZXksXG4gICAgICAgIGNvbnRleHRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgYmVmb3JlU2V0SXRlbXM8VD4oXG4gICAgZW50cmllczogQmF0Y2hJdGVtczxUPixcbiAgICBjb250ZXh0OiBQbHVnaW5Db250ZXh0XG4gICk6IFByb21pc2U8QmF0Y2hJdGVtczxUPj4ge1xuICAgIGxldCBjdXJyZW50ID0gZW50cmllcztcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoKSkge1xuICAgICAgaWYgKCFwbHVnaW4uYmVmb3JlU2V0SXRlbXMpIGNvbnRpbnVlO1xuICAgICAgY3VycmVudCA9IGF3YWl0IHRoaXMuaW52b2tlVmFsdWVIb29rKFxuICAgICAgICBwbHVnaW4sXG4gICAgICAgICgpID0+IHBsdWdpbi5iZWZvcmVTZXRJdGVtcyEoY3VycmVudCwgY29udGV4dCksXG4gICAgICAgICdiZWZvcmUnLFxuICAgICAgICAnc2V0SXRlbXMnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIGN1cnJlbnRcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjdXJyZW50O1xuICB9XG5cbiAgYXN5bmMgYWZ0ZXJTZXRJdGVtczxUPihcbiAgICBlbnRyaWVzOiBCYXRjaFJlc3BvbnNlPFQ+LFxuICAgIGNvbnRleHQ6IFBsdWdpbkNvbnRleHRcbiAgKTogUHJvbWlzZTxCYXRjaFJlc3BvbnNlPFQ+PiB7XG4gICAgbGV0IGN1cnJlbnQgPSBlbnRyaWVzO1xuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHRoaXMuZ2V0QWN0aXZlUGx1Z2lucyh7IHJldmVyc2U6IHRydWUgfSkpIHtcbiAgICAgIGlmICghcGx1Z2luLmFmdGVyU2V0SXRlbXMpIGNvbnRpbnVlO1xuICAgICAgY3VycmVudCA9IGF3YWl0IHRoaXMuaW52b2tlVmFsdWVIb29rKFxuICAgICAgICBwbHVnaW4sXG4gICAgICAgICgpID0+IHBsdWdpbi5hZnRlclNldEl0ZW1zIShjdXJyZW50LCBjb250ZXh0KSxcbiAgICAgICAgJ2FmdGVyJyxcbiAgICAgICAgJ3NldEl0ZW1zJyxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICBjb250ZXh0LFxuICAgICAgICBjdXJyZW50XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gY3VycmVudDtcbiAgfVxuXG4gIGFzeW5jIGJlZm9yZUdldEl0ZW1zKFxuICAgIGtleXM6IHN0cmluZ1tdLFxuICAgIGNvbnRleHQ6IFBsdWdpbkNvbnRleHRcbiAgKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGxldCBjdXJyZW50S2V5cyA9IGtleXM7XG4gICAgZm9yIChjb25zdCBwbHVnaW4gb2YgdGhpcy5nZXRBY3RpdmVQbHVnaW5zKCkpIHtcbiAgICAgIGlmICghcGx1Z2luLmJlZm9yZUdldEl0ZW1zKSBjb250aW51ZTtcbiAgICAgIGN1cnJlbnRLZXlzID0gYXdhaXQgdGhpcy5pbnZva2VWYWx1ZUhvb2soXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgKCkgPT4gcGx1Z2luLmJlZm9yZUdldEl0ZW1zIShjdXJyZW50S2V5cywgY29udGV4dCksXG4gICAgICAgICdiZWZvcmUnLFxuICAgICAgICAnZ2V0SXRlbXMnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIGN1cnJlbnRLZXlzXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gY3VycmVudEtleXM7XG4gIH1cblxuICBhc3luYyBhZnRlckdldEl0ZW1zPFQ+KFxuICAgIGVudHJpZXM6IEJhdGNoUmVzcG9uc2U8VD4sXG4gICAgY29udGV4dDogUGx1Z2luQ29udGV4dFxuICApOiBQcm9taXNlPEJhdGNoUmVzcG9uc2U8VD4+IHtcbiAgICBsZXQgY3VycmVudCA9IGVudHJpZXM7XG4gICAgZm9yIChjb25zdCBwbHVnaW4gb2YgdGhpcy5nZXRBY3RpdmVQbHVnaW5zKHsgcmV2ZXJzZTogdHJ1ZSB9KSkge1xuICAgICAgaWYgKCFwbHVnaW4uYWZ0ZXJHZXRJdGVtcykgY29udGludWU7XG4gICAgICBjdXJyZW50ID0gYXdhaXQgdGhpcy5pbnZva2VWYWx1ZUhvb2soXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgKCkgPT4gcGx1Z2luLmFmdGVyR2V0SXRlbXMhKGN1cnJlbnQsIGNvbnRleHQpLFxuICAgICAgICAnYWZ0ZXInLFxuICAgICAgICAnZ2V0SXRlbXMnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGNvbnRleHQsXG4gICAgICAgIGN1cnJlbnRcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjdXJyZW50O1xuICB9XG5cbiAgYXN5bmMgYmVmb3JlUmVtb3ZlSXRlbXMoXG4gICAga2V5czogc3RyaW5nW10sXG4gICAgY29udGV4dDogUGx1Z2luQ29udGV4dFxuICApOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgbGV0IGN1cnJlbnRLZXlzID0ga2V5cztcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoKSkge1xuICAgICAgaWYgKCFwbHVnaW4uYmVmb3JlUmVtb3ZlSXRlbXMpIGNvbnRpbnVlO1xuICAgICAgY3VycmVudEtleXMgPSBhd2FpdCB0aGlzLmludm9rZVZhbHVlSG9vayhcbiAgICAgICAgcGx1Z2luLFxuICAgICAgICAoKSA9PiBwbHVnaW4uYmVmb3JlUmVtb3ZlSXRlbXMhKGN1cnJlbnRLZXlzLCBjb250ZXh0KSxcbiAgICAgICAgJ2JlZm9yZScsXG4gICAgICAgICdyZW1vdmVJdGVtcycsXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgY29udGV4dCxcbiAgICAgICAgY3VycmVudEtleXNcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjdXJyZW50S2V5cztcbiAgfVxuXG4gIGFzeW5jIGFmdGVyUmVtb3ZlSXRlbXMoXG4gICAga2V5czogc3RyaW5nW10sXG4gICAgY29udGV4dDogUGx1Z2luQ29udGV4dFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiB0aGlzLmdldEFjdGl2ZVBsdWdpbnMoeyByZXZlcnNlOiB0cnVlIH0pKSB7XG4gICAgICBpZiAoIXBsdWdpbi5hZnRlclJlbW92ZUl0ZW1zKSBjb250aW51ZTtcbiAgICAgIGF3YWl0IHRoaXMuaW52b2tlVm9pZEhvb2soXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgKCkgPT4gcGx1Z2luLmFmdGVyUmVtb3ZlSXRlbXMhKGtleXMsIGNvbnRleHQpLFxuICAgICAgICAnYWZ0ZXInLFxuICAgICAgICAncmVtb3ZlSXRlbXMnLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGNvbnRleHRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZGVzdHJveSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBwbHVnaW5zID0gdGhpcy5wbHVnaW5SZWdpc3RyeVxuICAgICAgLm1hcCgoZW50cnkpID0+IGVudHJ5LnBsdWdpbilcbiAgICAgIC5zbGljZSgpXG4gICAgICAucmV2ZXJzZSgpO1xuICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIHBsdWdpbnMpIHtcbiAgICAgIGlmICh0aGlzLmRlc3Ryb3llZC5oYXMocGx1Z2luKSB8fCB0aGlzLmRpc2FibGVkLmhhcyhwbHVnaW4pKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBwbHVnaW4ub25EZXN0cm95ICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRoaXMuZGVzdHJveWVkLmFkZChwbHVnaW4pO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLmNyZWF0ZUNvbnRleHQobnVsbCk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBwbHVnaW4ub25EZXN0cm95KGNvbnRleHQpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNwYXRjaFBsdWdpbkVycm9yKFxuICAgICAgICAgIHBsdWdpbixcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAnZGVzdHJveScsXG4gICAgICAgICAgJ2xpZmVjeWNsZScsXG4gICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgIGNvbnRleHRcbiAgICAgICAgKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHRoaXMuZGVzdHJveWVkLmFkZChwbHVnaW4pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIG5vcm1hbGl6ZUJhdGNoPFQ+KGl0ZW1zOiBCYXRjaEl0ZW1zPFQ+KTogQXJyYXk8eyBrZXk6IHN0cmluZzsgdmFsdWU6IFQgfT4ge1xuICAgIHJldHVybiBub3JtYWxpemVCYXRjaEVudHJpZXMoaXRlbXMpO1xuICB9XG5cbiAgcHJpdmF0ZSBzaG91bGRQcm9wYWdhdGUoZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgZXJyb3IgaW5zdGFuY2VvZiBMb2NhbFNwYWNlRXJyb3IgfHwgZXJyb3IgaW5zdGFuY2VvZiBQbHVnaW5BYm9ydEVycm9yXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZGlzcGF0Y2hQbHVnaW5FcnJvcihcbiAgICBwbHVnaW46IExvY2FsU3BhY2VQbHVnaW4sXG4gICAgZXJyb3I6IHVua25vd24sXG4gICAgc3RhZ2U6IFBsdWdpblN0YWdlLFxuICAgIG9wZXJhdGlvbjogUGx1Z2luT3BlcmF0aW9uLFxuICAgIGtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGNvbnRleHQ6IFBsdWdpbkNvbnRleHRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaW5mbzogUGx1Z2luRXJyb3JJbmZvID0ge1xuICAgICAgcGx1Z2luOiBwbHVnaW4ubmFtZSxcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIHN0YWdlLFxuICAgICAga2V5LFxuICAgICAgY29udGV4dCxcbiAgICAgIGVycm9yLFxuICAgIH07XG5cbiAgICBpZiAodHlwZW9mIHBsdWdpbi5vbkVycm9yID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBwbHVnaW4ub25FcnJvcihlcnJvciwgaW5mbyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gY2F0Y2ggKGhvb2tFcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgIGBQbHVnaW4gb25FcnJvciBoYW5kbGVyIGZhaWxlZCBmb3IgXCIke3BsdWdpbi5uYW1lfVwiYCxcbiAgICAgICAgICBob29rRXJyb3JcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zb2xlLndhcm4oYFBsdWdpbiBcIiR7cGx1Z2luLm5hbWV9XCIgZXJyb3IgZHVyaW5nICR7b3BlcmF0aW9ufWAsIGVycm9yKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaW52b2tlVmFsdWVIb29rPFQ+KFxuICAgIHBsdWdpbjogTG9jYWxTcGFjZVBsdWdpbixcbiAgICBleGVjdXRvcjogKCkgPT4gUHJvbWlzZTxUPiB8IFQsXG4gICAgc3RhZ2U6IFBsdWdpblN0YWdlLFxuICAgIG9wZXJhdGlvbjogUGx1Z2luT3BlcmF0aW9uLFxuICAgIGtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGNvbnRleHQ6IFBsdWdpbkNvbnRleHQsXG4gICAgZmFsbGJhY2s6IFRcbiAgKTogUHJvbWlzZTxUPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWN1dG9yKCk7XG4gICAgICByZXR1cm4gKHR5cGVvZiByZXN1bHQgPT09ICd1bmRlZmluZWQnID8gZmFsbGJhY2sgOiByZXN1bHQpIGFzIFQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICh0aGlzLnNob3VsZFByb3BhZ2F0ZShlcnJvcikpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLmRpc3BhdGNoUGx1Z2luRXJyb3IoXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgZXJyb3IsXG4gICAgICAgIHN0YWdlLFxuICAgICAgICBvcGVyYXRpb24sXG4gICAgICAgIGtleSxcbiAgICAgICAgY29udGV4dFxuICAgICAgKTtcbiAgICAgIHJldHVybiBmYWxsYmFjaztcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGludm9rZVZvaWRIb29rKFxuICAgIHBsdWdpbjogTG9jYWxTcGFjZVBsdWdpbixcbiAgICBleGVjdXRvcjogKCkgPT4gUHJvbWlzZTx2b2lkPiB8IHZvaWQsXG4gICAgc3RhZ2U6IFBsdWdpblN0YWdlLFxuICAgIG9wZXJhdGlvbjogUGx1Z2luT3BlcmF0aW9uLFxuICAgIGtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGNvbnRleHQ6IFBsdWdpbkNvbnRleHRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGV4ZWN1dG9yKCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICh0aGlzLnNob3VsZFByb3BhZ2F0ZShlcnJvcikpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLmRpc3BhdGNoUGx1Z2luRXJyb3IoXG4gICAgICAgIHBsdWdpbixcbiAgICAgICAgZXJyb3IsXG4gICAgICAgIHN0YWdlLFxuICAgICAgICBvcGVyYXRpb24sXG4gICAgICAgIGtleSxcbiAgICAgICAgY29udGV4dFxuICAgICAgKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.d.ts","sourceRoot":"","sources":["../../src/drivers/indexeddb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EASP,MAAM,UAAU,CAAC;AAulElB,QAAA,MAAM,YAAY,EAAE,MAkBnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"indexeddb.d.ts","sourceRoot":"","sources":["../../src/drivers/indexeddb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EASP,MAAM,UAAU,CAAC;AA4oElB,QAAA,MAAM,YAAY,EAAE,MAkBnB,CAAC;AAEF,eAAe,YAAY,CAAC"}