@vrtmrz/livesync-commonlib 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +17 -0
  2. package/dist/managers/EntryManager/EntryManagerImpls.js +1 -1
  3. package/dist/p2p/P2PService.d.ts +10 -1
  4. package/dist/p2p/P2PService.js +25 -2
  5. package/dist/p2p/index.d.ts +4 -1
  6. package/dist/p2p/index.js +2 -0
  7. package/dist/p2p/p2pDiagnostics.d.ts +35 -0
  8. package/dist/p2p/p2pDiagnostics.js +76 -0
  9. package/dist/pouchdb/ReplicatorShim.batch.d.ts +30 -0
  10. package/dist/pouchdb/ReplicatorShim.batch.js +62 -0
  11. package/dist/pouchdb/ReplicatorShim.d.ts +14 -1
  12. package/dist/pouchdb/ReplicatorShim.js +64 -80
  13. package/dist/replication/trystero/P2PLogCollector.d.ts +12 -0
  14. package/dist/replication/trystero/P2PLogCollector.js +107 -72
  15. package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +4 -0
  16. package/dist/replication/trystero/P2PRoomSessionOwner.js +39 -2
  17. package/dist/replication/trystero/TrysteroReplicator.d.ts +21 -24
  18. package/dist/replication/trystero/TrysteroReplicator.js +191 -69
  19. package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +11 -0
  20. package/dist/replication/trystero/p2pReplicationDiagnostics.d.ts +9 -0
  21. package/dist/replication/trystero/p2pReplicationDiagnostics.js +51 -0
  22. package/dist/replication/trystero/p2pReplicationProgress.d.ts +15 -0
  23. package/dist/replication/trystero/p2pReplicationProgress.js +37 -0
  24. package/dist/replication/trystero/types.d.ts +3 -0
  25. package/dist/services/base/APIService.d.ts +10 -0
  26. package/dist/services/base/APIService.js +13 -0
  27. package/dist/services/base/IService.d.ts +2 -0
  28. package/docs/journal-receive-recovery.md +7 -4
  29. package/docs/p2p-transport-lifecycle.md +117 -10
  30. package/docs/releasing.md +6 -0
  31. package/package.json +2 -2
@@ -2,14 +2,17 @@
2
2
  date: 2026-11-04
3
3
  commonlib-version: "0.3.1"
4
4
  self-hosted-livesync-version: "1.0.44"
5
- status: unreleased
5
+ status: published
6
+ published-in: "0.3.2"
7
+ publication-date: 2026-11-05
6
8
  ---
7
9
 
8
10
  # Journal receive failures and recovery
9
11
 
10
- This document describes unreleased receive behaviour. Hosts choose when to
11
- offer the manual skip operation and remain responsible for Vault reflection
12
- and conflict handling.
12
+ This document describes receive behaviour published in
13
+ [Commonlib 0.3.2](https://github.com/vrtmrz/livesync-commonlib/releases/tag/0.3.2).
14
+ Hosts choose when to offer the manual skip operation and remain responsible
15
+ for Vault reflection and conflict handling.
13
16
 
14
17
  ## Stop and retry by default
15
18
 
@@ -55,19 +55,126 @@ Ordinary consumers use the focused views returned by the service feature. They d
55
55
 
56
56
  The stable view objects close over the same private context, but do not expose that context or one another. They are capability boundaries for consumers, not separately allocated owners. A consumer receives only the views it needs.
57
57
 
58
- | View | Implemented responsibility |
59
- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
60
- | `P2PTransportLifecycle` | observe the current connection and accept explicit connect or disconnect intent |
61
- | `P2PConnectionProbeAdmission` | arbitrate a complete Setup signalling check against the current relay binding |
62
- | `P2PPeerDirectory` | supply a current peer advertisement snapshot |
63
- | `P2PPeerAdmission` | apply or revoke temporary and persisted acceptance decisions |
64
- | `P2PTargetedTransfer` | pull, request push, synchronise one peer, or execute the persisted configured-target set without peer-selection dialogue |
65
- | `P2PChangeRelay` | watch or unwatch a peer and enable or disable local-change broadcast |
66
- | `P2PConfigurationExchange` | retrieve configuration from one explicitly selected peer |
67
- | `P2PDiagnostics` | request status and project RTC metrics without exposing the room or peer connection |
58
+ | View | Implemented responsibility |
59
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
60
+ | `P2PTransportLifecycle` | observe the current connection and accept explicit connect or disconnect intent |
61
+ | `P2PConnectionProbeAdmission` | arbitrate a complete Setup signalling check against the current relay binding |
62
+ | `P2PPeerDirectory` | supply a current peer advertisement snapshot |
63
+ | `P2PPeerAdmission` | apply or revoke temporary and persisted acceptance decisions |
64
+ | `P2PTargetedTransfer` | pull, request push, synchronise one peer, or execute the persisted configured-target set without peer-selection dialogue |
65
+ | `P2PChangeRelay` | watch or unwatch a peer and enable or disable local-change broadcast |
66
+ | `P2PConfigurationExchange` | retrieve configuration from one explicitly selected peer |
67
+ | `P2PDiagnostics` | observe diagnostic events and replication progress, request status, and project RTC metrics without exposing transport handles |
68
68
 
69
69
  The optional host UI factory is an explicit compatibility boundary. Commonlib supplies both the deprecated compatibility Replicator and the stable views. Maintained modal transport and status controls use the views; legacy interactive execution and rebuild-specific setup markers may still use the compatibility Replicator. Receiving that façade does not transfer ownership of the room. `UseP2PReplicatorResult.replicator` remains deprecated for the same bounded migration work.
70
70
 
71
+ ## Per-peer replication progress
72
+
73
+ `P2PDiagnostics.getReplicationProgress?()` supplies a read-only snapshot sorted by
74
+ peer ID. `onReplicationProgress?(listener)` observes subsequent snapshots and
75
+ returns a subscription disposer. Hosts should check that these optional methods
76
+ exist when composing an older implementation. The service owns a `P2PLogCollector`
77
+ for these views, and releases its event registrations on platform unload. Peer
78
+ departure removes that peer, and room disconnect or replacement clears the snapshot.
79
+ Repeated advertisements update the peer name and retain its structured progress;
80
+ the legacy map and text keep their existing advertisement reset behaviour.
81
+
82
+ Each direction retains the established `current` and `max` numeric source sequence
83
+ values and `isActive` flag. `P2PLogCollector.p2pReplicationResult` and
84
+ `p2pReplicationLine` keep those sequence units and the existing text format.
85
+ Sequence subtraction does not measure transferred documents.
86
+
87
+ A direction may additionally supply `statistics: { documents, checkedChanges }`:
88
+
89
+ - `documents` counts successfully transferred database document revisions, including
90
+ Metadata and Chunks. It excludes already-held revisions and refresh reads. Two
91
+ missing conflict revisions of one document count as two transfers.
92
+ - `checkedChanges` counts changes-feed entries processed for revision comparison,
93
+ including entries which require no transfer and repeated entries checked again.
94
+
95
+ Both counters start at zero for each finite pull attempt, accumulate across its
96
+ batches, and retain their final values when the direction becomes inactive. The
97
+ sending direction observes the receiver's acknowledgements. An absent
98
+ `statistics` field means the peer has not supplied these counts; it differs from
99
+ an observed zero. A completed all-known batch updates statistics without invoking
100
+ the legacy document-processing callback. That callback still receives the
101
+ refreshed documents only when the batch has missing revisions.
102
+
103
+ The shim's optional `onStatistics` observer also reports accepted writes when a
104
+ later write, refresh, or checkpoint step fails. These counts do not establish a
105
+ committed checkpoint or a completed replication attempt. The observer's sequence
106
+ retains the latest successfully processed batch boundary when a later batch fails
107
+ or is cancelled before writing; the document callback keeps its original batch
108
+ sequence values. Observer failures do not change document processing or checkpoint
109
+ safety.
110
+
111
+ Progress uses the existing `onProgressAcknowledged` RPC. An optional third argument
112
+ carries a transient attempt number, allocated monotonically across room sessions
113
+ within the receiver's module lifetime. Trystero's default peer ID is also generated
114
+ for that module lifetime. The sending observer ignores older attempts, reordered
115
+ batch counts, and updates received after the same attempt's terminal marker. The
116
+ terminal acknowledgement keeps the legacy absent progress argument and adds the
117
+ final progress in its optional metadata, so a terminal marker which overtakes a
118
+ batch still supplies final sequences and counts. Older peers can ignore the extra
119
+ argument and continue using sequence progress. No handshake, retry, heartbeat, or
120
+ persistent replication state is added.
121
+
122
+ ## Latest diagnostic observations
123
+
124
+ The optional `P2PDiagnostics.getDiagnosticSnapshot()` and
125
+ `onDiagnosticEvent(listener)` methods expose the latest `relay`, `peer`, and
126
+ `sync` observations. A missing category is unobserved, rather than a successful
127
+ result or a measured zero. Each immutable event contains a source timestamp in
128
+ milliseconds since the Unix epoch, a fixed code, an optional fixed reason, and an
129
+ optional peer ID. Events do not include device names, settings, room IDs, keys,
130
+ SDP, IP addresses, or arbitrary error text.
131
+
132
+ The stable service owns only one latest event per category. Peer departure and
133
+ room closure retain the latest peer and sync evidence after the peer row has
134
+ disappeared. Room replacement fences the previous session's reporting port before
135
+ retirement, so a late authentication result, notification, or transport callback
136
+ cannot overwrite the current session's evidence. Platform unload detaches the
137
+ store and its subscribers. Older diagnostics implementations may omit both methods.
138
+
139
+ Accepted observations are also published once through the context-owned
140
+ `EVENT_P2P_DIAGNOSTIC` channel exported from `/p2p`. Hosts can format that same
141
+ stream for their summary and diagnostic log. Identical events with the same source
142
+ timestamp are coalesced; repeated advertisements of an already-known peer and
143
+ unchanged watch decisions do not produce another diagnostic transition. No
144
+ server-snapshot, document, or batch progress subscription is used for this stream.
145
+ Diagnostic subscribers and source reporting callbacks cannot change authentication,
146
+ replication outcomes, or room lifecycle control flow. Hosts using the general
147
+ EventHub channel should contain exceptions in their own listener, as with their
148
+ other EventHub listeners.
149
+
150
+ Owned observations include room opening, opening completion or failure, closure,
151
+ join-error callbacks, validated first peer advertisements, peer departure,
152
+ authentication acceptance or refusal, classified RPC failures, finite pull
153
+ outcomes, and watch or change-notification boundaries. Authentication refusal,
154
+ RPC timeout, cancellation, and other RPC errors have distinct fixed codes while
155
+ retaining the existing boolean and replication result contracts. Only an explicit
156
+ `false` authentication response indicates refusal. Missing or non-boolean responses
157
+ use `auth-error` with `authentication-unobserved`, while keeping the existing return
158
+ value and admission policy. An unavailable
159
+ remote broadcast status remains unobserved rather than being reported as an
160
+ explicit false result. Broadcast enablement is observed only after feed creation,
161
+ and an unexpected feed error supplies a fixed failure reason when broadcasting
162
+ stops. No diagnostic operation retries, reconnects, or alters a checkpoint.
163
+
164
+ A room-opened observation means that the owned Trystero room is active. It does
165
+ not establish that a Nostr relay accepted its advertisement. In the reviewed
166
+ `@trystero-p2p/nostr` 0.26.0 API, relay `NOTICE`, rejected `OK`, and `CLOSED`
167
+ messages are written internally to the console without an owned callback. The
168
+ public socket getter is shared across rooms and replaces sockets during
169
+ reconnection. This diagnostic stream therefore uses `relay-details-unobserved`
170
+ and does not intercept console output or WebSocket globals, attach to shared
171
+ sockets, or poll. Relay rejection text remains unavailable through this API.
172
+
173
+ The existing detailed RTC failure subscription is also process-wide and supplies
174
+ no peer or room attribution. Its typed failure reasons remain in the existing
175
+ Diag logging path. They are not presented as a failure of an arbitrary owned room
176
+ or peer in the new stream.
177
+
71
178
  ## Room demands and automation generations
72
179
 
73
180
  `P2PRoomSessionOwner` opens a room while at least one room demand exists. Persistent demands are currently `explicit`, `automatic`, and `rebuild-continuation`. A finite target operation receives an unexported symbol demand for its own lifetime. Removing one demand cannot close a room retained by another persistent or finite demand.
package/docs/releasing.md CHANGED
@@ -67,6 +67,12 @@ For 0.2.3, the documented exceptions are the `HandlerFunction.setHandler` and `L
67
67
 
68
68
  Version 0.3.0 introduces a source compatibility change: the custom client passed to `LiveSyncJournalReplicator.ensureBucketIsCompatible` must provide `hasRemoteJournals(): Promise<boolean>`. The operation distinguishes an empty bucket from Journal files left without an identifying milestone. Keeping it required makes missing client capability a type error. The standard `JournalSyncCore` client already supplies it. This change uses the next minor version under the policy above.
69
69
 
70
+ Version 0.4.0 changes the P2P action wire format by adopting Trystero 0.26.0.
71
+ Communicating peers must use compatible transport versions. Custom `IAPIService`
72
+ implementations must also provide `registerCleanup(callback: () => void): void`;
73
+ subclasses of `APIService` inherit its default terminal-unload implementation.
74
+ These changes use the next minor version under the compatibility policy.
75
+
70
76
  ## Preparing a release
71
77
 
72
78
  Choose the version explicitly. For the 0.2 line, start at 0.2.0. A stable candidate can use its final version on the `next` dist-tag, then be checked by exact source revision and tarball SHA-256 before the same version is promoted to `latest`. No `-next.N` or `-rc.N` version is required; use a separate prerelease version only when it is useful for a distinct candidate. Package-proof versions are local artefacts and cannot be staged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrtmrz/livesync-commonlib",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Shared data, storage, and replication primitives for Self-hosted LiveSync clients.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -1020,7 +1020,7 @@
1020
1020
  "@smithy/middleware-apply-body-checksum": "^4.3.9",
1021
1021
  "@smithy/types": "^4.14.3",
1022
1022
  "@smithy/util-retry": "^4.4.5",
1023
- "@trystero-p2p/nostr": "0.25.3",
1023
+ "@trystero-p2p/nostr": "0.26.0",
1024
1024
  "@vrtmrz/value-store": "0.1.0",
1025
1025
  "diff-match-patch": "^1.0.5",
1026
1026
  "events": "^3.3.0",