@rozenite/storage-plugin 1.8.0 → 1.9.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.
@@ -24,13 +24,13 @@ export declare type AsyncStorageLike = {
24
24
  removeItem: (key: string) => Promise<void>;
25
25
  };
26
26
 
27
- export declare let createAsyncStorageAdapter: createAsyncStorageAdapter_2;
27
+ export declare let createAsyncStorageAdapter: typeof createAsyncStorageAdapter_2;
28
28
 
29
29
  declare const createAsyncStorageAdapter_2: (options: CreateAsyncStorageAdapterOptions) => StorageAdapter;
30
30
 
31
31
  export declare type CreateAsyncStorageAdapterOptions = SingleStorageOptions | MultiStorageOptions;
32
32
 
33
- export declare let createExpoAsyncStorageAdapter: createExpoAsyncStorageAdapter_2;
33
+ export declare let createExpoAsyncStorageAdapter: typeof createExpoAsyncStorageAdapter_2;
34
34
 
35
35
  /**
36
36
  * @deprecated Use createAsyncStorageAdapter instead.
@@ -39,7 +39,7 @@ declare const createExpoAsyncStorageAdapter_2: (options: CreateAsyncStorageAdapt
39
39
 
40
40
  export declare type CreateExpoAsyncStorageAdapterOptions = CreateAsyncStorageAdapterOptions;
41
41
 
42
- export declare let createExpoSecureStorageAdapter: createExpoSecureStorageAdapter_2;
42
+ export declare let createExpoSecureStorageAdapter: typeof createExpoSecureStorageAdapter_2;
43
43
 
44
44
  declare const createExpoSecureStorageAdapter_2: ({ storage, keys, adapterId, adapterName, storageId, storageName, blacklist, }: CreateExpoSecureStorageAdapterOptions) => StorageAdapter;
45
45
 
@@ -53,7 +53,7 @@ export declare type CreateExpoSecureStorageAdapterOptions = {
53
53
  blacklist?: RegExp;
54
54
  };
55
55
 
56
- export declare let createMMKVStorageAdapter: createMMKVStorageAdapter_2;
56
+ export declare let createMMKVStorageAdapter: typeof createMMKVStorageAdapter_2;
57
57
 
58
58
  declare const createMMKVStorageAdapter_2: ({ adapterId, adapterName, storages, blacklist, }: CreateMMKVStorageAdapterOptions) => StorageAdapter;
59
59
 
@@ -86,6 +86,11 @@ export declare type SecureStorageLike = {
86
86
  deleteItemAsync: (key: string) => Promise<void>;
87
87
  };
88
88
 
89
+ declare type SerializedBlacklist = {
90
+ source: string;
91
+ flags: string;
92
+ };
93
+
89
94
  declare type SingleStorageOptions = {
90
95
  storage: AsyncStorageLike;
91
96
  adapterId?: string;
@@ -133,7 +138,7 @@ export declare type StorageEntryType = StorageEntry['type'];
133
138
 
134
139
  export declare type StorageEntryValue = StorageEntry['value'];
135
140
 
136
- declare type StorageEvent_2 = StorageSnapshotEvent | StorageSetEntryEvent | StorageDeleteEntryEvent | StorageGetSnapshotEvent;
141
+ declare type StorageEvent_2 = StorageSnapshotEvent | StorageSetEntryEvent | StorageDeleteEntryEvent | StorageGetSnapshotEvent | StorageImportEntriesEvent | StorageImportResultEvent;
137
142
 
138
143
  declare type StorageEventMap = {
139
144
  [K in StorageEvent_2['type']]: Extract<StorageEvent_2, {
@@ -146,12 +151,29 @@ declare type StorageGetSnapshotEvent = {
146
151
  target: StorageTarget | 'all';
147
152
  };
148
153
 
154
+ declare type StorageImportEntriesEvent = {
155
+ type: 'import-entries';
156
+ target: StorageTarget;
157
+ entries: StorageEntry[];
158
+ };
159
+
160
+ declare type StorageImportResultEvent = {
161
+ type: 'import-result';
162
+ target: StorageTarget;
163
+ ok: boolean;
164
+ written: number;
165
+ total: number;
166
+ failedKey?: string;
167
+ error?: string;
168
+ };
169
+
149
170
  export declare type StorageNode = {
150
171
  id: string;
151
172
  name: string;
152
173
  storage: SyncStorage | AsyncStorage;
153
174
  capabilities: StorageCapabilities;
154
175
  blacklist?: RegExp;
176
+ shouldFilterKey?: (key: string) => boolean;
155
177
  };
156
178
 
157
179
  declare type StorageSetEntryEvent = {
@@ -166,6 +188,7 @@ declare type StorageSnapshotEvent = {
166
188
  adapterName: string;
167
189
  storageName: string;
168
190
  capabilities: StorageCapabilities;
191
+ blacklist?: SerializedBlacklist;
169
192
  entries: StorageEntry[];
170
193
  };
171
194
 
@@ -187,7 +210,7 @@ export declare type SyncStorage = {
187
210
  subscribe?: (callback: (key: string) => void) => StorageSubscription;
188
211
  };
189
212
 
190
- export declare let useRozeniteStoragePlugin: useRozeniteStoragePlugin_2;
213
+ export declare let useRozeniteStoragePlugin: typeof useRozeniteStoragePlugin_2;
191
214
 
192
215
  declare const useRozeniteStoragePlugin_2: ({ storages, }: RozeniteStoragePluginOptions) => RozeniteDevToolsClient<StorageEventMap> | null;
193
216
 
@@ -1 +1 @@
1
- {"name":"@rozenite/storage-plugin","version":"1.8.0","description":"Generic Storage Inspector for Rozenite.","panels":[{"name":"Storage","source":"/devtools/panel.html"}]}
1
+ {"name":"@rozenite/storage-plugin","version":"1.9.0","description":"Generic Storage Inspector for Rozenite.","panels":[{"name":"Storage","source":"/devtools/panel.html"}]}
@@ -99,6 +99,7 @@ export declare type StorageNode = {
99
99
  storage: SyncStorage | AsyncStorage;
100
100
  capabilities: StorageCapabilities;
101
101
  blacklist?: RegExp;
102
+ shouldFilterKey?: (key: string) => boolean;
102
103
  };
103
104
 
104
105
  export declare type StorageReadEntryArgs = StorageSelection & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rozenite/storage-plugin",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Generic Storage Inspector for Rozenite.",
5
5
  "type": "module",
6
6
  "main": "./dist/react-native/index.cjs",
@@ -15,9 +15,9 @@
15
15
  "url": "https://github.com/callstackincubator/rozenite.git"
16
16
  },
17
17
  "dependencies": {
18
- "@rozenite/agent-shared": "1.8.0",
19
- "@rozenite/agent-bridge": "1.8.0",
20
- "@rozenite/plugin-bridge": "1.8.0"
18
+ "@rozenite/plugin-bridge": "1.9.0",
19
+ "@rozenite/agent-shared": "1.9.0",
20
+ "@rozenite/agent-bridge": "1.9.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@tanstack/react-table": "^8.21.3",
@@ -38,8 +38,8 @@
38
38
  "tailwindcss-animate": "^1.0.7",
39
39
  "typescript": "~5.9.3",
40
40
  "vite": "^7.3.1",
41
- "@rozenite/vite-plugin": "1.8.0",
42
- "rozenite": "1.8.0"
41
+ "@rozenite/vite-plugin": "1.9.0",
42
+ "rozenite": "1.9.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@react-native-async-storage/async-storage": "*",
@@ -0,0 +1,182 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { handleImportEntries, type ImportEmittedEvent } from '../import';
3
+ import type { StorageView } from '../storage-view';
4
+ import { getStorageViewId } from '../../shared/types';
5
+ import type { StorageEntry, StorageTarget } from '../../shared/types';
6
+ import type { StorageImportEntriesEvent } from '../../shared/messaging';
7
+
8
+ const target: StorageTarget = { adapterId: 'mmkv', storageId: 'user' };
9
+
10
+ const buildView = (overrides?: Partial<StorageView>): StorageView => {
11
+ const unexpected = (method: string) =>
12
+ vi.fn(() => {
13
+ throw new Error(`Unexpected call to ${method}`);
14
+ });
15
+
16
+ return {
17
+ id: getStorageViewId(target),
18
+ target,
19
+ adapterName: 'MMKV',
20
+ storageName: 'user',
21
+ capabilities: {
22
+ supportedTypes: ['string', 'number', 'boolean', 'buffer'],
23
+ },
24
+ get: unexpected('get'),
25
+ set: vi.fn(async () => {}),
26
+ delete: unexpected('delete'),
27
+ getAllKeys: unexpected('getAllKeys'),
28
+ getAllEntries: unexpected('getAllEntries'),
29
+ watch: unexpected('watch'),
30
+ ...overrides,
31
+ };
32
+ };
33
+
34
+ const buildEntries = (count: number): StorageEntry[] =>
35
+ Array.from({ length: count }, (_, index) => ({
36
+ key: `k${index}`,
37
+ type: 'string' as const,
38
+ value: `v${index}`,
39
+ }));
40
+
41
+ describe('handleImportEntries', () => {
42
+ it('emits a set-entry echo per write followed by a success import-result', async () => {
43
+ const view = buildView();
44
+ const entries = buildEntries(5);
45
+ const event: StorageImportEntriesEvent = {
46
+ type: 'import-entries',
47
+ target,
48
+ entries,
49
+ };
50
+ const emitted: ImportEmittedEvent[] = [];
51
+
52
+ await handleImportEntries([view], event, (out) => emitted.push(out));
53
+
54
+ expect(view.set).toHaveBeenCalledTimes(5);
55
+
56
+ expect(emitted).toHaveLength(6);
57
+ expect(emitted.slice(0, 5)).toEqual(
58
+ entries.map((entry) => ({
59
+ type: 'set-entry',
60
+ target,
61
+ entry,
62
+ })),
63
+ );
64
+ expect(emitted[5]).toEqual({
65
+ type: 'import-result',
66
+ target,
67
+ ok: true,
68
+ written: 5,
69
+ total: 5,
70
+ });
71
+ });
72
+
73
+ it('stops at the first write that throws and reports the failed key', async () => {
74
+ const failingKey = 'k2';
75
+ const view = buildView({
76
+ set: vi.fn(async (entry: StorageEntry) => {
77
+ if (entry.key === failingKey) {
78
+ throw new Error('boom');
79
+ }
80
+ }),
81
+ });
82
+ const entries = buildEntries(5);
83
+ const event: StorageImportEntriesEvent = {
84
+ type: 'import-entries',
85
+ target,
86
+ entries,
87
+ };
88
+ const emitted: ImportEmittedEvent[] = [];
89
+
90
+ await handleImportEntries([view], event, (out) => emitted.push(out));
91
+
92
+ // 2 set-entry echoes (k0, k1), then the failure result. No echoes for k2+.
93
+ expect(view.set).toHaveBeenCalledTimes(3);
94
+ expect(emitted).toHaveLength(3);
95
+ expect(emitted[0]).toMatchObject({ type: 'set-entry', entry: entries[0] });
96
+ expect(emitted[1]).toMatchObject({ type: 'set-entry', entry: entries[1] });
97
+ expect(emitted[2]).toEqual({
98
+ type: 'import-result',
99
+ target,
100
+ ok: false,
101
+ written: 2,
102
+ total: 5,
103
+ failedKey: failingKey,
104
+ error: 'boom',
105
+ });
106
+ });
107
+
108
+ it('coerces non-Error throws to a string error message', async () => {
109
+ const view = buildView({
110
+ set: vi.fn(async () => {
111
+ throw 'plain string failure';
112
+ }),
113
+ });
114
+ const event: StorageImportEntriesEvent = {
115
+ type: 'import-entries',
116
+ target,
117
+ entries: buildEntries(1),
118
+ };
119
+ const emitted: ImportEmittedEvent[] = [];
120
+
121
+ await handleImportEntries([view], event, (out) => emitted.push(out));
122
+
123
+ expect(emitted).toHaveLength(1);
124
+ expect(emitted[0]).toMatchObject({
125
+ type: 'import-result',
126
+ ok: false,
127
+ error: 'plain string failure',
128
+ });
129
+ });
130
+
131
+ it('emits an unknown-target import-result without calling set', async () => {
132
+ const view = buildView();
133
+ const unknownTarget: StorageTarget = {
134
+ adapterId: 'async-storage',
135
+ storageId: 'default',
136
+ };
137
+ const entries = buildEntries(3);
138
+ const event: StorageImportEntriesEvent = {
139
+ type: 'import-entries',
140
+ target: unknownTarget,
141
+ entries,
142
+ };
143
+ const emitted: ImportEmittedEvent[] = [];
144
+
145
+ await handleImportEntries([view], event, (out) => emitted.push(out));
146
+
147
+ expect(view.set).not.toHaveBeenCalled();
148
+ expect(emitted).toEqual([
149
+ {
150
+ type: 'import-result',
151
+ target: unknownTarget,
152
+ ok: false,
153
+ written: 0,
154
+ total: 3,
155
+ error: 'Target storage not found',
156
+ },
157
+ ]);
158
+ });
159
+
160
+ it('handles empty entries as a successful no-op', async () => {
161
+ const view = buildView();
162
+ const event: StorageImportEntriesEvent = {
163
+ type: 'import-entries',
164
+ target,
165
+ entries: [],
166
+ };
167
+ const emitted: ImportEmittedEvent[] = [];
168
+
169
+ await handleImportEntries([view], event, (out) => emitted.push(out));
170
+
171
+ expect(view.set).not.toHaveBeenCalled();
172
+ expect(emitted).toEqual([
173
+ {
174
+ type: 'import-result',
175
+ target,
176
+ ok: true,
177
+ written: 0,
178
+ total: 0,
179
+ },
180
+ ]);
181
+ });
182
+ });
@@ -0,0 +1,141 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { createMMKVStorageAdapter } from '../mmkv';
3
+ import { createStorageViews } from '../../storage-view';
4
+
5
+ type StoredValue = string | number | boolean | ArrayBuffer;
6
+
7
+ const createFakeMMKVV3 = (id: string) => {
8
+ const values = new Map<string, StoredValue>();
9
+
10
+ return {
11
+ id,
12
+ set: vi.fn((key: string, value: StoredValue) => {
13
+ values.set(key, value);
14
+ }),
15
+ getBoolean: vi.fn((key: string) => {
16
+ const value = values.get(key);
17
+ return typeof value === 'boolean' ? value : undefined;
18
+ }),
19
+ getString: vi.fn((key: string) => {
20
+ const value = values.get(key);
21
+ return typeof value === 'string' ? value : undefined;
22
+ }),
23
+ getNumber: vi.fn((key: string) => {
24
+ const value = values.get(key);
25
+ return typeof value === 'number' ? value : undefined;
26
+ }),
27
+ getBuffer: vi.fn((key: string) => {
28
+ const value = values.get(key);
29
+ return value instanceof ArrayBuffer ? value : undefined;
30
+ }),
31
+ delete: vi.fn((key: string) => {
32
+ values.delete(key);
33
+ }),
34
+ getAllKeys: vi.fn(() => [...values.keys()]),
35
+ addOnValueChangedListener: vi.fn(() => ({ remove: vi.fn() })),
36
+ };
37
+ };
38
+
39
+ const createFakeMMKVV4 = () => {
40
+ const values = new Map<string, StoredValue>();
41
+
42
+ return {
43
+ set: vi.fn((key: string, value: StoredValue) => {
44
+ values.set(key, value);
45
+ }),
46
+ getBoolean: vi.fn((key: string) => {
47
+ const value = values.get(key);
48
+ return typeof value === 'boolean' ? value : undefined;
49
+ }),
50
+ getString: vi.fn((key: string) => {
51
+ const value = values.get(key);
52
+ return typeof value === 'string' ? value : undefined;
53
+ }),
54
+ getNumber: vi.fn((key: string) => {
55
+ const value = values.get(key);
56
+ return typeof value === 'number' ? value : undefined;
57
+ }),
58
+ getBuffer: vi.fn((key: string) => {
59
+ const value = values.get(key);
60
+ return value instanceof ArrayBuffer ? value : undefined;
61
+ }),
62
+ remove: vi.fn((key: string) => {
63
+ values.delete(key);
64
+ }),
65
+ getAllKeys: vi.fn(() => [...values.keys()]),
66
+ addOnValueChangedListener: vi.fn(() => ({ remove: vi.fn() })),
67
+ };
68
+ };
69
+
70
+ describe('createMMKVStorageAdapter', () => {
71
+ it('supports MMKV v3 storages passed as an array', async () => {
72
+ const storage = createFakeMMKVV3('user-storage');
73
+ const adapter = createMMKVStorageAdapter({ storages: [storage as any] });
74
+ const [view] = createStorageViews([adapter]);
75
+
76
+ await view.set({ key: 'theme', type: 'string', value: 'dark' });
77
+
78
+ expect(view.target).toEqual({
79
+ adapterId: 'mmkv',
80
+ storageId: 'user-storage',
81
+ });
82
+ await expect(view.get('theme')).resolves.toEqual({
83
+ key: 'theme',
84
+ type: 'string',
85
+ value: 'dark',
86
+ });
87
+ });
88
+
89
+ it('supports MMKV v4 storages passed as a record', async () => {
90
+ const storage = createFakeMMKVV4();
91
+ const adapter = createMMKVStorageAdapter({
92
+ storages: { 'user-storage': storage as any },
93
+ });
94
+ const [view] = createStorageViews([adapter]);
95
+
96
+ await view.set({ key: 'logged-in', type: 'boolean', value: true });
97
+ await expect(view.get('logged-in')).resolves.toEqual({
98
+ key: 'logged-in',
99
+ type: 'boolean',
100
+ value: true,
101
+ });
102
+
103
+ await view.delete('logged-in');
104
+
105
+ expect(storage.remove).toHaveBeenCalledWith('logged-in');
106
+ await expect(view.get('logged-in')).resolves.toBeUndefined();
107
+ });
108
+
109
+ it('rejects MMKV v4 storages passed as an array', () => {
110
+ const storage = createFakeMMKVV4();
111
+
112
+ expect(() => createMMKVStorageAdapter({ storages: [storage as any] })).toThrow(
113
+ /MMKV arrays are not supported for v4 storages/
114
+ );
115
+ });
116
+
117
+ it('applies global blacklist patterns against storageId:key', async () => {
118
+ const userStorage = createFakeMMKVV3('user-storage');
119
+ const cacheStorage = createFakeMMKVV3('cache-storage');
120
+
121
+ userStorage.set('visible', 'ok');
122
+ userStorage.set('secret', 'hide');
123
+ cacheStorage.set('temp-file', 'hide');
124
+ cacheStorage.set('persisted', 'ok');
125
+
126
+ const adapter = createMMKVStorageAdapter({
127
+ storages: [userStorage as any, cacheStorage as any],
128
+ blacklist: /user-storage:secret|cache-storage:temp.*/,
129
+ });
130
+
131
+ const views = createStorageViews([adapter]);
132
+ const userView = views.find((view) => view.target.storageId === 'user-storage');
133
+ const cacheView = views.find((view) => view.target.storageId === 'cache-storage');
134
+
135
+ expect(userView).toBeDefined();
136
+ expect(cacheView).toBeDefined();
137
+
138
+ await expect(userView?.getAllKeys()).resolves.toEqual(['visible']);
139
+ await expect(cacheView?.getAllKeys()).resolves.toEqual(['persisted']);
140
+ });
141
+ });
@@ -148,6 +148,20 @@ const getStorageBlacklist = (
148
148
  return config[storageId];
149
149
  };
150
150
 
151
+ const createStorageBlacklistMatcher = (
152
+ config: MMKVBlacklistConfig | undefined,
153
+ storageId: string
154
+ ) => {
155
+ if (!(config instanceof RegExp)) {
156
+ return undefined;
157
+ }
158
+
159
+ return (key: string) => {
160
+ config.lastIndex = 0;
161
+ return config.test(`${storageId}:${key}`);
162
+ };
163
+ };
164
+
151
165
  export const createMMKVStorageAdapter = ({
152
166
  adapterId = 'mmkv',
153
167
  adapterName = 'MMKV',
@@ -164,6 +178,7 @@ export const createMMKVStorageAdapter = ({
164
178
  id: storageId,
165
179
  name: storageId,
166
180
  blacklist: getStorageBlacklist(blacklist, storageId),
181
+ shouldFilterKey: createStorageBlacklistMatcher(blacklist, storageId),
167
182
  capabilities: {
168
183
  supportedTypes: DEFAULT_SUPPORTED_TYPES,
169
184
  },
@@ -0,0 +1,67 @@
1
+ import type {
2
+ StorageImportEntriesEvent,
3
+ StorageImportResultEvent,
4
+ StorageSetEntryEvent,
5
+ } from '../shared/messaging';
6
+ import type { StorageView } from './storage-view';
7
+
8
+ export type ImportEmittedEvent =
9
+ | StorageSetEntryEvent
10
+ | StorageImportResultEvent;
11
+
12
+ export const handleImportEntries = async (
13
+ views: StorageView[],
14
+ event: StorageImportEntriesEvent,
15
+ emit: (out: ImportEmittedEvent) => void,
16
+ ): Promise<void> => {
17
+ const view = views.find(
18
+ (candidate) =>
19
+ candidate.target.adapterId === event.target.adapterId &&
20
+ candidate.target.storageId === event.target.storageId,
21
+ );
22
+
23
+ if (!view) {
24
+ emit({
25
+ type: 'import-result',
26
+ target: event.target,
27
+ ok: false,
28
+ written: 0,
29
+ total: event.entries.length,
30
+ error: 'Target storage not found',
31
+ });
32
+ return;
33
+ }
34
+
35
+ for (let i = 0; i < event.entries.length; i++) {
36
+ const entry = event.entries[i];
37
+
38
+ try {
39
+ await view.set(entry);
40
+ } catch (error) {
41
+ emit({
42
+ type: 'import-result',
43
+ target: event.target,
44
+ ok: false,
45
+ written: i,
46
+ total: event.entries.length,
47
+ failedKey: entry.key,
48
+ error: error instanceof Error ? error.message : String(error),
49
+ });
50
+ return;
51
+ }
52
+
53
+ emit({
54
+ type: 'set-entry',
55
+ target: event.target,
56
+ entry,
57
+ });
58
+ }
59
+
60
+ emit({
61
+ type: 'import-result',
62
+ target: event.target,
63
+ ok: true,
64
+ written: event.entries.length,
65
+ total: event.entries.length,
66
+ });
67
+ };
@@ -34,6 +34,10 @@ const toSnapshotMap = (entries: StorageEntry[]) => {
34
34
  };
35
35
 
36
36
  const shouldFilterKey = (storage: StorageNode, key: string) => {
37
+ if (storage.shouldFilterKey?.(key)) {
38
+ return true;
39
+ }
40
+
37
41
  if (!storage.blacklist) {
38
42
  return false;
39
43
  }
@@ -45,14 +49,14 @@ const shouldFilterKey = (storage: StorageNode, key: string) => {
45
49
  const checkTypeSupport = (
46
50
  capabilities: StorageCapabilities,
47
51
  type: StorageEntryType,
48
- target: StorageTarget
52
+ target: StorageTarget,
49
53
  ) => {
50
54
  if (supportsType(capabilities, type)) {
51
55
  return;
52
56
  }
53
57
 
54
58
  throw new Error(
55
- `Type "${type}" is not supported by storage "${target.storageId}" in adapter "${target.adapterId}".`
59
+ `Type "${type}" is not supported by storage "${target.storageId}" in adapter "${target.adapterId}".`,
56
60
  );
57
61
  };
58
62
 
@@ -96,6 +100,7 @@ export type StorageView = {
96
100
  adapterName: string;
97
101
  storageName: string;
98
102
  capabilities: StorageCapabilities;
103
+ blacklist?: RegExp;
99
104
  get: (key: string) => Promise<StorageEntry | undefined>;
100
105
  set: (entry: StorageEntry) => Promise<void>;
101
106
  delete: (key: string) => Promise<void>;
@@ -108,7 +113,7 @@ export type StorageView = {
108
113
  };
109
114
 
110
115
  const buildSnapshotMap = async (
111
- getAllEntries: () => Promise<StorageEntry[]>
116
+ getAllEntries: () => Promise<StorageEntry[]>,
112
117
  ): Promise<StorageSnapshotMap> => {
113
118
  const entries = await getAllEntries();
114
119
  return toSnapshotMap(entries);
@@ -120,7 +125,7 @@ const diffSnapshots = (
120
125
  handlers: {
121
126
  onSet: (entry: StorageEntry) => void;
122
127
  onDelete: (key: string) => void;
123
- }
128
+ },
124
129
  ) => {
125
130
  next.forEach((nextEntry, key) => {
126
131
  const previousEntry = previous.get(key);
@@ -147,7 +152,7 @@ const createPollingSubscription = async (
147
152
  handlers: {
148
153
  onSet: (entry: StorageEntry) => void;
149
154
  onDelete: (key: string) => void;
150
- }
155
+ },
151
156
  ): Promise<StorageSubscription> => {
152
157
  let previousSnapshot = await buildSnapshotMap(getAllEntries);
153
158
 
@@ -170,7 +175,7 @@ const createPollingSubscription = async (
170
175
 
171
176
  export const createStorageView = (
172
177
  adapter: StorageAdapter,
173
- storageNode: StorageNode
178
+ storageNode: StorageNode,
174
179
  ): StorageView => {
175
180
  const storage = storageNode.storage;
176
181
  const target: StorageTarget = {
@@ -191,7 +196,7 @@ export const createStorageView = (
191
196
  const visibleEntries = await Promise.all(
192
197
  keys
193
198
  .filter((key) => !shouldFilterKey(storageNode, key))
194
- .map((key) => getEntry(storage, key))
199
+ .map((key) => getEntry(storage, key)),
195
200
  );
196
201
 
197
202
  return visibleEntries.filter((entry): entry is StorageEntry => !!entry);
@@ -203,6 +208,7 @@ export const createStorageView = (
203
208
  adapterName: adapter.name,
204
209
  storageName: storageNode.name,
205
210
  capabilities: storageNode.capabilities,
211
+ blacklist: storageNode.blacklist,
206
212
  get,
207
213
  set: async (entry) => {
208
214
  checkTypeSupport(storageNode.capabilities, entry.type, target);
@@ -241,5 +247,7 @@ export const createStorageView = (
241
247
 
242
248
  export const createStorageViews = (storages: StorageAdapter[]) =>
243
249
  storages.flatMap((adapter) =>
244
- adapter.storages.map((storageNode) => createStorageView(adapter, storageNode))
250
+ adapter.storages.map((storageNode) =>
251
+ createStorageView(adapter, storageNode),
252
+ ),
245
253
  );