dbinspect_hive
A Hive adapter for
dbinspect_bridge, so a desktop
client can browse your app's boxes while it runs.
import 'package:dbinspect_bridge/dbinspect_bridge.dart';
import 'package:dbinspect_hive/dbinspect_hive.dart';
await startBridge(
appName: 'example_app',
adapters: [
HiveAdapter(boxes: [settings, sessions], id: 'hive',
displayName: 'app boxes'),
],
);
A box is a key/value store, not a table
Every store is two columns wide — key and value — and the schema is always
reported as inferred, because a box has no schema at all. The client shows a key
search box rather than a SQL editor or a filter builder.
Keys page in Hive's own ascending order, read by index, so a page of a 100k-entry box costs the page and not the box.
Boxes are handed in, never discovered
BoxBase names a box you already hold, and nothing in Hive lists what an
application has open — so you pass the boxes you want inspected. A box that was
not passed in is not listed, rather than listed and unopenable. Both Box and
LazyBox are accepted.
Values your client has no class for
A box holds whatever your TypeAdapters registered, and the inspecting client
has none of those classes. So:
- a value with a
toJson()is sent as that — your own serialisation, rendered as itself; - anything else is sent as
{"__lossy": "<toString()>", "type": "Order"}, and the client renders it as a description and refuses to edit it.
A description that read as data is how a value gets silently replaced by its own
toString(), which is why the flag is on the wire rather than left to the
client to guess.
Filtering
The key console sends a filter of prefix, from and to, all optional and
all compared as text:
{"prefix": "user:"}
{"from": "user:100", "to": "user:200"}
A filtered page carries no total — counting it means walking every key a
second time — and anything else in the filter is refused rather than ignored.
Watching
capabilities.watch is true with watchScope: "engine": Hive's own
watch() sees every write in this process, not only this bridge's own.
A BoxEvent carries {key, value, deleted} and cannot tell an insert from an
update, so this adapter emits upsert and remove rather than picking one of
insert/update and being wrong half the time.
Writing is off unless you say otherwise
HiveAdapter(boxes: [settings], id: 'hive', displayName: 'app boxes',
allowWrite: true);
That opens the row editor. Three rules it enforces, none of them adjustable:
- an insert carries its own key in
values— a box assigns no identity, so there is nothing to fall back to; - an insert onto an occupied key is refused rather than overwriting it;
- an update never moves an entry to another key, and an update to a key that is
no longer there reports
changes: 0instead of quietly creating it.
Values are limited to strings, numbers, booleans and null, which is the
protocol's rule for every engine. Editing a TypeAdapter-registered object is
not possible through the bridge and will not silently half-work.
hive_ce — unsupported as of 0.1.0, and it fails at compile time
hive_ce is a community fork with the same
class names in a different package. Dart identifies a type by its library, so a
package:hive_ce Box is not a package:hive BoxBase and cannot be
passed to HiveAdapter at all:
error - The element type 'Box<Object?>' can't be assigned to the list type
'BoxBase<Object?>'.
Tested against hive_ce 2.19.3 on 2026-08-08. This is a build failure, not a
runtime surprise, which is the good direction to fail in: nothing half-works and
no data is at risk.
There is no workaround inside this package. Supporting the fork means a sibling
dbinspect_hive_ce compiled against package:hive_ce — the adapter's logic is
identical and only the import changes — and it is not built until someone asks
for it.
Licence
Apache-2.0.
Libraries
- dbinspect_hive
- A Hive adapter for
dbinspect_bridge.