@web_of_trust/adapter-yjs 0.1.2
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 +136 -0
- package/dist/YjsPersonalDocManager.d.ts +56 -0
- package/dist/YjsPersonalDocManager.d.ts.map +1 -0
- package/dist/YjsPersonalSyncAdapter.d.ts +33 -0
- package/dist/YjsPersonalSyncAdapter.d.ts.map +1 -0
- package/dist/YjsReplicationAdapter.d.ts +151 -0
- package/dist/YjsReplicationAdapter.d.ts.map +1 -0
- package/dist/YjsStorageAdapter.d.ts +35 -0
- package/dist/YjsStorageAdapter.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1816 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# @web_of_trust/adapter-yjs
|
|
2
|
+
|
|
3
|
+
Default CRDT adapter for Web of Trust — pure JavaScript, no WASM required.
|
|
4
|
+
|
|
5
|
+
Implements the `ReplicationAdapter` and personal document interfaces from `@web_of_trust/core` using [Yjs](https://yjs.dev). Chosen as the default CRDT after benchmarking showed 76x faster initialisation on Android compared to the Automerge/WASM alternative.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @web_of_trust/adapter-yjs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires `@web_of_trust/core` as a peer dependency.
|
|
14
|
+
|
|
15
|
+
## Key Features
|
|
16
|
+
|
|
17
|
+
- **Pure JavaScript** — no WASM, no worker, no WASM bundle (69 KB vs 1.7 MB)
|
|
18
|
+
- **YjsPersonalDocManager** — personal data (profile, contacts, attestations, group keys) stored in a `Y.Doc` with proxy-based mutation API
|
|
19
|
+
- **YjsReplicationAdapter** — encrypted shared spaces backed by `Y.Doc`, drop-in replacement for the Automerge adapter
|
|
20
|
+
- **YjsPersonalSyncAdapter** — multi-device sync for the personal document via the Relay
|
|
21
|
+
- **Built-in garbage collection** — `ydoc.gc = true`; no history-stripping hack needed
|
|
22
|
+
- **CRDT-agnostic persistence** — serialises to `Uint8Array` via `Y.encodeStateAsUpdate()`, stored in CompactStore (IndexedDB) and Vault
|
|
23
|
+
|
|
24
|
+
## API Overview
|
|
25
|
+
|
|
26
|
+
### Personal Document
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import {
|
|
30
|
+
initYjsPersonalDoc,
|
|
31
|
+
getYjsPersonalDoc,
|
|
32
|
+
changeYjsPersonalDoc,
|
|
33
|
+
onYjsPersonalDocChange,
|
|
34
|
+
flushYjsPersonalDoc,
|
|
35
|
+
} from '@web_of_trust/adapter-yjs'
|
|
36
|
+
|
|
37
|
+
// Initialise (loads from CompactStore / Vault on first call)
|
|
38
|
+
await initYjsPersonalDoc({ identity, compactStore, vaultClient })
|
|
39
|
+
|
|
40
|
+
// Read
|
|
41
|
+
const doc = getYjsPersonalDoc()
|
|
42
|
+
const contact = doc.contacts['did:key:z6Mk...']
|
|
43
|
+
|
|
44
|
+
// Mutate (proxy-based — plain assignment works)
|
|
45
|
+
changeYjsPersonalDoc((doc) => {
|
|
46
|
+
doc.profile.name = 'Alice'
|
|
47
|
+
doc.contacts['did:key:z6Mk...'] = { did: '...', name: 'Bob', ... }
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Subscribe to changes
|
|
51
|
+
const unsub = onYjsPersonalDocChange(() => {
|
|
52
|
+
const latest = getYjsPersonalDoc()
|
|
53
|
+
// re-render
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Persist immediately (normally automatic)
|
|
57
|
+
await flushYjsPersonalDoc()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Replication Adapter (Shared Spaces)
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { YjsReplicationAdapter } from '@web_of_trust/adapter-yjs'
|
|
64
|
+
|
|
65
|
+
const replication = new YjsReplicationAdapter({
|
|
66
|
+
identity, // WotIdentity
|
|
67
|
+
messaging, // MessagingAdapter
|
|
68
|
+
groupKeyService, // GroupKeyService
|
|
69
|
+
metadataStorage, // SpaceMetadataStorage (optional)
|
|
70
|
+
compactStore, // YjsCompactStore (optional, IDB-backed)
|
|
71
|
+
vaultUrl, // string (optional)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Open a space (creates Y.Doc if new, restores if known)
|
|
75
|
+
const handle = await replication.openSpace<{ notes: string }>(spaceInfo)
|
|
76
|
+
|
|
77
|
+
// Read current state
|
|
78
|
+
const doc = handle.getDoc()
|
|
79
|
+
|
|
80
|
+
// Mutate
|
|
81
|
+
await handle.transact((doc) => {
|
|
82
|
+
doc.notes = 'Hello from Alice'
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// React to remote updates
|
|
86
|
+
handle.onRemoteUpdate(() => {
|
|
87
|
+
console.log('Remote change received:', handle.getDoc())
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// Close when done
|
|
91
|
+
handle.close()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Personal Sync (Multi-Device)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { YjsPersonalSyncAdapter } from '@web_of_trust/adapter-yjs'
|
|
98
|
+
|
|
99
|
+
const sync = new YjsPersonalSyncAdapter({ identity, messaging, compactStore })
|
|
100
|
+
await sync.start()
|
|
101
|
+
// Encrypted Y.Doc updates are now forwarded to / from other devices via the Relay
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## How to Run
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Build (watch mode during development)
|
|
108
|
+
pnpm dev
|
|
109
|
+
|
|
110
|
+
# Build once
|
|
111
|
+
pnpm build
|
|
112
|
+
|
|
113
|
+
# Run tests
|
|
114
|
+
pnpm test
|
|
115
|
+
|
|
116
|
+
# Run tests in watch mode
|
|
117
|
+
pnpm test:watch
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## CRDT Switch
|
|
121
|
+
|
|
122
|
+
The demo app selects adapters via the `VITE_CRDT` environment variable:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Default — uses adapter-yjs
|
|
126
|
+
pnpm dev:demo
|
|
127
|
+
|
|
128
|
+
# Switch to Automerge
|
|
129
|
+
VITE_CRDT=automerge pnpm dev:demo
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Both adapters pass the same 7 end-to-end Playwright tests.
|
|
133
|
+
|
|
134
|
+
## Main Repo
|
|
135
|
+
|
|
136
|
+
[github.com/antontranelis/web-of-trust](https://github.com/antontranelis/web-of-trust)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { WotIdentity, MessagingAdapter } from '@web_of_trust/core';
|
|
2
|
+
import { PersonalDoc } from './types';
|
|
3
|
+
export type { PersonalDoc as YjsPersonalDoc };
|
|
4
|
+
/**
|
|
5
|
+
* Initialize the personal document as a Yjs Y.Doc.
|
|
6
|
+
*
|
|
7
|
+
* Load order: CompactStore → Vault → Empty
|
|
8
|
+
*
|
|
9
|
+
* @param identity - WotIdentity for key derivation
|
|
10
|
+
* @param messaging - Optional MessagingAdapter for multi-device sync via relay
|
|
11
|
+
* @param vaultUrl - Optional vault URL for encrypted backup
|
|
12
|
+
*/
|
|
13
|
+
export declare function initYjsPersonalDoc(identity: WotIdentity, messaging?: MessagingAdapter, vaultUrl?: string, externalCompactStore?: {
|
|
14
|
+
open(): Promise<void>;
|
|
15
|
+
save(id: string, data: Uint8Array): Promise<void>;
|
|
16
|
+
load(id: string): Promise<Uint8Array | null>;
|
|
17
|
+
delete(id: string): Promise<void>;
|
|
18
|
+
list(): Promise<string[]>;
|
|
19
|
+
close(): void;
|
|
20
|
+
}): Promise<PersonalDoc>;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current personal document snapshot.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getYjsPersonalDoc(): PersonalDoc;
|
|
25
|
+
/**
|
|
26
|
+
* Apply a change to the personal document.
|
|
27
|
+
* Uses a Proxy that maps property assignments to Y.Map operations.
|
|
28
|
+
*/
|
|
29
|
+
export declare function changeYjsPersonalDoc(fn: (doc: PersonalDoc) => void, options?: {
|
|
30
|
+
background?: boolean;
|
|
31
|
+
}): PersonalDoc;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to changes on the personal document.
|
|
34
|
+
*/
|
|
35
|
+
export declare function onYjsPersonalDocChange(callback: () => void): () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Force-flush to CompactStore and Vault immediately.
|
|
38
|
+
* Waits for any in-progress pushes to complete, then does a final push.
|
|
39
|
+
*/
|
|
40
|
+
export declare function flushYjsPersonalDoc(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Pull the latest PersonalDoc from the Vault and merge into the local Y.Doc.
|
|
43
|
+
* Used as a fallback when a Space Vault-Pull fails due to a missing key —
|
|
44
|
+
* the Vault may have a newer PersonalDoc with the required key.
|
|
45
|
+
*/
|
|
46
|
+
export declare function refreshYjsPersonalDocFromVault(): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Reset — shut down and clear all state.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resetYjsPersonalDoc(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Delete — reset + delete IndexedDB databases.
|
|
53
|
+
* Used on logout to fully clear persisted state.
|
|
54
|
+
*/
|
|
55
|
+
export declare function deleteYjsPersonalDocDB(): Promise<void>;
|
|
56
|
+
//# sourceMappingURL=YjsPersonalDocManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YjsPersonalDocManager.d.ts","sourceRoot":"","sources":["../src/YjsPersonalDocManager.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAYvE,OAAO,KAAK,EACV,WAAW,EAEZ,MAAM,SAAS,CAAA;AAGhB,YAAY,EAAE,WAAW,IAAI,cAAc,EAAE,CAAA;AA4W7C;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE;IAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAqNrW;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAG/C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,WAAW,CAmBpH;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAGvE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAED;;;;GAIG;AACH,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,OAAO,CAAC,CAEvE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWzD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO5D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { MessagingAdapter } from '@web_of_trust/core';
|
|
2
|
+
/**
|
|
3
|
+
* YjsPersonalSyncAdapter — Multi-device sync for Yjs Personal Doc
|
|
4
|
+
*
|
|
5
|
+
* Bridges the Y.Doc to the MessagingAdapter for encrypted multi-device sync.
|
|
6
|
+
* Equivalent to PersonalNetworkAdapter but for Yjs instead of Automerge.
|
|
7
|
+
*
|
|
8
|
+
* - Listens to Y.Doc 'update' events
|
|
9
|
+
* - Encrypts updates with the personal key (EncryptedSyncService)
|
|
10
|
+
* - Sends encrypted updates via MessagingAdapter to self (other devices)
|
|
11
|
+
* - Receives encrypted updates from other devices, decrypts, applies to Y.Doc
|
|
12
|
+
*/
|
|
13
|
+
import * as Y from 'yjs';
|
|
14
|
+
export declare class YjsPersonalSyncAdapter {
|
|
15
|
+
private doc;
|
|
16
|
+
private messaging;
|
|
17
|
+
private personalKey;
|
|
18
|
+
private myDid;
|
|
19
|
+
private unsubDocUpdate;
|
|
20
|
+
private unsubMessage;
|
|
21
|
+
private unsubStateChange;
|
|
22
|
+
private started;
|
|
23
|
+
/** Track message IDs we sent, so we ignore our own echoes from the relay */
|
|
24
|
+
private sentMessageIds;
|
|
25
|
+
private signFn?;
|
|
26
|
+
constructor(doc: Y.Doc, messaging: MessagingAdapter, personalKey: Uint8Array, myDid: string, signFn?: (data: string) => Promise<string>);
|
|
27
|
+
start(): void;
|
|
28
|
+
private sendSyncRequest;
|
|
29
|
+
private sendFullState;
|
|
30
|
+
private sendUpdate;
|
|
31
|
+
destroy(): void;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=YjsPersonalSyncAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YjsPersonalSyncAdapter.d.ts","sourceRoot":"","sources":["../src/YjsPersonalSyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAG1D,qBAAa,sBAAsB;IACjC,OAAO,CAAC,GAAG,CAAO;IAClB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,WAAW,CAAY;IAC/B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,OAAO,CAAQ;IACvB,4EAA4E;IAC5E,OAAO,CAAC,cAAc,CAAoB;IAC1C,OAAO,CAAC,MAAM,CAAC,CAAmC;gBAEtC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC;IAQvI,KAAK,IAAI,IAAI;IAiEb,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,aAAa;YAOP,UAAU;IA2CxB,OAAO,IAAI,IAAI;CAgBhB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ReplicationAdapter, SpaceHandle, TransactOptions, Subscribable, MessagingAdapter, WotIdentity, SpaceInfo, SpaceDocMeta, SpaceMemberChange, ReplicationState, GroupKeyService, VaultClient, SpaceMetadataStorage } from '@web_of_trust/core';
|
|
2
|
+
/**
|
|
3
|
+
* YjsReplicationAdapter — ReplicationAdapter backed by Yjs CRDTs
|
|
4
|
+
*
|
|
5
|
+
* Drop-in alternative to AutomergeReplicationAdapter.
|
|
6
|
+
* Uses Y.Doc (pure JavaScript) instead of Automerge (Rust→WASM).
|
|
7
|
+
*
|
|
8
|
+
* Key differences:
|
|
9
|
+
* - No Repo, DocHandle, NetworkAdapter (automerge-repo concepts)
|
|
10
|
+
* - One Y.Doc per space, stored in a simple Map
|
|
11
|
+
* - Encrypted sync via MessagingAdapter directly (same pattern as YjsPersonalSyncAdapter)
|
|
12
|
+
* - No compaction needed (Yjs has built-in GC)
|
|
13
|
+
*/
|
|
14
|
+
import * as Y from 'yjs';
|
|
15
|
+
/** Duck-typed interface for CompactStorageManager / InMemoryCompactStore */
|
|
16
|
+
export interface YjsCompactStore {
|
|
17
|
+
save(docId: string, data: Uint8Array): Promise<void>;
|
|
18
|
+
load(docId: string): Promise<Uint8Array | null>;
|
|
19
|
+
}
|
|
20
|
+
interface YjsSpaceState {
|
|
21
|
+
info: SpaceInfo;
|
|
22
|
+
doc: Y.Doc;
|
|
23
|
+
handles: Set<YjsSpaceHandle<any>>;
|
|
24
|
+
memberEncryptionKeys: Map<string, Uint8Array>;
|
|
25
|
+
unsubUpdate: (() => void) | null;
|
|
26
|
+
}
|
|
27
|
+
interface YjsReplicationConfig {
|
|
28
|
+
identity: WotIdentity;
|
|
29
|
+
messaging: MessagingAdapter;
|
|
30
|
+
groupKeyService: GroupKeyService;
|
|
31
|
+
metadataStorage?: SpaceMetadataStorage;
|
|
32
|
+
compactStore?: YjsCompactStore;
|
|
33
|
+
vaultUrl?: string;
|
|
34
|
+
vault?: VaultClient;
|
|
35
|
+
spaceFilter?: (info: SpaceInfo) => boolean;
|
|
36
|
+
/** Flush PersonalDoc to Vault immediately (for key rotation safety) */
|
|
37
|
+
flushPersonalDoc?: () => Promise<void>;
|
|
38
|
+
/** Pull PersonalDoc from Vault (for lazy key refresh) */
|
|
39
|
+
refreshPersonalDocFromVault?: () => Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
declare class YjsSpaceHandle<T> implements SpaceHandle<T> {
|
|
42
|
+
private spaceState;
|
|
43
|
+
private adapter;
|
|
44
|
+
readonly id: string;
|
|
45
|
+
private closed;
|
|
46
|
+
private remoteUpdateCallbacks;
|
|
47
|
+
private unsubChange;
|
|
48
|
+
constructor(spaceState: YjsSpaceState, adapter: YjsReplicationAdapter);
|
|
49
|
+
info(): SpaceInfo;
|
|
50
|
+
getDoc(): T;
|
|
51
|
+
getMeta(): SpaceDocMeta;
|
|
52
|
+
transact(fn: (doc: T) => void, options?: TransactOptions): void;
|
|
53
|
+
onRemoteUpdate(callback: () => void): () => void;
|
|
54
|
+
close(): void;
|
|
55
|
+
}
|
|
56
|
+
export declare class YjsReplicationAdapter implements ReplicationAdapter {
|
|
57
|
+
private identity;
|
|
58
|
+
private messaging;
|
|
59
|
+
private groupKeyService;
|
|
60
|
+
private metadataStorage?;
|
|
61
|
+
private compactStore?;
|
|
62
|
+
private vault?;
|
|
63
|
+
private spaceFilter?;
|
|
64
|
+
private spaces;
|
|
65
|
+
private spaceListeners;
|
|
66
|
+
private memberChangeListeners;
|
|
67
|
+
private vaultSchedulers;
|
|
68
|
+
private compactSchedulers;
|
|
69
|
+
private vaultSeqs;
|
|
70
|
+
/** Cache 404 responses from Vault to avoid repeated requests for non-existent docs */
|
|
71
|
+
private vault404Cache;
|
|
72
|
+
private static VAULT_404_TTL;
|
|
73
|
+
private unsubMessage;
|
|
74
|
+
private unsubStateChange;
|
|
75
|
+
private started;
|
|
76
|
+
private sentMessageIds;
|
|
77
|
+
private pendingMessages;
|
|
78
|
+
private static PENDING_TTL;
|
|
79
|
+
private flushPersonalDoc?;
|
|
80
|
+
private refreshPersonalDocFromVault?;
|
|
81
|
+
constructor(config: YjsReplicationConfig);
|
|
82
|
+
start(): Promise<void>;
|
|
83
|
+
stop(): Promise<void>;
|
|
84
|
+
getState(): ReplicationState;
|
|
85
|
+
createSpace<T>(type: SpaceInfo['type'], initialDoc: T, meta?: {
|
|
86
|
+
name?: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
appTag?: string;
|
|
89
|
+
modules?: string[];
|
|
90
|
+
}): Promise<SpaceInfo>;
|
|
91
|
+
openSpace<T>(spaceId: string): Promise<SpaceHandle<T>>;
|
|
92
|
+
getSpace(spaceId: string): Promise<SpaceInfo | null>;
|
|
93
|
+
getSpaces(): Promise<SpaceInfo[]>;
|
|
94
|
+
watchSpaces(): Subscribable<SpaceInfo[]>;
|
|
95
|
+
addMember(spaceId: string, memberDid: string, memberEncryptionPublicKey: Uint8Array): Promise<void>;
|
|
96
|
+
removeMember(spaceId: string, memberDid: string): Promise<void>;
|
|
97
|
+
onMemberChange(callback: (change: SpaceMemberChange) => void): () => void;
|
|
98
|
+
/** Leave a space: clean up local state, metadata, group keys, compact store */
|
|
99
|
+
leaveSpace(spaceId: string): Promise<void>;
|
|
100
|
+
requestSync(spaceId: string): Promise<void>;
|
|
101
|
+
private static readonly VAULT_PULL_CONCURRENCY;
|
|
102
|
+
/** Pull from Vault for all spaces with concurrency limit */
|
|
103
|
+
private _pullAllFromVault;
|
|
104
|
+
/**
|
|
105
|
+
* Pull the latest snapshot from the Vault and merge into the local Y.Doc.
|
|
106
|
+
* This ensures multi-device sync even when devices were not online simultaneously.
|
|
107
|
+
* If decryption fails (missing key after rotation), tries to refresh the PersonalDoc
|
|
108
|
+
* from the Vault to get the new key, then retries.
|
|
109
|
+
*/
|
|
110
|
+
private _pullFromVault;
|
|
111
|
+
/** Reload group keys from metadata storage into the GroupKeyService */
|
|
112
|
+
private _reloadGroupKeys;
|
|
113
|
+
/**
|
|
114
|
+
* Send full Y.Doc state of all spaces to own DID (multi-device sync).
|
|
115
|
+
* Other devices of the same identity merge the state via Y.applyUpdate.
|
|
116
|
+
* Analogous to YjsPersonalSyncAdapter.sendFullState().
|
|
117
|
+
*/
|
|
118
|
+
private _sendFullStateAllSpaces;
|
|
119
|
+
getKeyGeneration(spaceId: string): number;
|
|
120
|
+
updateSpace(spaceId: string, meta: SpaceDocMeta): Promise<void>;
|
|
121
|
+
restoreSpacesFromMetadata(): Promise<void>;
|
|
122
|
+
private setupSpaceSync;
|
|
123
|
+
private sendEncryptedUpdate;
|
|
124
|
+
private handleContentMessage;
|
|
125
|
+
private handleSpaceInvite;
|
|
126
|
+
private handleMemberUpdate;
|
|
127
|
+
private handleGroupKeyRotation;
|
|
128
|
+
/**
|
|
129
|
+
* Handle sync request from another device: respond with full state for the requested space.
|
|
130
|
+
*/
|
|
131
|
+
private handleSpaceSyncRequest;
|
|
132
|
+
/**
|
|
133
|
+
* Send a sync request for a specific space to own DID (multi-device).
|
|
134
|
+
* Other devices that have this space will respond with their full state.
|
|
135
|
+
*/
|
|
136
|
+
private sendSpaceSyncRequest;
|
|
137
|
+
_saveToCompactStore(state: YjsSpaceState): Promise<void>;
|
|
138
|
+
_pushSnapshotToVault(state: YjsSpaceState): Promise<void>;
|
|
139
|
+
private ensureSchedulers;
|
|
140
|
+
_scheduleCompactImmediate(state: YjsSpaceState): void;
|
|
141
|
+
_scheduleCompactDebounced(state: YjsSpaceState): void;
|
|
142
|
+
_scheduleVaultImmediate(state: YjsSpaceState): void;
|
|
143
|
+
_scheduleVaultDebounced(state: YjsSpaceState): void;
|
|
144
|
+
/** Run async tasks with a concurrency limit */
|
|
145
|
+
private _runWithConcurrency;
|
|
146
|
+
private sendMemberUpdate;
|
|
147
|
+
private saveSpaceMetadata;
|
|
148
|
+
private notifySpaceListeners;
|
|
149
|
+
}
|
|
150
|
+
export {};
|
|
151
|
+
//# sourceMappingURL=YjsReplicationAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YjsReplicationAdapter.d.ts","sourceRoot":"","sources":["../src/YjsReplicationAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { StorageAdapter, ReactiveStorageAdapter, Subscribable, Identity, Profile, Contact, Verification, Attestation, AttestationMetadata } from '@web_of_trust/core';
|
|
2
|
+
export declare class YjsStorageAdapter implements StorageAdapter, ReactiveStorageAdapter {
|
|
3
|
+
private did;
|
|
4
|
+
private cachedIdentity;
|
|
5
|
+
constructor(did: string);
|
|
6
|
+
createIdentity(did: string, profile: Profile): Promise<Identity>;
|
|
7
|
+
getIdentity(): Promise<Identity | null>;
|
|
8
|
+
updateIdentity(identity: Identity): Promise<void>;
|
|
9
|
+
private profileFromDoc;
|
|
10
|
+
addContact(contact: Contact): Promise<void>;
|
|
11
|
+
getContacts(): Promise<Contact[]>;
|
|
12
|
+
getContact(did: string): Promise<Contact | null>;
|
|
13
|
+
updateContact(contact: Contact): Promise<void>;
|
|
14
|
+
removeContact(did: string): Promise<void>;
|
|
15
|
+
saveVerification(verification: Verification): Promise<void>;
|
|
16
|
+
getReceivedVerifications(): Promise<Verification[]>;
|
|
17
|
+
getAllVerifications(): Promise<Verification[]>;
|
|
18
|
+
getVerification(id: string): Promise<Verification | null>;
|
|
19
|
+
saveAttestation(attestation: Attestation): Promise<void>;
|
|
20
|
+
getReceivedAttestations(): Promise<Attestation[]>;
|
|
21
|
+
getAttestation(id: string): Promise<Attestation | null>;
|
|
22
|
+
getAttestationMetadata(attestationId: string): Promise<AttestationMetadata | null>;
|
|
23
|
+
setAttestationAccepted(attestationId: string, accepted: boolean): Promise<void>;
|
|
24
|
+
setDeliveryStatus(attestationId: string, status: string): Promise<void>;
|
|
25
|
+
getAllDeliveryStatuses(): Promise<Map<string, string>>;
|
|
26
|
+
init(): Promise<void>;
|
|
27
|
+
clear(): Promise<void>;
|
|
28
|
+
watchIdentity(): Subscribable<Identity | null>;
|
|
29
|
+
watchContacts(): Subscribable<Contact[]>;
|
|
30
|
+
watchAllVerifications(): Subscribable<Verification[]>;
|
|
31
|
+
watchReceivedVerifications(): Subscribable<Verification[]>;
|
|
32
|
+
watchAllAttestations(): Subscribable<Attestation[]>;
|
|
33
|
+
watchReceivedAttestations(): Subscribable<Attestation[]>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=YjsStorageAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"YjsStorageAdapter.d.ts","sourceRoot":"","sources":["../src/YjsStorageAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,OAAO,EACP,YAAY,EACZ,WAAW,EACX,mBAAmB,EACpB,MAAM,oBAAoB,CAAA;AAsD3B,qBAAa,iBAAkB,YAAW,cAAc,EAAE,sBAAsB;IAGlE,OAAO,CAAC,GAAG;IAFvB,OAAO,CAAC,cAAc,CAAwB;gBAE1B,GAAG,EAAE,MAAM;IAIzB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAqBhE,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAiBvC,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvD,OAAO,CAAC,cAAc;IAahB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3C,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAKjC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAMhD,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB3D,wBAAwB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAOnD,mBAAmB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAO9C,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAQzD,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBxD,uBAAuB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAOjD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQvD,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAWlF,sBAAsB,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB/E,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevE,sBAAsB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAatD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,aAAa,IAAI,YAAY,CAAC,QAAQ,GAAG,IAAI,CAAC;IAqC9C,aAAa,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;IAyBxC,qBAAqB,IAAI,YAAY,CAAC,YAAY,EAAE,CAAC;IA6BrD,0BAA0B,IAAI,YAAY,CAAC,YAAY,EAAE,CAAC;IA6B1D,oBAAoB,IAAI,YAAY,CAAC,WAAW,EAAE,CAAC;IA6BnD,yBAAyB,IAAI,YAAY,CAAC,WAAW,EAAE,CAAC;CA4BzD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { initYjsPersonalDoc, getYjsPersonalDoc, changeYjsPersonalDoc, onYjsPersonalDocChange, flushYjsPersonalDoc, refreshYjsPersonalDocFromVault, resetYjsPersonalDoc, deleteYjsPersonalDocDB, } from './YjsPersonalDocManager';
|
|
2
|
+
export type { YjsPersonalDoc } from './YjsPersonalDocManager';
|
|
3
|
+
export { YjsPersonalSyncAdapter } from './YjsPersonalSyncAdapter';
|
|
4
|
+
export { YjsReplicationAdapter } from './YjsReplicationAdapter';
|
|
5
|
+
export type { YjsCompactStore } from './YjsReplicationAdapter';
|
|
6
|
+
export { YjsStorageAdapter } from './YjsStorageAdapter';
|
|
7
|
+
export type { PersonalDoc, ProfileDoc, ContactDoc, VerificationDoc, AttestationDoc, AttestationMetadataDoc, OutboxEntryDoc, SpaceMetadataDoc, GroupKeyDoc, } from './types';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,8BAA8B,EAC9B,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAGvD,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,WAAW,GACZ,MAAM,SAAS,CAAA"}
|