@interop/was-react 0.20.0 → 0.21.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 (104) hide show
  1. package/README.md +8 -2
  2. package/dist/dev/provisionDevGrants.js +1 -1
  3. package/dist/dev/provisionDevGrants.js.map +1 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +9 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/session/authStore.d.ts.map +1 -1
  9. package/dist/session/authStore.js +48 -11
  10. package/dist/session/authStore.js.map +1 -1
  11. package/dist/storage/adopt.d.ts.map +1 -1
  12. package/dist/storage/adopt.js +2 -1
  13. package/dist/storage/adopt.js.map +1 -1
  14. package/dist/storage/descriptorManager.d.ts +1 -0
  15. package/dist/storage/descriptorManager.d.ts.map +1 -1
  16. package/dist/storage/descriptorManager.js +39 -21
  17. package/dist/storage/descriptorManager.js.map +1 -1
  18. package/dist/{sync → storage}/docCipher.d.ts +3 -29
  19. package/dist/storage/docCipher.d.ts.map +1 -0
  20. package/dist/{sync → storage}/docCipher.js +0 -20
  21. package/dist/storage/docCipher.js.map +1 -0
  22. package/dist/storage/entityStore.d.ts.map +1 -1
  23. package/dist/storage/entityStore.js +2 -1
  24. package/dist/storage/entityStore.js.map +1 -1
  25. package/dist/storage/localStore.d.ts +1 -1
  26. package/dist/storage/localStore.d.ts.map +1 -1
  27. package/dist/storage/localStore.js +14 -2
  28. package/dist/storage/localStore.js.map +1 -1
  29. package/dist/storage/sharedCollectionReader.d.ts +1 -1
  30. package/dist/storage/sharedCollectionReader.d.ts.map +1 -1
  31. package/dist/storage/sharedCollectionReader.js +1 -1
  32. package/dist/storage/sharedCollectionReader.js.map +1 -1
  33. package/dist/storage/storageContext.d.ts +7 -5
  34. package/dist/storage/storageContext.d.ts.map +1 -1
  35. package/dist/storage/storageContext.js +8 -4
  36. package/dist/storage/storageContext.js.map +1 -1
  37. package/dist/storage/storageManager.d.ts +7 -3
  38. package/dist/storage/storageManager.d.ts.map +1 -1
  39. package/dist/storage/storageManager.js +6 -2
  40. package/dist/storage/storageManager.js.map +1 -1
  41. package/dist/storage/syncController.d.ts +30 -19
  42. package/dist/storage/syncController.d.ts.map +1 -1
  43. package/dist/storage/syncController.js +84 -157
  44. package/dist/storage/syncController.js.map +1 -1
  45. package/dist/storage/syncStatusStore.d.ts +8 -7
  46. package/dist/storage/syncStatusStore.d.ts.map +1 -1
  47. package/dist/storage/syncStatusStore.js.map +1 -1
  48. package/dist/storage/wasRemoteStore.d.ts +24 -10
  49. package/dist/storage/wasRemoteStore.d.ts.map +1 -1
  50. package/dist/storage/wasRemoteStore.js +92 -37
  51. package/dist/storage/wasRemoteStore.js.map +1 -1
  52. package/dist/storage/wasSync.d.ts +25 -10
  53. package/dist/storage/wasSync.d.ts.map +1 -1
  54. package/dist/storage/wasSync.js +53 -22
  55. package/dist/storage/wasSync.js.map +1 -1
  56. package/dist/{sync → storage}/wasSyncPort.d.ts +14 -8
  57. package/dist/storage/wasSyncPort.d.ts.map +1 -0
  58. package/dist/storage/wasSyncPort.js.map +1 -0
  59. package/dist/storage/writerId.d.ts +7 -13
  60. package/dist/storage/writerId.d.ts.map +1 -1
  61. package/dist/storage/writerId.js +30 -46
  62. package/dist/storage/writerId.js.map +1 -1
  63. package/package.json +13 -10
  64. package/dist/sync/changesQuery.d.ts +0 -44
  65. package/dist/sync/changesQuery.d.ts.map +0 -1
  66. package/dist/sync/changesQuery.js +0 -54
  67. package/dist/sync/changesQuery.js.map +0 -1
  68. package/dist/sync/docCipher.d.ts.map +0 -1
  69. package/dist/sync/docCipher.js.map +0 -1
  70. package/dist/sync/feedMasterPort.d.ts +0 -38
  71. package/dist/sync/feedMasterPort.d.ts.map +0 -1
  72. package/dist/sync/feedMasterPort.js +0 -116
  73. package/dist/sync/feedMasterPort.js.map +0 -1
  74. package/dist/sync/index.d.ts +0 -23
  75. package/dist/sync/index.d.ts.map +0 -1
  76. package/dist/sync/index.js +0 -27
  77. package/dist/sync/index.js.map +0 -1
  78. package/dist/sync/lww.d.ts +0 -50
  79. package/dist/sync/lww.d.ts.map +0 -1
  80. package/dist/sync/lww.js +0 -69
  81. package/dist/sync/lww.js.map +0 -1
  82. package/dist/sync/lwwConflictHandler.d.ts +0 -83
  83. package/dist/sync/lwwConflictHandler.d.ts.map +0 -1
  84. package/dist/sync/lwwConflictHandler.js +0 -114
  85. package/dist/sync/lwwConflictHandler.js.map +0 -1
  86. package/dist/sync/pushWrites.d.ts +0 -76
  87. package/dist/sync/pushWrites.d.ts.map +0 -1
  88. package/dist/sync/pushWrites.js +0 -221
  89. package/dist/sync/pushWrites.js.map +0 -1
  90. package/dist/sync/syncedDocSchema.d.ts +0 -22
  91. package/dist/sync/syncedDocSchema.d.ts.map +0 -1
  92. package/dist/sync/syncedDocSchema.js +0 -29
  93. package/dist/sync/syncedDocSchema.js.map +0 -1
  94. package/dist/sync/types.d.ts +0 -319
  95. package/dist/sync/types.d.ts.map +0 -1
  96. package/dist/sync/types.js +0 -58
  97. package/dist/sync/types.js.map +0 -1
  98. package/dist/sync/wasReplication.d.ts +0 -47
  99. package/dist/sync/wasReplication.d.ts.map +0 -1
  100. package/dist/sync/wasReplication.js +0 -92
  101. package/dist/sync/wasReplication.js.map +0 -1
  102. package/dist/sync/wasSyncPort.d.ts.map +0 -1
  103. package/dist/sync/wasSyncPort.js.map +0 -1
  104. /package/dist/{sync → storage}/wasSyncPort.js +0 -0
@@ -1,319 +0,0 @@
1
- /*!
2
- * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
- */
4
- /**
5
- * Shared types for the collection-agnostic WAS replication adapter.
6
- *
7
- * The adapter drives an RxDB `replicateRxCollection` state machine against a
8
- * remote WAS Collection's replication endpoints. It is deliberately free of any
9
- * React or app imports so it can stand alone; all WAS access is injected through
10
- * the {@link WasSyncPort} seam rather than importing `@interop/was-client`
11
- * directly.
12
- *
13
- * The wire contract follows the WAS `changes` feed and its V2 encrypted-metadata
14
- * profile: a synced document carries both a content revision (`version` /
15
- * `data`) and an independently-versioned metadata sub-resource (`metaVersion` /
16
- * `custom`). A metadata-only edit re-surfaces the resource with a bumped
17
- * `updatedAt` / `metaVersion` but unchanged `version` / `data`. The sync layer
18
- * moves both bodies opaquely: `data` is the stored content body (plaintext JSON,
19
- * or the EDV envelope on an encrypted collection) and `custom` is the stored
20
- * metadata body (an opaque envelope on an encrypted collection); encrypt/decrypt
21
- * stays a read/write-time concern above this layer.
22
- *
23
- * The two small helpers that travel with these shapes live here as well: the
24
- * opaque-body equality every routing decision is made on, and the optional-field
25
- * copy every wire-to-local mapping runs.
26
- */
27
- import type { Json } from '@interop/was-client';
28
- import type { MasterState as ClientMasterState, SyncCheckpoint as ClientSyncCheckpoint } from '@interop/was-client/sync';
29
- /**
30
- * The typed port signals, owned by `@interop/was-client` (its sync port raises
31
- * them) and re-exported here so the names this package's consumers already
32
- * import stay put -- and so an `instanceof` check anywhere in this package
33
- * matches the very class the port throws.
34
- *
35
- * `WasSyncConflictError` marks a conditional write rejected with `412
36
- * precondition-failed` (a lost-update conflict, or a create-if-absent whose
37
- * target already exists); the push handler catches exactly it to trigger the
38
- * re-read-and-report-conflict path. `WasSyncAuthError` marks a request refused
39
- * on authorization grounds -- `401`, `403`, or the `404` a WAS server masks a
40
- * failed capability invocation as, which on the sync paths (where the invoked
41
- * collection is known to exist) means the invocation was rejected. It keeps the
42
- * offending HTTP status on `status`, which the `/meta` push path reads to tell
43
- * a masked denial from an ordinary delete race.
44
- */
45
- export { WasSyncAuthError, WasSyncConflictError } from '@interop/was-client/sync';
46
- /**
47
- * A JSON value -- the opaque stored resource body the sync layer moves verbatim.
48
- * For a plaintext collection this is the user document; for an encrypted one it
49
- * is the EDV envelope. The adapter never inspects or transforms it. Re-exported
50
- * from `@interop/was-client`, which owns the wire model, so a body crosses the
51
- * port boundary without a cast.
52
- */
53
- export type { Json };
54
- /**
55
- * The optional half of a synced document, shared verbatim by every shape it
56
- * travels in ({@link WireDoc} on the feed, {@link SyncedDoc} locally,
57
- * {@link MasterState} on the conflict re-read): the independently-versioned
58
- * metadata revision and body, the content body, and the content body's
59
- * key-epoch stamp. Each is genuinely absent rather than `undefined` when the
60
- * server has nothing for it, so every mapping between the shapes copies them
61
- * conditionally -- see {@link copyOptionalBodyFields}.
62
- */
63
- export interface OptionalBodyFields {
64
- metaVersion?: number;
65
- data?: Json;
66
- custom?: Json;
67
- epoch?: string;
68
- }
69
- /**
70
- * Structural equality over two opaque bodies, by canonical-free JSON string.
71
- * Decides whether the content or the metadata half changed -- which endpoint(s)
72
- * a push writes, and whether two states compare equal for conflict resolution.
73
- * Content-addressed collections never mutate `data` for a given id, and a real
74
- * metadata edit re-encrypts to fresh bytes, so this coarse comparison suffices.
75
- *
76
- * @param left {Json | undefined}
77
- * @param right {Json | undefined}
78
- * @returns {boolean}
79
- */
80
- export declare function bodiesEqual(left: Json | undefined, right: Json | undefined): boolean;
81
- /**
82
- * Copies the {@link OptionalBodyFields} that are present on `source` onto
83
- * `target`, leaving an absent field absent (never writing an explicit
84
- * `undefined`, which would surface the key in a serialized body). The single
85
- * place every wire-to-local, feed-to-master, and master-to-conflict mapping
86
- * shares, so a new optional wire field is added once.
87
- *
88
- * @param options {object}
89
- * @param options.source {OptionalBodyFields}
90
- * @param options.target {OptionalBodyFields} mutated in place
91
- * @returns {void}
92
- */
93
- export declare function copyOptionalBodyFields({ source, target }: {
94
- source: OptionalBodyFields;
95
- target: OptionalBodyFields;
96
- }): void;
97
- /**
98
- * The keyset position in the change feed: the `{ id, updatedAt }` of the last
99
- * document a pull returned. Passed back verbatim to resume, and used as the
100
- * RxDB replication checkpoint. `id` is the total-order tiebreaker within a
101
- * single `updatedAt`. The client's own checkpoint type, aliased here so the
102
- * replication layer and the port agree by construction.
103
- */
104
- export type SyncCheckpoint = ClientSyncCheckpoint;
105
- /**
106
- * One document as it travels on the `changes` feed wire
107
- * (`POST /space/:s/:c/query`, profile `changes`). `id` is the WAS resourceId,
108
- * `version` is the content master revision (feeds the content push `If-Match`
109
- * ETag) and the user content body is nested under `data`; `metaVersion` is the
110
- * independent metadata revision (feeds the `/meta` push `If-Match` ETag) and the
111
- * user-writable metadata body is under `custom`. A tombstone carries
112
- * `_deleted: true` with no `data`. `metaVersion` / `custom` are present only
113
- * once metadata has been written for the resource.
114
- */
115
- export interface WireDoc {
116
- id: string;
117
- _deleted: boolean;
118
- updatedAt: string;
119
- version: number;
120
- metaVersion?: number;
121
- data?: Json;
122
- custom?: Json;
123
- /**
124
- * The opaque key-epoch id the content body was encrypted under (the
125
- * `key-epochs` feature), present when the server holds a stamp for the
126
- * resource. Moved verbatim; the sync layer never interprets it.
127
- */
128
- epoch?: string;
129
- }
130
- /**
131
- * The local RxDB document shape, shared across every synced collection. The
132
- * envelope fields are top-level (`id` primary key, `updatedAt` the checkpoint
133
- * sort field, `version` / `metaVersion` the server master revisions); the user
134
- * bodies stay nested (`data` for content, `custom` for metadata) to avoid field
135
- * collisions. `_deleted` is managed by RxDB via `deletedField` and so is not
136
- * part of this "clean" shape (handlers work with RxDB's `WithDeleted<SyncedDoc>`).
137
- */
138
- export interface SyncedDoc {
139
- id: string;
140
- updatedAt: string;
141
- version: number;
142
- metaVersion?: number;
143
- data?: Json;
144
- custom?: Json;
145
- /**
146
- * The opaque key-epoch id `data` was encrypted under, when known (stamped by
147
- * the encrypting cipher on a local write, or pulled off the feed). Sent as
148
- * the `Key-Epoch` header on the content push so the server's stamp stays
149
- * in step with the envelope.
150
- */
151
- epoch?: string;
152
- }
153
- /**
154
- * The current master state of a single resource, as read back for the 412
155
- * conflict path: the client's own `MasterState` (content `version` /
156
- * `updatedAt`, plus the optional `metaVersion` / `data` / `custom` /
157
- * `createdBy` / `epoch`) plus the `deleted` flag that distinguishes a tombstone
158
- * from a live resource. The flag is required here because this package resolves
159
- * the master from the changes feed, where a tombstone travels as a document
160
- * rather than as an absent read.
161
- */
162
- export interface MasterState extends ClientMasterState {
163
- deleted: boolean;
164
- }
165
- /**
166
- * The short-lived master-read memo the rows of ONE push batch share. A
167
- * resolving `get` implementation may answer from `byId` and MUST record every
168
- * master it resolved on the way there; a feed-walking implementation pages past
169
- * all of them anyway, so a batch of k conflicts costs one walk instead of k.
170
- *
171
- * `inFlight` is what makes that hold under concurrency: the batch's rows push in
172
- * parallel, so without it every row would start its own walk before the first
173
- * one finished and the memo would never be read. A `get` that must walk
174
- * publishes its walk here; a `get` that finds a walk already running awaits it
175
- * and re-checks `byId` first. It settles (never rejects) so one row's failed
176
- * read is not another row's, and is `null` whenever no walk is running.
177
- *
178
- * The whole object is created per batch invocation and dropped with it: a memo
179
- * held across batches would go stale.
180
- */
181
- export interface MasterReadCache {
182
- byId: Map<string, MasterState | null>;
183
- inFlight: Promise<void> | null;
184
- }
185
- /**
186
- * The write/query half of the injected WAS-access seam. An adapter (the app-side
187
- * `createWasSyncPort`) implements this over `@interop/was-client`; the core
188
- * module depends only on this interface, never on `was-client` itself. Every
189
- * method moves the stored body verbatim -- no codec, no key handling -- so the
190
- * same port works for plaintext and encrypted collections alike.
191
- *
192
- * `putContent` / `deleteContent` / `putMeta` MUST throw
193
- * {@link WasSyncConflictError} when the server rejects a conditional write with
194
- * `412 precondition-failed`, and let every other error propagate so RxDB's
195
- * retry/backoff handles it.
196
- *
197
- * The 412 conflict re-read (`get`) is deliberately NOT part of this base:
198
- * `createWasSyncPort` returns a `WasSyncBasePort`, and `withFeedMasterRead`
199
- * supplies a `get` that resolves the master state from the changes-feed body
200
- * (origin-independent) to produce a full {@link WasSyncPort}.
201
- */
202
- export interface WasSyncBasePort {
203
- /**
204
- * Pulls one page of the `changes` feed. Omit `checkpoint` for the first page.
205
- * Returns the page's `documents` and its resume `checkpoint`, or
206
- * `checkpoint: null` for an empty (no-change) page.
207
- *
208
- * @param options {object}
209
- * @param [options.checkpoint] {SyncCheckpoint} resume position
210
- * @param options.limit {number} requested batch size
211
- * @returns {Promise<{ documents: WireDoc[], checkpoint: SyncCheckpoint | null }>}
212
- */
213
- query(options: {
214
- checkpoint?: SyncCheckpoint;
215
- limit: number;
216
- }): Promise<{
217
- documents: WireDoc[];
218
- checkpoint: SyncCheckpoint | null;
219
- }>;
220
- /**
221
- * Conditionally writes the content body verbatim (`PUT /:id`). Pass
222
- * `ifNoneMatch: true` for a create-if-absent, or `ifMatch` (a quoted ETag over
223
- * the content `version`) for an update-if-unchanged. `epoch` is the opaque
224
- * key-epoch id the body was encrypted under, sent as the `Key-Epoch`
225
- * header (an absent epoch clears any prior stamp on the server, per the
226
- * `key-epochs` feature). Returns the new content `version` parsed from the
227
- * response ETag (the acked master revision), or `undefined` when the server
228
- * does not supply one.
229
- *
230
- * @param options {object}
231
- * @param options.id {string}
232
- * @param options.data {Json}
233
- * @param [options.ifMatch] {string}
234
- * @param [options.ifNoneMatch] {boolean}
235
- * @param [options.epoch] {string}
236
- * @returns {Promise<number | undefined>}
237
- */
238
- putContent(options: {
239
- id: string;
240
- data: Json;
241
- ifMatch?: string;
242
- ifNoneMatch?: boolean;
243
- epoch?: string;
244
- }): Promise<number | undefined>;
245
- /**
246
- * Conditionally deletes a resource (writes a tombstone; `DELETE /:id`). Pass
247
- * `ifMatch` (a quoted ETag over the content `version`) to delete only if
248
- * unchanged. Returns the tombstone `version` parsed from the response ETag
249
- * when the server supplies one (the reference server does not). MUST treat a
250
- * `404` as success (resolve `undefined`): the resource is already absent --
251
- * a row deleted locally before its first push, or deleted remotely first --
252
- * so the tombstone's goal state holds; rejecting would wedge the push batch
253
- * in RxDB's retry loop.
254
- *
255
- * @param options {object}
256
- * @param options.id {string}
257
- * @param [options.ifMatch] {string}
258
- * @returns {Promise<number | undefined>}
259
- */
260
- deleteContent(options: {
261
- id: string;
262
- ifMatch?: string;
263
- }): Promise<number | undefined>;
264
- /**
265
- * Conditionally writes the metadata body verbatim (`PUT /:id/meta`, body
266
- * `{ custom }`). An ABSENT `custom` writes the CLEARED state (a body with no
267
- * `custom` member -- the server's metadata replace clears every property the
268
- * body omits), so removing a resource's metadata replicates rather than being
269
- * skipped. Pass `ifNoneMatch: true` when the resource has no metadata yet, or
270
- * `ifMatch` (a quoted ETag over `metaVersion`) for an update-if-unchanged.
271
- * The resource must already exist (the server does not create a resource from
272
- * a `/meta` write). Returns the new `metaVersion` parsed from the response
273
- * ETag, or `undefined` when the server does not supply one.
274
- *
275
- * @param options {object}
276
- * @param [options.custom] {Json} absent = write the cleared state
277
- * @param options.id {string}
278
- * @param [options.ifMatch] {string}
279
- * @param [options.ifNoneMatch] {boolean}
280
- * @returns {Promise<number | undefined>}
281
- */
282
- putMeta(options: {
283
- id: string;
284
- custom?: Json;
285
- ifMatch?: string;
286
- ifNoneMatch?: boolean;
287
- }): Promise<number | undefined>;
288
- }
289
- /**
290
- * The full sync port the core consumes: a {@link WasSyncBasePort}'s write/query
291
- * methods plus the `get` used by the 412 conflict assembler. The push handler
292
- * and `createWasReplication` require this full port; build one by wrapping a
293
- * base port with `withFeedMasterRead`, which supplies `get`.
294
- */
295
- export interface WasSyncPort extends WasSyncBasePort {
296
- /**
297
- * Re-reads a single resource's current master state (content + metadata) for
298
- * the 412 conflict assembler. Returns `null` when the resource is genuinely
299
- * absent (a delete/delete race); throws a retryable error when the master
300
- * cannot be resolved (e.g. a feed re-read that exhausts its scan budget), so
301
- * the replication cycle retries rather than fabricating a false tombstone.
302
- *
303
- * `cache` is an OPTIONAL {@link MasterReadCache}, shared by the rows of one
304
- * push batch (see its own docs for the contract). A hit is no staler than a
305
- * read issued at the same moment, since the memo lives only for that batch. An
306
- * implementation that ignores it is fully conformant, and a caller that omits
307
- * it gets an uncached read.
308
- *
309
- * @param options {object}
310
- * @param options.id {string}
311
- * @param [options.cache] {MasterReadCache}
312
- * @returns {Promise<MasterState | null>}
313
- */
314
- get(options: {
315
- id: string;
316
- cache?: MasterReadCache;
317
- }): Promise<MasterState | null>;
318
- }
319
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
@@ -1,58 +0,0 @@
1
- /**
2
- * The typed port signals, owned by `@interop/was-client` (its sync port raises
3
- * them) and re-exported here so the names this package's consumers already
4
- * import stay put -- and so an `instanceof` check anywhere in this package
5
- * matches the very class the port throws.
6
- *
7
- * `WasSyncConflictError` marks a conditional write rejected with `412
8
- * precondition-failed` (a lost-update conflict, or a create-if-absent whose
9
- * target already exists); the push handler catches exactly it to trigger the
10
- * re-read-and-report-conflict path. `WasSyncAuthError` marks a request refused
11
- * on authorization grounds -- `401`, `403`, or the `404` a WAS server masks a
12
- * failed capability invocation as, which on the sync paths (where the invoked
13
- * collection is known to exist) means the invocation was rejected. It keeps the
14
- * offending HTTP status on `status`, which the `/meta` push path reads to tell
15
- * a masked denial from an ordinary delete race.
16
- */
17
- export { WasSyncAuthError, WasSyncConflictError } from '@interop/was-client/sync';
18
- /**
19
- * Structural equality over two opaque bodies, by canonical-free JSON string.
20
- * Decides whether the content or the metadata half changed -- which endpoint(s)
21
- * a push writes, and whether two states compare equal for conflict resolution.
22
- * Content-addressed collections never mutate `data` for a given id, and a real
23
- * metadata edit re-encrypts to fresh bytes, so this coarse comparison suffices.
24
- *
25
- * @param left {Json | undefined}
26
- * @param right {Json | undefined}
27
- * @returns {boolean}
28
- */
29
- export function bodiesEqual(left, right) {
30
- return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
31
- }
32
- /**
33
- * Copies the {@link OptionalBodyFields} that are present on `source` onto
34
- * `target`, leaving an absent field absent (never writing an explicit
35
- * `undefined`, which would surface the key in a serialized body). The single
36
- * place every wire-to-local, feed-to-master, and master-to-conflict mapping
37
- * shares, so a new optional wire field is added once.
38
- *
39
- * @param options {object}
40
- * @param options.source {OptionalBodyFields}
41
- * @param options.target {OptionalBodyFields} mutated in place
42
- * @returns {void}
43
- */
44
- export function copyOptionalBodyFields({ source, target }) {
45
- if (source.data !== undefined) {
46
- target.data = source.data;
47
- }
48
- if (source.metaVersion !== undefined) {
49
- target.metaVersion = source.metaVersion;
50
- }
51
- if (source.custom !== undefined) {
52
- target.custom = source.custom;
53
- }
54
- if (source.epoch !== undefined) {
55
- target.epoch = source.epoch;
56
- }
57
- }
58
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,0BAA0B,CAAA;AA2BjC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsB,EACtB,KAAuB;IAEvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAA;AACvE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EAIP;IACC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;IAC3B,CAAC;IACD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;IACzC,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC/B,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;IAC7B,CAAC;AACH,CAAC"}
@@ -1,47 +0,0 @@
1
- /*!
2
- * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
- */
4
- /**
5
- * `createWasReplication` -- wires an RxDB collection to a remote WAS Collection
6
- * through the collection-agnostic pull/push handlers. This is the single public
7
- * entry point of the sync module; the caller supplies an already-open RxDB
8
- * collection and a {@link WasSyncPort} (its only WAS dependency), and gets back
9
- * the live `RxReplicationState` to observe (`error$` / `active$`) and control
10
- * (`reSync()` / `cancel()`).
11
- *
12
- * No React and no `@interop/was-client` imports -- only RxDB (the replication
13
- * engine being wrapped) and the injected port. This is the seam that keeps the
14
- * WAS access injectable.
15
- */
16
- import { type RxReplicationState } from 'rxdb/plugins/replication';
17
- import type { RxCollection } from 'rxdb/plugins/core';
18
- import type { SyncCheckpoint, SyncedDoc, WasSyncPort } from './types.js';
19
- /**
20
- * Starts (or configures) replication of one RxDB collection against a remote WAS
21
- * Collection. Poll-based only -- no `pull.stream$` (live streaming is deferred
22
- * server-side); RxDB's own `retryTime` backoff and `error$` are the reachability
23
- * signal (the replication attempt is the probe).
24
- *
25
- * @param options {object}
26
- * @param options.rxCollection {RxCollection<SyncedDoc>} the local replica
27
- * @param options.wasPort {WasSyncPort} injected WAS access
28
- * @param options.replicationIdentifier {string} stable id (include the server
29
- * URL + collection) so RxDB can resume across reloads
30
- * @param [options.batchSize] {number} pull `limit` / push batch (default 100)
31
- * @param [options.retryTime] {number} ms backoff between failed cycles
32
- * @param [options.live] {boolean} ongoing (default true) vs one-shot
33
- * @param [options.autoStart] {boolean} start immediately (default true)
34
- * @param [options.deletedField] {string} RxDB deleted flag (default `_deleted`)
35
- * @returns {RxReplicationState<SyncedDoc, SyncCheckpoint>}
36
- */
37
- export declare function createWasReplication({ rxCollection, wasPort, replicationIdentifier, batchSize, retryTime, live, autoStart, deletedField }: {
38
- rxCollection: RxCollection<SyncedDoc>;
39
- wasPort: WasSyncPort;
40
- replicationIdentifier: string;
41
- batchSize?: number;
42
- retryTime?: number;
43
- live?: boolean;
44
- autoStart?: boolean;
45
- deletedField?: string;
46
- }): RxReplicationState<SyncedDoc, SyncCheckpoint>;
47
- //# sourceMappingURL=wasReplication.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wasReplication.d.ts","sourceRoot":"","sources":["../../src/sync/wasReplication.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AACH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA2CxE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,YAAY,EACZ,OAAO,EACP,qBAAqB,EACrB,SAAe,EACf,SAAS,EACT,IAAW,EACX,SAAgB,EAChB,YAAyB,EAC1B,EAAE;IACD,YAAY,EAAE,YAAY,CAAC,SAAS,CAAC,CAAA;IACrC,OAAO,EAAE,WAAW,CAAA;IACpB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,kBAAkB,CAAC,SAAS,EAAE,cAAc,CAAC,CAiBhD"}
@@ -1,92 +0,0 @@
1
- /*!
2
- * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
- */
4
- /**
5
- * `createWasReplication` -- wires an RxDB collection to a remote WAS Collection
6
- * through the collection-agnostic pull/push handlers. This is the single public
7
- * entry point of the sync module; the caller supplies an already-open RxDB
8
- * collection and a {@link WasSyncPort} (its only WAS dependency), and gets back
9
- * the live `RxReplicationState` to observe (`error$` / `active$`) and control
10
- * (`reSync()` / `cancel()`).
11
- *
12
- * No React and no `@interop/was-client` imports -- only RxDB (the replication
13
- * engine being wrapped) and the injected port. This is the seam that keeps the
14
- * WAS access injectable.
15
- */
16
- import { replicateRxCollection } from 'rxdb/plugins/replication';
17
- import { createPullHandler } from './changesQuery.js';
18
- import { createPushHandler } from './pushWrites.js';
19
- /**
20
- * Builds the push write-back: patches an accepted write's acked server
21
- * revision(s) (`version` / `metaVersion`) into the local row so the next
22
- * conditional write's `If-Match` matches the server. Skips rows that are gone
23
- * or already current (a tombstoned row is invisible to `findOne` and needs no
24
- * write-back -- nothing further is pushed for a deleted id). Failures are
25
- * swallowed: the write itself succeeded, and a missed write-back only means
26
- * the acked revision is adopted from the change feed's echo on a later pull.
27
- *
28
- * @param rxCollection {RxCollection<SyncedDoc>}
29
- * @returns {(ack: PushWriteAck) => Promise<void>}
30
- */
31
- function createAckWriteBack(rxCollection) {
32
- return async function writeBack(ack) {
33
- try {
34
- const doc = await rxCollection.findOne(ack.id).exec();
35
- if (doc === null) {
36
- return;
37
- }
38
- const patch = {};
39
- if (ack.version !== undefined && doc.get('version') !== ack.version) {
40
- patch.version = ack.version;
41
- }
42
- if (ack.metaVersion !== undefined &&
43
- doc.get('metaVersion') !== ack.metaVersion) {
44
- patch.metaVersion = ack.metaVersion;
45
- }
46
- if (Object.keys(patch).length > 0) {
47
- await doc.incrementalPatch(patch);
48
- }
49
- }
50
- catch {
51
- // Best-effort: the server write was accepted; the revision echo on the
52
- // next pull corrects the row if this local patch could not be applied.
53
- }
54
- };
55
- }
56
- /**
57
- * Starts (or configures) replication of one RxDB collection against a remote WAS
58
- * Collection. Poll-based only -- no `pull.stream$` (live streaming is deferred
59
- * server-side); RxDB's own `retryTime` backoff and `error$` are the reachability
60
- * signal (the replication attempt is the probe).
61
- *
62
- * @param options {object}
63
- * @param options.rxCollection {RxCollection<SyncedDoc>} the local replica
64
- * @param options.wasPort {WasSyncPort} injected WAS access
65
- * @param options.replicationIdentifier {string} stable id (include the server
66
- * URL + collection) so RxDB can resume across reloads
67
- * @param [options.batchSize] {number} pull `limit` / push batch (default 100)
68
- * @param [options.retryTime] {number} ms backoff between failed cycles
69
- * @param [options.live] {boolean} ongoing (default true) vs one-shot
70
- * @param [options.autoStart] {boolean} start immediately (default true)
71
- * @param [options.deletedField] {string} RxDB deleted flag (default `_deleted`)
72
- * @returns {RxReplicationState<SyncedDoc, SyncCheckpoint>}
73
- */
74
- export function createWasReplication({ rxCollection, wasPort, replicationIdentifier, batchSize = 100, retryTime, live = true, autoStart = true, deletedField = '_deleted' }) {
75
- return replicateRxCollection({
76
- replicationIdentifier,
77
- collection: rxCollection,
78
- deletedField,
79
- live,
80
- autoStart,
81
- ...(retryTime !== undefined && { retryTime }),
82
- pull: {
83
- handler: createPullHandler(wasPort),
84
- batchSize
85
- },
86
- push: {
87
- handler: createPushHandler(wasPort, createAckWriteBack(rxCollection)),
88
- batchSize
89
- }
90
- });
91
- }
92
- //# sourceMappingURL=wasReplication.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wasReplication.js","sourceRoot":"","sources":["../../src/sync/wasReplication.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AACH,OAAO,EACL,qBAAqB,EAEtB,MAAM,0BAA0B,CAAA;AAGjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAqB,MAAM,iBAAiB,CAAA;AAEtE;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CAAC,YAAqC;IAC/D,OAAO,KAAK,UAAU,SAAS,CAAC,GAAiB;QAC/C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;YACrD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,OAAM;YACR,CAAC;YACD,MAAM,KAAK,GAAuB,EAAE,CAAA;YACpC,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;gBACpE,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;YAC7B,CAAC;YACD,IACE,GAAG,CAAC,WAAW,KAAK,SAAS;gBAC7B,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,GAAG,CAAC,WAAW,EAC1C,CAAC;gBACD,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAA;YACrC,CAAC;YACD,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACnC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,uEAAuE;QACzE,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,oBAAoB,CAAC,EACnC,YAAY,EACZ,OAAO,EACP,qBAAqB,EACrB,SAAS,GAAG,GAAG,EACf,SAAS,EACT,IAAI,GAAG,IAAI,EACX,SAAS,GAAG,IAAI,EAChB,YAAY,GAAG,UAAU,EAU1B;IACC,OAAO,qBAAqB,CAA4B;QACtD,qBAAqB;QACrB,UAAU,EAAE,YAAY;QACxB,YAAY;QACZ,IAAI;QACJ,SAAS;QACT,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;QAC7C,IAAI,EAAE;YACJ,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC;YACnC,SAAS;SACV;QACD,IAAI,EAAE;YACJ,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;YACrE,SAAS;SACV;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"wasSyncPort.d.ts","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAkB,eAAe,EAAW,MAAM,YAAY,CAAA;AAE1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EACX,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB,GAAG,eAAe,CAqClB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"wasSyncPort.js","sourceRoot":"","sources":["../../src/sync/wasSyncPort.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,iBAAiB,IAAI,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AAIpF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,GAAG,EACH,OAAO,EACP,YAAY,EACZ,UAAU,EAMX;IACC,MAAM,IAAI,GAAG,oBAAoB,CAAC;QAChC,GAAG;QACH,OAAO;QACP,YAAY;QACZ,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,CAAC;QAC/C,aAAa,EAAE,IAAI;KACpB,CAAC,CAAA;IACF,8EAA8E;IAC9E,4EAA4E;IAC5E,4EAA4E;IAC5E,+BAA+B;IAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IACxB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,6DAA6D;YAC3D,iCAAiC,CACpC,CAAA;IACH,CAAC;IAED,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAO;YACjB,sEAAsE;YACtE,qEAAqE;YACrE,uDAAuD;YACvD,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAGhC,CAAA;QACH,CAAC;QAED,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAE/C,aAAa,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAErD,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;KACrC,CAAA;AACH,CAAC"}
File without changes