@interop/wallet-core 0.67.0 → 0.69.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 +14 -13
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +12 -6
- package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -1
- package/dist/clientAnnex/credentialAnchoredGenesis.js +10 -7
- package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -1
- package/dist/clientAnnex/establish.d.ts +11 -12
- package/dist/clientAnnex/establish.d.ts.map +1 -1
- package/dist/clientAnnex/establish.js +20 -30
- package/dist/clientAnnex/establish.js.map +1 -1
- package/dist/clientAnnex/forget.d.ts +7 -16
- package/dist/clientAnnex/forget.d.ts.map +1 -1
- package/dist/clientAnnex/forget.js +8 -18
- package/dist/clientAnnex/forget.js.map +1 -1
- package/dist/clientAnnex/forgetLast.d.ts +8 -17
- package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
- package/dist/clientAnnex/forgetLast.js +19 -34
- package/dist/clientAnnex/forgetLast.js.map +1 -1
- package/dist/clientAnnex/gc.d.ts +26 -12
- package/dist/clientAnnex/gc.d.ts.map +1 -1
- package/dist/clientAnnex/gc.js +60 -57
- package/dist/clientAnnex/gc.js.map +1 -1
- package/dist/clientAnnex/heal.d.ts +3 -12
- package/dist/clientAnnex/heal.d.ts.map +1 -1
- package/dist/clientAnnex/heal.js +19 -32
- package/dist/clientAnnex/heal.js.map +1 -1
- package/dist/clientAnnex/index.d.ts +2 -2
- package/dist/clientAnnex/index.d.ts.map +1 -1
- package/dist/clientAnnex/index.js +1 -1
- package/dist/clientAnnex/index.js.map +1 -1
- package/dist/clientAnnex/ladderAnchored.d.ts +25 -70
- package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/ladderAnchored.js +34 -83
- package/dist/clientAnnex/ladderAnchored.js.map +1 -1
- package/dist/clientAnnex/log.d.ts +55 -68
- package/dist/clientAnnex/log.d.ts.map +1 -1
- package/dist/clientAnnex/log.js +82 -111
- package/dist/clientAnnex/log.js.map +1 -1
- package/dist/clientAnnex/mend.d.ts +19 -8
- package/dist/clientAnnex/mend.d.ts.map +1 -1
- package/dist/clientAnnex/mend.js +89 -66
- package/dist/clientAnnex/mend.js.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts +5 -12
- package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
- package/dist/clientAnnex/recoveryLadderAnchored.js +7 -13
- package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
- package/dist/clientAnnex/rosterDeliveredEpochs.d.ts +13 -14
- package/dist/clientAnnex/rosterDeliveredEpochs.d.ts.map +1 -1
- package/dist/clientAnnex/rosterDeliveredEpochs.js +12 -12
- package/dist/clientAnnex/rosterDeliveredEpochs.js.map +1 -1
- package/dist/clientAnnex/selfEnroll.d.ts +6 -10
- package/dist/clientAnnex/selfEnroll.d.ts.map +1 -1
- package/dist/clientAnnex/selfEnroll.js +12 -17
- package/dist/clientAnnex/selfEnroll.js.map +1 -1
- package/dist/descriptors/index.d.ts +21 -46
- package/dist/descriptors/index.d.ts.map +1 -1
- package/dist/descriptors/index.js +21 -45
- package/dist/descriptors/index.js.map +1 -1
- package/dist/descriptors/logSource.d.ts +45 -56
- package/dist/descriptors/logSource.d.ts.map +1 -1
- package/dist/descriptors/logSource.js +64 -74
- package/dist/descriptors/logSource.js.map +1 -1
- package/dist/genesis/accountGenesis.d.ts +15 -6
- package/dist/genesis/accountGenesis.d.ts.map +1 -1
- package/dist/genesis/accountGenesis.js +14 -7
- package/dist/genesis/accountGenesis.js.map +1 -1
- package/dist/keys/collectionLogStore.d.ts +73 -0
- package/dist/keys/collectionLogStore.d.ts.map +1 -0
- package/dist/keys/collectionLogStore.js +60 -0
- package/dist/keys/collectionLogStore.js.map +1 -0
- package/dist/keys/index.d.ts +18 -6
- package/dist/keys/index.d.ts.map +1 -1
- package/dist/keys/index.js +18 -6
- package/dist/keys/index.js.map +1 -1
- package/dist/keys/rosterLogStore.d.ts +44 -6
- package/dist/keys/rosterLogStore.d.ts.map +1 -1
- package/dist/keys/rosterLogStore.js +51 -238
- package/dist/keys/rosterLogStore.js.map +1 -1
- package/dist/keys/rosterStore.d.ts.map +1 -1
- package/dist/keys/rosterStore.js +2 -1
- package/dist/keys/rosterStore.js.map +1 -1
- package/dist/keys/spaceEpochs.d.ts +67 -34
- package/dist/keys/spaceEpochs.d.ts.map +1 -1
- package/dist/keys/spaceEpochs.js +80 -30
- package/dist/keys/spaceEpochs.js.map +1 -1
- package/dist/keys/userKeyCascade.d.ts +26 -1
- package/dist/keys/userKeyCascade.d.ts.map +1 -1
- package/dist/keys/userKeyCascade.js +29 -2
- package/dist/keys/userKeyCascade.js.map +1 -1
- package/dist/keys/userKeyRoster.d.ts +5 -0
- package/dist/keys/userKeyRoster.d.ts.map +1 -1
- package/dist/keys/userKeyRoster.js +5 -0
- package/dist/keys/userKeyRoster.js.map +1 -1
- package/dist/keys/userKeyRosterCascade.d.ts +54 -16
- package/dist/keys/userKeyRosterCascade.d.ts.map +1 -1
- package/dist/keys/userKeyRosterCascade.js +50 -22
- package/dist/keys/userKeyRosterCascade.js.map +1 -1
- package/dist/recovery/continuation.d.ts +2 -7
- package/dist/recovery/continuation.d.ts.map +1 -1
- package/dist/recovery/continuation.js +2 -6
- package/dist/recovery/continuation.js.map +1 -1
- package/dist/recovery/recoveryWebvh.d.ts +11 -25
- package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
- package/dist/recovery/recoveryWebvh.js +13 -26
- package/dist/recovery/recoveryWebvh.js.map +1 -1
- package/dist/resourceLog/controller.d.ts +18 -6
- package/dist/resourceLog/controller.d.ts.map +1 -1
- package/dist/resourceLog/controller.js +5 -3
- package/dist/resourceLog/controller.js.map +1 -1
- package/dist/resourceLog/errors.d.ts +17 -43
- package/dist/resourceLog/errors.d.ts.map +1 -1
- package/dist/resourceLog/errors.js +17 -50
- package/dist/resourceLog/errors.js.map +1 -1
- package/dist/resourceLog/index.d.ts +6 -3
- package/dist/resourceLog/index.d.ts.map +1 -1
- package/dist/resourceLog/index.js +6 -3
- package/dist/resourceLog/index.js.map +1 -1
- package/dist/resourceLog/logClass.d.ts +69 -0
- package/dist/resourceLog/logClass.d.ts.map +1 -0
- package/dist/resourceLog/logClass.js +43 -0
- package/dist/resourceLog/logClass.js.map +1 -0
- package/dist/space/collections.d.ts +22 -2
- package/dist/space/collections.d.ts.map +1 -1
- package/dist/space/collections.js +18 -0
- package/dist/space/collections.js.map +1 -1
- package/dist/space/index.d.ts +4 -3
- package/dist/space/index.d.ts.map +1 -1
- package/dist/space/index.js +4 -3
- package/dist/space/index.js.map +1 -1
- package/dist/space/provisioning.d.ts +16 -6
- package/dist/space/provisioning.d.ts.map +1 -1
- package/dist/space/provisioning.js +11 -7
- package/dist/space/provisioning.js.map +1 -1
- package/dist/sync/engine.d.ts +4 -2
- package/dist/sync/engine.d.ts.map +1 -1
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/index.d.ts +9 -6
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +8 -5
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/push.d.ts +0 -29
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +30 -28
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/types.d.ts +39 -21
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/sync/types.js +13 -7
- package/dist/sync/types.js.map +1 -1
- package/dist/unlock/retire.d.ts +12 -13
- package/dist/unlock/retire.d.ts.map +1 -1
- package/dist/unlock/retire.js +12 -15
- package/dist/unlock/retire.js.map +1 -1
- package/dist/unlock/standingWebvh.d.ts +8 -22
- package/dist/unlock/standingWebvh.d.ts.map +1 -1
- package/dist/unlock/standingWebvh.js +7 -18
- package/dist/unlock/standingWebvh.js.map +1 -1
- package/dist/webvh/accountEntry.d.ts +5 -12
- package/dist/webvh/accountEntry.d.ts.map +1 -1
- package/dist/webvh/accountEntry.js +11 -22
- package/dist/webvh/accountEntry.js.map +1 -1
- package/dist/webvh/delegatedLogStore.d.ts +7 -2
- package/dist/webvh/delegatedLogStore.d.ts.map +1 -1
- package/dist/webvh/delegatedLogStore.js +9 -1
- package/dist/webvh/delegatedLogStore.js.map +1 -1
- package/dist/webvh/didWebvh.d.ts +69 -80
- package/dist/webvh/didWebvh.d.ts.map +1 -1
- package/dist/webvh/didWebvh.js +74 -117
- package/dist/webvh/didWebvh.js.map +1 -1
- package/dist/webvh/enrollClient.d.ts +2 -8
- package/dist/webvh/enrollClient.d.ts.map +1 -1
- package/dist/webvh/enrollClient.js +3 -8
- package/dist/webvh/enrollClient.js.map +1 -1
- package/dist/webvh/index.d.ts +1 -1
- package/dist/webvh/index.d.ts.map +1 -1
- package/dist/webvh/index.js +1 -1
- package/dist/webvh/index.js.map +1 -1
- package/dist/webvh/revokeClient.d.ts +3 -9
- package/dist/webvh/revokeClient.d.ts.map +1 -1
- package/dist/webvh/revokeClient.js +4 -9
- package/dist/webvh/revokeClient.js.map +1 -1
- package/dist/webvh/verifyLog.d.ts +24 -4
- package/dist/webvh/verifyLog.d.ts.map +1 -1
- package/dist/webvh/verifyLog.js +26 -7
- package/dist/webvh/verifyLog.js.map +1 -1
- package/dist/webvh/wasIdStore.d.ts +16 -3
- package/dist/webvh/wasIdStore.d.ts.map +1 -1
- package/dist/webvh/wasIdStore.js +18 -3
- package/dist/webvh/wasIdStore.js.map +1 -1
- package/package.json +4 -4
- package/dist/descriptors/acquire.d.ts +0 -122
- package/dist/descriptors/acquire.d.ts.map +0 -1
- package/dist/descriptors/acquire.js +0 -100
- package/dist/descriptors/acquire.js.map +0 -1
- package/dist/descriptors/cipher.d.ts +0 -71
- package/dist/descriptors/cipher.d.ts.map +0 -1
- package/dist/descriptors/cipher.js +0 -109
- package/dist/descriptors/cipher.js.map +0 -1
- package/dist/descriptors/errors.d.ts +0 -44
- package/dist/descriptors/errors.d.ts.map +0 -1
- package/dist/descriptors/errors.js +0 -46
- package/dist/descriptors/errors.js.map +0 -1
- package/dist/descriptors/refresh.d.ts +0 -62
- package/dist/descriptors/refresh.d.ts.map +0 -1
- package/dist/descriptors/refresh.js +0 -69
- package/dist/descriptors/refresh.js.map +0 -1
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { isResourceLogRefusal } from '../resourceLog/errors.js';
|
|
2
|
-
/**
|
|
3
|
-
* The {@link EncryptionDescriptorSource} over a was-client handle: reads the
|
|
4
|
-
* collection's Description in the given Space and returns its `encryption`
|
|
5
|
-
* descriptor.
|
|
6
|
-
*
|
|
7
|
-
* @param options {object}
|
|
8
|
-
* @param options.was {WasClient} a client whose signer can read the Space
|
|
9
|
-
* @param options.spaceId {string}
|
|
10
|
-
* @returns {EncryptionDescriptorSource}
|
|
11
|
-
*/
|
|
12
|
-
export function wasDescriptorSource({ was, spaceId }) {
|
|
13
|
-
return {
|
|
14
|
-
async collectionEncryption({ collectionId }) {
|
|
15
|
-
const description = await was
|
|
16
|
-
.space(spaceId)
|
|
17
|
-
.collection(collectionId)
|
|
18
|
-
.describe();
|
|
19
|
-
return description?.encryption ?? undefined;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Acquires one collection's descriptor: fetches it from the source, caching a
|
|
25
|
-
* success; falls back to the cached copy whenever the fetch yields no
|
|
26
|
-
* descriptor (it threw, or it came back empty -- a masked 404 for an
|
|
27
|
-
* unauthorized read looks exactly like an unencrypted collection); and with no
|
|
28
|
-
* source at all (a purely local code path) reads the cache alone. Any cached
|
|
29
|
-
* copy is deliberately left in place, never cleared by an empty fetch.
|
|
30
|
-
* `undefined` means no descriptor exists anywhere for this collection.
|
|
31
|
-
*
|
|
32
|
-
* @param options {object}
|
|
33
|
-
* @param [options.source] {EncryptionDescriptorSource} omit for cache-only
|
|
34
|
-
* acquisition
|
|
35
|
-
* @param options.cache {EncryptionDescriptorCache}
|
|
36
|
-
* @param options.collectionId {string}
|
|
37
|
-
* @param [options.onFetchError] {function} observes a swallowed fetch
|
|
38
|
-
* failure (the thrown-fetch branch only; an empty description is not an
|
|
39
|
-
* error). Errors from the cache itself throw through, as do a log-governed
|
|
40
|
-
* source's refusal classes (a fabricated or discontinuous log is a security
|
|
41
|
-
* signal, not an outage the cache should paper over) -- except a continuity
|
|
42
|
-
* `rollback`, which falls back to the cache like any transport hiccup
|
|
43
|
-
* @returns {Promise<CollectionEncryption | undefined>}
|
|
44
|
-
*/
|
|
45
|
-
export async function acquireDescriptor({ source, cache, collectionId, onFetchError }) {
|
|
46
|
-
if (!source) {
|
|
47
|
-
return cache.readDescriptor({ collectionId });
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const fetched = await source.collectionEncryption({ collectionId });
|
|
51
|
-
if (fetched) {
|
|
52
|
-
await cache.writeDescriptor({ collectionId, descriptor: fetched });
|
|
53
|
-
return fetched;
|
|
54
|
-
}
|
|
55
|
-
// Empty description: not authoritative (an unauthorized read is masked as
|
|
56
|
-
// an absent one), so a warm cache still serves the collection.
|
|
57
|
-
return cache.readDescriptor({ collectionId });
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
// A resource-log refusal the cache must not paper over -- a fabricated
|
|
61
|
-
// log, or one that is not the continuation of the pinned history. A
|
|
62
|
-
// rollback is not one of them and falls through to the cache, as any
|
|
63
|
-
// transport failure does.
|
|
64
|
-
if (isResourceLogRefusal(err)) {
|
|
65
|
-
throw err;
|
|
66
|
-
}
|
|
67
|
-
onFetchError?.(err, { collectionId });
|
|
68
|
-
return cache.readDescriptor({ collectionId });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Acquires descriptors for a set of collections concurrently (each fetch is an
|
|
73
|
-
* independent signed round trip, so a session start is not gated on a serial
|
|
74
|
-
* chain of describes). Collections that resolve no descriptor are simply
|
|
75
|
-
* absent from the result.
|
|
76
|
-
*
|
|
77
|
-
* @param options {object}
|
|
78
|
-
* @param [options.source] {EncryptionDescriptorSource} omit for cache-only
|
|
79
|
-
* acquisition
|
|
80
|
-
* @param options.cache {EncryptionDescriptorCache}
|
|
81
|
-
* @param options.collectionIds {string[]}
|
|
82
|
-
* @param [options.onFetchError] {function} observes each swallowed fetch
|
|
83
|
-
* failure
|
|
84
|
-
* @returns {Promise<Record<string, CollectionEncryption>>} keyed by
|
|
85
|
-
* collection id
|
|
86
|
-
*/
|
|
87
|
-
export async function acquireDescriptors({ source, cache, collectionIds, onFetchError }) {
|
|
88
|
-
const resolved = await Promise.all(collectionIds.map(async (collectionId) => [
|
|
89
|
-
collectionId,
|
|
90
|
-
await acquireDescriptor({ source, cache, collectionId, onFetchError })
|
|
91
|
-
]));
|
|
92
|
-
const descriptors = {};
|
|
93
|
-
for (const [collectionId, descriptor] of resolved) {
|
|
94
|
-
if (descriptor) {
|
|
95
|
-
descriptors[collectionId] = descriptor;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return descriptors;
|
|
99
|
-
}
|
|
100
|
-
//# sourceMappingURL=acquire.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"acquire.js","sourceRoot":"","sources":["../../src/descriptors/acquire.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AA+B/D;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAClC,GAAG,EACH,OAAO,EAIR;IACC,OAAO;QACL,KAAK,CAAC,oBAAoB,CAAC,EAAE,YAAY,EAAE;YACzC,MAAM,WAAW,GAAG,MAAM,GAAG;iBAC1B,KAAK,CAAC,OAAO,CAAC;iBACd,UAAU,CAAC,YAAY,CAAC;iBACxB,QAAQ,EAAE,CAAA;YACb,OAAO,WAAW,EAAE,UAAU,IAAI,SAAS,CAAA;QAC7C,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,MAAM,EACN,KAAK,EACL,YAAY,EACZ,YAAY,EAMb;IACC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;QACnE,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,KAAK,CAAC,eAAe,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAA;YAClE,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,0EAA0E;QAC1E,+DAA+D;QAC/D,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,uEAAuE;QACvE,oEAAoE;QACpE,qEAAqE;QACrE,0BAA0B;QAC1B,IAAI,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAA;QACX,CAAC;QACD,YAAY,EAAE,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;QACrC,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EACvC,MAAM,EACN,KAAK,EACL,aAAa,EACb,YAAY,EAMb;IACC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,aAAa,CAAC,GAAG,CACf,KAAK,EAAC,YAAY,EAAC,EAAE,CACnB;QACE,YAAY;QACZ,MAAM,iBAAiB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;KAC9D,CACb,CACF,CAAA;IACD,MAAM,WAAW,GAAyC,EAAE,CAAA;IAC5D,KAAK,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,IAAI,QAAQ,EAAE,CAAC;QAClD,IAAI,UAAU,EAAE,CAAC;YACf,WAAW,CAAC,YAAY,CAAC,GAAG,UAAU,CAAA;QACxC,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* A self-refreshing EDV document cipher: `createEdvDocCipher` bound to
|
|
6
|
-
* descriptor acquisition and the once-per-session refresh rule, for a host
|
|
7
|
-
* whose decrypt seam is the cipher itself (a sync engine's `decryptDoc`, a
|
|
8
|
-
* conflict resolver) rather than a row-scanning store.
|
|
9
|
-
*
|
|
10
|
-
* Built, the cipher acquires the collection's descriptor (fetch, cache the
|
|
11
|
-
* success, cached fallback whenever the fetch yields none -- see
|
|
12
|
-
* `acquire.ts`) and constructs the
|
|
13
|
-
* underlying EDV cipher from it; with no descriptor, or a descriptor with no
|
|
14
|
-
* epochs, the build refuses fail-closed (every encrypted collection's
|
|
15
|
-
* descriptor carries an epoch roster from provisioning, so the absence can
|
|
16
|
-
* only mean the install has not landed or the host is lying). When a decrypt
|
|
17
|
-
* throws
|
|
18
|
-
* `UnknownEpochError`, the cipher re-acquires the descriptor, rebuilds itself,
|
|
19
|
-
* and retries that decrypt exactly once -- and only once per cipher instance,
|
|
20
|
-
* which the host scopes to one `(profile, collection)` session by dropping
|
|
21
|
-
* its cipher cache when the session ends. A second failure (or any unknown
|
|
22
|
-
* epoch after the one refresh is spent) propagates. A refresh that itself
|
|
23
|
-
* fails does not count as spent -- the original `UnknownEpochError` is
|
|
24
|
-
* rethrown and a later decrypt may try again.
|
|
25
|
-
*
|
|
26
|
-
* Only `UnknownEpochError` drives that refresh, and by design. The client
|
|
27
|
-
* splits the two ways a decrypt can find no key: an epoch the descriptor does
|
|
28
|
-
* not list at all raises `UnknownEpochError`, because a fresher descriptor may
|
|
29
|
-
* well list it; an epoch the descriptor does list but this reader holds no key
|
|
30
|
-
* for raises `KeyUnwrapError` (never a recipient, or removed and the epoch
|
|
31
|
-
* rotated). The second is rethrown immediately, with the refresh left
|
|
32
|
-
* untouched, since re-reading the same descriptor cannot produce a key the
|
|
33
|
-
* reader was not given.
|
|
34
|
-
*/
|
|
35
|
-
import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
|
|
36
|
-
import { type DocCipher } from '@interop/was-client/edv';
|
|
37
|
-
import { type EncryptionDescriptorCache, type EncryptionDescriptorSource } from './acquire.js';
|
|
38
|
-
/**
|
|
39
|
-
* Builds a {@link DocCipher} whose descriptor is acquired through the
|
|
40
|
-
* source/cache seams and refreshed (once per instance) on an unknown-epoch
|
|
41
|
-
* decrypt.
|
|
42
|
-
*
|
|
43
|
-
* With no `source` the descriptor is served from the cache alone and the
|
|
44
|
-
* refresh path is inert (an unknown-epoch decrypt propagates immediately) --
|
|
45
|
-
* the shape for a purely local code path that must never touch the network.
|
|
46
|
-
*
|
|
47
|
-
* @param options {object}
|
|
48
|
-
* @param options.keyAgreementKey {IKeyAgreementKey} the vault key pair this
|
|
49
|
-
* collection's envelopes are sealed to
|
|
50
|
-
* @param options.keyResolver {IKeyResolver}
|
|
51
|
-
* @param options.collectionId {string}
|
|
52
|
-
* @param [options.idDerivation] {'content' | 'random'} defaults to
|
|
53
|
-
* `'content'`
|
|
54
|
-
* @param [options.source] {EncryptionDescriptorSource}
|
|
55
|
-
* @param options.cache {EncryptionDescriptorCache}
|
|
56
|
-
* @param [options.onFetchError] {function} observes swallowed
|
|
57
|
-
* descriptor-fetch failures
|
|
58
|
-
* @returns {Promise<DocCipher>}
|
|
59
|
-
*/
|
|
60
|
-
export declare function createRefreshingEdvDocCipher({ keyAgreementKey, keyResolver, collectionId, idDerivation, source, cache, onFetchError }: {
|
|
61
|
-
keyAgreementKey: IKeyAgreementKey;
|
|
62
|
-
keyResolver: IKeyResolver;
|
|
63
|
-
collectionId: string;
|
|
64
|
-
idDerivation?: 'content' | 'random';
|
|
65
|
-
source?: EncryptionDescriptorSource;
|
|
66
|
-
cache: EncryptionDescriptorCache;
|
|
67
|
-
onFetchError?: (err: unknown, info: {
|
|
68
|
-
collectionId: string;
|
|
69
|
-
}) => void;
|
|
70
|
-
}): Promise<DocCipher>;
|
|
71
|
-
//# sourceMappingURL=cipher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAChC,MAAM,cAAc,CAAA;AAErB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,4BAA4B,CAAC,EACjD,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,YAAY,EACb,EAAE;IACD,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,MAAM,CAAC,EAAE,0BAA0B,CAAA;IACnC,KAAK,EAAE,yBAAyB,CAAA;IAChC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,GAAG,OAAO,CAAC,SAAS,CAAC,CAyFrB"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { createEdvDocCipher, UnknownEpochError } from '@interop/was-client/edv';
|
|
2
|
-
import { acquireDescriptor } from './acquire.js';
|
|
3
|
-
/**
|
|
4
|
-
* Builds a {@link DocCipher} whose descriptor is acquired through the
|
|
5
|
-
* source/cache seams and refreshed (once per instance) on an unknown-epoch
|
|
6
|
-
* decrypt.
|
|
7
|
-
*
|
|
8
|
-
* With no `source` the descriptor is served from the cache alone and the
|
|
9
|
-
* refresh path is inert (an unknown-epoch decrypt propagates immediately) --
|
|
10
|
-
* the shape for a purely local code path that must never touch the network.
|
|
11
|
-
*
|
|
12
|
-
* @param options {object}
|
|
13
|
-
* @param options.keyAgreementKey {IKeyAgreementKey} the vault key pair this
|
|
14
|
-
* collection's envelopes are sealed to
|
|
15
|
-
* @param options.keyResolver {IKeyResolver}
|
|
16
|
-
* @param options.collectionId {string}
|
|
17
|
-
* @param [options.idDerivation] {'content' | 'random'} defaults to
|
|
18
|
-
* `'content'`
|
|
19
|
-
* @param [options.source] {EncryptionDescriptorSource}
|
|
20
|
-
* @param options.cache {EncryptionDescriptorCache}
|
|
21
|
-
* @param [options.onFetchError] {function} observes swallowed
|
|
22
|
-
* descriptor-fetch failures
|
|
23
|
-
* @returns {Promise<DocCipher>}
|
|
24
|
-
*/
|
|
25
|
-
export async function createRefreshingEdvDocCipher({ keyAgreementKey, keyResolver, collectionId, idDerivation, source, cache, onFetchError }) {
|
|
26
|
-
const build = async () => {
|
|
27
|
-
const encryption = await acquireDescriptor({
|
|
28
|
-
source,
|
|
29
|
-
cache,
|
|
30
|
-
collectionId,
|
|
31
|
-
onFetchError
|
|
32
|
-
});
|
|
33
|
-
if (!encryption) {
|
|
34
|
-
throw new Error(`Collection "${collectionId}" has no encryption descriptor available ` +
|
|
35
|
-
'(fetched or cached). Every encrypted collection carries its key ' +
|
|
36
|
-
'epochs from provisioning; refusing to build a cipher without them.');
|
|
37
|
-
}
|
|
38
|
-
return createEdvDocCipher({
|
|
39
|
-
keyAgreementKey,
|
|
40
|
-
keyResolver,
|
|
41
|
-
collectionId,
|
|
42
|
-
idDerivation,
|
|
43
|
-
encryption
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
let inner = await build();
|
|
47
|
-
// The one descriptor refresh this cipher instance (= this collection this
|
|
48
|
-
// session) may spend, shared so concurrent unknown-epoch decrypts ride a
|
|
49
|
-
// single re-read instead of each spending one.
|
|
50
|
-
let refreshed = null;
|
|
51
|
-
return {
|
|
52
|
-
encrypt: options => inner.encrypt(options),
|
|
53
|
-
encryptUpdate: options => {
|
|
54
|
-
if (!inner.encryptUpdate) {
|
|
55
|
-
throw new Error(`Collection "${collectionId}" cipher has no in-place update.`);
|
|
56
|
-
}
|
|
57
|
-
return inner.encryptUpdate(options);
|
|
58
|
-
},
|
|
59
|
-
async decrypt({ envelope }) {
|
|
60
|
-
try {
|
|
61
|
-
return await inner.decrypt({ envelope });
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
// `instanceof` is safe here and only here: `inner` is built in this
|
|
65
|
-
// file by `createEdvDocCipher`, from the same `@interop/was-client`
|
|
66
|
-
// import this class comes from, so no injected seam is crossed. A
|
|
67
|
-
// caller classifying what THIS cipher throws is crossing one, and uses
|
|
68
|
-
// `isUnknownEpochError` / `isKeyUnwrapError` instead.
|
|
69
|
-
if (!(err instanceof UnknownEpochError) || !source) {
|
|
70
|
-
throw err;
|
|
71
|
-
}
|
|
72
|
-
if (!refreshed) {
|
|
73
|
-
const attempt = build().then(cipher => {
|
|
74
|
-
inner = cipher;
|
|
75
|
-
});
|
|
76
|
-
refreshed = attempt;
|
|
77
|
-
// Only a COMPLETED refresh is spent. A rejected one (the description
|
|
78
|
-
// could not be read and no cached copy answered either) un-arms the
|
|
79
|
-
// guard so a later unknown-epoch decrypt may try again; a successful
|
|
80
|
-
// refresh that still cannot route the envelope stays spent for the
|
|
81
|
-
// session, which is what keeps a genuinely foreign envelope from
|
|
82
|
-
// driving a refetch loop.
|
|
83
|
-
attempt.catch(() => {
|
|
84
|
-
if (refreshed === attempt) {
|
|
85
|
-
refreshed = null;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
await refreshed;
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
// The refresh failed, so nothing was learned about this envelope's
|
|
94
|
-
// epoch: surface the original UnknownEpochError rather than the
|
|
95
|
-
// build failure, so callers classifying on it (the create-loss
|
|
96
|
-
// re-mint) still see the row they exist to repair.
|
|
97
|
-
throw err;
|
|
98
|
-
}
|
|
99
|
-
// One retry under the swapped cipher. If the refresh was already
|
|
100
|
-
// spent before this decrypt began, this re-attempt is a local
|
|
101
|
-
// no-network decrypt that fails the same way -- so a genuinely
|
|
102
|
-
// foreign envelope still surfaces UnknownEpochError, and never a
|
|
103
|
-
// second description read.
|
|
104
|
-
return inner.decrypt({ envelope });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
//# sourceMappingURL=cipher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../src/descriptors/cipher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The read-side classification of what an injected `DocCipher` throws when it
|
|
6
|
-
* cannot open an envelope.
|
|
7
|
-
*
|
|
8
|
-
* A decrypt has two distinguishable no-key outcomes, and a host that scans
|
|
9
|
-
* rows must tell them apart: an epoch the descriptor this reader holds does
|
|
10
|
-
* not list at all (`UnknownEpochError` -- possibly fresh data behind a stale
|
|
11
|
-
* descriptor, so a re-read may fix it), and an epoch the descriptor does list
|
|
12
|
-
* but this reader holds no key for (`KeyUnwrapError` -- real data, and
|
|
13
|
-
* permanently unreadable here, since re-reading the same descriptor cannot
|
|
14
|
-
* produce a key the reader was not given). Neither is corruption, so neither
|
|
15
|
-
* row may be treated as garbage.
|
|
16
|
-
*
|
|
17
|
-
* Both are matched on `err.name`, never `instanceof`: the cipher is an
|
|
18
|
-
* injected seam, and in a wallet whose `@interop/was-client` resolves to a
|
|
19
|
-
* second copy (a `link:` dev setup, a dedupe miss through a dependency tree)
|
|
20
|
-
* the class the cipher throws is not the class the caller imported. The cost
|
|
21
|
-
* of the miss lands on real data -- a scan that misses `KeyUnwrapError` drops
|
|
22
|
-
* the row into its undecryptable bucket, which a host is entitled to purge.
|
|
23
|
-
* Both classes assign their `name` explicitly, which is what makes the string
|
|
24
|
-
* a contract.
|
|
25
|
-
*
|
|
26
|
-
* The unknown-epoch half of the pair ships from `@interop/was-client/sync`
|
|
27
|
-
* as `isUnknownEpochError`, beside the class that assigns the name. This half
|
|
28
|
-
* stays here on policy rather than on class adjacency: it classifies a
|
|
29
|
-
* roster-membership failure the wallet layer owns, and no sync driver
|
|
30
|
-
* dispatches on it. The file sits beside the cipher that raises the error and
|
|
31
|
-
* stays import-free for the same reason `resourceLog/errors.ts` does.
|
|
32
|
-
*/
|
|
33
|
-
/**
|
|
34
|
-
* Whether an error is the cipher's not-a-recipient signal (`KeyUnwrapError`):
|
|
35
|
-
* the envelope's epoch IS on the descriptor this reader holds, but the reader
|
|
36
|
-
* has no key for it -- never a recipient of that epoch, or removed and the
|
|
37
|
-
* epoch rotated since. Real data, unreadable by this wallet, and never
|
|
38
|
-
* garbage: a caller skips such a row and leaves it in place.
|
|
39
|
-
*
|
|
40
|
-
* @param err {unknown}
|
|
41
|
-
* @returns {boolean}
|
|
42
|
-
*/
|
|
43
|
-
export declare function isKeyUnwrapError(err: unknown): boolean;
|
|
44
|
-
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/descriptors/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEtD"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The read-side classification of what an injected `DocCipher` throws when it
|
|
6
|
-
* cannot open an envelope.
|
|
7
|
-
*
|
|
8
|
-
* A decrypt has two distinguishable no-key outcomes, and a host that scans
|
|
9
|
-
* rows must tell them apart: an epoch the descriptor this reader holds does
|
|
10
|
-
* not list at all (`UnknownEpochError` -- possibly fresh data behind a stale
|
|
11
|
-
* descriptor, so a re-read may fix it), and an epoch the descriptor does list
|
|
12
|
-
* but this reader holds no key for (`KeyUnwrapError` -- real data, and
|
|
13
|
-
* permanently unreadable here, since re-reading the same descriptor cannot
|
|
14
|
-
* produce a key the reader was not given). Neither is corruption, so neither
|
|
15
|
-
* row may be treated as garbage.
|
|
16
|
-
*
|
|
17
|
-
* Both are matched on `err.name`, never `instanceof`: the cipher is an
|
|
18
|
-
* injected seam, and in a wallet whose `@interop/was-client` resolves to a
|
|
19
|
-
* second copy (a `link:` dev setup, a dedupe miss through a dependency tree)
|
|
20
|
-
* the class the cipher throws is not the class the caller imported. The cost
|
|
21
|
-
* of the miss lands on real data -- a scan that misses `KeyUnwrapError` drops
|
|
22
|
-
* the row into its undecryptable bucket, which a host is entitled to purge.
|
|
23
|
-
* Both classes assign their `name` explicitly, which is what makes the string
|
|
24
|
-
* a contract.
|
|
25
|
-
*
|
|
26
|
-
* The unknown-epoch half of the pair ships from `@interop/was-client/sync`
|
|
27
|
-
* as `isUnknownEpochError`, beside the class that assigns the name. This half
|
|
28
|
-
* stays here on policy rather than on class adjacency: it classifies a
|
|
29
|
-
* roster-membership failure the wallet layer owns, and no sync driver
|
|
30
|
-
* dispatches on it. The file sits beside the cipher that raises the error and
|
|
31
|
-
* stays import-free for the same reason `resourceLog/errors.ts` does.
|
|
32
|
-
*/
|
|
33
|
-
/**
|
|
34
|
-
* Whether an error is the cipher's not-a-recipient signal (`KeyUnwrapError`):
|
|
35
|
-
* the envelope's epoch IS on the descriptor this reader holds, but the reader
|
|
36
|
-
* has no key for it -- never a recipient of that epoch, or removed and the
|
|
37
|
-
* epoch rotated since. Real data, unreadable by this wallet, and never
|
|
38
|
-
* garbage: a caller skips such a row and leaves it in place.
|
|
39
|
-
*
|
|
40
|
-
* @param err {unknown}
|
|
41
|
-
* @returns {boolean}
|
|
42
|
-
*/
|
|
43
|
-
export function isKeyUnwrapError(err) {
|
|
44
|
-
return err?.name === 'KeyUnwrapError';
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/descriptors/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,OAAQ,GAAiC,EAAE,IAAI,KAAK,gBAAgB,CAAA;AACtE,CAAC"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The unknown-epoch refresh policy: an epoch rotation emits no change-feed
|
|
6
|
-
* entry, so a cipher built from a cached descriptor can meet envelopes stamped
|
|
7
|
-
* with an epoch it has never seen. The remedy is one re-read of the
|
|
8
|
-
* Collection Description plus a cipher rebuild and a single retry -- and the
|
|
9
|
-
* policy guards that remedy to ONCE per collection per session, so a
|
|
10
|
-
* genuinely foreign envelope (one no descriptor will ever route) cannot drive
|
|
11
|
-
* a refetch loop, let alone a refetch per resource.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Tracks which collections have already spent their one refresh this session,
|
|
15
|
-
* and runs reads under the refresh-and-retry-once rule. One instance per
|
|
16
|
-
* session (it IS the session scope of the guard); the injected `refresh` does
|
|
17
|
-
* the host's whole swap -- re-acquire the descriptor(s), rebuild the
|
|
18
|
-
* cipher(s), and install them wherever the host keeps them.
|
|
19
|
-
*/
|
|
20
|
-
export declare class DescriptorRefreshPolicy {
|
|
21
|
-
#private;
|
|
22
|
-
constructor({ refresh }: {
|
|
23
|
-
refresh: (options: {
|
|
24
|
-
collectionId: string;
|
|
25
|
-
}) => Promise<void>;
|
|
26
|
-
});
|
|
27
|
-
/**
|
|
28
|
-
* Whether a collection still has its one refresh this session.
|
|
29
|
-
*/
|
|
30
|
-
shouldRefresh({ collectionId }: {
|
|
31
|
-
collectionId: string;
|
|
32
|
-
}): boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Runs a read that reports whether it skipped unknown-epoch rows; on the
|
|
35
|
-
* first such report for a collection this session, spends the collection's
|
|
36
|
-
* refresh (descriptor re-read + cipher swap, via the injected `refresh`) and
|
|
37
|
-
* re-reads once. A later unknown-epoch report for the same collection
|
|
38
|
-
* returns the read's value as-is.
|
|
39
|
-
*
|
|
40
|
-
* @param options {object}
|
|
41
|
-
* @param options.collectionId {string}
|
|
42
|
-
* @param options.read {function} the read, reporting `unknownEpoch`
|
|
43
|
-
* @returns {Promise<T>} the (possibly re-read) value
|
|
44
|
-
*/
|
|
45
|
-
readWithRefresh<T>({ collectionId, read }: {
|
|
46
|
-
collectionId: string;
|
|
47
|
-
read: () => Promise<{
|
|
48
|
-
value: T;
|
|
49
|
-
unknownEpoch: boolean;
|
|
50
|
-
}>;
|
|
51
|
-
}): Promise<T>;
|
|
52
|
-
/**
|
|
53
|
-
* Re-arms the guard -- for one collection, or (with no argument) for all.
|
|
54
|
-
* Call when a fresh descriptor is installed by some other path (a share,
|
|
55
|
-
* unshare, or recipient rotation this session performed itself), since the
|
|
56
|
-
* next unknown-epoch read is then evidence of a NEW rotation elsewhere.
|
|
57
|
-
*/
|
|
58
|
-
reset(options?: {
|
|
59
|
-
collectionId?: string;
|
|
60
|
-
}): void;
|
|
61
|
-
}
|
|
62
|
-
//# sourceMappingURL=refresh.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/descriptors/refresh.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,qBAAa,uBAAuB;;gBAKtB,EACV,OAAO,EACR,EAAE;QACD,OAAO,EAAE,CAAC,OAAO,EAAE;YAAE,YAAY,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAC9D;IAID;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,EAAE,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAIlE;;;;;;;;;;;OAWG;IACG,eAAe,CAAC,CAAC,EAAE,EACvB,YAAY,EACZ,IAAI,EACL,EAAE;QACD,YAAY,EAAE,MAAM,CAAA;QACpB,IAAI,EAAE,MAAM,OAAO,CAAC;YAAE,KAAK,EAAE,CAAC,CAAC;YAAC,YAAY,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KACzD,GAAG,OAAO,CAAC,CAAC,CAAC;IAUd;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAOjD"}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* The unknown-epoch refresh policy: an epoch rotation emits no change-feed
|
|
6
|
-
* entry, so a cipher built from a cached descriptor can meet envelopes stamped
|
|
7
|
-
* with an epoch it has never seen. The remedy is one re-read of the
|
|
8
|
-
* Collection Description plus a cipher rebuild and a single retry -- and the
|
|
9
|
-
* policy guards that remedy to ONCE per collection per session, so a
|
|
10
|
-
* genuinely foreign envelope (one no descriptor will ever route) cannot drive
|
|
11
|
-
* a refetch loop, let alone a refetch per resource.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Tracks which collections have already spent their one refresh this session,
|
|
15
|
-
* and runs reads under the refresh-and-retry-once rule. One instance per
|
|
16
|
-
* session (it IS the session scope of the guard); the injected `refresh` does
|
|
17
|
-
* the host's whole swap -- re-acquire the descriptor(s), rebuild the
|
|
18
|
-
* cipher(s), and install them wherever the host keeps them.
|
|
19
|
-
*/
|
|
20
|
-
export class DescriptorRefreshPolicy {
|
|
21
|
-
#refresh;
|
|
22
|
-
// Collection ids whose one refresh this session is already spent.
|
|
23
|
-
#refreshed = new Set();
|
|
24
|
-
constructor({ refresh }) {
|
|
25
|
-
this.#refresh = refresh;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Whether a collection still has its one refresh this session.
|
|
29
|
-
*/
|
|
30
|
-
shouldRefresh({ collectionId }) {
|
|
31
|
-
return !this.#refreshed.has(collectionId);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Runs a read that reports whether it skipped unknown-epoch rows; on the
|
|
35
|
-
* first such report for a collection this session, spends the collection's
|
|
36
|
-
* refresh (descriptor re-read + cipher swap, via the injected `refresh`) and
|
|
37
|
-
* re-reads once. A later unknown-epoch report for the same collection
|
|
38
|
-
* returns the read's value as-is.
|
|
39
|
-
*
|
|
40
|
-
* @param options {object}
|
|
41
|
-
* @param options.collectionId {string}
|
|
42
|
-
* @param options.read {function} the read, reporting `unknownEpoch`
|
|
43
|
-
* @returns {Promise<T>} the (possibly re-read) value
|
|
44
|
-
*/
|
|
45
|
-
async readWithRefresh({ collectionId, read }) {
|
|
46
|
-
const first = await read();
|
|
47
|
-
if (first.unknownEpoch && this.shouldRefresh({ collectionId })) {
|
|
48
|
-
this.#refreshed.add(collectionId);
|
|
49
|
-
await this.#refresh({ collectionId });
|
|
50
|
-
return (await read()).value;
|
|
51
|
-
}
|
|
52
|
-
return first.value;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Re-arms the guard -- for one collection, or (with no argument) for all.
|
|
56
|
-
* Call when a fresh descriptor is installed by some other path (a share,
|
|
57
|
-
* unshare, or recipient rotation this session performed itself), since the
|
|
58
|
-
* next unknown-epoch read is then evidence of a NEW rotation elsewhere.
|
|
59
|
-
*/
|
|
60
|
-
reset(options) {
|
|
61
|
-
if (options?.collectionId === undefined) {
|
|
62
|
-
this.#refreshed.clear();
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
this.#refreshed.delete(options.collectionId);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=refresh.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/descriptors/refresh.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,MAAM,OAAO,uBAAuB;IACzB,QAAQ,CAAsD;IACvE,kEAAkE;IACzD,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IAEvC,YAAY,EACV,OAAO,EAGR;QACC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACzB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,EAAE,YAAY,EAA4B;QACtD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAC3C,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,eAAe,CAAI,EACvB,YAAY,EACZ,IAAI,EAIL;QACC,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAA;QAC1B,IAAI,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YACjC,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;YACrC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAA;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAA;IACpB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAmC;QACvC,IAAI,OAAO,EAAE,YAAY,KAAK,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;CACF"}
|