v0.21.0
Changed
- The WAS replication driver now lives in
@interop/was-syncand is a
dependency of this package. What moved: the changes-feed pull handler, the
conditional-write push handler, thereplicateRxCollectionwiring, the
feed-backed conflict re-read, the synced-document schema, the conflict-handler
seam with its last-write-wins default, the writer-id mint, and the controller
core.src/sync/is gone;docCipher.tsandwasSyncPort.tsmoved to
src/storage/, which is where this package's key handling stays. SyncController(src/storage/syncController.ts) is now a binding over the
package'screateSyncController. Its public shape is unchanged
(start({ remoteStore, localStore, onRemoteChange, onAuthError }),reSync,
a terminalstop), and so are the skip of an uncovered collection, the status
keying on the logical collection key, and the failed bring-up that flags every
collection and rethrows. One behavior is new: the periodic re-sync now skips
its tick while the browser reports itself offline, instead of firing into a
known-down network.storage/writerId.tsis a thin binding over the package's mint: it supplies
DEFAULT_STORAGE_KEY_PREFIXandlocalStorage.getWriterIdand
clearPersistedWriterIdkeep their names and their optional-prefix signature.isAuthErrorkeeps its name and is re-exported from@interop/was-sync/rxdb.
It is still exported from this package's root.SyncStatusis re-exported from@interop/was-client/sync, which now owns
the four-string vocabulary the replication driver and the wallets' own sync
engine both report. The Zustand status store,deriveSyncRollup, and
useSyncStatusare unchanged.- The "master" names became "primary" in the package:
MasterStateis
PrimaryState,MasterReadCacheisPrimaryReadCache, and
withFeedMasterReadiswithFeedPrimaryRead. RxDB's ownassumedMasterState
andrealMasterStatefields are RxDB's API and are untouched. - The replica schema is the package's merged one, which adds
createdBy. RxDB
hashes a schema and refuses to open a replica whose stored hash differs at the
sameversion, and it ships atversion: 0with no migration strategy. Every
existing local replica must therefore be cleared once: clear local data and
log in again, and the collections re-pull from WAS. Anything written only
locally and never synced is lost with it.
Removed
The root barrel no longer re-exports the driver. Every name below is gone from
@interop/was-react; import it from the package named beside it.
- From
@interop/was-sync:syncedDocSchema,makeLwwConflictHandler,
lwwFields, and the typesLwwFields,SyncCheckpoint,SyncedDoc,
WireDoc,WasSyncBasePort,WasSyncPort, andMasterState/
MasterReadCache(asPrimaryState/PrimaryReadCache). - From
@interop/was-sync/rxdb:createWasReplication,createPullHandler,
wireDocToRxDoc,createPushHandler, the typePushWriteAck, and
withFeedMasterRead(aswithFeedPrimaryRead). - From
@interop/was-client/sync:errorStatus,errorMessage,formatEtag,
isEncryptedEnvelope,isUnknownEpochError,WasSyncConflictError,
WasSyncAuthError, and the typeJson(also available from
@interop/was-sync). These were pass-throughs; the client owns them. - From
@interop/was-client/edv:hasKeyEpochs,epochRostersEqual, also
pass-throughs.
createDocCipher, createPlaintextDocCodec, createUnprovisionedDocCipher,
the type DocCipher, and createWasSyncPort stay exported from this package's
root: they hold this library's key handling and the client seam, which the
driver never touches.
Dependencies
@interop/was-sync^0.1.0, added.rxdb ^17is still a required peer:LocalStoreis exported from the root
entry and imports it. A replica-less app can drop it once that entry point is
split (WR-44).
Changed
- The last-write-wins comparison is
remotePayloadWinsfrom
@interop/social-core, andsrc/sync/lww.tsis deleted. Its stamp accessor
(lwwFields,LwwFields) moves tosrc/sync/types.tsand still ships from
the root barrel. This is a behavior change on the three sites that compare
outside conflict resolution: the anonymous-to-connected adopt, the
duplicate-id pick inhydrateSingleton, and the entity store's patch. On a
pair where exactly oneupdatedAtparses, the parseable side no longer wins;
the raw strings compare lexically. One rule now, the one every wallet's stored
data already converges under. - A
412-refused delete whose re-read body is unchanged is re-issued against
the current ETag. A locally created row pushed with a revision the server has
since moved past would otherwise be refused forever and stay live on the
server. Every other412is still a real conflict. bodiesEqualcompares JCS-canonicalized JSON. A stored body a host
re-serializes with a different key order no longer reads as a change, which is
what keeps the delete retry firing and stops a spuriousPUTon an immutable
content-addressed row.- The push handler and the sync controller's
isAuthErrormatch the port's
typed signals byerr.name, throughisSyncConflictError,isSyncAuthError,
andisUnknownEpochErrorfrom@interop/was-client/sync, never by
instanceof. An error raised by a second physical copy of the client is
classified the same as this copy's.err.statusis read off the matched value
as a plain property. - The server-managed
createdBycreator DID is carried across the sync layer:
it joinsOptionalBodyFields,WireDoc, andSyncedDoc, and rides the pull
mapping (live documents and tombstones) and the assembled conflict entry. The
RxDB schema does not declare it yet; that lands with the merged schema when
the driver moves into its own package. MasterState.deletedis optional. A feed-backed read sets it; a clientget
resolvesnullfor a tombstone and sets nothing, and the push handler reads
an absent flag asfalse.getWriterIdno longer adopts a value left under the pre-rename
<prefix>clientIdkey, andclearPersistedWriterIdno longer removes that
key. WherelocalStoragecannot answer,getWriterIdmints a fresh id per
call instead of remembering one for the process: a shared fallback stamped one
label into two accounts' histories in the same tab.docCipher.tsno longer declares its own unknown-epoch predicate or its own
base cipher shape.isUnknownEpochErrorships from@interop/was-client/sync
(still re-exported from the root barrel), andDocCipherextends the
client's, adding the requiredencryptUpdateand the optional blinded-index
applyMeta.- Dependency floors:
@interop/was-client^0.49.0,@interop/wallet-core
^0.67.0,@interop/webkms-client^14.7.5(matching wallet-core's).
@interop/social-coreandjson-canonicalizeare added.
Removed
- The root barrel no longer exports
remotePayloadWins. It is
@interop/social-core's name, and one name has one owner; import it from
there.