@interop/wallet-core 0.100.0 → 0.101.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 +8 -0
- package/dist/space/ceremony.d.ts +5 -4
- package/dist/space/ceremony.d.ts.map +1 -1
- package/dist/space/ceremony.js +7 -4
- package/dist/space/ceremony.js.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +17 -25
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/remint.d.ts +1 -1
- package/dist/sync/remint.d.ts.map +1 -1
- package/dist/sync/remint.js +2 -2
- package/dist/sync/remint.js.map +1 -1
- package/dist/sync/types.d.ts +36 -33
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/sync/types.js +8 -5
- package/dist/sync/types.js.map +1 -1
- package/dist/testing/accountBuilder.d.ts +237 -0
- package/dist/testing/accountBuilder.d.ts.map +1 -0
- package/dist/testing/accountBuilder.js +510 -0
- package/dist/testing/accountBuilder.js.map +1 -0
- package/dist/testing/fastKdf.d.ts +16 -0
- package/dist/testing/fastKdf.d.ts.map +1 -0
- package/dist/testing/fastKdf.js +8 -0
- package/dist/testing/fastKdf.js.map +1 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/{testing.d.ts → testing/signerFixture.d.ts} +2 -2
- package/dist/testing/signerFixture.d.ts.map +1 -0
- package/dist/{testing.js → testing/signerFixture.js} +1 -1
- package/dist/testing/signerFixture.js.map +1 -0
- package/package.json +12 -10
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js.map +0 -1
package/README.md
CHANGED
|
@@ -251,6 +251,14 @@ derives clients and opens records without ever touching the account log:
|
|
|
251
251
|
None of these leaves reach wallet-core's own `webvh`, `resourceLog`, or
|
|
252
252
|
`clientAnnex` modules. The module barrels still re-export the same names.
|
|
253
253
|
|
|
254
|
+
The `testing` subpath holds test fixtures only: the recorded-grant signer
|
|
255
|
+
fixture, `FAST_KDF` (an HKDF stand-in for the shipped Argon2id unlock KDF), and
|
|
256
|
+
the shared account builder, which takes a booted WAS server's URL and produces a
|
|
257
|
+
real account through the package's own ceremonies in four named shapes (one
|
|
258
|
+
passphrase, a second standing credential, an issued recovery code, one enrolled
|
|
259
|
+
client). It imports no server package. Consumers restrict
|
|
260
|
+
`@interop/wallet-core/testing` to their test globs with a lint rule.
|
|
261
|
+
|
|
254
262
|
## Contribute
|
|
255
263
|
|
|
256
264
|
PRs accepted. See [CONTRIBUTING.md](CONTRIBUTING.md) for editor setup (Prettier,
|
package/dist/space/ceremony.d.ts
CHANGED
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
* separate diagnostics surface, and its events do carry them.
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
14
|
-
* The account ceremony ids, in ceremony-inventory order. The last
|
|
15
|
-
* (account deletion, the shared wipe executor, content migration,
|
|
16
|
-
* export) are implemented in the app
|
|
14
|
+
* The account ceremony ids, in ceremony-inventory order. The last six
|
|
15
|
+
* (account deletion, the shared wipe executor, content migration, backup
|
|
16
|
+
* export, request consent, and grant revocation) are implemented in the app
|
|
17
|
+
* for now.
|
|
17
18
|
*/
|
|
18
|
-
export declare const CEREMONY_IDS: readonly ["account-genesis", "credential-anchored-genesis", "self-enrollment", "client-enrollment", "client-revocation", "recovery-code-issuance", "recovery-code-spend", "recovery-code-revocation", "unlock-credential-rotation", "forget-client", "last-client-transition", "update-key-rotation", "account-deletion", "wallet-wipe", "content-migration", "backup-export"];
|
|
19
|
+
export declare const CEREMONY_IDS: readonly ["account-genesis", "credential-anchored-genesis", "self-enrollment", "client-enrollment", "client-revocation", "recovery-code-issuance", "recovery-code-spend", "recovery-code-revocation", "unlock-credential-rotation", "forget-client", "last-client-transition", "update-key-rotation", "account-deletion", "wallet-wipe", "content-migration", "backup-export", "request-consent", "grant-revocation"];
|
|
19
20
|
/**
|
|
20
21
|
* One id from {@link CEREMONY_IDS}.
|
|
21
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../src/space/ceremony.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH
|
|
1
|
+
{"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../src/space/ceremony.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,uZAmBf,CAAA;AAEV;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
package/dist/space/ceremony.js
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* separate diagnostics surface, and its events do carry them.
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
14
|
-
* The account ceremony ids, in ceremony-inventory order. The last
|
|
15
|
-
* (account deletion, the shared wipe executor, content migration,
|
|
16
|
-
* export) are implemented in the app
|
|
14
|
+
* The account ceremony ids, in ceremony-inventory order. The last six
|
|
15
|
+
* (account deletion, the shared wipe executor, content migration, backup
|
|
16
|
+
* export, request consent, and grant revocation) are implemented in the app
|
|
17
|
+
* for now.
|
|
17
18
|
*/
|
|
18
19
|
export const CEREMONY_IDS = [
|
|
19
20
|
'account-genesis',
|
|
@@ -31,6 +32,8 @@ export const CEREMONY_IDS = [
|
|
|
31
32
|
'account-deletion',
|
|
32
33
|
'wallet-wipe',
|
|
33
34
|
'content-migration',
|
|
34
|
-
'backup-export'
|
|
35
|
+
'backup-export',
|
|
36
|
+
'request-consent',
|
|
37
|
+
'grant-revocation'
|
|
35
38
|
];
|
|
36
39
|
//# sourceMappingURL=ceremony.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceremony.js","sourceRoot":"","sources":["../../src/space/ceremony.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH
|
|
1
|
+
{"version":3,"file":"ceremony.js","sourceRoot":"","sources":["../../src/space/ceremony.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,iBAAiB;IACjB,6BAA6B;IAC7B,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,wBAAwB;IACxB,qBAAqB;IACrB,0BAA0B;IAC1B,4BAA4B;IAC5B,eAAe;IACf,wBAAwB;IACxB,qBAAqB;IACrB,kBAAkB;IAClB,aAAa;IACb,mBAAmB;IACnB,eAAe;IACf,iBAAiB;IACjB,kBAAkB;CACV,CAAA"}
|
package/dist/sync/index.d.ts
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* needs a `DocCipher` to reach the fields it compares.
|
|
33
33
|
*
|
|
34
34
|
* The RxDB driver is intentionally not part of this subpath: it ships from
|
|
35
|
-
* `@interop/was-sync`, and its metadata (`putMeta` / `
|
|
35
|
+
* `@interop/was-sync`, and its metadata (`putMeta` / `metaEtag`) push half
|
|
36
36
|
* stays driver-side. See `push.ts` for why the metadata half is left out of
|
|
37
37
|
* the shared core.
|
|
38
38
|
*/
|
package/dist/sync/index.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* needs a `DocCipher` to reach the fields it compares.
|
|
33
33
|
*
|
|
34
34
|
* The RxDB driver is intentionally not part of this subpath: it ships from
|
|
35
|
-
* `@interop/was-sync`, and its metadata (`putMeta` / `
|
|
35
|
+
* `@interop/was-sync`, and its metadata (`putMeta` / `metaEtag`) push half
|
|
36
36
|
* stays driver-side. See `push.ts` for why the metadata half is left out of
|
|
37
37
|
* the shared core.
|
|
38
38
|
*/
|
package/dist/sync/push.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAQ,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAQ,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAkM/E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,eAAe,EACf,QAAQ,EACR,MAAM,EACP,EAAE;IACD,IAAI,EAAE,WAAW,CAAA;IACjB,KAAK,EAAE,SAAS,CAAA;IAChB,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBzD"}
|
package/dist/sync/push.js
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
* resource replica only ever pushes as a create (`If-None-Match: *`) and a
|
|
11
11
|
* tombstone as a delete; there is no update path. A mutable (last-write-wins)
|
|
12
12
|
* collection pushes a live resource replica as a create while never-acked
|
|
13
|
-
*
|
|
13
|
+
* and as an in-place update (`If-Match`) once acked, and settles
|
|
14
14
|
* a `412` through its injected {@link ResolveConflict} policy.
|
|
15
15
|
*
|
|
16
|
-
* This loop covers the CONTENT sub-resource only (`data
|
|
17
|
-
* `PUT/DELETE /:id`). It does not drive the independently-
|
|
18
|
-
* sub-resource (`custom` / `
|
|
16
|
+
* This loop covers the CONTENT sub-resource only (`data`, at
|
|
17
|
+
* `PUT/DELETE /:id`). It does not drive the independently-validated METADATA
|
|
18
|
+
* sub-resource (`custom` / `metaEtag`, at `PUT /:id/meta`): a replica that
|
|
19
19
|
* syncs user-writable metadata (the web wallet's RxDB driver, via
|
|
20
20
|
* `WasSyncPort.putMeta`) keeps that half in its own push handler. It is left
|
|
21
21
|
* out of this core deliberately -- none of the wallet Space collections
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import { isSyncConflictError, isSyncNotFoundError } from '@interop/was-client/sync';
|
|
36
36
|
/**
|
|
37
|
-
* Pushes a dirty live resource replica. A never-acked resource replica
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
37
|
+
* Pushes a dirty live resource replica. A never-acked resource replica is a
|
|
38
|
+
* create (`PUT /:id` with `If-None-Match: *`); an acked one is an in-place
|
|
39
|
+
* update (`If-Match` over its stored `etag`, echoed back verbatim -- absent
|
|
40
|
+
* only where the server never exposed one) -- reachable only on a mutable
|
|
41
|
+
* collection, since a content-addressed resource replica never mutates in
|
|
42
|
+
* place. On success `acked` and the `etag` are recorded and the resource
|
|
43
|
+
* replica goes clean --
|
|
44
44
|
* unless a local write landed while the write was in flight, which the resource
|
|
45
45
|
* replica's `revision` token detects (see {@link SyncStore.markPushed}) so the
|
|
46
46
|
* newer write stays dirty for the rerun cycle.
|
|
@@ -50,7 +50,7 @@ import { isSyncConflictError, isSyncNotFoundError } from '@interop/was-client/sy
|
|
|
50
50
|
* pick the deterministic winner, apply-remote or re-encrypt-local).
|
|
51
51
|
* - An insert-only content-addressed collection (no resolver) applies the
|
|
52
52
|
* built-in settlement: master live -> the identical envelope already exists
|
|
53
|
-
* (same content hash), adopt its
|
|
53
|
+
* (same content hash), adopt its state, projection untouched; master
|
|
54
54
|
* absent/tombstone -> deletion wins, adopt the tombstone and delete the
|
|
55
55
|
* projection (a later re-add re-encrypts to a fresh id, so nothing is blocked).
|
|
56
56
|
*/
|
|
@@ -59,14 +59,11 @@ async function pushUpsert({ port, store, replica, resolveConflict, writerId }) {
|
|
|
59
59
|
const ack = await port.putContent({
|
|
60
60
|
id: replica.id,
|
|
61
61
|
data: replica.data ?? null,
|
|
62
|
-
...(replica.
|
|
63
|
-
? { ifMatch: replica.etag }
|
|
64
|
-
: { ifNoneMatch: true }),
|
|
62
|
+
...(replica.acked ? { ifMatch: replica.etag } : { ifNoneMatch: true }),
|
|
65
63
|
...(writerId !== undefined && { writerId })
|
|
66
64
|
});
|
|
67
65
|
await store.markPushed({
|
|
68
66
|
id: replica.id,
|
|
69
|
-
version: ack.version,
|
|
70
67
|
etag: ack.etag,
|
|
71
68
|
...(replica.revision !== undefined && { revision: replica.revision })
|
|
72
69
|
});
|
|
@@ -77,11 +74,7 @@ async function pushUpsert({ port, store, replica, resolveConflict, writerId }) {
|
|
|
77
74
|
throw err;
|
|
78
75
|
}
|
|
79
76
|
if (resolveConflict) {
|
|
80
|
-
await resolveConflict({
|
|
81
|
-
id: replica.id,
|
|
82
|
-
version: replica.version,
|
|
83
|
-
data: replica.data
|
|
84
|
-
});
|
|
77
|
+
await resolveConflict({ id: replica.id, data: replica.data });
|
|
85
78
|
// The resolver may have left the resource replica dirty (local-wins
|
|
86
79
|
// re-encrypt); the caller reruns so the re-push settles within the same
|
|
87
80
|
// sync run.
|
|
@@ -122,7 +115,6 @@ async function tryDelete({ port, store, id, ifMatch, revision, writerId }) {
|
|
|
122
115
|
});
|
|
123
116
|
await store.markDeletedPushed({
|
|
124
117
|
id,
|
|
125
|
-
version: ack?.version,
|
|
126
118
|
etag: ack?.etag,
|
|
127
119
|
...revisionAck
|
|
128
120
|
});
|
|
@@ -141,18 +133,18 @@ async function tryDelete({ port, store, id, ifMatch, revision, writerId }) {
|
|
|
141
133
|
}
|
|
142
134
|
/**
|
|
143
135
|
* Pushes a dirty tombstone. `DELETE /:id` with `If-Match` over the resource
|
|
144
|
-
* replica's stored `etag` when the resource replica was ever acked (`
|
|
136
|
+
* replica's stored `etag` when the resource replica was ever acked (`acked`,
|
|
145
137
|
* 0`), unconditional otherwise:
|
|
146
138
|
* - `204` / `404` -> settled (clean).
|
|
147
139
|
* - `412` then master absent/tombstone -> delete/delete race, settled.
|
|
148
140
|
* - `412` then master live -> retry once with the master's fresh `etag`; a
|
|
149
141
|
* second `412` leaves the resource replica dirty for the next cycle (the next
|
|
150
|
-
* pull refreshes its `
|
|
142
|
+
* pull refreshes its `etag` via the dirty-deleted-vs-live rule,
|
|
151
143
|
* so the retry's `If-Match` becomes current).
|
|
152
144
|
*/
|
|
153
145
|
async function pushDelete({ port, store, replica, writerId }) {
|
|
154
146
|
const revisionAck = replica.revision !== undefined ? { revision: replica.revision } : {};
|
|
155
|
-
const firstIfMatch = replica.
|
|
147
|
+
const firstIfMatch = replica.acked ? replica.etag : undefined;
|
|
156
148
|
if (await tryDelete({
|
|
157
149
|
port,
|
|
158
150
|
store,
|
package/dist/sync/push.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,0BAA0B,CAAA;AAGjC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,UAAU,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,OAAO,EACP,eAAe,EACf,QAAQ,EAaT;IACC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAChC,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;YAC1B,GAAG,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/remint.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { DocCipher, Json, SyncStore } from './types.js';
|
|
|
14
14
|
* so under its current epoch), and handed to {@link SyncStore.replacePending}
|
|
15
15
|
* -- which may re-key the resource replica, since the re-mint is a fresh
|
|
16
16
|
* encryption. Resource replicas already readable under the adopted descriptor,
|
|
17
|
-
* acked resource replicas (`
|
|
17
|
+
* acked resource replicas (`acked` -- they HAVE feed existence and are
|
|
18
18
|
* never re-minted), and tombstones are left untouched.
|
|
19
19
|
*
|
|
20
20
|
* Two decrypt failures are told apart. An unknown epoch is the create-loss
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remint.d.ts","sourceRoot":"","sources":["../../src/sync/remint.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAW5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,KAAK,EACL,MAAM,EACN,YAAY,EACZ,MAAM,EACP,EAAE;IACD,KAAK,EAAE,SAAS,GAAG;QACjB,cAAc,EAAE,WAAW,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAA;KACzD,CAAA;IACD,MAAM,EAAE,SAAS,CAAA;IACjB,YAAY,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxE,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"remint.d.ts","sourceRoot":"","sources":["../../src/sync/remint.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAW5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,KAAK,EACL,MAAM,EACN,YAAY,EACZ,MAAM,EACP,EAAE;IACD,KAAK,EAAE,SAAS,GAAG;QACjB,cAAc,EAAE,WAAW,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAA;KACzD,CAAA;IACD,MAAM,EAAE,SAAS,CAAA;IACjB,YAAY,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxE,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+EjD"}
|
package/dist/sync/remint.js
CHANGED
|
@@ -54,7 +54,7 @@ const MAX_REMINT_ATTEMPTS = 5;
|
|
|
54
54
|
* so under its current epoch), and handed to {@link SyncStore.replacePending}
|
|
55
55
|
* -- which may re-key the resource replica, since the re-mint is a fresh
|
|
56
56
|
* encryption. Resource replicas already readable under the adopted descriptor,
|
|
57
|
-
* acked resource replicas (`
|
|
57
|
+
* acked resource replicas (`acked` -- they HAVE feed existence and are
|
|
58
58
|
* never re-minted), and tombstones are left untouched.
|
|
59
59
|
*
|
|
60
60
|
* Two decrypt failures are told apart. An unknown epoch is the create-loss
|
|
@@ -110,7 +110,7 @@ export async function remintPendingEnvelopes({ store, cipher, decryptStale, sign
|
|
|
110
110
|
break;
|
|
111
111
|
}
|
|
112
112
|
const replicas = await store.getDirtyResourceReplicas();
|
|
113
|
-
const pendingReplicas = replicas.filter(replica => !replica.deleted && replica.
|
|
113
|
+
const pendingReplicas = replicas.filter(replica => !replica.deleted && !replica.acked && replica.data !== null);
|
|
114
114
|
pending ??= pendingReplicas.length;
|
|
115
115
|
skipped = [];
|
|
116
116
|
for (const replica of pendingReplicas) {
|
package/dist/sync/remint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remint.js","sourceRoot":"","sources":["../../src/sync/remint.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEhF,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAG/B;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAA;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,EAC3C,KAAK,EACL,MAAM,EACN,YAAY,EACZ,MAAM,EAQP;IACC,IAAI,OAA2B,CAAA;IAC/B,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,OAAO,GAAa,EAAE,CAAA;IAC1B,8EAA8E;IAC9E,6EAA6E;IAC7E,uEAAuE;IACvE,kBAAkB;IAClB,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAA;IAEtC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,mBAAmB,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAClE,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAK;QACP,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,wBAAwB,EAAE,CAAA;QACvD,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CACrC,OAAO,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"remint.js","sourceRoot":"","sources":["../../src/sync/remint.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/types.d.ts
CHANGED
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
* `@interop/was-client/sync` too, beside the classes that assign the names they
|
|
14
14
|
* match; `push.ts` and `remint.ts` import them from there.
|
|
15
15
|
*
|
|
16
|
-
* The server's `ETag` is opaque
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* The server's `ETag` is opaque: `"<generation>.<ms>.<counter>.<originId>"`,
|
|
17
|
+
* with no revision number to read out of it. The wire carries no `version`
|
|
18
|
+
* either; a record's write stamp is `(updatedAt, updatedAtCounter, originId)`,
|
|
19
|
+
* minted at the writing origin, and this engine reads none of it (preconditions
|
|
20
|
+
* key on the validator, last-write-wins on the payload). `MasterState.etag` /
|
|
21
|
+
* `WireDoc.etag` / `WriteAck.etag` carry the validator verbatim; a store that
|
|
22
|
+
* persists resource replicas MUST keep the string beside its own `acked` flag
|
|
23
|
+
* and echo it back as a later write's `ifMatch`.
|
|
21
24
|
*
|
|
22
25
|
* The local-persistence seam (`SyncStore`, `SyncedResourceReplica`,
|
|
23
26
|
* `ProjectionAction`, `ResolveConflict`) is the replica's side of the contract:
|
|
@@ -37,11 +40,14 @@ import type { Json, MasterState, SyncCheckpoint, WireDoc } from '@interop/was-cl
|
|
|
37
40
|
* A dirty resource replica awaiting push: the replica's local copy of one WAS
|
|
38
41
|
* Resource. `data` is the stored body (the EDV envelope on an encrypted
|
|
39
42
|
* collection, or the plaintext JSON on a plaintext one), `null` for a
|
|
40
|
-
* tombstone. `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* tombstone. `acked` says whether the server has ever acknowledged this
|
|
44
|
+
* resource replica (a push ack, a pull, or an adopted master); `false` means a
|
|
45
|
+
* create. It is the replica's own durable flag, since an ack carries no
|
|
46
|
+
* revision number and `etag` presence cannot stand in for it: a write a server
|
|
47
|
+
* accepted without exposing its `ETag` header is acked with no validator. `etag`
|
|
48
|
+
* is the opaque validator the acked state was recorded under, echoed back
|
|
49
|
+
* verbatim as a later write's `ifMatch` -- absent when the resource replica has
|
|
50
|
+
* never been acked, or where the header did not reach the client.
|
|
45
51
|
*
|
|
46
52
|
* `revision` is the store's own local revision token for the resource replica:
|
|
47
53
|
* any opaque value the store bumps on EVERY local write (a counter, a hash of
|
|
@@ -54,7 +60,7 @@ import type { Json, MasterState, SyncCheckpoint, WireDoc } from '@interop/was-cl
|
|
|
54
60
|
*/
|
|
55
61
|
export interface SyncedResourceReplica {
|
|
56
62
|
id: string;
|
|
57
|
-
|
|
63
|
+
acked: boolean;
|
|
58
64
|
etag?: string;
|
|
59
65
|
updatedAt: string;
|
|
60
66
|
deleted: boolean;
|
|
@@ -92,7 +98,6 @@ export type ProjectionAction = {
|
|
|
92
98
|
*/
|
|
93
99
|
export type ResolveConflict = (local: {
|
|
94
100
|
id: string;
|
|
95
|
-
version: number;
|
|
96
101
|
data: Json | null;
|
|
97
102
|
}) => Promise<void>;
|
|
98
103
|
/**
|
|
@@ -117,8 +122,8 @@ export interface SyncStore {
|
|
|
117
122
|
* table), write the matching projection action, and advance the checkpoint.
|
|
118
123
|
* `projections` is keyed by document id. Each document's `etag` (and
|
|
119
124
|
* `metaEtag`, on a collection that syncs metadata) MUST be recorded onto its
|
|
120
|
-
* resource replica
|
|
121
|
-
* write echoes back as `ifMatch`.
|
|
125
|
+
* resource replica, and the resource replica marked `acked` -- the `etag` is
|
|
126
|
+
* the validator a later local write echoes back as `ifMatch`.
|
|
122
127
|
*/
|
|
123
128
|
applyPulledPage(options: {
|
|
124
129
|
documents: WireDoc[];
|
|
@@ -126,32 +131,30 @@ export interface SyncStore {
|
|
|
126
131
|
projections: Map<string, ProjectionAction>;
|
|
127
132
|
}): Promise<void>;
|
|
128
133
|
/**
|
|
129
|
-
* Marks a pushed create/update as acked:
|
|
130
|
-
*
|
|
131
|
-
* provided, and clear dirty -- but ONLY if the resource replica's current
|
|
134
|
+
* Marks a pushed create/update as acked: set `acked`, record the opaque
|
|
135
|
+
* `etag` validator the write landed behind (the write's {@link WriteAck})
|
|
136
|
+
* when provided, and clear dirty -- but ONLY if the resource replica's current
|
|
132
137
|
* {@link SyncedResourceReplica.revision} still equals the `revision` that was
|
|
133
138
|
* pushed. A local write that landed while the write was in flight leaves a
|
|
134
|
-
* newer token, and that resource replica MUST stay dirty (with the
|
|
135
|
-
* `
|
|
136
|
-
*
|
|
137
|
-
*
|
|
139
|
+
* newer token, and that resource replica MUST stay dirty (with `acked` and the
|
|
140
|
+
* `etag` still recorded, so the re-push's `ifMatch` is current) so the rerun
|
|
141
|
+
* cycle pushes it. When `revision` is `undefined` -- a store that does not
|
|
142
|
+
* track a revision token -- dirty is cleared unconditionally.
|
|
138
143
|
*/
|
|
139
144
|
markPushed(options: {
|
|
140
145
|
id: string;
|
|
141
|
-
version?: number;
|
|
142
146
|
etag?: string;
|
|
143
147
|
revision?: string | number;
|
|
144
148
|
}): Promise<void>;
|
|
145
149
|
/**
|
|
146
|
-
* Marks a pushed delete as settled: keep the tombstone,
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
150
|
+
* Marks a pushed delete as settled: keep the tombstone, set `acked`, record
|
|
151
|
+
* the `etag` when provided, and clear dirty under the same revision condition
|
|
152
|
+
* as {@link SyncStore.markPushed} -- a resource replica rewritten locally
|
|
153
|
+
* mid-flight stays dirty and keeps its local state rather than being forced
|
|
154
|
+
* to a clean tombstone.
|
|
151
155
|
*/
|
|
152
156
|
markDeletedPushed(options: {
|
|
153
157
|
id: string;
|
|
154
|
-
version?: number;
|
|
155
158
|
etag?: string;
|
|
156
159
|
revision?: string | number;
|
|
157
160
|
}): Promise<void>;
|
|
@@ -160,10 +163,10 @@ export interface SyncStore {
|
|
|
160
163
|
* contract's RxDB-derived naming) for a resource replica whose push hit a
|
|
161
164
|
* `412`, applying `projection` in the same transaction. `latest === null`
|
|
162
165
|
* means the server has a tombstone (or the resource is absent): record the
|
|
163
|
-
* tombstone and delete the projection.
|
|
164
|
-
* `
|
|
165
|
-
* `
|
|
166
|
-
* back as `ifMatch`.
|
|
166
|
+
* tombstone and delete the projection. Either way the resource replica is
|
|
167
|
+
* `acked`: the server has a state for it. A non-null `latest` carries its
|
|
168
|
+
* own `etag`, which the store MUST record onto the resource replica -- it is
|
|
169
|
+
* the validator the resource replica's next push echoes back as `ifMatch`.
|
|
167
170
|
*/
|
|
168
171
|
adoptLatest(options: {
|
|
169
172
|
id: string;
|
|
@@ -196,7 +199,7 @@ export interface SyncStore {
|
|
|
196
199
|
* Replaces the body of a pending resource replica (dirty, never-acked, live
|
|
197
200
|
* -- no feed existence) with a re-minted envelope, re-keying it from `id` to
|
|
198
201
|
* `newId` when the fresh encryption minted a different resource id, all in
|
|
199
|
-
* ONE transaction: the resource replica
|
|
202
|
+
* ONE transaction: the resource replica stays never-acked and dirty,
|
|
200
203
|
* and whatever links the plaintext projection / app row to the resource
|
|
201
204
|
* replica moves to `newId` with it. Under the same revision condition as
|
|
202
205
|
* {@link SyncStore.markPushed}: when `revision` is provided and the resource
|
package/dist/sync/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/types.js
CHANGED
|
@@ -13,11 +13,14 @@
|
|
|
13
13
|
* `@interop/was-client/sync` too, beside the classes that assign the names they
|
|
14
14
|
* match; `push.ts` and `remint.ts` import them from there.
|
|
15
15
|
*
|
|
16
|
-
* The server's `ETag` is opaque
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* The server's `ETag` is opaque: `"<generation>.<ms>.<counter>.<originId>"`,
|
|
17
|
+
* with no revision number to read out of it. The wire carries no `version`
|
|
18
|
+
* either; a record's write stamp is `(updatedAt, updatedAtCounter, originId)`,
|
|
19
|
+
* minted at the writing origin, and this engine reads none of it (preconditions
|
|
20
|
+
* key on the validator, last-write-wins on the payload). `MasterState.etag` /
|
|
21
|
+
* `WireDoc.etag` / `WriteAck.etag` carry the validator verbatim; a store that
|
|
22
|
+
* persists resource replicas MUST keep the string beside its own `acked` flag
|
|
23
|
+
* and echo it back as a later write's `ifMatch`.
|
|
21
24
|
*
|
|
22
25
|
* The local-persistence seam (`SyncStore`, `SyncedResourceReplica`,
|
|
23
26
|
* `ProjectionAction`, `ResolveConflict`) is the replica's side of the contract:
|
package/dist/sync/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,0BAA0B,CAAA"}
|