@interop/was-react 0.16.0 → 0.18.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 +12 -9
- package/dist/identity/seedStore.d.ts +58 -2
- package/dist/identity/seedStore.d.ts.map +1 -1
- package/dist/identity/seedStore.js +27 -8
- package/dist/identity/seedStore.js.map +1 -1
- package/dist/session/authStore.d.ts.map +1 -1
- package/dist/session/authStore.js +20 -146
- package/dist/session/authStore.js.map +1 -1
- package/dist/storage/descriptorManager.d.ts +61 -0
- package/dist/storage/descriptorManager.d.ts.map +1 -0
- package/dist/storage/descriptorManager.js +177 -0
- package/dist/storage/descriptorManager.js.map +1 -0
- package/dist/storage/localStore.d.ts +32 -0
- package/dist/storage/localStore.d.ts.map +1 -1
- package/dist/storage/localStore.js +59 -1
- package/dist/storage/localStore.js.map +1 -1
- package/dist/storage/wasRemoteStore.d.ts +24 -4
- package/dist/storage/wasRemoteStore.d.ts.map +1 -1
- package/dist/storage/wasRemoteStore.js +40 -5
- package/dist/storage/wasRemoteStore.js.map +1 -1
- package/dist/storage/wasSync.d.ts.map +1 -1
- package/dist/storage/wasSync.js +120 -54
- package/dist/storage/wasSync.js.map +1 -1
- package/dist/sync/docCipher.d.ts +26 -1
- package/dist/sync/docCipher.d.ts.map +1 -1
- package/dist/sync/docCipher.js +9 -2
- package/dist/sync/docCipher.js.map +1 -1
- package/package.json +2 -2
package/dist/storage/wasSync.js
CHANGED
|
@@ -2,6 +2,57 @@ import { hasKeyEpochs } from '../sync/index.js';
|
|
|
2
2
|
import { isPublicCollection } from '../config.js';
|
|
3
3
|
import { WasRemoteStore, remoteDescriptorSource } from './wasRemoteStore.js';
|
|
4
4
|
import { SharedCollectionReader } from './sharedCollectionReader.js';
|
|
5
|
+
/**
|
|
6
|
+
* The one read-filter-cache pass over a grant set, shared by the login-time
|
|
7
|
+
* {@link readRemoteDescriptors} and the sync bootstrap: per REGISTERED
|
|
8
|
+
* collection the grants actually cover, read the private ones' encryption
|
|
9
|
+
* descriptor ONCE (reusing one the caller already read) and keep only the
|
|
10
|
+
* epoch-bearing ones -- a rosterless descriptor cannot build a cipher. A
|
|
11
|
+
* granted id the app never registered is nobody's business here, and a public
|
|
12
|
+
* collection carries no descriptor at all.
|
|
13
|
+
*
|
|
14
|
+
* `onCollection` is the bootstrap's hook: it runs per granted collection --
|
|
15
|
+
* public ones included -- with the RAW descriptor as read (epoch-bearing or
|
|
16
|
+
* not), so the description PUTs and the cipher rebuild ride the same single
|
|
17
|
+
* read. Collections are processed concurrently, hook included, so one slow
|
|
18
|
+
* collection never holds up the others.
|
|
19
|
+
*
|
|
20
|
+
* @param options {object}
|
|
21
|
+
* @param options.remoteStore {WasRemoteStore}
|
|
22
|
+
* @param options.collections {WasCollectionConfig[]}
|
|
23
|
+
* @param options.parsed {ParsedGrants}
|
|
24
|
+
* @param [options.knownDescriptors] {Record<string, CollectionEncryption>}
|
|
25
|
+
* descriptors already read live in this bring-up, reused instead of re-read
|
|
26
|
+
* @param [options.onCollection] {(options) => Promise<void>} per granted
|
|
27
|
+
* collection, with its raw descriptor (absent for a public one)
|
|
28
|
+
* @returns {Promise<Record<string, CollectionEncryption>>} the epoch-bearing
|
|
29
|
+
* descriptors, keyed by WAS collection id
|
|
30
|
+
*/
|
|
31
|
+
async function readGrantedEncryption({ remoteStore, collections, parsed, knownDescriptors = {}, onCollection }) {
|
|
32
|
+
const granted = collections.filter(collection => parsed.byCollectionId[collection.id] !== undefined);
|
|
33
|
+
const descriptors = {};
|
|
34
|
+
await Promise.all(granted.map(async (collection) => {
|
|
35
|
+
const { id: collectionId } = collection;
|
|
36
|
+
let encryption;
|
|
37
|
+
if (!isPublicCollection(collection)) {
|
|
38
|
+
// A descriptor the caller read seconds ago is reused as-is; only ids it
|
|
39
|
+
// did not cover (or a hot restore, which passes none) are read live.
|
|
40
|
+
encryption =
|
|
41
|
+
knownDescriptors[collectionId] ??
|
|
42
|
+
(await remoteStore.readCollectionEncryption(collectionId));
|
|
43
|
+
if (hasKeyEpochs(encryption)) {
|
|
44
|
+
descriptors[collectionId] = encryption;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (onCollection) {
|
|
48
|
+
await onCollection({
|
|
49
|
+
collection,
|
|
50
|
+
...(encryption && { encryption })
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
return descriptors;
|
|
55
|
+
}
|
|
5
56
|
/**
|
|
6
57
|
* One live encryption-descriptor read per granted private collection, invoked
|
|
7
58
|
* with the grants' delegated zcaps and keyed by WAS collection id. Only
|
|
@@ -25,18 +76,7 @@ export async function readRemoteDescriptors({ parsed, zcapClient, collections })
|
|
|
25
76
|
zcapClient,
|
|
26
77
|
collections
|
|
27
78
|
});
|
|
28
|
-
|
|
29
|
-
await Promise.all(collections.map(async (collection) => {
|
|
30
|
-
const { id } = collection;
|
|
31
|
-
if (isPublicCollection(collection) || !parsed.byCollectionId[id]) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const encryption = await remoteStore.readCollectionEncryption(id);
|
|
35
|
-
if (hasKeyEpochs(encryption)) {
|
|
36
|
-
descriptors[id] = encryption;
|
|
37
|
-
}
|
|
38
|
-
}));
|
|
39
|
-
return descriptors;
|
|
79
|
+
return await readGrantedEncryption({ remoteStore, collections, parsed });
|
|
40
80
|
}
|
|
41
81
|
/**
|
|
42
82
|
* Builds the remote store, opens the shared-collection readers, and starts
|
|
@@ -97,6 +137,15 @@ export async function startWasSync({ parsed, zcapClient, collections, localStore
|
|
|
97
137
|
// the fresh set to the descriptor-cache refresher so an offline session can
|
|
98
138
|
// rebuild its epoch-aware ciphers without a live read.
|
|
99
139
|
//
|
|
140
|
+
// A private collection with a blinding key gets one more ride-along on the
|
|
141
|
+
// same pass: its stored collection metadata is fetched RAW (the opaque
|
|
142
|
+
// envelope, not the decoded form) and installed on that collection's local
|
|
143
|
+
// cipher, which carries the persisted blinded-index schema. Documents written
|
|
144
|
+
// from then on carry blinded `indexed` entries and are findable by
|
|
145
|
+
// `collection.find()`. It runs AFTER the declaration deliberately: the
|
|
146
|
+
// declaration may have written fresh attributes into the persisted schema, and
|
|
147
|
+
// the metadata read must see them.
|
|
148
|
+
//
|
|
100
149
|
// The description is READ ONCE per collection and feeds both: the same
|
|
101
150
|
// descriptor answers the encryption PUT's read-before-write roster-clobber
|
|
102
151
|
// guard and the cipher rebuild, rather than each fetching it separately.
|
|
@@ -104,51 +153,68 @@ export async function startWasSync({ parsed, zcapClient, collections, localStore
|
|
|
104
153
|
// SHARED collections never appear here: they are wallet-owned, absent from
|
|
105
154
|
// the app-owned registry, and a read-only grant would draw nothing but a
|
|
106
155
|
// pointless 403.
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
156
|
+
const descriptors = await readGrantedEncryption({
|
|
157
|
+
remoteStore,
|
|
158
|
+
collections,
|
|
159
|
+
parsed,
|
|
160
|
+
knownDescriptors,
|
|
161
|
+
onCollection: async ({ collection, encryption }) => {
|
|
162
|
+
const { id: collectionId } = collection;
|
|
163
|
+
if (!isPublicCollection(collection)) {
|
|
164
|
+
// Only an epoch-bearing descriptor enters the offline cache or
|
|
165
|
+
// rebuilds a cipher; a collection without a key-epoch roster stays
|
|
166
|
+
// fail-closed, stated plainly here rather than surfacing later as
|
|
167
|
+
// per-row decrypt failures.
|
|
168
|
+
if (hasKeyEpochs(encryption)) {
|
|
169
|
+
await localStore.applyRemoteDescriptor({ collectionId, encryption });
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.warn(`Collection "${collectionId}" has no key-epoch roster on its ` +
|
|
173
|
+
`encryption descriptor; it stays unreadable (fail-closed) ` +
|
|
174
|
+
`until its provisioner installs one.`);
|
|
175
|
+
}
|
|
176
|
+
const declared = await remoteStore.markCollectionEncrypted(collectionId, { encryption });
|
|
177
|
+
if (!declared.ok) {
|
|
178
|
+
console.warn(`Encryption descriptor PUT not authorized for "${collectionId}" (status ${declared.status ?? 'n/a'}).`);
|
|
179
|
+
}
|
|
180
|
+
// The private-collection counterpart of the public `indexes` PUT: the
|
|
181
|
+
// blinded-index schema lives in the collection's own encrypted
|
|
182
|
+
// metadata, so it is written through the collection handle rather than
|
|
183
|
+
// the description. Non-fatal: an unqueryable collection is still a
|
|
184
|
+
// fully replicating one.
|
|
185
|
+
const blinded = await remoteStore.declareBlindedIndexes(collectionId, {
|
|
186
|
+
encryption
|
|
187
|
+
});
|
|
188
|
+
if (!blinded.ok) {
|
|
189
|
+
console.warn(`Blinded-index declaration failed for "${collectionId}": ` +
|
|
190
|
+
`${blinded.error ?? 'unknown error'} (status ${blinded.status ?? 'n/a'}).`);
|
|
191
|
+
}
|
|
192
|
+
// The schema the declaration just settled is then installed on this
|
|
193
|
+
// collection's local cipher, so the documents this replica writes from
|
|
194
|
+
// now on carry blinded `indexed` entries. A descriptor with no `hmac`
|
|
195
|
+
// carries no blinding key at all, so the install could only be a no-op:
|
|
196
|
+
// the metadata read is skipped rather than spent.
|
|
197
|
+
if (hasKeyEpochs(encryption) && encryption.hmac) {
|
|
198
|
+
const meta = await remoteStore.readCollectionMeta(collectionId);
|
|
199
|
+
if (meta) {
|
|
200
|
+
try {
|
|
201
|
+
await localStore.applyCollectionMeta({
|
|
202
|
+
collectionId,
|
|
203
|
+
custom: meta.custom
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
console.warn(`Blinded-index schema install failed for "${collectionId}":`, err);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
133
211
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// the description. Non-fatal: an unqueryable collection is still a
|
|
138
|
-
// fully replicating one.
|
|
139
|
-
const blinded = await remoteStore.declareBlindedIndexes(collectionId, {
|
|
140
|
-
encryption
|
|
141
|
-
});
|
|
142
|
-
if (!blinded.ok) {
|
|
143
|
-
console.warn(`Blinded-index declaration failed for "${collectionId}": ` +
|
|
144
|
-
`${blinded.error ?? 'unknown error'} (status ${blinded.status ?? 'n/a'}).`);
|
|
212
|
+
const indexes = await remoteStore.declareCollectionIndexes(collectionId);
|
|
213
|
+
if (!indexes.ok) {
|
|
214
|
+
console.warn(`Indexes declaration PUT not authorized for "${collectionId}" (status ${indexes.status ?? 'n/a'}).`);
|
|
145
215
|
}
|
|
146
216
|
}
|
|
147
|
-
|
|
148
|
-
if (!indexes.ok) {
|
|
149
|
-
console.warn(`Indexes declaration PUT not authorized for "${collectionId}" (status ${indexes.status ?? 'n/a'}).`);
|
|
150
|
-
}
|
|
151
|
-
}));
|
|
217
|
+
});
|
|
152
218
|
// Install the encryption-descriptor source so a decrypt that meets an unseen
|
|
153
219
|
// epoch (a rotation on another device) re-reads the descriptor and rebuilds
|
|
154
220
|
// the cipher -- once per collection per session.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasSync.js","sourceRoot":"","sources":["../../src/storage/wasSync.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,YAAY,EAAkB,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAGnB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAcpE
|
|
1
|
+
{"version":3,"file":"wasSync.js","sourceRoot":"","sources":["../../src/storage/wasSync.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/docCipher.d.ts
CHANGED
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
* prior envelope. `decrypt` reverses it. The sync layer moves the envelope
|
|
12
12
|
* verbatim; it never touches these keys.
|
|
13
13
|
*
|
|
14
|
+
* On a collection whose encryption descriptor declares a blinded-index key, the
|
|
15
|
+
* cipher can also carry the collection's persisted index schema (supplied at
|
|
16
|
+
* build time as `meta`, or installed afterwards through `applyMeta`), so the
|
|
17
|
+
* envelopes it writes carry the same blinded `indexed` entries a direct write
|
|
18
|
+
* through a collection handle emits -- which is what makes a pushed document
|
|
19
|
+
* findable by an equality query.
|
|
20
|
+
*
|
|
14
21
|
* A PUBLIC (plaintext) collection uses {@link createPlaintextDocCodec} instead:
|
|
15
22
|
* the same {@link DocCipher} seam with pass-through implementations, so the
|
|
16
23
|
* storage layer above needs no encrypted-vs-plaintext fork.
|
|
@@ -42,6 +49,12 @@ export declare function isUnknownEpochError(err: unknown): boolean;
|
|
|
42
49
|
* reverses either. An EDV (key-epoch) cipher also surfaces the `epoch` id it
|
|
43
50
|
* encrypted under, which rides the content push as the `Key-Epoch` header; the
|
|
44
51
|
* plaintext codec returns none.
|
|
52
|
+
*
|
|
53
|
+
* `applyMeta` is the blinded-index schema install hook an EDV cipher exposes:
|
|
54
|
+
* given the collection's stored `/meta` value, it installs the persisted index
|
|
55
|
+
* schema so subsequent writes emit blinded `indexed` entries. It is absent on
|
|
56
|
+
* the pass-through plaintext codec and on the fail-closed placeholder, neither
|
|
57
|
+
* of which has a schema to install -- hence optional here.
|
|
45
58
|
*/
|
|
46
59
|
export interface DocCipher {
|
|
47
60
|
encrypt(options: {
|
|
@@ -63,6 +76,9 @@ export interface DocCipher {
|
|
|
63
76
|
decrypt(options: {
|
|
64
77
|
envelope: Json;
|
|
65
78
|
}): Promise<Json>;
|
|
79
|
+
applyMeta?(options: {
|
|
80
|
+
custom?: unknown;
|
|
81
|
+
}): Promise<unknown>;
|
|
66
82
|
}
|
|
67
83
|
/**
|
|
68
84
|
* Builds the pass-through codec for a PUBLIC (plaintext) collection: payloads
|
|
@@ -118,13 +134,22 @@ export declare function hasKeyEpochs(encryption?: CollectionEncryption): encrypt
|
|
|
118
134
|
* @param options.collectionId {string} labels errors; the codec is agnostic
|
|
119
135
|
* @param options.encryption {CollectionEncryption} the collection's
|
|
120
136
|
* encryption descriptor; must carry the key-epoch roster
|
|
137
|
+
* @param [options.meta] {object} the collection's stored `/meta` value as the
|
|
138
|
+
* replica holds it (its `custom` is the opaque encrypted metadata envelope,
|
|
139
|
+
* decrypted by the codec). When supplied and the descriptor declares a
|
|
140
|
+
* blinded-index key, the persisted index schema is installed, so writes emit
|
|
141
|
+
* blinded `indexed` entries. Without it, writes emit none -- exactly what an
|
|
142
|
+
* offline replica holding no collection metadata wrote before
|
|
121
143
|
* @returns {Promise<DocCipher>}
|
|
122
144
|
*/
|
|
123
|
-
export declare function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption }: {
|
|
145
|
+
export declare function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption, meta }: {
|
|
124
146
|
keyAgreementKey: IKeyAgreementKey;
|
|
125
147
|
keyResolver: IKeyResolver;
|
|
126
148
|
collectionId: string;
|
|
127
149
|
encryption: CollectionEncryption;
|
|
150
|
+
meta?: {
|
|
151
|
+
custom?: unknown;
|
|
152
|
+
};
|
|
128
153
|
}): Promise<DocCipher>;
|
|
129
154
|
/**
|
|
130
155
|
* The fail-closed placeholder cipher for a private collection whose
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docCipher.d.ts","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"docCipher.d.ts","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAG/D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKzD;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE;QACf,IAAI,EAAE,IAAI,CAAA;KACX,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3D,aAAa,CAAC,OAAO,EAAE;QACrB,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,IAAI,CAAA;QACV,OAAO,EAAE,IAAI,CAAA;KACd,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3D,OAAO,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,SAAS,CAAC,CAAC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAC5D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,EACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,SAAS,CAiCZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,UAAU,CAAC,EAAE,oBAAoB,GAChC,UAAU,IAAI,oBAAoB,CAOpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,eAAe,CAAC,EACpC,eAAe,EACf,WAAW,EACX,YAAY,EACZ,UAAU,EACV,IAAI,EACL,EAAE;IACD,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,oBAAoB,CAAA;IAChC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAC5B,GAAG,OAAO,CAAC,SAAS,CAAC,CAUrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,YAAY,EACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,SAAS,CAkBZ"}
|
package/dist/sync/docCipher.js
CHANGED
|
@@ -103,15 +103,22 @@ export function hasKeyEpochs(encryption) {
|
|
|
103
103
|
* @param options.collectionId {string} labels errors; the codec is agnostic
|
|
104
104
|
* @param options.encryption {CollectionEncryption} the collection's
|
|
105
105
|
* encryption descriptor; must carry the key-epoch roster
|
|
106
|
+
* @param [options.meta] {object} the collection's stored `/meta` value as the
|
|
107
|
+
* replica holds it (its `custom` is the opaque encrypted metadata envelope,
|
|
108
|
+
* decrypted by the codec). When supplied and the descriptor declares a
|
|
109
|
+
* blinded-index key, the persisted index schema is installed, so writes emit
|
|
110
|
+
* blinded `indexed` entries. Without it, writes emit none -- exactly what an
|
|
111
|
+
* offline replica holding no collection metadata wrote before
|
|
106
112
|
* @returns {Promise<DocCipher>}
|
|
107
113
|
*/
|
|
108
|
-
export async function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption }) {
|
|
114
|
+
export async function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption, meta }) {
|
|
109
115
|
const cipher = await createEdvDocCipher({
|
|
110
116
|
keyAgreementKey,
|
|
111
117
|
keyResolver,
|
|
112
118
|
collectionId,
|
|
113
119
|
idDerivation: 'random',
|
|
114
|
-
encryption
|
|
120
|
+
encryption,
|
|
121
|
+
...(meta !== undefined && { meta })
|
|
115
122
|
});
|
|
116
123
|
return cipher;
|
|
117
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docCipher.js","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"docCipher.js","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interop/was-react",
|
|
3
3
|
"description": "React library for building 'Bring Your Own Everything' (BYOE) apps on Wallet Attached Storage: DID Auth login via CHAPI wallet, local-first encrypted storage, and background sync to a WAS server.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "pnpm run clear && tsc",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@interop/vc": "^11.0.6",
|
|
55
55
|
"@interop/verifier-core": "^3.5.4",
|
|
56
56
|
"@interop/wallet-core": "^0.35.0",
|
|
57
|
-
"@interop/was-client": "^0.
|
|
57
|
+
"@interop/was-client": "^0.36.0",
|
|
58
58
|
"@interop/webkms-client": "^14.7.1",
|
|
59
59
|
"@scure/base": "^2.2.0",
|
|
60
60
|
"byoe-context": "^0.3.0",
|