localspace 0.2.1 → 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.
- package/README.md +98 -12
- package/dist/core/plugin-manager.d.ts +48 -0
- package/dist/core/plugin-manager.d.ts.map +1 -0
- package/dist/core/plugin-manager.js +334 -0
- package/dist/drivers/indexeddb.d.ts.map +1 -1
- package/dist/drivers/indexeddb.js +398 -322
- package/dist/drivers/localstorage.d.ts.map +1 -1
- package/dist/drivers/localstorage.js +85 -65
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +54 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/localspace.d.ts +17 -3
- package/dist/localspace.d.ts.map +1 -1
- package/dist/localspace.js +547 -241
- package/dist/plugins/compression.d.ts +16 -0
- package/dist/plugins/compression.d.ts.map +1 -0
- package/dist/plugins/compression.js +59 -0
- package/dist/plugins/encryption.d.ts +26 -0
- package/dist/plugins/encryption.d.ts.map +1 -0
- package/dist/plugins/encryption.js +136 -0
- package/dist/plugins/quota.d.ts +22 -0
- package/dist/plugins/quota.d.ts.map +1 -0
- package/dist/plugins/quota.js +162 -0
- package/dist/plugins/sync.d.ts +16 -0
- package/dist/plugins/sync.d.ts.map +1 -0
- package/dist/plugins/sync.js +182 -0
- package/dist/plugins/ttl.d.ts +14 -0
- package/dist/plugins/ttl.d.ts.map +1 -0
- package/dist/plugins/ttl.js +94 -0
- package/dist/types.d.ts +71 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/utils/helpers.js +7 -8
- package/dist/utils/serializer.d.ts.map +1 -1
- package/dist/utils/serializer.js +40 -37
- package/package.json +12 -3
- package/src/core/plugin-manager.ts +522 -0
- package/src/drivers/indexeddb.ts +305 -120
- package/src/drivers/localstorage.ts +251 -152
- package/src/errors.ts +120 -0
- package/src/index.ts +27 -0
- package/src/localspace.ts +446 -26
- package/src/plugins/compression.ts +97 -0
- package/src/plugins/encryption.ts +254 -0
- package/src/plugins/quota.ts +244 -0
- package/src/plugins/sync.ts +267 -0
- package/src/plugins/ttl.ts +146 -0
- package/src/types.ts +122 -1
- package/src/utils/helpers.ts +8 -5
- package/src/utils/serializer.ts +30 -6
package/README.md
CHANGED
|
@@ -54,23 +54,21 @@ localspace is built on a foundation designed for growth. Here's what's planned:
|
|
|
54
54
|
- [x] Batch operations (`setItems()`, `getItems()`, `removeItems()`) for higher throughput
|
|
55
55
|
- [x] Automatic write coalescing (3-10x faster rapid writes, enabled by default)
|
|
56
56
|
- [x] Connection pooling, transaction batching, and warmup
|
|
57
|
+
- [x] **Improved error handling** - Structured error types with detailed context
|
|
57
58
|
|
|
58
59
|
### TODO
|
|
59
|
-
- [
|
|
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
|
-
- [
|
|
70
|
-
- [
|
|
71
|
-
- [
|
|
72
|
-
- [
|
|
73
|
-
- [
|
|
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
|
|
|
@@ -210,6 +208,14 @@ await Promise.all([
|
|
|
210
208
|
coalesced.setItem('fast-2', 'b'),
|
|
211
209
|
]); // batched into one tx within the window
|
|
212
210
|
|
|
211
|
+
// These features work independently and can be combined
|
|
212
|
+
const optimized = localspace.createInstance({
|
|
213
|
+
coalesceWrites: true, // optimizes single-item writes (setItem/removeItem)
|
|
214
|
+
coalesceWindowMs: 8,
|
|
215
|
+
maxBatchSize: 200, // limits batch API chunk size (setItems/removeItems)
|
|
216
|
+
});
|
|
217
|
+
await optimized.setDriver([optimized.INDEXEDDB]);
|
|
218
|
+
|
|
213
219
|
// Note: localStorage batches are not atomic—writes are applied one by one.
|
|
214
220
|
// For critical flows, prefer IndexedDB or handle your own compensating logic.
|
|
215
221
|
```
|
|
@@ -275,6 +281,82 @@ await localspace.setItem('file', file);
|
|
|
275
281
|
const restored = await localspace.getItem<Blob>('file');
|
|
276
282
|
```
|
|
277
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
|
+
|
|
278
360
|
## Migration Guide
|
|
279
361
|
|
|
280
362
|
### Note differences from localForage before upgrading
|
|
@@ -316,10 +398,11 @@ localspace.setItem('key', 'value', (err, value) => {
|
|
|
316
398
|
```
|
|
317
399
|
|
|
318
400
|
## Performance notes
|
|
319
|
-
- **Automatic write coalescing (enabled by default):** localspace automatically merges rapid single writes 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.
|
|
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'`.
|
|
320
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).
|
|
321
404
|
- **Transaction helpers:** `runTransaction()` lets you co-locate reads/writes in a single transaction for atomic migrations and to shorten lock time.
|
|
322
|
-
- **Batch sizing:** Use `maxBatchSize` to split very large
|
|
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.
|
|
323
406
|
- **IndexedDB durability defaults:** Chrome 121+ uses relaxed durability by default; keep it for speed or set `durability: 'strict'` in `config` for migration-style writes.
|
|
324
407
|
- **Storage Buckets (Chromium 122+):** supply a `bucket` option to isolate critical data and hint durability/persistence per bucket.
|
|
325
408
|
- **Connection warmup:** IndexedDB instances pre-warm a transaction after init to reduce first-op latency (`prewarmTransactions` enabled by default; set to `false` to skip).
|
|
@@ -331,8 +414,11 @@ When `compatibilityMode` is off, driver setup methods also use Node-style callba
|
|
|
331
414
|
## Troubleshooting
|
|
332
415
|
- **Wait for readiness:** Call `await localspace.ready()` before the first operation when you need to confirm driver selection.
|
|
333
416
|
- **Inspect drivers:** Use `localspace.driver()` to confirm which driver is active in different environments.
|
|
334
|
-
- **
|
|
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.
|
|
418
|
+
- **Handle quota errors:** Check for `error.code === 'QUOTA_EXCEEDED'` (or inspect `error.cause`) from `setItem` to inform users about storage limits.
|
|
335
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.
|
|
336
422
|
|
|
337
423
|
## License
|
|
338
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;
|
|
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"}
|