@rozenite/storage-plugin 1.8.1 → 1.10.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/CHANGELOG.md +34 -0
- package/README.md +23 -0
- package/dist/devtools/assets/panel-Bm-SWF7d.js +33 -0
- package/dist/devtools/assets/panel-DIqI4WSp.css +1 -0
- package/dist/devtools/panel.html +2 -2
- package/dist/react-native/chunks/index.require.cjs +1 -1
- package/dist/react-native/chunks/index.require.js +43 -57
- package/dist/react-native/chunks/useRozeniteStoragePlugin.require.cjs +1 -1
- package/dist/react-native/chunks/useRozeniteStoragePlugin.require.js +253 -191
- package/dist/react-native/index.d.ts +29 -6
- package/dist/rozenite.json +1 -1
- package/dist/sdk/index.d.ts +1 -0
- package/package.json +9 -6
- package/src/react-native/__tests__/import.test.ts +182 -0
- package/src/react-native/adapters/__tests__/mmkv.test.ts +436 -0
- package/src/react-native/adapters/mmkv.ts +65 -39
- package/src/react-native/import.ts +67 -0
- package/src/react-native/storage-view.ts +16 -8
- package/src/react-native/useRozeniteStoragePlugin.ts +61 -36
- package/src/shared/__tests__/snapshot.test.ts +361 -0
- package/src/shared/messaging.ts +25 -1
- package/src/shared/snapshot.ts +276 -0
- package/src/shared/types.ts +1 -0
- package/src/ui/__tests__/binary-value-editor-state.test.ts +199 -0
- package/src/ui/__tests__/binary.test.ts +251 -0
- package/src/ui/__tests__/type-conversion.test.ts +123 -0
- package/src/ui/add-entry-dialog.tsx +83 -173
- package/src/ui/binary-value-editor-state.ts +125 -0
- package/src/ui/binary-value-editor.tsx +168 -0
- package/src/ui/binary.ts +123 -0
- package/src/ui/edit-entry-dialog.tsx +64 -161
- package/src/ui/editable-table.tsx +12 -10
- package/src/ui/editor-switcher.tsx +62 -0
- package/src/ui/entry-detail-dialog.tsx +14 -6
- package/src/ui/import-dialog.tsx +261 -0
- package/src/ui/panel.tsx +257 -57
- package/src/ui/type-conversion.ts +105 -0
- package/src/ui/typed-value-editor.tsx +96 -0
- package/src/ui/utils.ts +30 -0
- package/dist/devtools/assets/panel-DMhXYHH4.css +0 -1
- package/dist/devtools/assets/panel-eGOuOVos.js +0 -22
- package/src/react-native/is-garbled.ts +0 -17
|
@@ -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
|
|
package/dist/rozenite.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@rozenite/storage-plugin","version":"1.
|
|
1
|
+
{"name":"@rozenite/storage-plugin","version":"1.10.0","description":"Generic Storage Inspector for Rozenite.","panels":[{"name":"Storage","source":"/devtools/panel.html"}]}
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Generic Storage Inspector for Rozenite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/react-native/index.cjs",
|
|
@@ -15,11 +15,14 @@
|
|
|
15
15
|
"url": "https://github.com/callstackincubator/rozenite.git"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@rozenite/agent-shared": "1.
|
|
19
|
-
"@rozenite/agent-bridge": "1.
|
|
20
|
-
"@rozenite/plugin-bridge": "1.
|
|
18
|
+
"@rozenite/agent-shared": "1.10.0",
|
|
19
|
+
"@rozenite/agent-bridge": "1.10.0",
|
|
20
|
+
"@rozenite/plugin-bridge": "1.10.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
+
"@codemirror/commands": "^6.10.3",
|
|
24
|
+
"@codemirror/state": "^6.6.0",
|
|
25
|
+
"@codemirror/view": "^6.40.0",
|
|
23
26
|
"@tanstack/react-table": "^8.21.3",
|
|
24
27
|
"@types/react": "~19.2.2",
|
|
25
28
|
"autoprefixer": "^10.4.21",
|
|
@@ -38,8 +41,8 @@
|
|
|
38
41
|
"tailwindcss-animate": "^1.0.7",
|
|
39
42
|
"typescript": "~5.9.3",
|
|
40
43
|
"vite": "^7.3.1",
|
|
41
|
-
"@rozenite/vite-plugin": "1.
|
|
42
|
-
"rozenite": "1.
|
|
44
|
+
"@rozenite/vite-plugin": "1.10.0",
|
|
45
|
+
"rozenite": "1.10.0"
|
|
43
46
|
},
|
|
44
47
|
"peerDependencies": {
|
|
45
48
|
"@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
|
+
});
|