Skip to content

feat(storage-plugin): add storage-level JSON import/export#261

Merged
V3RON merged 5 commits into
callstackincubator:mainfrom
burczu:feat/add-storage-level-json-import-export-storage-plugin
May 11, 2026
Merged

feat(storage-plugin): add storage-level JSON import/export#261
V3RON merged 5 commits into
callstackincubator:mainfrom
burczu:feat/add-storage-level-json-import-export-storage-plugin

Conversation

@burczu
Copy link
Copy Markdown
Contributor

@burczu burczu commented May 11, 2026

Closes #247.

Summary

  • Adds Import and Export buttons to the storage panel toolbar, scoped to the currently selected storage.
  • Defines a stable, versioned (version: 1) JSON snapshot format with plugin, createdAt, source storage metadata, and typed entries[].
  • Hand-written parseSnapshot with path-precise errors (e.g. entries[3].value: Expected finite number…). No new runtime deps.
  • Import is an upsert with validate-before-write: any unsupported type aborts before any writes. The preview shows new / overwrite / skipped (blacklisted) counts and warns when the file's source storage differs from the target.
  • Runtime delivers a new import-entries event; emits a set-entry echo per successful write so the table updates row by row, then a single import-result for completion. Stops at the first failed write and reports the offending key.
  • Extends the snapshot wire format with an optional serialized blacklist (RegExp source/flags) so the panel can compute skip counts against the runtime's filter.
  • Docs: new Import / Export section in the storage plugin docs covering behavior, schema, cross-adapter compatibility, and versioning. Pointer added to the package README.
  • Changeset: minor bump for @rozenite/storage-plugin.

Test plan

Automated:

  • Snapshot parser unit tests — happy paths, every rejection branch, path precision (packages/storage-plugin/src/shared/__tests__/snapshot.test.ts).
  • computePreview pure-function tests — bucket priority, blacklist skip, unsupported types, metadata mismatch.
  • Runtime bulk handler tests — per-write echo, stop-on-first-error, unknown target, empty entries (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):

  • Export downloads a valid JSON file named rozenite-storage-<adapter>-<storage>-YYYYMMDD-HHmmss.json.
  • Importing an exported file (unchanged) is a no-op preview that applies cleanly.
  • Importing a file with version: 2 is rejected with a path-pointed error.
  • Importing into an adapter that doesn't support a present type (e.g. buffer into AsyncStorage) disables Apply and lists offenders.
  • Importing from a different storage source triggers the metadata-mismatch warning banner.
  • Importing an empty entries: [] file applies as a no-op.
  • Importing valid edits updates the table row by row as writes land.

Out of scope

  • Global cross-storage export.
  • replace-all / clear-storage semantics during import.
  • Adapter-specific native dump formats.
  • Surfacing storages that use shouldFilterKey (function form) — only the blacklist RegExp form is exposed to the UI today.

burczu added 5 commits May 11, 2026 09:56
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
@burczu burczu marked this pull request as ready for review May 11, 2026 09:04
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason for handling imports like this instead of sending a batch of set-entry commands from the DevTools UI side?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@V3RON V3RON self-requested a review May 11, 2026 14:22
@V3RON V3RON merged commit 328dba7 into callstackincubator:main May 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add storage-level JSON import/export to the storage plugin

2 participants