/** * Cross-tab write propagation. A role-agnostic relay: it broadcasts * a ciphertext-blind signal ({vault, collection, docId, action}) for every * locally-committed write (via onAfterWrite), and on receiving a peer * tab's signal it asks the host to refresh that document's in-memory view by * re-reading the shared encrypted store. Nothing decrypted crosses the wire. */ import type { TabChannel, Unsubscribe } from './tab-coordination.js'; import type { WriteEvent } from '../port/with/write-hooks.js'; export interface TabWriteMsg { readonly kind: 'tab-write'; readonly writerId: string; readonly vault: string; readonly collection: string; readonly docId: string; readonly action: 'put' | 'delete'; readonly baseV: number; readonly v: number; } export interface CrossTabWriteRelayOptions { /** The broadcast channel (its own — distinct from the presence channel). */ readonly channel: TabChannel; /** This tab's id — outgoing signals carry it; incoming self-signals are ignored. */ readonly writerId: string; /** Subscribe to committed writes (the host's onAfterWrite). */ readonly subscribeAfterWrite: (handler: (e: WriteEvent) => void) => Unsubscribe; /** Refresh a document's in-memory view from the shared store. */ readonly applyRemoteWrite: (vault: string, collection: string, docId: string, action: 'put' | 'delete') => void | Promise; /** Report a detected conflict (host captures + converges + emits). */ readonly reportConflict?: (vault: string, collection: string, docId: string, action: 'put' | 'delete', baseV: number, v: number, ownV: number) => void | Promise; /** Close the channel on dispose (only when the relay created it). Default false. */ readonly closeChannelOnDispose?: boolean; } export declare class CrossTabWriteRelay { #private; constructor(opts: CrossTabWriteRelayOptions); start(): void; dispose(): void; }