@interop/was-react 0.20.1 → 0.22.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.
- package/README.md +28 -2
- package/dist/auth/loginFlow.d.ts.map +1 -1
- package/dist/auth/loginFlow.js +5 -5
- package/dist/auth/loginFlow.js.map +1 -1
- package/dist/auth/verifyResponse.d.ts.map +1 -1
- package/dist/auth/verifyResponse.js +7 -4
- package/dist/auth/verifyResponse.js.map +1 -1
- package/dist/dev/provisionDevGrants.js +1 -1
- package/dist/dev/provisionDevGrants.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +48 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +52 -0
- package/dist/log.js.map +1 -0
- package/dist/session/authStore.d.ts.map +1 -1
- package/dist/session/authStore.js +12 -10
- package/dist/session/authStore.js.map +1 -1
- package/dist/session/localWipe.d.ts.map +1 -1
- package/dist/session/localWipe.js +5 -4
- package/dist/session/localWipe.js.map +1 -1
- package/dist/storage/adopt.d.ts.map +1 -1
- package/dist/storage/adopt.js +2 -1
- package/dist/storage/adopt.js.map +1 -1
- package/dist/storage/descriptorManager.d.ts.map +1 -1
- package/dist/storage/descriptorManager.js +5 -4
- package/dist/storage/descriptorManager.js.map +1 -1
- package/dist/{sync → storage}/docCipher.d.ts +3 -29
- package/dist/storage/docCipher.d.ts.map +1 -0
- package/dist/{sync → storage}/docCipher.js +0 -20
- package/dist/storage/docCipher.js.map +1 -0
- package/dist/storage/entityStore.d.ts.map +1 -1
- package/dist/storage/entityStore.js +2 -1
- package/dist/storage/entityStore.js.map +1 -1
- package/dist/storage/localStore.d.ts +1 -1
- package/dist/storage/localStore.d.ts.map +1 -1
- package/dist/storage/localStore.js +15 -2
- package/dist/storage/localStore.js.map +1 -1
- package/dist/storage/sharedCollectionReader.d.ts +1 -1
- package/dist/storage/sharedCollectionReader.d.ts.map +1 -1
- package/dist/storage/sharedCollectionReader.js +11 -11
- package/dist/storage/sharedCollectionReader.js.map +1 -1
- package/dist/storage/storageContext.d.ts +1 -2
- package/dist/storage/storageContext.d.ts.map +1 -1
- package/dist/storage/storageContext.js.map +1 -1
- package/dist/storage/storageManager.d.ts +1 -1
- package/dist/storage/storageManager.d.ts.map +1 -1
- package/dist/storage/syncController.d.ts +30 -19
- package/dist/storage/syncController.d.ts.map +1 -1
- package/dist/storage/syncController.js +86 -157
- package/dist/storage/syncController.js.map +1 -1
- package/dist/storage/syncStatusStore.d.ts +8 -7
- package/dist/storage/syncStatusStore.d.ts.map +1 -1
- package/dist/storage/syncStatusStore.js.map +1 -1
- package/dist/storage/wasRemoteStore.d.ts.map +1 -1
- package/dist/storage/wasRemoteStore.js +6 -2
- package/dist/storage/wasRemoteStore.js.map +1 -1
- package/dist/storage/wasSync.d.ts +1 -1
- package/dist/storage/wasSync.d.ts.map +1 -1
- package/dist/storage/wasSync.js +28 -15
- package/dist/storage/wasSync.js.map +1 -1
- package/dist/{sync → storage}/wasSyncPort.d.ts +14 -8
- package/dist/storage/wasSyncPort.d.ts.map +1 -0
- package/dist/storage/wasSyncPort.js.map +1 -0
- package/dist/storage/writerId.d.ts +7 -13
- package/dist/storage/writerId.d.ts.map +1 -1
- package/dist/storage/writerId.js +30 -46
- package/dist/storage/writerId.js.map +1 -1
- package/package.json +16 -11
- package/dist/sync/changesQuery.d.ts +0 -44
- package/dist/sync/changesQuery.d.ts.map +0 -1
- package/dist/sync/changesQuery.js +0 -54
- package/dist/sync/changesQuery.js.map +0 -1
- package/dist/sync/docCipher.d.ts.map +0 -1
- package/dist/sync/docCipher.js.map +0 -1
- package/dist/sync/feedMasterPort.d.ts +0 -38
- package/dist/sync/feedMasterPort.d.ts.map +0 -1
- package/dist/sync/feedMasterPort.js +0 -116
- package/dist/sync/feedMasterPort.js.map +0 -1
- package/dist/sync/index.d.ts +0 -23
- package/dist/sync/index.d.ts.map +0 -1
- package/dist/sync/index.js +0 -27
- package/dist/sync/index.js.map +0 -1
- package/dist/sync/lww.d.ts +0 -50
- package/dist/sync/lww.d.ts.map +0 -1
- package/dist/sync/lww.js +0 -69
- package/dist/sync/lww.js.map +0 -1
- package/dist/sync/lwwConflictHandler.d.ts +0 -83
- package/dist/sync/lwwConflictHandler.d.ts.map +0 -1
- package/dist/sync/lwwConflictHandler.js +0 -114
- package/dist/sync/lwwConflictHandler.js.map +0 -1
- package/dist/sync/pushWrites.d.ts +0 -76
- package/dist/sync/pushWrites.d.ts.map +0 -1
- package/dist/sync/pushWrites.js +0 -221
- package/dist/sync/pushWrites.js.map +0 -1
- package/dist/sync/syncedDocSchema.d.ts +0 -22
- package/dist/sync/syncedDocSchema.d.ts.map +0 -1
- package/dist/sync/syncedDocSchema.js +0 -29
- package/dist/sync/syncedDocSchema.js.map +0 -1
- package/dist/sync/types.d.ts +0 -319
- package/dist/sync/types.d.ts.map +0 -1
- package/dist/sync/types.js +0 -58
- package/dist/sync/types.js.map +0 -1
- package/dist/sync/wasReplication.d.ts +0 -47
- package/dist/sync/wasReplication.d.ts.map +0 -1
- package/dist/sync/wasReplication.js +0 -92
- package/dist/sync/wasReplication.js.map +0 -1
- package/dist/sync/wasSyncPort.d.ts.map +0 -1
- package/dist/sync/wasSyncPort.js.map +0 -1
- /package/dist/{sync → storage}/wasSyncPort.js +0 -0
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The push side of the WAS replication adapter: fans each local change out to
|
|
6
|
-
* conditional WAS writes and assembles the RxDB conflict entry when the server
|
|
7
|
-
* rejects a write with `412`.
|
|
8
|
-
*
|
|
9
|
-
* A single RxDB document spans two independently-versioned sub-resources: the
|
|
10
|
-
* content (`data` / `version`, at `PUT/DELETE /:id`) and the metadata (`custom`
|
|
11
|
-
* / `metaVersion`, at `PUT /:id/meta`). This handler diffs the new local state
|
|
12
|
-
* against the assumed master to route each half:
|
|
13
|
-
*
|
|
14
|
-
* - content changed -> `PUT /:id` (`If-Match: "<version>"`) or, on create,
|
|
15
|
-
* `PUT /:id` (`If-None-Match: *`); a delete -> `DELETE /:id`.
|
|
16
|
-
* - metadata changed -> `PUT /:id/meta` (`If-Match: "<metaVersion>"`, or
|
|
17
|
-
* `If-None-Match: *` when the resource has no metadata yet); a metadata
|
|
18
|
-
* CLEAR (the new state carries no `custom`) writes the cleared state rather
|
|
19
|
-
* than being skipped.
|
|
20
|
-
*
|
|
21
|
-
* Content is written before metadata on a create, because the server rejects a
|
|
22
|
-
* `/meta` write to a resource that does not yet exist.
|
|
23
|
-
*
|
|
24
|
-
* RxDB's push contract asks only for *conflicts* back (the current master state
|
|
25
|
-
* of each rejected row), so a successful write's new `version` / `metaVersion`
|
|
26
|
-
* is reported out-of-band: the response ETag of each accepted write is captured
|
|
27
|
-
* and handed to the optional `onWriteAccepted` callback, which writes the acked
|
|
28
|
-
* revision back into the local row (see `createWasReplication`). Without that
|
|
29
|
-
* write-back the local `version` would stay one revision behind the server and
|
|
30
|
-
* every subsequent conditional write would send a stale `If-Match` and 412. The
|
|
31
|
-
* write-back only touches the revision fields (never `data` / `updatedAt`), so
|
|
32
|
-
* the follow-up push cycle it triggers finds nothing changed to write and
|
|
33
|
-
* settles -- no re-push loop.
|
|
34
|
-
*/
|
|
35
|
-
import type { WithDeleted } from 'rxdb/plugins/core';
|
|
36
|
-
import type { SyncedDoc, WasSyncPort } from './types.js';
|
|
37
|
-
/**
|
|
38
|
-
* The acked server revisions of one row's accepted writes: the new content
|
|
39
|
-
* `version` (from a `PUT /:id` or `DELETE /:id` response ETag) and/or the new
|
|
40
|
-
* `metaVersion` (from a `PUT /:id/meta` response ETag). Absent fields mean the
|
|
41
|
-
* corresponding write did not run or its response carried no ETag.
|
|
42
|
-
*/
|
|
43
|
-
export interface PushWriteAck {
|
|
44
|
-
id: string;
|
|
45
|
-
version?: number;
|
|
46
|
-
metaVersion?: number;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Builds the RxDB push handler that fans a batch of local changes out to
|
|
50
|
-
* conditional WAS writes and returns the conflicting rows' master states.
|
|
51
|
-
*
|
|
52
|
-
* Rows are pushed concurrently; if any non-conflict error is thrown the whole
|
|
53
|
-
* batch rejects (RxDB re-sends it later), matching RxDB's all-or-nothing retry.
|
|
54
|
-
*
|
|
55
|
-
* Each accepted write's acked server revision(s) are handed to
|
|
56
|
-
* `onWriteAccepted` (when supplied) as soon as that row's writes settle, so the
|
|
57
|
-
* caller can write the new `version` / `metaVersion` back into the local row
|
|
58
|
-
* and keep subsequent conditional writes' `If-Match` in step with the server.
|
|
59
|
-
*
|
|
60
|
-
* Each batch gets one short-lived master-read memo, shared by its rows and
|
|
61
|
-
* discarded with the batch (never held across batches, where it would go
|
|
62
|
-
* stale). A conflict re-read walks the changes feed from its origin and so pages
|
|
63
|
-
* past every other conflicting row's master on the way; without the memo a batch
|
|
64
|
-
* with k conflicts would run k concurrent full-feed walks.
|
|
65
|
-
*
|
|
66
|
-
* @param port {WasSyncPort}
|
|
67
|
-
* @param [onWriteAccepted] {(ack: PushWriteAck) => Promise<void>}
|
|
68
|
-
* @returns {(rows: Array<{ newDocumentState: WithDeleted<SyncedDoc>,
|
|
69
|
-
* assumedMasterState?: WithDeleted<SyncedDoc> }>) =>
|
|
70
|
-
* Promise<WithDeleted<SyncedDoc>[]>}
|
|
71
|
-
*/
|
|
72
|
-
export declare function createPushHandler(port: WasSyncPort, onWriteAccepted?: (ack: PushWriteAck) => Promise<void>): (rows: Array<{
|
|
73
|
-
newDocumentState: WithDeleted<SyncedDoc>;
|
|
74
|
-
assumedMasterState?: WithDeleted<SyncedDoc>;
|
|
75
|
-
}>) => Promise<WithDeleted<SyncedDoc>[]>;
|
|
76
|
-
//# sourceMappingURL=pushWrites.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pushWrites.d.ts","sourceRoot":"","sources":["../../src/sync/pushWrites.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,KAAK,EAGV,SAAS,EACT,WAAW,EACZ,MAAM,YAAY,CAAA;AAQnB;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAqND;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,IAGpD,MAAM,KAAK,CAAC;IACV,gBAAgB,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IACxC,kBAAkB,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CAC5C,CAAC,KACD,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAsBrC"}
|
package/dist/sync/pushWrites.js
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { formatEtag } from '@interop/was-client/sync';
|
|
2
|
-
import { bodiesEqual, copyOptionalBodyFields, WasSyncAuthError, WasSyncConflictError } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Maps a re-read master state into the RxDB conflict entry for one row, or --
|
|
5
|
-
* when the re-read found the resource genuinely absent (`master === null`, a
|
|
6
|
-
* delete/delete race) -- synthesizes the tombstone conflict entry from what we
|
|
7
|
-
* know locally. Shared by the `412` assembler and the `/meta` 404 recovery, so
|
|
8
|
-
* both report an absent master identically.
|
|
9
|
-
*
|
|
10
|
-
* @param options {object}
|
|
11
|
-
* @param options.id {string}
|
|
12
|
-
* @param options.master {MasterState | null}
|
|
13
|
-
* @param options.fallbackUpdatedAt {string} used if the resource is now absent
|
|
14
|
-
* @param options.fallbackVersion {number} used if the resource is now absent
|
|
15
|
-
* @returns {WithDeleted<SyncedDoc>}
|
|
16
|
-
*/
|
|
17
|
-
function masterOrTombstone({ id, master, fallbackUpdatedAt, fallbackVersion }) {
|
|
18
|
-
if (master === null) {
|
|
19
|
-
return {
|
|
20
|
-
id,
|
|
21
|
-
updatedAt: fallbackUpdatedAt,
|
|
22
|
-
version: fallbackVersion,
|
|
23
|
-
_deleted: true
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const conflict = {
|
|
27
|
-
id,
|
|
28
|
-
updatedAt: master.updatedAt,
|
|
29
|
-
version: master.version,
|
|
30
|
-
_deleted: master.deleted
|
|
31
|
-
};
|
|
32
|
-
copyOptionalBodyFields({ source: master, target: conflict });
|
|
33
|
-
return conflict;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Sends one local change to the remote Collection as up to two conditional
|
|
37
|
-
* writes (content, then metadata). Returns the master-state conflict entry on a
|
|
38
|
-
* `412` at either step, or the accepted writes' acked revisions on success
|
|
39
|
-
* (`ack: null` when no response carried a revision). A conflict on the
|
|
40
|
-
* metadata half still returns the content half's earned ack alongside the
|
|
41
|
-
* conflict entry, so an accepted content version is never discarded.
|
|
42
|
-
*
|
|
43
|
-
* @param options {object}
|
|
44
|
-
* @param options.port {WasSyncPort}
|
|
45
|
-
* @param options.newDocumentState {WithDeleted<SyncedDoc>}
|
|
46
|
-
* @param [options.assumedMasterState] {WithDeleted<SyncedDoc>}
|
|
47
|
-
* @param [options.cache] {MasterReadCache} the push batch's shared
|
|
48
|
-
* master-read memo
|
|
49
|
-
* @returns {Promise<{ conflict: WithDeleted<SyncedDoc> | null,
|
|
50
|
-
* ack: PushWriteAck | null }>}
|
|
51
|
-
*/
|
|
52
|
-
async function pushRow({ port, newDocumentState, assumedMasterState, cache }) {
|
|
53
|
-
const { id } = newDocumentState;
|
|
54
|
-
const assumedVersion = assumedMasterState?.version;
|
|
55
|
-
const isCreate = assumedMasterState === undefined;
|
|
56
|
-
const ack = { id };
|
|
57
|
-
const hasAck = () => ack.version !== undefined || ack.metaVersion !== undefined;
|
|
58
|
-
const fallbackVersion = () => ack.version ?? assumedVersion ?? newDocumentState.version;
|
|
59
|
-
// Re-reads this row's master. A row that has ALREADY written this batch
|
|
60
|
-
// (a content write accepted before a `/meta` rejection) bypasses the batch
|
|
61
|
-
// memo: a sibling's feed read may have paged past this resource before our
|
|
62
|
-
// own write landed, and the conflict entry must carry the revision that write
|
|
63
|
-
// produced. Rows that wrote nothing -- the ordinary content 412, the common
|
|
64
|
-
// case -- are exactly what the memo is for.
|
|
65
|
-
const readMaster = async () => hasAck()
|
|
66
|
-
? port.get({ id })
|
|
67
|
-
: port.get({ id, ...(cache !== undefined && { cache }) });
|
|
68
|
-
// Builds the conflict outcome from a re-read master (or from its absence, a
|
|
69
|
-
// delete/delete race), PRESERVING any ack already earned: a content write
|
|
70
|
-
// accepted before a `/meta` 412 must keep its acked `version` (and feed it to
|
|
71
|
-
// the absent-master fallback), or the local row keeps the pre-write version
|
|
72
|
-
// and every later conditional write sends a stale `If-Match`.
|
|
73
|
-
const conflictOutcome = (master) => ({
|
|
74
|
-
conflict: masterOrTombstone({
|
|
75
|
-
id,
|
|
76
|
-
master,
|
|
77
|
-
fallbackUpdatedAt: newDocumentState.updatedAt,
|
|
78
|
-
fallbackVersion: fallbackVersion()
|
|
79
|
-
}),
|
|
80
|
-
ack: hasAck() ? ack : null
|
|
81
|
-
});
|
|
82
|
-
// The 412 path: re-read the resource, then report its real master state.
|
|
83
|
-
const conflictResult = async () => conflictOutcome(await readMaster());
|
|
84
|
-
try {
|
|
85
|
-
if (newDocumentState._deleted) {
|
|
86
|
-
// Delete supersedes any metadata write: drop the content, tombstone wins.
|
|
87
|
-
const ackedVersion = await port.deleteContent({
|
|
88
|
-
id,
|
|
89
|
-
...(assumedVersion !== undefined && {
|
|
90
|
-
ifMatch: formatEtag(assumedVersion)
|
|
91
|
-
})
|
|
92
|
-
});
|
|
93
|
-
if (ackedVersion !== undefined) {
|
|
94
|
-
ack.version = ackedVersion;
|
|
95
|
-
}
|
|
96
|
-
return { conflict: null, ack: ack.version !== undefined ? ack : null };
|
|
97
|
-
}
|
|
98
|
-
// Content half: write on create, or when the content body changed. For a
|
|
99
|
-
// content-addressed collection the update case never fires (an immutable
|
|
100
|
-
// body for a stable id), but it is handled for generality.
|
|
101
|
-
const contentChanged = isCreate || !bodiesEqual(newDocumentState.data, assumedMasterState?.data);
|
|
102
|
-
if (contentChanged) {
|
|
103
|
-
const ackedVersion = await port.putContent({
|
|
104
|
-
id,
|
|
105
|
-
data: newDocumentState.data ?? null,
|
|
106
|
-
...(newDocumentState.epoch !== undefined && {
|
|
107
|
-
epoch: newDocumentState.epoch
|
|
108
|
-
}),
|
|
109
|
-
...(isCreate
|
|
110
|
-
? { ifNoneMatch: true }
|
|
111
|
-
: assumedVersion !== undefined && {
|
|
112
|
-
ifMatch: formatEtag(assumedVersion)
|
|
113
|
-
})
|
|
114
|
-
});
|
|
115
|
-
if (ackedVersion !== undefined) {
|
|
116
|
-
ack.version = ackedVersion;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
if (err instanceof WasSyncConflictError) {
|
|
122
|
-
return await conflictResult();
|
|
123
|
-
}
|
|
124
|
-
// Any non-conflict error (network, 5xx, auth) propagates so RxDB retries
|
|
125
|
-
// the whole batch with backoff.
|
|
126
|
-
throw err;
|
|
127
|
-
}
|
|
128
|
-
// Metadata half: write when the metadata changed -- including a CLEAR (the
|
|
129
|
-
// new state carries no `custom` while the assumed master does; `putMeta`
|
|
130
|
-
// with no `custom` writes the cleared state). On a create this runs after
|
|
131
|
-
// the content write (the resource must exist first). Its own try/catch so a
|
|
132
|
-
// rejection here can never discard an ack the content half already earned.
|
|
133
|
-
const metadataChanged = !bodiesEqual(newDocumentState.custom, assumedMasterState?.custom);
|
|
134
|
-
if (metadataChanged) {
|
|
135
|
-
try {
|
|
136
|
-
const assumedMetaVersion = assumedMasterState?.metaVersion;
|
|
137
|
-
const ackedMetaVersion = await port.putMeta({
|
|
138
|
-
id,
|
|
139
|
-
...(newDocumentState.custom !== undefined && {
|
|
140
|
-
custom: newDocumentState.custom
|
|
141
|
-
}),
|
|
142
|
-
...(assumedMetaVersion !== undefined
|
|
143
|
-
? { ifMatch: formatEtag(assumedMetaVersion) }
|
|
144
|
-
: { ifNoneMatch: true })
|
|
145
|
-
});
|
|
146
|
-
if (ackedMetaVersion !== undefined) {
|
|
147
|
-
ack.metaVersion = ackedMetaVersion;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
catch (err) {
|
|
151
|
-
if (err instanceof WasSyncConflictError) {
|
|
152
|
-
return await conflictResult();
|
|
153
|
-
}
|
|
154
|
-
// Corroborate before condemnation: under WAS 404-masking a `/meta` 404
|
|
155
|
-
// is ambiguous -- expired access, or an ordinary race with a remote
|
|
156
|
-
// delete (a PUT to the `/meta` of a nonexistent resource legitimately
|
|
157
|
-
// 404s). An independent request decides: re-read the master off the
|
|
158
|
-
// changes feed. A feed read that is itself denied rethrows its own auth
|
|
159
|
-
// error (access genuinely expired, so the controller escalates); a feed
|
|
160
|
-
// that answers with an absent/deleted master confirms the delete race,
|
|
161
|
-
// and the row is resolved with that tombstone as the conflict entry
|
|
162
|
-
// (the conflict handler reconciles it) instead of flipping the whole
|
|
163
|
-
// session to "access expired" and wedging the batch in RxDB's retries.
|
|
164
|
-
if (err instanceof WasSyncAuthError && err.status === 404) {
|
|
165
|
-
const master = await readMaster();
|
|
166
|
-
if (master === null || master.deleted) {
|
|
167
|
-
return conflictOutcome(master);
|
|
168
|
-
}
|
|
169
|
-
// The resource is alive and readable while its `/meta` write 404s:
|
|
170
|
-
// the write itself was rejected, so the auth signal stands.
|
|
171
|
-
}
|
|
172
|
-
throw err;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return { conflict: null, ack: hasAck() ? ack : null };
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Builds the RxDB push handler that fans a batch of local changes out to
|
|
179
|
-
* conditional WAS writes and returns the conflicting rows' master states.
|
|
180
|
-
*
|
|
181
|
-
* Rows are pushed concurrently; if any non-conflict error is thrown the whole
|
|
182
|
-
* batch rejects (RxDB re-sends it later), matching RxDB's all-or-nothing retry.
|
|
183
|
-
*
|
|
184
|
-
* Each accepted write's acked server revision(s) are handed to
|
|
185
|
-
* `onWriteAccepted` (when supplied) as soon as that row's writes settle, so the
|
|
186
|
-
* caller can write the new `version` / `metaVersion` back into the local row
|
|
187
|
-
* and keep subsequent conditional writes' `If-Match` in step with the server.
|
|
188
|
-
*
|
|
189
|
-
* Each batch gets one short-lived master-read memo, shared by its rows and
|
|
190
|
-
* discarded with the batch (never held across batches, where it would go
|
|
191
|
-
* stale). A conflict re-read walks the changes feed from its origin and so pages
|
|
192
|
-
* past every other conflicting row's master on the way; without the memo a batch
|
|
193
|
-
* with k conflicts would run k concurrent full-feed walks.
|
|
194
|
-
*
|
|
195
|
-
* @param port {WasSyncPort}
|
|
196
|
-
* @param [onWriteAccepted] {(ack: PushWriteAck) => Promise<void>}
|
|
197
|
-
* @returns {(rows: Array<{ newDocumentState: WithDeleted<SyncedDoc>,
|
|
198
|
-
* assumedMasterState?: WithDeleted<SyncedDoc> }>) =>
|
|
199
|
-
* Promise<WithDeleted<SyncedDoc>[]>}
|
|
200
|
-
*/
|
|
201
|
-
export function createPushHandler(port, onWriteAccepted) {
|
|
202
|
-
return async function push(rows) {
|
|
203
|
-
const cache = { byId: new Map(), inFlight: null };
|
|
204
|
-
const results = await Promise.all(rows.map(async (row) => {
|
|
205
|
-
const result = await pushRow({
|
|
206
|
-
port,
|
|
207
|
-
newDocumentState: row.newDocumentState,
|
|
208
|
-
assumedMasterState: row.assumedMasterState,
|
|
209
|
-
cache
|
|
210
|
-
});
|
|
211
|
-
if (result.ack !== null && onWriteAccepted !== undefined) {
|
|
212
|
-
await onWriteAccepted(result.ack);
|
|
213
|
-
}
|
|
214
|
-
return result;
|
|
215
|
-
}));
|
|
216
|
-
return results
|
|
217
|
-
.map(result => result.conflict)
|
|
218
|
-
.filter((conflict) => conflict !== null);
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
//# sourceMappingURL=pushWrites.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pushWrites.js","sourceRoot":"","sources":["../../src/sync/pushWrites.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The single generic RxDB JSON schema reused across every synced collection.
|
|
6
|
-
* One shape (`{ id, updatedAt, version, metaVersion?, data?, custom? }`) carries
|
|
7
|
-
* both a content revision and an independently-versioned metadata sub-resource;
|
|
8
|
-
* `_deleted` is added by RxDB via `deletedField`. `data` / `custom` are opaque
|
|
9
|
-
* bodies (plaintext JSON, or an EDV envelope on an encrypted collection), so
|
|
10
|
-
* they are typed as free-form objects.
|
|
11
|
-
*/
|
|
12
|
-
import type { RxJsonSchema } from 'rxdb/plugins/core';
|
|
13
|
-
import type { SyncedDoc } from './types.js';
|
|
14
|
-
/**
|
|
15
|
-
* Returns the synced-doc schema. `id` is the primary key (the WAS resourceId);
|
|
16
|
-
* `updatedAt` is indexed because it is the change-feed sort field / checkpoint
|
|
17
|
-
* component.
|
|
18
|
-
*
|
|
19
|
-
* @returns {RxJsonSchema<SyncedDoc>}
|
|
20
|
-
*/
|
|
21
|
-
export declare function syncedDocSchema(): RxJsonSchema<SyncedDoc>;
|
|
22
|
-
//# sourceMappingURL=syncedDocSchema.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncedDocSchema.d.ts","sourceRoot":"","sources":["../../src/sync/syncedDocSchema.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAAC,SAAS,CAAC,CAoBzD"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns the synced-doc schema. `id` is the primary key (the WAS resourceId);
|
|
3
|
-
* `updatedAt` is indexed because it is the change-feed sort field / checkpoint
|
|
4
|
-
* component.
|
|
5
|
-
*
|
|
6
|
-
* @returns {RxJsonSchema<SyncedDoc>}
|
|
7
|
-
*/
|
|
8
|
-
export function syncedDocSchema() {
|
|
9
|
-
return {
|
|
10
|
-
version: 0,
|
|
11
|
-
primaryKey: 'id',
|
|
12
|
-
type: 'object',
|
|
13
|
-
properties: {
|
|
14
|
-
id: { type: 'string', maxLength: 256 },
|
|
15
|
-
updatedAt: { type: 'string', maxLength: 64 },
|
|
16
|
-
version: { type: 'number' },
|
|
17
|
-
metaVersion: { type: 'number' },
|
|
18
|
-
// The opaque key-epoch id `data` was encrypted under (the `Key-Epoch`
|
|
19
|
-
// content-push header), when known.
|
|
20
|
-
epoch: { type: 'string', maxLength: 256 },
|
|
21
|
-
// Opaque stored bodies -- content and metadata envelopes -- moved verbatim.
|
|
22
|
-
data: { type: 'object', additionalProperties: true },
|
|
23
|
-
custom: { type: 'object', additionalProperties: true }
|
|
24
|
-
},
|
|
25
|
-
required: ['id', 'updatedAt', 'version'],
|
|
26
|
-
indexes: ['updatedAt']
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=syncedDocSchema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncedDocSchema.js","sourceRoot":"","sources":["../../src/sync/syncedDocSchema.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,IAAI;QAChB,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;YACtC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE;YAC5C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,sEAAsE;YACtE,oCAAoC;YACpC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;YACzC,4EAA4E;YAC5E,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACpD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE;SACvD;QACD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC;QACxC,OAAO,EAAE,CAAC,WAAW,CAAC;KACI,CAAA;AAC9B,CAAC"}
|