- mark capability and lifecycle ADRs as accepted - add lifecycle, fencing, and provider-extension guidance - split project terminology into a dedicated glossary
41 KiB
date, commonlib-version, self-hosted-livesync-version, commonlib-source-commit, status
| date | commonlib-version | self-hosted-livesync-version | commonlib-source-commit | status |
|---|---|---|---|---|
| 2026-09-03 | 0.1.21 | 1.0.24 | e770f617ff0fc88f4823226b0ab3aefdff50cc1e | accepted |
Replicator architecture
This is the implemented architecture for Self-hosted LiveSync 1.0.24 with @vrtmrz/livesync-commonlib 0.1.21. It is an implementation overview for developers maintaining the composition or adding a built-in provider. The corresponding Commonlib source was inspected at commit e770f617ff0fc88f4823226b0ab3aefdff50cc1e.
Status, scope, and source-of-truth boundary
The plug-in repository is the source of truth for host composition, host scheduling, Obsidian/CLI/WebApp/WebPeer integration, provider declarations, and host-owned resource adapters. Commonlib is the source of truth for the provider contract, the active-publication state machine, typed replication runners, P2P service ownership, and Journal transport primitives. This repository consumes Commonlib as the published 0.1.21 package; it does not maintain a source mirror or a generated fallback.
The implementation has three built-in providers:
- CouchDB, composed by this repository;
- Object Storage, composed by this repository; and
- P2P, composed by Commonlib's
useP2PReplicatorFeaturein each application runtime which supports it.
The catalogue is closed at host composition. src/common/replicatorProviders.ts exhaustively composes the central providers, while the Commonlib P2P feature composes its P2P provider. This is not a runtime third-party registry: a provider cannot be added by registering a name, loading a plug-in, or supplying a setting at runtime. Adding a provider means changing the relevant Commonlib and host composition, then shipping and testing that composition.
The three capability ADRs record the decisions which led to this shape. They are useful decision history, but this document describes the current implementation and its ownership boundaries rather than repeating the ADR sequence.
Terminology
The Project glossary is canonical for project-specific vocabulary in this document. In particular, see Replicator, Replicator provider definition, Active publication, Admission and reservation, Configuration identity, Capability, Central remote, Publication retirement, and Fence, generation, and epoch. The glossary also fixes the ownership meanings of Adjunct P2P transport, Remote resource and probe, Non-owning adapter, P2P service, room session, and demand, Interaction authority, Journal remote epoch, Replication outcome, and Suspension. The user-facing glossary also distinguishes OneShot Sync from Continuous replication. Names shown in code font are source identifiers, not additional prose terms.
Ownership and topology
The portable topology below names ownership rather than merely call order. An arrow means that the object or layer composes, invokes, or owns the next item.
Application composition
Obsidian main / CLI / WebApp --> LiveSyncBaseCore --+
WebPeerRuntime ------------------------------------+--> Service Hub
|
+----------------------------------------+---------------------+
| |
v v
ReplicatorService (Commonlib) ReplicationService (Commonlib)
| |
+--> closed provider catalogue +--> typed replication runners
| CouchDB / Object Storage / P2P | readiness + outcomes
| |
+--> active publication <------ exact-publication admission ---+
provider + instance + identity
useP2PReplicatorFeature (Commonlib)
|
+--> registers the P2P provider, whose factory creates non-owning active adapters
|
+--> stable P2P service views and lifecycle
|
+--> P2PRoomSessionOwner
|
+--> P2PAutomationCoordinator
+--> current P2PRoomSession
|
+--> P2PHost / TrysteroReplicator
|
+--> Trystero room, relays, and physical peers
LiveSyncBaseCore receives a Service Hub, registers the central provider definitions, composes serviceFeature functions, and retains only focused views. WebPeerRuntime composes directly over its browser Service Hub because it is a P2P-only host. The P2P feature is composed by each supporting application runtime, so the CLI and web applications can use the same transport ownership without making the active adapter a second owner.
| Owner | Responsibility | Explicitly does not own |
|---|---|---|
| Host composition | Selects the closed provider catalogue, supplies host adapters, and registers features before lifecycle work begins. | Active-instance retirement or operation admission. |
Commonlib ReplicatorService |
Provider registration, active publication, exact-publication reservations, serial lifecycle transitions, transfer stop during suspension or retirement, and physical close. | Replication readiness, trigger policy, or P2P room ownership. |
Commonlib ReplicationService and its typed coordinator |
User and unattended OneShot dispatch, Continuous startup, readiness, interaction authority, finite-activity accounting, outcomes, and failure hand-off. | Active publication replacement or scheduling policy. |
Host replication scheduling serviceFeature |
Decides when resume, Periodic, and Continuous requests may run, and fences stale scheduled work. | Provider construction, transfer mechanics, or active Replicator close. |
| Provider definition and runner | Declares what one remote kind supports and adapts its transfer results to typed outcomes. | Selecting when a request should run. |
| Stable P2P service and room-session owner | P2P demand, binding reconciliation, session retirement, finite room operations, automation state, and focused views. | The active P2P adapter's publication lifetime or Trystero's physical peers. |
Request flow
- Composition registers the central provider definitions before lifecycle-driven provider initialisation. P2P composition registers its own Commonlib provider and returns stable P2P views and lifecycle controls.
ReplicatorServiceserialises setting realisation, active-provider initialisation, database lifecycle transitions, suspension, and unload.ReplicationServiceowns per-request readiness. Resume work is separately owned by the host scheduling feature and the P2P service lifecycle.ReplicatorServiceresolves the currentremoteType, checksisConfigured, and computes the provider's opaque configuration identity. If the provider and identity are unchanged, the active publication is retained. If either changes, the replacement fence runs before a new publication is created.- A typed operation such as
runUserInitiated,runUnattended, orstartContinuousacquires the current publication after earlier queued lifecycle transitions have settled. It checks interaction authority, capability support, and readiness in the order required by the request type, then takes an immutable settings snapshot. - The operation admits a reservation against the exact publication and identity. The provider-specific runner owns the transfer; finite operations are counted as bounded remote activity, while continuous replication is not.
- Provider resources are created through the declared resource factories when a feature needs a connection, preferred-tweak, Security Seed, or synchronisation-information probe. Resource ownership is explicit, and owned resources are disposed in the caller's
finallypath. - The runner returns a
ReplicationOutcomerather than usingundefinedas a success signal. Documents delivered throughparseSynchroniseResultare queued by the host result processor for local application; central compatibility recovery and Security Seed preflight remain host features around the typed operation. - Automatic
database-event,editor-save,file-open,merge,resume,periodic, anddaemonrequests select unattended authority explicitly. Unattended work cannot prompt, select a peer interactively, or silently fall back to a legacy capability.
The active publication may change while a request is being prepared. The reservation keeps the admitted old instance alive until the operation settles; a new request admitted after the queued transition observes the new publication. A callback which holds a reservation must not await a lifecycle transition which itself waits for that reservation.
Provider contract and current capability matrix
The Commonlib contract is deliberately small. A provider definition supplies the following shape (with the exact generic types omitted here for readability):
{
kind,
diagnosticName,
readiness,
isConfigured(setting),
configurationIdentity(setting),
create(setting),
remoteResources,
centralRemoteAdministration?,
userInitiatedOneShot,
unattendedOneShot,
continuous,
stopActiveTransfer
}
defineReplicatorProviderDefinitions makes the definition map exhaustive for the selected RemoteType tuple and rejects duplicate, missing, extra, or mismatched runtime definitions. Capability declarations are explicit. supported adapts a provider runner to ReplicationOutcome; not-implemented and not-applicable produce typed blocked outcomes. The contract distinguishes user authority from NO_INTERACTION, so a provider cannot accidentally prompt from an unattended trigger.
The factory receives the fully merged effective settings. It returns a ReplicatorInstance with only four required lifecycle methods:
| Method | Contract |
|---|---|
initializeDatabaseForReplication() |
Prepare local state before publication. false rejects and disposes the candidate. |
openReplication(setting, keepAlive, showResult, ignoreCleanLock) |
Retained compatibility entry point for finite or Continuous work. A typed provider runner must convert its void or Boolean settlement to an explicit outcome; void is not finite success. |
terminateSync() |
Request cancellation of active transfer work and settle synchronously or asynchronously. It does not transfer ownership or replace physical close. |
closeReplication() |
Release resources owned by this instance. It runs only after admitted work drains; a non-owning adapter, such as P2P, must leave service-owned resources alone. |
Provider-specific methods remain on provider-specific interfaces or host-owned adapters. They are not added to the generic contract merely because an old compatibility class exposed them.
Current capability matrix
| Capability | CouchDB | Object Storage | P2P |
|---|---|---|---|
| Readiness | Central remote preparation required | Central remote preparation required | Central preparation not applicable; peer readiness is provider-owned |
| Active Replicator factory | LiveSyncCouchDBReplicator |
LiveSyncJournalReplicator |
P2PActiveReplicatorAdapter over the stable P2P service |
| User-initiated OneShot | Supported | Supported | Supported, with explicit peer selection |
| Unattended OneShot | Supported | Supported | Supported for configured targets; no peer-selection prompt |
| Continuous replication | Supported | Not applicable | Not applicable |
| Stop active transfer | Supported | Supported | Supported; cancels finite operations while retaining the room when appropriate |
| Connection resource | Supported | Supported | Not applicable |
| Preferred-tweak resource | Supported | Supported | Not applicable |
| Security Seed resource | Supported | Supported | Not applicable |
| Synchronisation-information resource | Supported | Not applicable | Not applicable |
| Central remote administration | CouchDB administration supported | Object Storage administration supported | Not applicable |
The matrix is the current host composition, not a promise that every provider must support every row. A new provider must declare every resource kind and every operation capability, using not-applicable where the concept does not exist. Central remote administration is a cohesive capability: it covers the applicable verification milestone and mark-resolved, lock, and unlock mutations rather than exposing individual legacy helpers as generic operations.
Active Replicator lifecycle and exact replacement fence
Commonlib's ReplicatorService serialises lifecycle transitions on one queue. It owns the active publication, reservations against that publication, transfer stop, and final close. The effective configuration identity is deliberately opaque; comparing it is valid, but inspecting or persisting it is not.
absent
|
| configured lifecycle initialisation
v
candidate (private and not admitted)
| \
| initialised and current \ failed or stale --> closed; no active publication
v
active publication
| \ same provider and identity --> retained
| \ suspension ----------------> transfer stopped; publication retained
|
| provider, identity, database, or terminal lifecycle change
v
quiescing (removed from current; new admission fenced)
|
| stop --> drain exact reservations --> close --> complete retirement
v
absent --> optional replacement candidate
For a provider or effective-configuration change, the exact fence is:
- Enqueue the transition on the serial lifecycle queue.
- Read the current setting, resolve the closed provider definition, check
isConfigured, and compute the effective identity. - If the current publication has a different provider or identity, call
beginRetirement. This stops new reservations and removes the publication from the current slot. - Request the provider's
stopActiveTransfercapability. The legacyterminateSyncpath is retained only for an untyped compatibility publication. - Await settlement of reservations admitted from the retiring publication. New operations cannot enter it.
- Call the old instance's
closeReplication. - Mark the retirement complete. No publication is installed between removal of the old publication and this completion.
- Create a candidate through the provider definition, reset provider statistics, and yield the required microtask boundary.
- Initialise the candidate for the current database and run
onBeforeReplicatorPublicationhandlers. - Re-read the current setting, provider, and opaque identity. If any is stale, dispose the candidate and publish nothing; the queued lifecycle work will resolve the newer state.
- Publish the provider, candidate instance, and identity atomically as the new active publication.
The same provider and identity retain the current publication. Database initialisation is a lifecycle boundary even when the setting identity is unchanged: the old publication is retired before the physical local database is replaced, then a candidate is created for the new database. A failed or stale candidate leaves the service without an active publication; it is not silently substituted with a previous instance.
If transfer stop fails, retirement still proceeds to draining and physical close. If physical close rejects, retirement remains fenced and no replacement can be published; a later serial transition may retry the same retirement. The service never restores admission to a publication once retirement has begun.
Generation and epoch fences
These values protect different state machines. They must not be collapsed into one general-purpose generation.
| Fence | Owner and representation | Changes when | Protects | Does not protect |
|---|---|---|---|---|
| Active publication identity | Commonlib ActiveReplicatorPublication object, containing provider, instance, and opaque configuration identity; not a numeric counter |
Provider/configuration replacement, or a database lifecycle replacement | Admission and completion against the exact active instance | Delayed scheduling, P2P automation baselines, or Journal remote-wipe decisions |
| Host scheduling lifecycle generation | ReplicationSchedulingContext.lifecycleGeneration |
Scheduling resumes after the lifecycle was disabled | Resume operations and timer callbacks from a previous host scheduling lifecycle | Provider replacement, P2P room callbacks, or Journal transfers |
| P2P service lifecycle generation | Private P2PServiceState.lifecycleGeneration |
Explicit disconnect or host lifecycle closure | Delayed P2P AutoStart and service-level automatic demand | A room's operation set, automation baseline, or remote Journal epoch |
| P2P session object / epoch fence | The current P2PRoomSession object, its acceptingOperations flag, session abort signal, and the owner's lifecycle queue; there is no exported numeric P2P session epoch |
Room binding replacement, retirement, or owner close | Room callbacks, finite operations, peer handlers, and stale candidate sessions | Cross-session automation deduplication and host scheduling |
| P2P automation generation | P2PAutomationCoordinator.generation |
beginLifecycle or effective identity reconciliation (namespace or database object) |
Completed peer baseline publication and stale automation completions | Room ownership, explicit disconnect veto, and physical peer connection ownership |
| Journal stop generation | LiveSyncJournalReplicator.journalTransferStopGeneration |
terminateSync requests a stop |
Admitted Journal transfers after setup and before client.sync; repeated stops share settlement |
Provider publication identity and remote checkpoint/cache identity |
| Journal remote epoch | CheckPointInfo.journalEpoch, derived as protocolVersion:pbkdf2salt |
Successfully read sync parameters yield a different value; a subsequent history probe decides whether checkpoint caches must be reset | Journal checkpoint and deduplication-cache reconciliation across remote histories | Local cancellation, provider retirement, or transfer admission |
In particular, a numeric value in one row cannot be used as evidence that an operation in another row is current. Failure to read Journal sync parameters does not produce a new remote epoch, and a P2P transport replacement does not by itself clear the automation coordinator's completed-peer baseline.
Suspension, terminal retirement, and database replacement
| Event | ReplicatorService publication |
P2P service and adapter | Result |
|---|---|---|---|
| Application suspension | Requests stopActiveTransfer and retains the active publication |
closeForLifecycle closes the current room/session and invalidates delayed automation; the active adapter is non-owning and does not close the service through closeReplication |
Suspension is reversible. Resumption schedules the appropriate P2P AutoStart and host replication work. |
| Provider setting or effective identity change | Runs the complete replacement fence | Reconciles or replaces the P2P room when its effective binding changes | The old publication/session cannot receive new work. |
| Database replacement or rebuild | Retires and closes the active publication before physical database teardown; database-ready events permit reinitialisation | Closes the P2P room before database destruction and creates a binding for the new database object | No provider or room may retain the old database. |
| Unload or terminal lifecycle close | Stops, drains, closes, and completes retirement; no active publication remains | closeForLifecycle clears owner demand, closes the current room, and invalidates automation |
Terminal retirement is not resumed. |
Suspension and retirement therefore have different guarantees. ReplicatorService suspension stops transfer but intentionally retains the provider instance and publication. Terminal retirement removes admission, drains it, closes it, and does not publish a replacement unless a later lifecycle event explicitly initialises one. P2P transport is additionally closed on suspension because its service lifecycle owns a room session, but the active P2P adapter is only a compatibility handle and does not own that session.
Owned resources and probes
| Resource or probe | Owner | Lifetime and disposal rule |
|---|---|---|
| Active Replicator publication | Commonlib ReplicatorService |
Publication retirement fences admission, drains reservations, calls closeReplication, and completes the retirement. |
| Central connection probe | Host resource factory in src/common/replicatorResources/connection.ts |
A caller-owned CouchDB or Object Storage snapshot backed by a concrete Replicator/connection; dispose it in finally. It does not replace the active publication. |
| Preferred-tweak probe | Host preferredTweak resource factory |
Read through the declared resource, then dispose the owned resource. |
| Security Seed probe | Host securitySeed resource factory and the replication preflight |
Use createRemoteResource and withOwnedRemoteResource; reject an empty seed and always dispose the resource. It does not assume that an active Replicator exists. |
| Synchronisation-information probe | Host synchronisationInformation resource factory |
Check or read through the resource and dispose it; an unavailable remote is not treated as a confirmed absence. |
| Central administration operation | Provider administration runner | Uses its declared verification and mutation ownership. A fresh connection may be owned by the operation; an active Journal client borrowed from the active provider is not disposed by the borrower. |
| Journal client and transfer set | LiveSyncJournalReplicator |
The Journal Replicator owns the client and active transfer promises. terminateSync requests stop and awaits the shared settlement; closeReplication disposes the client without lazily creating one. |
| P2P room/session, finite operation set, and relay actions | P2PRoomSessionOwner and current P2PRoomSession |
The owner serialises binding and demand changes. Session retirement rejects admission, aborts and awaits operations, disables broadcast, and disposes the session Replicator. |
| Physical Trystero peer connections | Trystero runtime | Commonlib must not close raw room.getPeers() connections merely because a logical room session retires; shared Trystero ownership may outlive an idle room callback. |
| Physical local database | Commonlib DatabaseService | Database lifecycle owns teardown and readiness. Replicator and P2P owners close before the database is destroyed. |
Probe callers must use the resource capability rather than reaching through LiveSyncBaseCore.replicator. This keeps a short-lived observation from acquiring ownership of the active transfer or publication.
P2P special ownership and the non-owning adapter
P2P is composed as a serviceFeature and has more state than a central provider. It can remain enabled as an adjunct while CouchDB or Object Storage is the selected main remote; ReplicatorService publishes the P2P active adapter only when remoteType is P2P. The active-publication owner and the room-session owner are therefore deliberately independent.
The stable service owns persistent demand (explicit, automatic, or rebuild-continuation), finite-operation demand, the lifecycle queue, the effective binding, and the current room session. The room owner compares the local database object separately and includes the effective device name in its binding signature, so the binding is not interchangeable with the P2P provider's active-publication configuration identity. The automation coordinator owns automation-baseline deduplication. The current P2PRoomSession owns one room, peer handlers, advertisements, RPC, session cancellation, and finite operations. Trystero owns shared relay clients and physical peer connections.
P2PActiveReplicatorAdapter implements the minimal ReplicatorInstance view required by the provider contract. Its initializeDatabaseForReplication, openReplication, and terminateSync methods delegate to the P2P service. Its closeReplication is intentionally a no-op: closing the active adapter must not close the room, relay actions, finite-operation registry, or stable P2P service. The service lifecycle (closeForLifecycle, owner close, or binding reconciliation) is the only owner which retires the room.
The P2P connection probe follows the same boundary. An active compatible room may be observed; an incompatible active binding blocks the probe. An idle probe can run a caller-owned trial through the owner queue and must await clean-up. It must not publish itself as the active room or close resources owned by another session.
Automatic configured-target replication acquires finite room demand, waits for peer advertisements within a bounded window, evaluates admission without prompting, shares the baseline through P2PAutomationCoordinator, and returns an explicit completed, partial, blocked, cancelled, or failed outcome. Explicit disconnect veto remains distinct from host lifecycle closure. AutoStart cannot clear an explicit disconnect veto; rebuild continuation is a separately authorised path.
Adding a built-in provider
Provider work crosses the Commonlib package boundary and this repository's host composition. The following sequence is the smallest complete path; omit a step only when the provider genuinely has no corresponding concept.
First decide whether this is a provider
A new provider is appropriate when a remote kind needs a distinct active Replicator lifecycle, effective configuration identity, readiness policy, or replication roles. A new S3-compatible service or another backend which retains the Object Storage Journal protocol is usually an IJournalStorage adapter instead; see Journal Replicator 2nd Edition. A new read-only observation over an existing provider is usually a remote resource or a focused view. Neither case needs another active provider.
- Define the canonical remote kind in Commonlib. Add the
RemoteTypevalue and its setting type insrc/common/models/setting.const.tsandsrc/common/models/setting.type.ts, update exports such assrc/common/types.ts, and add defaults or persistence fields only where the provider needs them. Add focused setting and migration tests. - Implement the Replicator in Commonlib. Place the provider-specific Replicator and transport code under
src/replication/<provider>/. Implement the minimalReplicatorInstancecontract, cancellation, and close semantics. Keep provider-specific operations on focused facets. Add unit tests for success, cancellation, failure, stop, and replacement-sensitive clean-up. - Define effective configuration identity. Include every setting which changes the live binding, and exclude profile labels or policy-only settings. Normalise two spellings only when the runtime genuinely treats them as equivalent. Put shared identity logic in Commonlib when the provider is shared there; put the host projection in
src/common/replicatorConfigurationIdentity.tswhen this repository owns it. Test that equivalent effective settings retain an instance and binding changes replace it. Never expose identity values in logs, UI, or persistence. - Add configuration and setup seams in Commonlib. If the provider has a connection string, profile, migration, or document representation, update the applicable files, including
src/common/ConnectionString.ts,src/remoteConfigurations.ts,src/common/configForDoc.ts,src/API/processSetting.ts, and their focused tests. These files are conditional: do not add a setting representation which the provider does not need. - Declare the provider contract surface at its composition owner. Add a central provider to the tuple and definition map in this repository's
src/common/replicatorProviders.ts; add a P2P-like provider to the closed tuple owned by its CommonlibserviceFeature. In the definition, declare readiness, all four remote-resource capability entries, user and unattended OneShot runners, Continuous where applicable,stopActiveTransfer, and central administration where applicable. ExtendRemoteResourcekinds only for a genuinely cross-provider resource; do not encode provider-specific helpers as generic capabilities. - Implement stateful transport ownership, if required. For a P2P-like provider, add a stable service owner, focused views, lifecycle ownership, binding identity, session retirement, and automation fences in Commonlib, then compose it through a
serviceFeature. Keep any active adapter non-owning if the service owns a replaceable transport. Add lifecycle, stale-callback, probe, and database-replacement tests before host integration. - Compose the provider in each supporting application. Central definitions are registered by
LiveSyncBaseCore. A dedicated stateful feature must be composed from the applicable hosts:src/main.ts,src/apps/cli/main.ts,src/apps/webapp/WebAppRuntime.ts, andsrc/apps/webpeer/src/WebPeerRuntime.ts. Each selected catalogue must remain exhaustive and closed; add no runtime provider registry. - Add host-owned resources and administration. Add or extend
src/common/replicatorResources/for connection, preferred-tweak, Security Seed, and synchronisation-information probes. Add provider-specific central verification and mutations insrc/common/centralRemoteAdministration.tswhen applicable. Test ownership, snapshots, the distinction between unavailable and absent states, postconditions, and disposal. - Integrate setup and user-facing configuration. Update the relevant setup dialogue files under
src/modules/features/SetupWizard/dialogs/, includingdialogs/setupDialogTypes.ts, SetupManager or setup features, remote configuration handling, and message resources undersrc/common/messagesYAMLplus generated baked messages where required. Follow the terminology and settings mappings in the repository documentation, and add setup, serialisation, and migration tests. - Integrate host operations and triggers. Adapt only the capability call sites which the provider supports. Check
src/serviceFeatures/replicationScheduling.ts,src/serviceFeatures/replication/, CLI commands undersrc/apps/cli/commands, and application-specific lifecycle composition. Ensure unattended paths useNO_INTERACTION, periodic and resume fallback obey capability outcomes, and no caller reaches forgetNewReplicatoror theLiveSyncBaseCore.replicatorcompatibility getter. - Validate the package boundary. In Commonlib, run its focused unit tests, build or pack the exact candidate artefact, and test the downstream LiveSync consumer against that artefact. In this repository, run provider map, configuration-identity, resource, central-administration, scheduling, and replication-feature unit tests. Add a real remote integration test, CLI E2E coverage, or real Obsidian E2E coverage for every boundary the provider claims to support.
A provider is complete only when its source ownership, replacement fence, capability matrix, setup path, and tests agree. Updating a setting type or adding a class without adding the closed composition definition does not make it a built-in provider.
Compatibility seams and non-goals
ReplicatorService.getNewReplicator,getActiveReplicator, and theLiveSyncBaseCore.replicatorgetter remain compatibility seams for existing callers. BeyondReplicatorInstance,LiveSyncBaseCore.replicatorexposes provider-specific members only as an optional compatibility view. None is a new provider extension point.ReplicationService.performReplicationremains a direct legacy path through the active instance. New call sites usereplicateUserInitiated,replicateUnattended,replicateUnattendedByEvent,startContinuous, orstopActiveTransfer, as appropriate.LiveSyncAbstractReplicatorand other legacy classes may retain methods needed by existing modules. New features use typed provider capabilities, resource factories, and focused service views; they do not infer capabilities from a large legacy class.- The generic contract does not unify directional Journal operations, Streaming replication, Chunk retrieval, remote-size inspection, garbage collection, repair workflows, or provider-specific administration. Those remain explicit provider or host features.
- The provider catalogue is not a public runtime registry, dynamic plug-in API, or settings-driven discovery mechanism. Unknown
RemoteTypevalues are composition/configuration failures, not third-party providers which the runtime should load. - Commonlib remains an external authoritative package. This repository must not recreate
src/lib,_types, or another source mirror to bypass the package boundary. - P2P logical room retirement does not authorise closing shared raw
RTCPeerConnectionobjects. Physical transport ownership remains with Trystero. - No numeric P2P session epoch is exported. Session object identity, admission flags, abort signals, and the owner queue provide the fence; the P2P automation generation and the host scheduling generation protect different concerns.
- Suspension is not a database replacement or a successful replication result. It stops or closes the appropriate active work and relies on the next lifecycle event to resume, reconcile, or retire it.
Source map
This repository
| Concern | Source and tests |
|---|---|
| Host composition and compatibility boundary | LiveSyncBaseCore.ts, main.ts, src/apps/cli/main.ts, WebAppRuntime.ts, WebPeerRuntime.ts |
| Closed central provider map | replicatorProviders.ts, replicatorProviders.unit.spec.ts |
| Provider identities and resources | replicatorConfigurationIdentity.ts, replicatorResources/, replicatorResources.unit.spec.ts |
| Central administration and preflight | centralRemoteAdministration.ts, centralRemoteAdministration.unit.spec.ts, replication/preflight.ts |
| Host scheduling and replication feature | replicationScheduling.ts, replicationScheduling.unit.spec.ts, replication/index.ts |
| Service graph and bounded local activity | ObsidianServices.ts, ObsidianServiceHub.ts |
| Architecture guidance | devs.md, Service feature and legacy Module boundaries, Project glossary, Documentation style and vocabulary conventions, docs/settings.md, docs/troubleshooting.md |
Commonlib 0.1.21
The exact package tree described here is pinned at commit e770f617ff0fc88f4823226b0ab3aefdff50cc1e. The source and design-document links below target that commit.
| Concern | Commonlib source or design document at the pinned commit |
|---|---|
| Provider contract, outcomes, identities, and resource capabilities | src/replication/ReplicatorInstance.ts, src/replication/ReplicatorProvider.ts, src/replication/RemoteResource.ts, src/replication/CentralRemoteAdministration.ts, src/replication/CentralCompatibility.ts |
| Active publication and typed operations | src/services/base/ReplicatorService.ts, activeReplicatorState.ts, typedReplication.ts, readiness.ts |
| P2P service, room ownership, and automation | P2PService.ts, P2PRoomSessionOwner.ts, P2PRoomSession.ts, useP2PReplicatorFeature.ts, P2PAutomationCoordinator.ts |
| P2P lifecycle design | docs/p2p-transport-lifecycle.md |
| Database and service-feature lifecycle | docs/database-lifecycle.md, docs/service-feature-composition.md, docs/settings-lifecycle.md |
| Journal transfer and remote epoch | LiveSyncJournalReplicator.ts, JournalSyncCore.ts, JournalSyncTypes.ts |
| Journal storage adapter boundary | JournalStorageAdapter.ts |