/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * The push side of the WAS replication adapter: fans each local change out to * conditional WAS writes and assembles the RxDB conflict entry when the server * rejects a write with `412`. * * A single RxDB document spans two independently-versioned sub-resources: the * content (`data` / `version`, at `PUT/DELETE /:id`) and the metadata (`custom` * / `metaVersion`, at `PUT /:id/meta`). This handler diffs the new local state * against the assumed master to route each half: * * - content changed -> `PUT /:id` (`If-Match: ""`) or, on create, * `PUT /:id` (`If-None-Match: *`); a delete -> `DELETE /:id`. * - metadata changed -> `PUT /:id/meta` (`If-Match: ""`, or * `If-None-Match: *` when the resource has no metadata yet); a metadata * CLEAR (the new state carries no `custom`) writes the cleared state rather * than being skipped. * * Content is written before metadata on a create, because the server rejects a * `/meta` write to a resource that does not yet exist. * * RxDB's push contract asks only for *conflicts* back (the current master state * of each rejected row), so a successful write's new `version` / `metaVersion` * is reported out-of-band: the response ETag of each accepted write is captured * and handed to the optional `onWriteAccepted` callback, which writes the acked * revision back into the local row (see `createWasReplication`). Without that * write-back the local `version` would stay one revision behind the server and * every subsequent conditional write would send a stale `If-Match` and 412. The * write-back only touches the revision fields (never `data` / `updatedAt`), so * the follow-up push cycle it triggers finds nothing changed to write and * settles -- no re-push loop. */ import type { WithDeleted } from 'rxdb/plugins/core'; import type { SyncedDoc, WasSyncPort } from './types.js'; /** * The acked server revisions of one row's accepted writes: the new content * `version` (from a `PUT /:id` or `DELETE /:id` response ETag) and/or the new * `metaVersion` (from a `PUT /:id/meta` response ETag). Absent fields mean the * corresponding write did not run or its response carried no ETag. */ export interface PushWriteAck { id: string; version?: number; metaVersion?: number; } /** * Builds the RxDB push handler that fans a batch of local changes out to * conditional WAS writes and returns the conflicting rows' master states. * * Rows are pushed concurrently; if any non-conflict error is thrown the whole * batch rejects (RxDB re-sends it later), matching RxDB's all-or-nothing retry. * * Each accepted write's acked server revision(s) are handed to * `onWriteAccepted` (when supplied) as soon as that row's writes settle, so the * caller can write the new `version` / `metaVersion` back into the local row * and keep subsequent conditional writes' `If-Match` in step with the server. * * Each batch gets one short-lived master-read memo, shared by its rows and * discarded with the batch (never held across batches, where it would go * stale). A conflict re-read walks the changes feed from its origin and so pages * past every other conflicting row's master on the way; without the memo a batch * with k conflicts would run k concurrent full-feed walks. * * @param port {WasSyncPort} * @param [onWriteAccepted] {(ack: PushWriteAck) => Promise} * @returns {(rows: Array<{ newDocumentState: WithDeleted, * assumedMasterState?: WithDeleted }>) => * Promise[]>} */ export declare function createPushHandler(port: WasSyncPort, onWriteAccepted?: (ack: PushWriteAck) => Promise): (rows: Array<{ newDocumentState: WithDeleted; assumedMasterState?: WithDeleted; }>) => Promise[]>; //# sourceMappingURL=pushWrites.d.ts.map