passnote library

Passnote: an end-to-end encrypted, local-first CRDT sync engine for Dart.

This is the frozen app-facing library, covered by semver from v1.0.0 (see VERSIONING.md): the builder entry, databases, collections and queries, codecs and their annotations, merge strategies and CRDT types, the device / pairing / recovery API, configuration, events, and the port interfaces the builder's overrides accept.

Engine implementations, the conformance suites, protocol internals, and the passnoteLowLevel wiring function live on the advanced package:passnote/engine.dart library. Flutter bindings and batteries-included setup live in package:passnote_flutter.

Classes

Cipher
An authenticated symmetric cipher.
Codec<T>
Converts values of type T to and from a JSON-style map, and extracts a stable document identifier from each value.
Collection<T>
A typed, queryable set of documents backed by a per-collection CrdtTable.
CollectionQuery<T>
An immutable, typed query over a Collection, built by chaining where, orderBy, limit, and startAfter, and executed with get or page.
Crdt
Assigns a CrdtType to the annotated field, so concurrent edits to it merge by that type's rule instead of last-write-wins.
CrdtRecovery
What CrdtTable.recoveries reports when CrdtTable.init rebuilds an unreadable local store.
CrdtTable
CRDT record store: the persistence and merge layer beneath Collection.
CrdtType
The conflict-resolution rule for a single field of a document.
Database
A shared, encrypted, peer-synced database.
DeepMergeStrategy
A MergeStrategy that flattens nested maps recursively, joining keys with pathSeparator (default '.').
DeviceInfo
A device in a database's roster, as reported by Database.devices().
DevicePublicKey
A device's long-lived public identity: the key-exchange and signing public keys that peers use to seal keys to it and to verify what it signs.
DeviceRecord
A paired device: its public identity plus human-facing metadata.
DeviceRosterEntry
One row of the device roster. Every row is a DeviceRecord, a WrappedGroupKey, or a KeyRotation.
DiscoveryRestored
Peer discovery works again after a DiscoveryUnavailable.
DiscoveryUnavailable
Emitted (at most once per Transport.start) when the transport determines its peer-discovery mechanism is unavailable on this platform — for example, the OS refused the multicast sockets mDNS needs because a permission or entitlement is missing.
Document
Marks a class as a Passnote document model, so package:passnote_generator generates its codec, document-id extractor, and per-field CRDT schema in one pass — no hand-written maps, and the schema can never drift from the codec.
DocumentId
Marks the one field whose value identifies the document (Codec.idOf). Required, exactly once per Document class, on a non-nullable String field.
Frame
A tagged binary payload routed by room.
FrameHandlingFailed
An inbound frame was dropped because handling it threw.
Identity
This device's cryptographic identity.
InboundFrame
A Frame received from from.
JsonCodec<T>
A Codec backed by plain functions.
KeyRotation
A record that the group key was rotated to keyEpoch, excluding revokedDeviceId (empty for the initial founding at epoch 0).
KeyStore
Secure storage for per-database encryption keys.
LwwRegister
Last-write-wins register: the field with the higher Hybrid Logical Clock wins a merge and the other value is discarded.
MergeStrategy
Controls the granularity at which a document is split into independently timestamped CRDT records, and therefore how concurrent edits to the same document merge.
ObjectMergeStrategy
A MergeStrategy that treats each document as a single, atomic CRDT record.
OrSet
Observed-remove set: concurrent adds and removes of different elements both survive a merge, and an add wins over a concurrent remove that did not observe it.
PairingBundle
What a sponsor hands a newly paired device: the key for the reserved roster collection, and the sponsor's roster trust pins. The database room tag derives from the key, and the device's own wrapped group key arrives by normal sync once it opens the database.
PairingCode
A one-time code that authorises a device join.
Pake
A password-authenticated key exchange, used to authenticate device pairing.
PakeResult
The output of a completed Pake run.
PakeSession
One party's state within a single Pake run. Not reusable.
Passnote
The app-level handle for Passnote.
PassnoteBuilder
Staged configuration for a Passnote instance.
PassnoteConfig
Top-level configuration for a Passnote instance.
PassnoteDefaults
The platform factories PassnoteBuilder fills in for any slot the caller does not override.
PassnoteEvent
An observable event from a Passnote instance. Listen via Passnote.events.
PassphrasePolicy
Passphrase word-count and strictness policy.
PeerAppeared
A peer became reachable on the transport.
PeerConnected
Emitted when a new peer connects.
PeerDisappeared
A peer stopped being reachable.
PeerDiscoveryRestored
Discovery works again after a PeerDiscoveryUnavailable.
PeerDiscoveryUnavailable
The transport reported that peer discovery is unavailable on this platform (DiscoveryUnavailable at the transport layer) — typically a missing local-network permission or multicast entitlement.
PeerEvent
Base type for transport events: peer lifecycle and discovery state.
PeerIncompatible
A peer advertised wire versions that share nothing with this build's.
PeerLost
Emitted when a peer disconnects or becomes unreachable.
PnCounter
Positive/negative counter: the value is the sum of every peer's signed deltas, so concurrent increments on different devices all count.
QueryCursor
A position in a query's total order — the sort key of the last row of a page. Opaque to callers: obtain one from a returned page and feed it back to the same query to fetch the next page.
QueryPage<T>
One page of query results: the decoded items and, when the result set continues past them, the nextCursor to fetch the following page with CollectionQuery.startAfter.
QueryPredicate
One compiled where clause of a collection query: the field path it tests, the op, the value to compare against, and the type the collection's merge strategy assigns to that path (which selects how the engine reads the stored field — a plain value, a counter total, or set membership).
QueryRow
One row of a query result at the engine level: a matching document id and its resolved order-by value (for building the next QueryCursor).
QuerySpec
A compiled collection query, ready for a CrdtTable to execute: the conjunction of predicates, an optional order, and a keyset page window.
RangeDigest
The summary of one HLC range of a table, as CrdtTable.rangeDigest returns it: the input to range-based set reconciliation.
RangeDigestBuilder
Streams records into a RangeDigest: an engine calls add once per record in the range (any order) and takes build.
SchemaMergeStrategy
A MergeStrategy that decomposes a document per top-level field and assigns a CrdtType to named paths.
ShallowMergeStrategy
A MergeStrategy that gives each top-level field its own CRDT record.
SnapshotCapable
A CrdtTable that keeps periodic on-disk snapshots as a peerless recovery fallback.
StoreRecovered
A collection's local store was found unreadable on open and rebuilt.
Transport
Discovers same-app nodes and moves opaque frames between them.
WrappedGroupKey
The group key, sealed to one device at one key epoch.
WrappedKey
A symmetric key encrypted ("sealed") to one device's DevicePublicKey.

Enums

CrdtRecoverySource
How a CrdtTable rebuilt its local store after finding it unreadable.
DeviceState
Where a device sits relative to its database's group key after Passnote.openDatabase.
PassphraseStrictness
How Passnote.openDatabase treats a passphrase that is not a recognised BIP39 mnemonic.
QueryOp
How a QueryPredicate compares a field against its value.

Constants

kDeviceCollection → const String
The reserved collection that holds a database's device roster and the group key sealed to each device.

Functions

crdtTypeFromTag(String? tag) → CrdtType
Resolves a persisted CrdtType.tag back to a CrdtType.
newId() → String
Generates a collision-resistant document id.

Typedefs

FieldSpec = ({String path, CrdtType type, Object? value})
One field of a document, ready to be written as its own CRDT record: a stable path, the current value, and the CrdtType that governs how concurrent edits to it merge.
FieldValue = ({String path, Object? value})
One live field record read back from storage: its path and current value. The CrdtType is not needed to rebuild the document (the merge has already happened in the engine), so it is omitted here.
NodeId = String
A unique, stable identifier for this app instance within the transport.
PeerId = String
Identifies a remote peer.

Exceptions / Errors

CipherAuthError
Thrown when decryption fails due to an incorrect key or tampered ciphertext.
PairingRejected
Raised when the sponsor rejects a join: wrong code, too many tries, or the code was already used.
PairingTimeout
Raised when a join does not complete within the allowed time.
RosterPinsCorruptException
Thrown by Passnote.openDatabase and Passnote.reopenDatabase when the device roster's local trust pins (the founder, the device keys and the revocations this device has validated) are stored but unreadable.
SqlCipherUnavailableException
Thrown when an encryption key is supplied but the linked native SQLite library is not a SQLCipher build, so the key would be silently ignored and data would be written to disk in plaintext.
WeakPassphraseException
Thrown by Passnote.openDatabase when PassphrasePolicy.strictness is PassphraseStrictness.reject and the supplied passphrase is not a valid BIP39 mnemonic with known entropy.
WrongPassphraseException
Thrown when a supplied passphrase (or the key derived from it) does not decrypt a database's existing local data.