@interop/was-react 0.3.6 → 0.5.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 +84 -11
- package/dist/auth/loginFlow.d.ts +6 -0
- package/dist/auth/loginFlow.d.ts.map +1 -1
- package/dist/auth/loginFlow.js +28 -9
- package/dist/auth/loginFlow.js.map +1 -1
- package/dist/auth/loginRequest.d.ts +22 -1
- package/dist/auth/loginRequest.d.ts.map +1 -1
- package/dist/auth/loginRequest.js +17 -1
- package/dist/auth/loginRequest.js.map +1 -1
- package/dist/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -0
- package/dist/config.js.map +1 -1
- package/dist/identity/agents.d.ts +38 -11
- package/dist/identity/agents.d.ts.map +1 -1
- package/dist/identity/agents.js +35 -11
- package/dist/identity/agents.js.map +1 -1
- package/dist/identity/initAppSession.d.ts +6 -6
- package/dist/identity/initAppSession.js +6 -6
- package/dist/identity/seedCredential.d.ts +29 -5
- package/dist/identity/seedCredential.d.ts.map +1 -1
- package/dist/identity/seedCredential.js +47 -11
- package/dist/identity/seedCredential.js.map +1 -1
- package/dist/identity/seedStore.d.ts +11 -1
- package/dist/identity/seedStore.d.ts.map +1 -1
- package/dist/identity/seedStore.js +9 -0
- package/dist/identity/seedStore.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/react/hooks.d.ts +12 -0
- package/dist/react/hooks.d.ts.map +1 -1
- package/dist/react/hooks.js +14 -0
- package/dist/react/hooks.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/session/authStore.d.ts +9 -0
- package/dist/session/authStore.d.ts.map +1 -1
- package/dist/session/authStore.js +73 -18
- package/dist/session/authStore.js.map +1 -1
- package/dist/storage/adopt.js +2 -2
- package/dist/storage/localStore.d.ts +73 -11
- package/dist/storage/localStore.d.ts.map +1 -1
- package/dist/storage/localStore.js +187 -30
- package/dist/storage/localStore.js.map +1 -1
- package/dist/storage/sharedCollectionReader.d.ts +95 -0
- package/dist/storage/sharedCollectionReader.d.ts.map +1 -0
- package/dist/storage/sharedCollectionReader.js +338 -0
- package/dist/storage/sharedCollectionReader.js.map +1 -0
- package/dist/storage/wasRemoteStore.d.ts +24 -2
- package/dist/storage/wasRemoteStore.d.ts.map +1 -1
- package/dist/storage/wasRemoteStore.js +40 -0
- package/dist/storage/wasRemoteStore.js.map +1 -1
- package/dist/storage/wasSync.d.ts +42 -5
- package/dist/storage/wasSync.d.ts.map +1 -1
- package/dist/storage/wasSync.js +71 -5
- package/dist/storage/wasSync.js.map +1 -1
- package/dist/sync/docCipher.d.ts +19 -3
- package/dist/sync/docCipher.d.ts.map +1 -1
- package/dist/sync/docCipher.js +24 -59
- package/dist/sync/docCipher.js.map +1 -1
- package/package.json +5 -5
package/dist/storage/wasSync.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { WasRemoteStore } from './wasRemoteStore.js';
|
|
2
|
+
import { SharedCollectionReader } from './sharedCollectionReader.js';
|
|
2
3
|
/**
|
|
3
|
-
* Builds the remote store and starts
|
|
4
|
+
* Builds the remote store, opens the shared-collection readers, and starts
|
|
5
|
+
* background replication.
|
|
4
6
|
*
|
|
5
7
|
* @param options {object}
|
|
6
8
|
* @param options.parsed {ParsedGrants}
|
|
@@ -11,11 +13,21 @@ import { WasRemoteStore } from './wasRemoteStore.js';
|
|
|
11
13
|
* @param options.syncController {SyncController} a fresh per-session controller
|
|
12
14
|
* @param options.onRemoteChange {(collectionKey, event) => void} per-doc
|
|
13
15
|
* reactive patcher for pulled/conflict-resolved remote changes
|
|
16
|
+
* @param [options.sharedCollections] {SharedCollectionConfig[]} the shared
|
|
17
|
+
* (read-only, wallet-owned) registry; never replicated, never written to
|
|
18
|
+
* @param [options.identityKeys] {object} this app's IDENTITY key-agreement key
|
|
19
|
+
* and its resolver, the recipient identity a wallet writes into a shared
|
|
20
|
+
* collection's epoch roster. Required to open any shared-collection reader
|
|
21
|
+
* @param [options.identityKeys.keyAgreementKey] {IKeyAgreementKey}
|
|
22
|
+
* @param [options.identityKeys.keyResolver] {IKeyResolver}
|
|
14
23
|
* @param [options.onAuthError] {() => void} fired when replication hits a
|
|
15
24
|
* 401/403 (expired/revoked access) -- wired to the reconnect banner
|
|
16
|
-
* @
|
|
25
|
+
* @param [options.onMarkersFetched] {(markers) => void | Promise<void>} given
|
|
26
|
+
* the freshly fetched per-collection encryption markers (by WAS collection
|
|
27
|
+
* id), to refresh the offline marker cache
|
|
28
|
+
* @returns {Promise<WasSyncBootstrap>}
|
|
17
29
|
*/
|
|
18
|
-
export async function startWasSync({ parsed, zcapClient, collections, localStore, syncController, onRemoteChange, onAuthError }) {
|
|
30
|
+
export async function startWasSync({ parsed, zcapClient, collections, localStore, syncController, onRemoteChange, sharedCollections = [], identityKeys, onAuthError, onMarkersFetched }) {
|
|
19
31
|
const remoteStore = WasRemoteStore.fromGrants({
|
|
20
32
|
parsed,
|
|
21
33
|
zcapClient,
|
|
@@ -27,7 +39,10 @@ export async function startWasSync({ parsed, zcapClient, collections, localStore
|
|
|
27
39
|
// collections it does not apply to (reported ok + skipped): the encryption
|
|
28
40
|
// marker skips public collections, the indexes declaration skips private
|
|
29
41
|
// ones and public ones with no declared indexes.
|
|
30
|
-
|
|
42
|
+
const sharedIds = new Set(sharedCollections.map(entry => entry.id));
|
|
43
|
+
await Promise.all(Object.keys(parsed.byCollectionId)
|
|
44
|
+
.filter(collectionId => !sharedIds.has(collectionId))
|
|
45
|
+
.map(async (collectionId) => {
|
|
31
46
|
const marker = await remoteStore.markCollectionEncrypted(collectionId);
|
|
32
47
|
if (!marker.ok) {
|
|
33
48
|
console.warn(`Encryption marker PUT not authorized for "${collectionId}" (status ${marker.status ?? 'n/a'}).`);
|
|
@@ -37,12 +52,63 @@ export async function startWasSync({ parsed, zcapClient, collections, localStore
|
|
|
37
52
|
console.warn(`Indexes declaration PUT not authorized for "${collectionId}" (status ${indexes.status ?? 'n/a'}).`);
|
|
38
53
|
}
|
|
39
54
|
}));
|
|
55
|
+
// Fetch each granted private collection's encryption marker: rebuild that
|
|
56
|
+
// collection's cipher when its epoch roster differs from what the local store
|
|
57
|
+
// opened with (a wallet-side rotation, or first-ever epochs), and hand the
|
|
58
|
+
// fresh set to the marker-cache refresher so an offline session can rebuild
|
|
59
|
+
// its epoch-aware ciphers without a live read.
|
|
60
|
+
const privateIds = collections
|
|
61
|
+
.filter(collection => collection.visibility !== 'public')
|
|
62
|
+
.map(collection => collection.id)
|
|
63
|
+
.filter(id => parsed.byCollectionId[id] !== undefined);
|
|
64
|
+
const markers = {};
|
|
65
|
+
await Promise.all(privateIds.map(async (collectionId) => {
|
|
66
|
+
const encryption = await remoteStore.readCollectionEncryption(collectionId);
|
|
67
|
+
if (encryption) {
|
|
68
|
+
markers[collectionId] = encryption;
|
|
69
|
+
await localStore.applyRemoteMarker({ collectionId, encryption });
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
// Install the one-shot epoch refresher so a decrypt that meets an unseen epoch
|
|
73
|
+
// (a rotation on another device) re-reads the marker and rebuilds the cipher.
|
|
74
|
+
localStore.setEpochRefresher(collectionId => remoteStore.readCollectionEncryption(collectionId));
|
|
75
|
+
if (onMarkersFetched) {
|
|
76
|
+
await onMarkersFetched(markers);
|
|
77
|
+
}
|
|
78
|
+
// Shared collections stay entirely out of replication: one read-only reader
|
|
79
|
+
// each, opened over the delegated read zcap and the collection's epoch
|
|
80
|
+
// roster. Every failure mode here is a warn-and-skip -- an uncovered grant,
|
|
81
|
+
// a collection with no roster, an app that is not (or is no longer) a
|
|
82
|
+
// recipient -- so a removed share degrades one reader, never the session.
|
|
83
|
+
const sharedReaders = {};
|
|
84
|
+
for (const { key, id } of sharedCollections) {
|
|
85
|
+
if (!parsed.byCollectionId[id]) {
|
|
86
|
+
console.warn(`Skipping shared collection "${id}": no delegated capability covers it.`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!identityKeys) {
|
|
90
|
+
console.warn(`Skipping shared collection "${id}": no identity key-agreement key was ` +
|
|
91
|
+
`supplied to decrypt it with.`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
sharedReaders[key] = await SharedCollectionReader.open({
|
|
96
|
+
remoteStore,
|
|
97
|
+
keyAgreementKey: identityKeys.keyAgreementKey,
|
|
98
|
+
keyResolver: identityKeys.keyResolver,
|
|
99
|
+
collectionId: id
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
console.warn(`Skipping shared collection "${id}":`, err);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
40
106
|
await syncController.start({
|
|
41
107
|
remoteStore,
|
|
42
108
|
localStore,
|
|
43
109
|
onRemoteChange,
|
|
44
110
|
...(onAuthError && { onAuthError })
|
|
45
111
|
});
|
|
46
|
-
return remoteStore;
|
|
112
|
+
return { remoteStore, sharedCollections: sharedReaders };
|
|
47
113
|
}
|
|
48
114
|
//# sourceMappingURL=wasSync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasSync.js","sourceRoot":"","sources":["../../src/storage/wasSync.ts"],"names":[],"mappings":"
|
|
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
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* storage layer above needs no encrypted-vs-plaintext fork.
|
|
17
17
|
*/
|
|
18
18
|
import type { IKeyAgreementKey, IKeyResolver } from '@interop/data-integrity-core';
|
|
19
|
+
import type { CollectionEncryption } from '@interop/was-client';
|
|
19
20
|
import type { Json } from './types.js';
|
|
20
21
|
/**
|
|
21
22
|
* A per-collection document cipher. `encrypt` is the create path (mints a random
|
|
@@ -70,21 +71,36 @@ export declare function createPlaintextDocCodec({ collectionId }: {
|
|
|
70
71
|
collectionId: string;
|
|
71
72
|
}): DocCipher;
|
|
72
73
|
/**
|
|
73
|
-
* Builds a {@link DocCipher} for one collection from
|
|
74
|
-
* (the
|
|
74
|
+
* Builds a {@link DocCipher} for one collection from the caller's derived key
|
|
75
|
+
* material (the app's identity X25519 key agreement key, the same one every
|
|
76
|
+
* other collection uses). Keys are supplied directly (no
|
|
75
77
|
* keystore lookup). `idDerivation: 'random'` mints a stable random id updated in
|
|
76
78
|
* place via `sequence` -- the mutable head-document model every entity here uses
|
|
77
79
|
* (constant bump / toggle / re-categorize edits).
|
|
78
80
|
*
|
|
81
|
+
* Delegates to `@interop/was-client`'s `createEdvDocCipher`: with no
|
|
82
|
+
* `encryption` marker (or a marker with no key epochs) the cipher is
|
|
83
|
+
* single-recipient (the key-agreement key encrypts and decrypts directly, the
|
|
84
|
+
* behavior every collection has had); with epochs on the marker the cipher
|
|
85
|
+
* becomes multi-recipient -- writes stamp the marker's current epoch and reads
|
|
86
|
+
* route by the envelope's recipient key id, while a pre-epoch envelope still
|
|
87
|
+
* decrypts through the single-key path (a permanent tolerance, not a migration
|
|
88
|
+
* shim). The returned cipher's shape matches {@link DocCipher} exactly; only the
|
|
89
|
+
* nominal `Json` origin differs, so it crosses the boundary with a cast.
|
|
90
|
+
*
|
|
79
91
|
* @param options {object}
|
|
80
92
|
* @param options.keyAgreementKey {IKeyAgreementKey}
|
|
81
93
|
* @param options.keyResolver {IKeyResolver}
|
|
82
94
|
* @param options.collectionId {string} labels errors; the codec is agnostic
|
|
95
|
+
* @param [options.encryption] {CollectionEncryption} the collection's
|
|
96
|
+
* encryption marker; when it carries key epochs the cipher becomes
|
|
97
|
+
* multi-recipient
|
|
83
98
|
* @returns {Promise<DocCipher>}
|
|
84
99
|
*/
|
|
85
|
-
export declare function createDocCipher({ keyAgreementKey, keyResolver, collectionId }: {
|
|
100
|
+
export declare function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption }: {
|
|
86
101
|
keyAgreementKey: IKeyAgreementKey;
|
|
87
102
|
keyResolver: IKeyResolver;
|
|
88
103
|
collectionId: string;
|
|
104
|
+
encryption?: CollectionEncryption;
|
|
89
105
|
}): Promise<DocCipher>;
|
|
90
106
|
//# sourceMappingURL=docCipher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docCipher.d.ts","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"docCipher.d.ts","sourceRoot":"","sources":["../../src/sync/docCipher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAE/D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC,CAAA;IACzE,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,CAAA;KAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,OAAO,CAMnE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,EACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,SAAS,CAiCZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,eAAe,CAAC,EACpC,eAAe,EACf,WAAW,EACX,YAAY,EACZ,UAAU,EACX,EAAE;IACD,eAAe,EAAE,gBAAgB,CAAA;IACjC,WAAW,EAAE,YAAY,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,oBAAoB,CAAA;CAClC,GAAG,OAAO,CAAC,SAAS,CAAC,CASrB"}
|
package/dist/sync/docCipher.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createEdvDocCipher } from '@interop/was-client/edv';
|
|
2
2
|
/**
|
|
3
3
|
* Whether a stored body is an EDV encryption envelope (carries an object `jwe`)
|
|
4
4
|
* rather than plaintext. Lets read paths stay tolerant of any legacy plaintext
|
|
@@ -57,75 +57,40 @@ export function createPlaintextDocCodec({ collectionId }) {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* Builds a {@link DocCipher} for one collection from
|
|
61
|
-
* (the
|
|
60
|
+
* Builds a {@link DocCipher} for one collection from the caller's derived key
|
|
61
|
+
* material (the app's identity X25519 key agreement key, the same one every
|
|
62
|
+
* other collection uses). Keys are supplied directly (no
|
|
62
63
|
* keystore lookup). `idDerivation: 'random'` mints a stable random id updated in
|
|
63
64
|
* place via `sequence` -- the mutable head-document model every entity here uses
|
|
64
65
|
* (constant bump / toggle / re-categorize edits).
|
|
65
66
|
*
|
|
67
|
+
* Delegates to `@interop/was-client`'s `createEdvDocCipher`: with no
|
|
68
|
+
* `encryption` marker (or a marker with no key epochs) the cipher is
|
|
69
|
+
* single-recipient (the key-agreement key encrypts and decrypts directly, the
|
|
70
|
+
* behavior every collection has had); with epochs on the marker the cipher
|
|
71
|
+
* becomes multi-recipient -- writes stamp the marker's current epoch and reads
|
|
72
|
+
* route by the envelope's recipient key id, while a pre-epoch envelope still
|
|
73
|
+
* decrypts through the single-key path (a permanent tolerance, not a migration
|
|
74
|
+
* shim). The returned cipher's shape matches {@link DocCipher} exactly; only the
|
|
75
|
+
* nominal `Json` origin differs, so it crosses the boundary with a cast.
|
|
76
|
+
*
|
|
66
77
|
* @param options {object}
|
|
67
78
|
* @param options.keyAgreementKey {IKeyAgreementKey}
|
|
68
79
|
* @param options.keyResolver {IKeyResolver}
|
|
69
80
|
* @param options.collectionId {string} labels errors; the codec is agnostic
|
|
81
|
+
* @param [options.encryption] {CollectionEncryption} the collection's
|
|
82
|
+
* encryption marker; when it carries key epochs the cipher becomes
|
|
83
|
+
* multi-recipient
|
|
70
84
|
* @returns {Promise<DocCipher>}
|
|
71
85
|
*/
|
|
72
|
-
export async function createDocCipher({ keyAgreementKey, keyResolver, collectionId }) {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
77
|
-
const codec = await provider.codecFor({
|
|
78
|
-
spaceId: 'local',
|
|
86
|
+
export async function createDocCipher({ keyAgreementKey, keyResolver, collectionId, encryption }) {
|
|
87
|
+
const cipher = await createEdvDocCipher({
|
|
88
|
+
keyAgreementKey,
|
|
89
|
+
keyResolver,
|
|
79
90
|
collectionId,
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
idDerivation: 'random',
|
|
92
|
+
...(encryption && { encryption })
|
|
82
93
|
});
|
|
83
|
-
|
|
84
|
-
throw new Error(`Could not build the EDV cipher for collection "${collectionId}".`);
|
|
85
|
-
}
|
|
86
|
-
// Parses the codec's `EncodedWrite` (id + envelope body bytes) into the
|
|
87
|
-
// stored `{ id, envelope }` shape. Shared by the create and update paths.
|
|
88
|
-
const readEncoded = (encoded) => {
|
|
89
|
-
if (typeof encoded.id !== 'string' ||
|
|
90
|
-
!(encoded.body instanceof Uint8Array)) {
|
|
91
|
-
throw new Error(`EDV encrypt for collection "${collectionId}" returned no id/envelope body.`);
|
|
92
|
-
}
|
|
93
|
-
const envelope = JSON.parse(new TextDecoder().decode(encoded.body));
|
|
94
|
-
return { id: encoded.id, envelope };
|
|
95
|
-
};
|
|
96
|
-
return {
|
|
97
|
-
async encrypt({ data }) {
|
|
98
|
-
// `encode` with no caller id is the create path: encrypt, then use the
|
|
99
|
-
// minted random id.
|
|
100
|
-
const encoded = await codec.encode({
|
|
101
|
-
data: data
|
|
102
|
-
});
|
|
103
|
-
return readEncoded(encoded);
|
|
104
|
-
},
|
|
105
|
-
async encryptUpdate({ id, data, current }) {
|
|
106
|
-
// The update path: hand the codec the prior stored envelope so it advances
|
|
107
|
-
// `sequence` from it and re-encrypts under the same id. The codec reads
|
|
108
|
-
// `current.data` (the prior envelope) and its `etag` header (unused here;
|
|
109
|
-
// the wire `If-Match` is derived from the synced-doc `version`, not this).
|
|
110
|
-
const priorResponse = {
|
|
111
|
-
data: current,
|
|
112
|
-
json: async () => current,
|
|
113
|
-
headers: { get: () => null }
|
|
114
|
-
};
|
|
115
|
-
const encoded = await codec.encode({
|
|
116
|
-
id,
|
|
117
|
-
data: data,
|
|
118
|
-
current: priorResponse
|
|
119
|
-
});
|
|
120
|
-
return readEncoded(encoded);
|
|
121
|
-
},
|
|
122
|
-
async decrypt({ envelope }) {
|
|
123
|
-
const response = {
|
|
124
|
-
data: envelope,
|
|
125
|
-
json: async () => envelope
|
|
126
|
-
};
|
|
127
|
-
return (await codec.decode(response));
|
|
128
|
-
}
|
|
129
|
-
};
|
|
94
|
+
return cipher;
|
|
130
95
|
}
|
|
131
96
|
//# sourceMappingURL=docCipher.js.map
|
|
@@ -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":"AAsBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAmB5D;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAsB;IACxD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpE,OAAO,KAAK,CAAA;IACd,CAAC;IACD,MAAM,GAAG,GAAI,IAA0B,CAAC,GAAG,CAAA;IAC3C,OAAO,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAA;AAChD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACtC,YAAY,EAGb;IACC,MAAM,SAAS,GAAG,CAAC,IAAU,EAAU,EAAE;QACvC,MAAM,EAAE,GAAI,IAAgC,EAAE,EAAE,CAAA;QAChD,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,kCAAkC,YAAY,2BAA2B,CAC1E,CAAA;QACH,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAA;IACD,MAAM,eAAe,GAAG,CAAC,IAAU,EAAQ,EAAE;QAC3C,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,yCAAyC;gBAClE,yBAAyB,CAC5B,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IAED,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAkB;YACpC,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QAChD,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAA8B;YAC1D,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;QAC/B,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAsB;YAC5C,OAAO,eAAe,CAAC,QAAQ,CAAC,CAAA;QAClC,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EACpC,eAAe,EACf,WAAW,EACX,YAAY,EACZ,UAAU,EAMX;IACC,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;QACtC,eAAe;QACf,WAAW;QACX,YAAY;QACZ,YAAY,EAAE,QAAQ;QACtB,GAAG,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC;KAClC,CAAC,CAAA;IACF,OAAO,MAA8B,CAAA;AACvC,CAAC"}
|
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.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "pnpm run clear && tsc",
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
"types": "dist/index.d.ts",
|
|
47
47
|
"sideEffects": false,
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@interop/data-integrity-core": "^8.
|
|
49
|
+
"@interop/data-integrity-core": "^8.4.0",
|
|
50
50
|
"@interop/ed25519-signature": "^7.1.4",
|
|
51
51
|
"@interop/ezcap": "^7.4.1",
|
|
52
52
|
"@interop/security-document-loader": "^9.4.4",
|
|
53
53
|
"@interop/vc": "^11.0.6",
|
|
54
|
-
"@interop/verifier-core": "^3.
|
|
54
|
+
"@interop/verifier-core": "^3.5.0",
|
|
55
55
|
"@interop/wallet-core": "^0.5.0",
|
|
56
|
-
"@interop/was-client": "^0.
|
|
56
|
+
"@interop/was-client": "^0.20.0",
|
|
57
57
|
"@interop/webkms-client": "^14.7.1",
|
|
58
58
|
"@interop/x25519-key-agreement-key": "^5.2.1",
|
|
59
59
|
"@scure/base": "^2.2.0",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"typescript-eslint": "^8.59.4",
|
|
110
110
|
"vite": "^8.0.14",
|
|
111
111
|
"vitest": "^4.1.7",
|
|
112
|
-
"was-teaching-server": "^0.
|
|
112
|
+
"was-teaching-server": "^0.14.0",
|
|
113
113
|
"zustand": "^5.0.12"
|
|
114
114
|
},
|
|
115
115
|
"publishConfig": {
|