feat(storage-plugin): add storage-level JSON import/export#261
Conversation
Introduces the v1 JSON snapshot format for storage-level import/export, along with a hand-written parser that emits path-precise errors, a builder for exports, and a pure preview-diff helper used to classify entries into new / overwrite / skipped (blacklist) / unsupported buckets before any writes. Also extends the messaging union with the import-entries and import-result events that the runtime and panel will use in subsequent commits. Refs callstackincubator#247
Adds an import-entries message handler that iterates view.set per entry, emits a set-entry echo for each successful write so the panel table can update live, and reports completion via import-result. Stops on the first write that throws and reports the offending key. Unknown targets fail fast with a clear error. The handler logic lives in its own module so it can be unit-tested without React. Refs callstackincubator#247
Adds Import and Export buttons to the storage panel toolbar with a preview-confirm modal for imports. Export downloads the currently selected storage as a versioned JSON snapshot. Import reads a file, parses it with path-precise errors, shows new/overwrite/skipped counts (plus a metadata-mismatch warning when the source storage differs from the target), and applies entries as upserts with live row updates. The modal stays open through the import and surfaces progress, success, or a failure with the offending key. Also extends the snapshot wire format with an optional serialized blacklist so the panel can mirror the runtime's filter when computing preview skip counts. Refs callstackincubator#247
Adds an Import / Export section to the storage plugin docs covering behavior (scope, upsert, validate-before-write, stop-on-first-error, blacklist skip, live updates), the v1 JSON snapshot schema with field-by-field notes, a cross-adapter type-support matrix, and the strict versioning policy. Adds a short pointer from the package README to the canonical docs. Refs callstackincubator#247
Bumps @rozenite/storage-plugin as minor for the new storage-level JSON import/export feature. Refs callstackincubator#247
There was a problem hiding this comment.
Is there a specific reason for handling imports like this instead of sending a batch of set-entry commands from the DevTools UI side?
There was a problem hiding this comment.
client.send is fire-and-forget — no per-message ack. With N × set-entry, the UI knows it dispatched N messages but never learns whether the writes landed or where they failed, which makes the issue's "stop on first error" and the modal's "Imported 47/50, failed at userToken" outcome impossible to honor.
import-entries + import-result puts the loop, the stop-on-first-error rule, and the final { ok, written, total, failedKey, error } payload in one place. Per-write set-entry echoes still flow back, so the table updates row by row through the existing snapshot path.
Wire cost is two small event types, both unit-tested. Happy to switch if you'd rather accept silent partial failures.
Closes #247.
Summary
version: 1) JSON snapshot format withplugin,createdAt, sourcestoragemetadata, and typedentries[].parseSnapshotwith path-precise errors (e.g.entries[3].value: Expected finite number…). No new runtime deps.import-entriesevent; emits aset-entryecho per successful write so the table updates row by row, then a singleimport-resultfor completion. Stops at the first failed write and reports the offending key.blacklist(RegExpsource/flags) so the panel can compute skip counts against the runtime's filter.@rozenite/storage-plugin.Test plan
Automated:
packages/storage-plugin/src/shared/__tests__/snapshot.test.ts).computePreviewpure-function tests — bucket priority, blacklist skip, unsupported types, metadata mismatch.packages/storage-plugin/src/react-native/__tests__/import.test.ts).pnpm --filter @rozenite/storage-plugin test— 48/48 passing.pnpm --filter @rozenite/storage-plugin typecheck— clean.pnpm --filter @rozenite/storage-plugin lint— 0 errors (1 pre-existing unrelated warning).pnpm --filter @rozenite/docs build— website builds; new section renders.Manual (playground, MMKV / AsyncStorage / SecureStore via
apps/playground):rozenite-storage-<adapter>-<storage>-YYYYMMDD-HHmmss.json.version: 2is rejected with a path-pointed error.bufferinto AsyncStorage) disables Apply and lists offenders.entries: []file applies as a no-op.Out of scope
replace-all/ clear-storage semantics during import.shouldFilterKey(function form) — only theblacklistRegExp form is exposed to the UI today.