@rozenite/storage-plugin 2.0.0 → 2.2.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 (69) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/devtools/assets/panel-D5z1BY8U.js +32 -0
  3. package/dist/devtools/assets/panel-DVlWRg6d.css +1 -0
  4. package/dist/devtools/panel.html +2 -2
  5. package/dist/react-native/chunks/index.require.js +1 -3
  6. package/dist/react-native/chunks/secure-storage.require.js +2 -6
  7. package/dist/react-native/chunks/useRozeniteStoragePlugin.require.cjs +1 -1
  8. package/dist/react-native/chunks/useRozeniteStoragePlugin.require.js +266 -295
  9. package/dist/react-native/index.d.ts +14 -2
  10. package/dist/react-native/index.js +2 -10
  11. package/dist/rozenite.json +1 -1
  12. package/package.json +29 -29
  13. package/react-native.ts +11 -36
  14. package/rozenite.config.ts +2 -6
  15. package/sdk.ts +1 -5
  16. package/src/react-native/__tests__/entry-preview-pagination.test.ts +12 -40
  17. package/src/react-native/__tests__/export-snapshot.test.ts +2 -6
  18. package/src/react-native/__tests__/full-entry-request.test.ts +5 -17
  19. package/src/react-native/__tests__/import.test.ts +9 -8
  20. package/src/react-native/__tests__/storage-discovery.test.ts +7 -18
  21. package/src/react-native/__tests__/stress-verification.test.ts +5 -18
  22. package/src/react-native/__tests__/use-storage-agent-tools.test.ts +25 -35
  23. package/src/react-native/adapters/__tests__/mmkv.test.ts +20 -30
  24. package/src/react-native/adapters/async-storage.ts +2 -5
  25. package/src/react-native/adapters/index.ts +2 -8
  26. package/src/react-native/adapters/mmkv.ts +7 -24
  27. package/src/react-native/adapters/secure-storage.ts +2 -6
  28. package/src/react-native/entry-preview-pagination.ts +11 -27
  29. package/src/react-native/export-snapshot.ts +3 -9
  30. package/src/react-native/full-entry-request.ts +3 -8
  31. package/src/react-native/import.ts +10 -21
  32. package/src/react-native/storage-discovery.ts +2 -6
  33. package/src/react-native/storage-view.ts +2 -6
  34. package/src/react-native/useRozeniteStoragePlugin.ts +107 -119
  35. package/src/react-native/useStorageAgentTools.ts +8 -24
  36. package/src/shared/__tests__/entry-preview.test.ts +9 -27
  37. package/src/shared/__tests__/snapshot.test.ts +10 -32
  38. package/src/shared/agent-tools.ts +9 -30
  39. package/src/shared/entry-preview.ts +3 -8
  40. package/src/shared/messaging.ts +15 -11
  41. package/src/shared/snapshot.ts +4 -17
  42. package/src/shared/types.ts +2 -4
  43. package/src/ui/__tests__/binary-value-editor-state.test.ts +6 -16
  44. package/src/ui/__tests__/binary.test.ts +13 -33
  45. package/src/ui/__tests__/large-value-viewer.test.tsx +4 -13
  46. package/src/ui/__tests__/panel.test.tsx +50 -63
  47. package/src/ui/__tests__/storage-groups.test.ts +1 -4
  48. package/src/ui/__tests__/type-conversion.test.ts +8 -24
  49. package/src/ui/__tests__/use-storage-entries.test.tsx +18 -34
  50. package/src/ui/add-entry-dialog.tsx +66 -87
  51. package/src/ui/binary-value-editor-state.ts +6 -24
  52. package/src/ui/binary-value-editor.tsx +6 -18
  53. package/src/ui/binary.ts +6 -19
  54. package/src/ui/edit-entry-dialog.tsx +59 -78
  55. package/src/ui/editor-switcher.tsx +2 -11
  56. package/src/ui/entry-detail-dialog.tsx +9 -16
  57. package/src/ui/format-value.tsx +2 -9
  58. package/src/ui/import-dialog.tsx +12 -24
  59. package/src/ui/large-value-viewer-state.ts +2 -9
  60. package/src/ui/large-value-viewer.tsx +3 -9
  61. package/src/ui/panel.tsx +129 -235
  62. package/src/ui/query-client.tsx +4 -15
  63. package/src/ui/type-conversion.ts +2 -5
  64. package/src/ui/typed-value-editor.tsx +1 -5
  65. package/src/ui/use-storage-entries.ts +6 -21
  66. package/src/ui/utils.ts +1 -4
  67. package/tsconfig.json +4 -7
  68. package/dist/devtools/assets/panel-B6Wp0eie.css +0 -1
  69. package/dist/devtools/assets/panel-D7MFc4HG.js +0 -32
@@ -14,9 +14,7 @@ export type EntryDetailDialogProps = {
14
14
 
15
15
  const MAX_AUTO_JSON_INSPECTION_LENGTH = 50_000;
16
16
 
17
- export const jsonSafeParse = (
18
- value: string,
19
- ): Record<string, unknown> | unknown[] | null => {
17
+ export const jsonSafeParse = (value: string): Record<string, unknown> | unknown[] | null => {
20
18
  try {
21
19
  const parsed = JSON.parse(value) as unknown;
22
20
 
@@ -63,33 +61,28 @@ export const EntryDetailDialog = ({
63
61
  {entry && (
64
62
  <div className="flex max-h-[70vh] flex-col gap-4 overflow-auto">
65
63
  <div>
66
- <div className="mb-1 text-sm font-medium text-foreground">
67
- Key
68
- </div>
64
+ <div className="mb-1 text-sm font-medium text-foreground">Key</div>
69
65
  <div className="w-full break-all rounded-md border border-input bg-muted px-3 py-2 font-mono text-sm text-foreground">
70
66
  {entry.key}
71
67
  </div>
72
68
  </div>
73
69
 
74
70
  <div>
75
- <div className="mb-1 text-sm font-medium text-foreground">
76
- Type
77
- </div>
78
- <Badge variant="outline">{entry.type}</Badge>
71
+ <div className="mb-1 text-sm font-medium text-foreground">Type</div>
72
+ <Badge tone="neutral" variant="outline">
73
+ {entry.type}
74
+ </Badge>
79
75
  </div>
80
76
 
81
77
  <div className="flex min-h-0 flex-1 flex-col">
82
- <div className="mb-1 text-sm font-medium text-foreground">
83
- Value
84
- </div>
78
+ <div className="mb-1 text-sm font-medium text-foreground">Value</div>
85
79
  <div className="max-h-96 overflow-auto rounded-md border border-input bg-muted p-3">
86
80
  {jsonValue ? (
87
81
  <JsonInspector data={jsonValue} />
88
82
  ) : entry.type === 'buffer' ? (
89
83
  <div className="flex flex-col gap-2">
90
84
  <div className="text-xs text-muted-foreground">
91
- {entry.value.length}{' '}
92
- {entry.value.length === 1 ? 'byte' : 'bytes'}
85
+ {entry.value.length} {entry.value.length === 1 ? 'byte' : 'bytes'}
93
86
  </div>
94
87
  <HexdumpValueViewer bytes={entry.value} />
95
88
  </div>
@@ -105,7 +98,7 @@ export const EntryDetailDialog = ({
105
98
 
106
99
  <Dialog.Footer>
107
100
  {entry && onEdit && (
108
- <Button variant="outline" onClick={() => onEdit(entry)}>
101
+ <Button tone="neutral" variant="outline" onClick={() => onEdit(entry)}>
109
102
  <Edit3 className="h-3.5 w-3.5" />
110
103
  Edit
111
104
  </Button>
@@ -13,20 +13,13 @@ export const formatValue = (entry: StorageEntry) => {
13
13
 
14
14
  if (entry.type === 'boolean') {
15
15
  return (
16
- <span
17
- className={cn(
18
- 'font-mono',
19
- entry.value ? 'text-primary' : 'text-destructive',
20
- )}
21
- >
16
+ <span className={cn('font-mono', entry.value ? 'text-primary' : 'text-danger')}>
22
17
  {entry.value ? 'true' : 'false'}
23
18
  </span>
24
19
  );
25
20
  }
26
21
 
27
22
  return (
28
- <span className="font-mono text-muted-foreground">
29
- {compactBufferPreview(entry.value)}
30
- </span>
23
+ <span className="font-mono text-muted-foreground">{compactBufferPreview(entry.value)}</span>
31
24
  );
32
25
  };
@@ -82,26 +82,21 @@ const PreviewBody = ({
82
82
  <div className="flex items-start gap-2 rounded-md border border-border bg-muted p-2 text-xs text-foreground">
83
83
  <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
84
84
  <div>
85
- This file was exported from <strong>{sourceLabel}</strong>. You
86
- are importing into <strong>{targetLabel}</strong>.
85
+ This file was exported from <strong>{sourceLabel}</strong>. You are importing into{' '}
86
+ <strong>{targetLabel}</strong>.
87
87
  </div>
88
88
  </div>
89
89
  )}
90
90
 
91
91
  {hasUnsupported && (
92
- <div className="flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 p-2 text-xs text-destructive">
92
+ <div className="flex items-start gap-2 rounded-md border border-danger/40 bg-danger/10 p-2 text-xs text-danger">
93
93
  <XCircle className="mt-0.5 h-4 w-4 shrink-0" />
94
94
  <div>
95
95
  {preview.unsupportedTypes.length}{' '}
96
- {preview.unsupportedTypes.length === 1
97
- ? 'entry has a type'
98
- : 'entries have types'}{' '}
99
- not supported by this storage. Remove them from the file and try
100
- again.
96
+ {preview.unsupportedTypes.length === 1 ? 'entry has a type' : 'entries have types'}{' '}
97
+ not supported by this storage. Remove them from the file and try again.
101
98
  <div className="mt-1 max-h-20 overflow-auto rounded-md bg-muted px-2 py-1 font-mono text-xs">
102
- {preview.unsupportedTypes
103
- .map((u) => `${u.key} (${u.type})`)
104
- .join(', ')}
99
+ {preview.unsupportedTypes.map((u) => `${u.key} (${u.type})`).join(', ')}
105
100
  </div>
106
101
  </div>
107
102
  </div>
@@ -122,7 +117,7 @@ const PreviewBody = ({
122
117
  </div>
123
118
 
124
119
  <Dialog.Footer>
125
- <Button variant="outline" onClick={onCancel}>
120
+ <Button tone="neutral" variant="outline" onClick={onCancel}>
126
121
  Cancel
127
122
  </Button>
128
123
  <Button onClick={onApply} disabled={hasUnsupported}>
@@ -163,7 +158,7 @@ const ResultBody = ({
163
158
  </div>
164
159
  ) : (
165
160
  <div className="flex flex-col gap-2 py-2">
166
- <div className="flex items-center gap-2 text-destructive">
161
+ <div className="flex items-center gap-2 text-danger">
167
162
  <XCircle className="h-5 w-5" />
168
163
  <div className="text-sm font-medium">
169
164
  Import failed after {state.written} of {state.total}.
@@ -172,12 +167,12 @@ const ResultBody = ({
172
167
  {state.failedKey && (
173
168
  <div className="text-xs text-muted-foreground">
174
169
  Failed at key:{' '}
175
- <Badge variant="outline" className="font-mono">
170
+ <Badge tone="neutral" variant="outline" className="font-mono">
176
171
  {state.failedKey}
177
172
  </Badge>
178
173
  </div>
179
174
  )}
180
- <div className="rounded-md bg-muted px-2 py-1 font-mono text-xs text-destructive">
175
+ <div className="rounded-md bg-muted px-2 py-1 font-mono text-xs text-danger">
181
176
  {state.error}
182
177
  </div>
183
178
  </div>
@@ -191,12 +186,7 @@ const ResultBody = ({
191
186
  </>
192
187
  );
193
188
 
194
- export const ImportDialog = ({
195
- state,
196
- onApply,
197
- onCancel,
198
- onClose,
199
- }: ImportDialogProps) => {
189
+ export const ImportDialog = ({ state, onApply, onCancel, onClose }: ImportDialogProps) => {
200
190
  const title =
201
191
  state === null
202
192
  ? ''
@@ -227,9 +217,7 @@ export const ImportDialog = ({
227
217
  <PreviewBody state={state} onApply={onApply} onCancel={onCancel} />
228
218
  )}
229
219
  {state?.phase === 'importing' && <ImportingBody state={state} />}
230
- {state?.phase === 'result' && (
231
- <ResultBody state={state} onClose={onClose} />
232
- )}
220
+ {state?.phase === 'result' && <ResultBody state={state} onClose={onClose} />}
233
221
  </Dialog.Content>
234
222
  </Dialog>
235
223
  );
@@ -14,15 +14,8 @@ export const textRowRanges = (text: string): TextRange[] => {
14
14
  const newline = text.indexOf('\n', start);
15
15
  const lineEnd = newline === -1 ? text.length : newline + 1;
16
16
 
17
- for (
18
- let chunkStart = start;
19
- chunkStart < lineEnd;
20
- chunkStart += TEXT_CHUNK_SIZE
21
- ) {
22
- ranges.push([
23
- chunkStart,
24
- Math.min(chunkStart + TEXT_CHUNK_SIZE, lineEnd),
25
- ]);
17
+ for (let chunkStart = start; chunkStart < lineEnd; chunkStart += TEXT_CHUNK_SIZE) {
18
+ ranges.push([chunkStart, Math.min(chunkStart + TEXT_CHUNK_SIZE, lineEnd)]);
26
19
  }
27
20
 
28
21
  start = lineEnd;
@@ -1,15 +1,11 @@
1
1
  import { useMemo } from 'react';
2
2
  import { Virtuoso } from 'react-virtuoso';
3
3
  import { formatHexdumpRow } from './binary';
4
- import {
5
- textRowRanges,
6
- VIRTUALIZED_TEXT_THRESHOLD,
7
- } from './large-value-viewer-state';
4
+ import { textRowRanges, VIRTUALIZED_TEXT_THRESHOLD } from './large-value-viewer-state';
8
5
 
9
6
  export const TextValueViewer = ({ value }: { value: string }) => {
10
7
  const ranges = useMemo(
11
- () =>
12
- value.length > VIRTUALIZED_TEXT_THRESHOLD ? textRowRanges(value) : null,
8
+ () => (value.length > VIRTUALIZED_TEXT_THRESHOLD ? textRowRanges(value) : null),
13
9
  [value],
14
10
  );
15
11
 
@@ -45,9 +41,7 @@ export const HexdumpValueViewer = ({ bytes }: { bytes: readonly number[] }) => {
45
41
  const totalCount = Math.ceil(bytes.length / 16);
46
42
 
47
43
  if (totalCount === 0) {
48
- return (
49
- <div className="text-xs text-muted italic">No bytes to display.</div>
50
- );
44
+ return <div className="text-xs text-muted italic">No bytes to display.</div>;
51
45
  }
52
46
 
53
47
  return (