@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/dist/index.js ADDED
@@ -0,0 +1,1816 @@
1
+ var Se = Object.defineProperty;
2
+ var we = (a, e, t) => e in a ? Se(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
3
+ var y = (a, e, t) => we(a, typeof e != "symbol" ? e + "" : e, t);
4
+ import * as d from "yjs";
5
+ import { EncryptedSyncService as D, signEnvelope as O, getMetrics as be, registerDebugApi as De, CompactStorageManager as ve, VaultClient as ae, VaultPushScheduler as q, base64ToUint8 as B, verifyEnvelope as Me } from "@web_of_trust/core";
6
+ class Ae {
7
+ constructor(e, t, s, n, i) {
8
+ y(this, "doc");
9
+ y(this, "messaging");
10
+ y(this, "personalKey");
11
+ y(this, "myDid");
12
+ y(this, "unsubDocUpdate", null);
13
+ y(this, "unsubMessage", null);
14
+ y(this, "unsubStateChange", null);
15
+ y(this, "started", !1);
16
+ /** Track message IDs we sent, so we ignore our own echoes from the relay */
17
+ y(this, "sentMessageIds", /* @__PURE__ */ new Set());
18
+ y(this, "signFn");
19
+ this.doc = e, this.messaging = t, this.personalKey = s, this.myDid = n, this.signFn = i;
20
+ }
21
+ start() {
22
+ if (this.started) return;
23
+ this.started = !0, this.sendFullState(), this.unsubStateChange = this.messaging.onStateChange((t) => {
24
+ t === "connected" && this.started && (this.sendFullState(), this.sendSyncRequest());
25
+ });
26
+ const e = (t, s) => {
27
+ s !== "remote" && this.sendUpdate(t);
28
+ };
29
+ this.doc.on("update", e), this.unsubDocUpdate = () => this.doc.off("update", e), this.unsubMessage = this.messaging.onMessage(async (t) => {
30
+ if (t.type === "personal-sync") {
31
+ if (this.sentMessageIds.has(t.id)) {
32
+ this.sentMessageIds.delete(t.id);
33
+ return;
34
+ }
35
+ try {
36
+ const s = JSON.parse(t.payload);
37
+ if (s.syncRequest) {
38
+ this.sendFullState();
39
+ return;
40
+ }
41
+ const n = {
42
+ ciphertext: new Uint8Array(s.ciphertext),
43
+ nonce: new Uint8Array(s.nonce),
44
+ spaceId: "__personal__",
45
+ generation: 0,
46
+ fromDid: t.fromDid
47
+ }, i = await D.decryptChange(n, this.personalKey);
48
+ d.applyUpdate(this.doc, i, "remote");
49
+ } catch (s) {
50
+ console.debug("[YjsPersonalSync] Failed to process message:", s);
51
+ }
52
+ }
53
+ }), this.sendSyncRequest();
54
+ }
55
+ sendSyncRequest() {
56
+ const e = crypto.randomUUID();
57
+ this.sentMessageIds.add(e), setTimeout(() => this.sentMessageIds.delete(e), 3e4);
58
+ const t = {
59
+ v: 1,
60
+ id: e,
61
+ type: "personal-sync",
62
+ fromDid: this.myDid,
63
+ toDid: this.myDid,
64
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
65
+ encoding: "json",
66
+ payload: JSON.stringify({ syncRequest: !0 }),
67
+ signature: ""
68
+ };
69
+ this.signFn ? O(t, this.signFn).then(
70
+ (s) => this.messaging.send(s)
71
+ ).catch(() => {
72
+ }) : this.messaging.send(t).catch(() => {
73
+ });
74
+ }
75
+ sendFullState() {
76
+ const e = d.encodeStateAsUpdate(this.doc);
77
+ e.length > 1 && this.sendUpdate(e);
78
+ }
79
+ async sendUpdate(e) {
80
+ try {
81
+ const t = await D.encryptChange(
82
+ e,
83
+ this.personalKey,
84
+ "__personal__",
85
+ 0,
86
+ this.myDid
87
+ ), s = {
88
+ ciphertext: Array.from(t.ciphertext),
89
+ nonce: Array.from(t.nonce)
90
+ }, n = crypto.randomUUID();
91
+ this.sentMessageIds.add(n), setTimeout(() => this.sentMessageIds.delete(n), 3e4);
92
+ const i = {
93
+ v: 1,
94
+ id: n,
95
+ type: "personal-sync",
96
+ fromDid: this.myDid,
97
+ toDid: this.myDid,
98
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
99
+ encoding: "json",
100
+ payload: JSON.stringify(s),
101
+ signature: ""
102
+ };
103
+ if (this.signFn) {
104
+ const o = await O(i, this.signFn);
105
+ await this.messaging.send(o);
106
+ } else
107
+ await this.messaging.send(i);
108
+ } catch {
109
+ }
110
+ }
111
+ destroy() {
112
+ this.unsubDocUpdate && (this.unsubDocUpdate(), this.unsubDocUpdate = null), this.unsubMessage && (this.unsubMessage(), this.unsubMessage = null), this.unsubStateChange && (this.unsubStateChange(), this.unsubStateChange = null), this.sentMessageIds.clear(), this.started = !1;
113
+ }
114
+ }
115
+ const ie = "wot-yjs-compact-store", H = "personal-doc", V = "personal-doc";
116
+ let h = null, U = null, A = null, C = null, _ = null, j = null, N = 0, k = null, $ = /* @__PURE__ */ new Set();
117
+ function W() {
118
+ return h.getMap("profile");
119
+ }
120
+ function oe() {
121
+ return h.getMap("contacts");
122
+ }
123
+ function re() {
124
+ return h.getMap("verifications");
125
+ }
126
+ function ce() {
127
+ return h.getMap("attestations");
128
+ }
129
+ function de() {
130
+ return h.getMap("attestationMetadata");
131
+ }
132
+ function le() {
133
+ return h.getMap("outbox");
134
+ }
135
+ function ue() {
136
+ return h.getMap("spaces");
137
+ }
138
+ function pe() {
139
+ return h.getMap("groupKeys");
140
+ }
141
+ function G() {
142
+ if (!h) throw new Error("Yjs personal doc not initialized");
143
+ const a = W();
144
+ return {
145
+ profile: a.size > 0 ? Z(a) : null,
146
+ contacts: F(oe()),
147
+ verifications: F(re()),
148
+ attestations: F(ce()),
149
+ attestationMetadata: F(de()),
150
+ outbox: F(le()),
151
+ spaces: F(ue()),
152
+ groupKeys: F(pe())
153
+ };
154
+ }
155
+ function Z(a) {
156
+ const e = {};
157
+ return a.forEach((t, s) => {
158
+ t instanceof d.Map ? e[s] = Z(t) : t instanceof d.Array ? e[s] = t.toArray() : e[s] = t;
159
+ }), e;
160
+ }
161
+ function F(a) {
162
+ const e = {};
163
+ return a.forEach((t, s) => {
164
+ t instanceof d.Map && (e[s] = Z(t));
165
+ }), e;
166
+ }
167
+ function Ke() {
168
+ return {
169
+ get profile() {
170
+ const a = W();
171
+ return a.size === 0 ? null : ee(a);
172
+ },
173
+ set profile(a) {
174
+ const e = W();
175
+ if (a === null)
176
+ for (const t of Array.from(e.keys()))
177
+ e.delete(t);
178
+ else {
179
+ for (const t of Array.from(e.keys()))
180
+ t in a || e.delete(t);
181
+ L(e, a);
182
+ }
183
+ },
184
+ get contacts() {
185
+ return J(oe());
186
+ },
187
+ set contacts(a) {
188
+ },
189
+ get verifications() {
190
+ return J(re());
191
+ },
192
+ set verifications(a) {
193
+ },
194
+ get attestations() {
195
+ return J(ce());
196
+ },
197
+ set attestations(a) {
198
+ },
199
+ get attestationMetadata() {
200
+ return J(de());
201
+ },
202
+ set attestationMetadata(a) {
203
+ },
204
+ get outbox() {
205
+ return J(le());
206
+ },
207
+ set outbox(a) {
208
+ },
209
+ get spaces() {
210
+ return J(ue());
211
+ },
212
+ set spaces(a) {
213
+ },
214
+ get groupKeys() {
215
+ return J(pe());
216
+ },
217
+ set groupKeys(a) {
218
+ }
219
+ };
220
+ }
221
+ function J(a) {
222
+ return new Proxy({}, {
223
+ get(e, t) {
224
+ if (t === Symbol.iterator || t === "toJSON") return;
225
+ const s = a.get(t);
226
+ return s instanceof d.Map ? ee(s) : s;
227
+ },
228
+ set(e, t, s) {
229
+ if (s && typeof s == "object" && !(s instanceof d.Map)) {
230
+ let n = a.get(t);
231
+ n instanceof d.Map || (n = new d.Map(), a.set(t, n)), L(n, s);
232
+ } else
233
+ a.set(t, s);
234
+ return !0;
235
+ },
236
+ deleteProperty(e, t) {
237
+ return a.delete(t), !0;
238
+ },
239
+ has(e, t) {
240
+ return a.has(t);
241
+ },
242
+ ownKeys() {
243
+ return Array.from(a.keys());
244
+ },
245
+ getOwnPropertyDescriptor(e, t) {
246
+ if (a.has(t))
247
+ return { configurable: !0, enumerable: !0, writable: !0, value: a.get(t) };
248
+ }
249
+ });
250
+ }
251
+ function ee(a) {
252
+ return new Proxy({}, {
253
+ get(e, t) {
254
+ const s = a.get(t);
255
+ return s instanceof d.Map ? ee(s) : s instanceof d.Array ? s.toArray() : s;
256
+ },
257
+ set(e, t, s) {
258
+ if (Array.isArray(s)) {
259
+ const n = new d.Array();
260
+ n.push(s), a.set(t, n);
261
+ } else if (s && typeof s == "object") {
262
+ let n = a.get(t);
263
+ n instanceof d.Map || (n = new d.Map(), a.set(t, n)), L(n, s);
264
+ } else
265
+ a.set(t, s);
266
+ return !0;
267
+ },
268
+ deleteProperty(e, t) {
269
+ return a.delete(t), !0;
270
+ },
271
+ has(e, t) {
272
+ return a.has(t);
273
+ },
274
+ ownKeys() {
275
+ return Array.from(a.keys());
276
+ },
277
+ getOwnPropertyDescriptor(e, t) {
278
+ if (a.has(t))
279
+ return { configurable: !0, enumerable: !0, writable: !0, value: a.get(t) };
280
+ }
281
+ });
282
+ }
283
+ function L(a, e) {
284
+ for (const [t, s] of Object.entries(e))
285
+ if (Array.isArray(s)) {
286
+ const n = new d.Array();
287
+ n.push(s), a.set(t, n);
288
+ } else if (s && typeof s == "object") {
289
+ let n = a.get(t);
290
+ n instanceof d.Map || (n = new d.Map(), a.set(t, n)), L(n, s);
291
+ } else
292
+ a.set(t, s);
293
+ }
294
+ async function Q() {
295
+ if (!(!U || !h))
296
+ try {
297
+ const a = d.encodeStateAsUpdate(h);
298
+ await U.save(H, a);
299
+ } catch (a) {
300
+ console.error("[yjs-personal-doc] CompactStore save failed:", a);
301
+ }
302
+ }
303
+ async function X() {
304
+ if (!(!_ || !j || !h))
305
+ try {
306
+ const a = G();
307
+ if (!(a.profile || Object.keys(a.contacts).length > 0 || Object.keys(a.spaces).length > 0)) {
308
+ console.debug("[yjs-personal-doc] Skip vault push — no meaningful data yet");
309
+ return;
310
+ }
311
+ const t = d.encodeStateAsUpdate(h);
312
+ if (!t || t.length === 0) return;
313
+ const s = await D.encryptChange(
314
+ t,
315
+ j,
316
+ V,
317
+ 0,
318
+ ""
319
+ );
320
+ N++, await _.putSnapshot(V, s.ciphertext, s.nonce, N), console.debug(`[yjs-personal-doc] Vault push: ${t.length}B`);
321
+ } catch (a) {
322
+ console.error("[yjs-personal-doc] Vault push failed:", a);
323
+ }
324
+ }
325
+ async function he() {
326
+ var a;
327
+ if (!_ || !j || !h) return !1;
328
+ try {
329
+ const e = await _.getChanges(V, 0);
330
+ if (!e) return !1;
331
+ if ((a = e.snapshot) != null && a.data) {
332
+ const t = B(e.snapshot.data), s = t[0], n = t.slice(1, 1 + s), i = t.slice(1 + s), o = await D.decryptChange(
333
+ { ciphertext: i, nonce: n, spaceId: V, generation: 0, fromDid: "" },
334
+ j
335
+ );
336
+ d.applyUpdate(h, o), N = e.snapshot.upToSeq, console.debug("[yjs-personal-doc] Restored from vault snapshot");
337
+ }
338
+ for (const t of e.changes) {
339
+ const s = B(t.data), n = s[0], i = s.slice(1, 1 + n), o = s.slice(1 + n), r = await D.decryptChange(
340
+ { ciphertext: o, nonce: i, spaceId: V, generation: 0, fromDid: "" },
341
+ j
342
+ );
343
+ d.applyUpdate(h, r), N = Math.max(N, t.seq);
344
+ }
345
+ return e.snapshot !== null || e.changes.length > 0;
346
+ } catch (e) {
347
+ return console.debug("[yjs-personal-doc] Vault restore failed:", e), !1;
348
+ }
349
+ }
350
+ function E() {
351
+ if (!h) return null;
352
+ const a = d.encodeStateVector(h);
353
+ return Array.from(a).join(",");
354
+ }
355
+ function fe() {
356
+ for (const a of $)
357
+ try {
358
+ a();
359
+ } catch (e) {
360
+ console.error("[yjs-personal-doc] Listener error:", e);
361
+ }
362
+ }
363
+ async function Ie(a, e, t, s) {
364
+ if (h) return G();
365
+ const n = Date.now(), i = be();
366
+ i.setImpl("yjs"), De(i), typeof window < "u" && (window.wotDeleteSpace = async (u) => {
367
+ if (!h) return console.warn("PersonalDoc not loaded");
368
+ const p = h.getMap("spaces"), l = h.getMap("groupKeys"), g = p.size;
369
+ h.transact(() => {
370
+ p.delete(u);
371
+ for (const w of Array.from(l.keys()))
372
+ w.startsWith(u + ":") && (l.delete(w), console.log(`Deleted group key ${w}`));
373
+ }, "local");
374
+ const m = p.size;
375
+ console.log(`Deleted space ${u} (spaces: ${g} → ${m})`), await Q(), await X(), console.log("Persisted to CompactStore + Vault");
376
+ }, window.wotDocSizes = () => {
377
+ var g;
378
+ if (!h) return console.warn("PersonalDoc not loaded");
379
+ const u = ["profile", "contacts", "verifications", "attestations", "attestationMetadata", "spaces", "groupKeys", "outbox"], p = [];
380
+ for (const m of u) {
381
+ const w = h.getMap(m);
382
+ let b = 0;
383
+ const S = [];
384
+ for (const [M, I] of w.entries()) {
385
+ let P = 0;
386
+ try {
387
+ P = ((g = JSON.stringify(I)) == null ? void 0 : g.length) ?? 0;
388
+ } catch {
389
+ P = 100;
390
+ }
391
+ b += P, P > 10240 && S.push({ key: M, sizeKB: (P / 1024).toFixed(1) });
392
+ }
393
+ p.push({ map: m, entries: w.size, jsonSizeKB: (b / 1024).toFixed(1) }), S.length > 0 && console.log(` ${m} large entries:`, S);
394
+ }
395
+ const l = d.encodeStateAsUpdate(h).byteLength;
396
+ return p.push({ map: "TOTAL (binary)", entries: "-", jsonSizeKB: (l / 1024).toFixed(1) }), console.table(p), p;
397
+ }), h = new d.Doc();
398
+ let o = "new";
399
+ s ? (U = s, await U.open()) : (U = new ve(ie), await U.open());
400
+ const r = Date.now(), c = await U.load(H);
401
+ if (c && (d.applyUpdate(h, c), o = "compact-store", i.logLoad("compact-store", Date.now() - r, c.length), console.debug("[yjs-personal-doc] Restored from CompactStore")), t && (j = await a.deriveFrameworkKey("personal-doc-v1"), _ = new ae(t, a), o === "new")) {
402
+ const p = Date.now();
403
+ if (await he()) {
404
+ o = "vault";
405
+ const g = d.encodeStateAsUpdate(h).length;
406
+ i.logLoad("vault", Date.now() - p, g);
407
+ }
408
+ }
409
+ if (h.getMap("outbox").size > 0) {
410
+ const u = h, p = d.encodeStateAsUpdate(u).byteLength, l = ["profile", "contacts", "verifications", "attestations", "attestationMetadata", "spaces", "groupKeys"], g = /* @__PURE__ */ new Map();
411
+ for (const S of l) {
412
+ const M = u.getMap(S);
413
+ M.size > 0 && g.set(S, M.toJSON());
414
+ }
415
+ const m = new d.Doc();
416
+ m.transact(() => {
417
+ for (const [S, M] of g) {
418
+ const I = m.getMap(S);
419
+ if (S === "profile")
420
+ L(I, M);
421
+ else
422
+ for (const [P, me] of Object.entries(M)) {
423
+ const se = new d.Map();
424
+ I.set(P, se), L(se, me);
425
+ }
426
+ }
427
+ }, "local"), u.destroy(), h = m;
428
+ const w = d.encodeStateAsUpdate(h).byteLength;
429
+ console.debug(`[yjs-personal-doc] Migration: rebuilt doc without outbox (${(p / 1024).toFixed(0)}KB → ${(w / 1024).toFixed(0)}KB)`);
430
+ const b = d.encodeStateAsUpdate(h);
431
+ if (await U.save(H, b), _ && j)
432
+ try {
433
+ const S = await D.encryptChange(
434
+ b,
435
+ j,
436
+ V,
437
+ 0,
438
+ ""
439
+ );
440
+ N++, await _.putSnapshot(V, S.ciphertext, S.nonce, N), console.debug(`[yjs-personal-doc] Migration: vault updated (${(w / 1024).toFixed(0)}KB)`);
441
+ } catch (S) {
442
+ console.warn("[yjs-personal-doc] Migration vault push failed:", S);
443
+ }
444
+ }
445
+ if (A = new q({
446
+ pushFn: Q,
447
+ getHeadsFn: E,
448
+ debounceMs: 2e3
449
+ }), o === "compact-store" && A.setLastPushedHeads(E()), _ && (C = new q({
450
+ pushFn: X,
451
+ getHeadsFn: E,
452
+ debounceMs: 5e3
453
+ }), o === "vault" && C.setLastPushedHeads(E()), o === "compact-store" && C.pushDebounced()), h.on("update", (u, p) => {
454
+ if (p !== "local") {
455
+ const l = h.getMap("outbox");
456
+ l.size > 0 && h.transact(() => {
457
+ for (const g of Array.from(l.keys()))
458
+ l.delete(g);
459
+ }, "local"), fe(), A == null || A.pushDebounced();
460
+ }
461
+ }), e && j) {
462
+ const u = a.getDid();
463
+ k = new Ae(h, e, j, u, (p) => a.sign(p)), k.start();
464
+ }
465
+ return o === "new" && i.logLoad("new", 0, 0), console.debug(`[yjs-personal-doc] Initialized in ${Date.now() - n}ms (loaded from: ${o})`), G();
466
+ }
467
+ function v() {
468
+ if (!h) throw new Error("Yjs personal doc not initialized. Call initYjsPersonalDoc() first.");
469
+ return G();
470
+ }
471
+ function x(a, e) {
472
+ if (!h) throw new Error("Yjs personal doc not initialized. Call initYjsPersonalDoc() first.");
473
+ return h.transact(() => {
474
+ const t = Ke();
475
+ a(t);
476
+ }, "local"), fe(), e != null && e.background ? (A == null || A.pushDebounced(), C == null || C.pushDebounced()) : (A == null || A.pushImmediate(), C == null || C.pushImmediate()), G();
477
+ }
478
+ function T(a) {
479
+ return $.add(a), () => {
480
+ $.delete(a);
481
+ };
482
+ }
483
+ async function Ne() {
484
+ await Q(), await X();
485
+ }
486
+ async function Pe() {
487
+ return he();
488
+ }
489
+ async function Ce() {
490
+ k && (k.destroy(), k = null), h == null || h.destroy(), h = null, A && (A.destroy(), A = null), C && (C.destroy(), C = null), U && (U.close(), U = null), _ = null, j = null, N = 0, $.clear();
491
+ }
492
+ async function Fe() {
493
+ await Ce(), await new Promise((a) => {
494
+ const e = indexedDB.deleteDatabase(ie);
495
+ e.onsuccess = () => a(), e.onerror = () => a();
496
+ });
497
+ }
498
+ class Oe {
499
+ constructor(e, t) {
500
+ y(this, "id");
501
+ y(this, "closed", !1);
502
+ y(this, "remoteUpdateCallbacks", /* @__PURE__ */ new Set());
503
+ y(this, "unsubChange", null);
504
+ this.spaceState = e, this.adapter = t, this.id = e.info.id;
505
+ const s = (n, i) => {
506
+ if (i === "remote" && !this.closed)
507
+ for (const o of this.remoteUpdateCallbacks)
508
+ try {
509
+ o();
510
+ } catch (r) {
511
+ console.error("[YjsSpaceHandle] Remote update callback error:", r);
512
+ }
513
+ };
514
+ this.spaceState.doc.on("update", s), this.unsubChange = () => this.spaceState.doc.off("update", s), this.spaceState.handles.add(this);
515
+ }
516
+ info() {
517
+ return this.spaceState.info;
518
+ }
519
+ getDoc() {
520
+ return ge(this.spaceState.doc.getMap("data"));
521
+ }
522
+ getMeta() {
523
+ const e = this.spaceState.doc.getMap("_meta");
524
+ return {
525
+ name: e.get("name"),
526
+ description: e.get("description"),
527
+ image: e.get("image")
528
+ };
529
+ }
530
+ transact(e, t) {
531
+ this.closed || (this.spaceState.doc.transact(() => {
532
+ const s = ye(this.spaceState.doc.getMap("data"));
533
+ e(s);
534
+ }, "local"), t != null && t.stream ? (this.adapter._scheduleCompactDebounced(this.spaceState), this.adapter._scheduleVaultDebounced(this.spaceState)) : (this.adapter._scheduleCompactImmediate(this.spaceState), this.adapter._scheduleVaultImmediate(this.spaceState)));
535
+ }
536
+ onRemoteUpdate(e) {
537
+ return this.remoteUpdateCallbacks.add(e), () => {
538
+ this.remoteUpdateCallbacks.delete(e);
539
+ };
540
+ }
541
+ close() {
542
+ var e;
543
+ this.closed = !0, (e = this.unsubChange) == null || e.call(this), this.remoteUpdateCallbacks.clear(), this.spaceState.handles.delete(this);
544
+ }
545
+ }
546
+ function ge(a) {
547
+ const e = {};
548
+ return a.forEach((t, s) => {
549
+ t instanceof d.Map ? e[s] = ge(t) : t instanceof d.Array ? e[s] = t.toArray() : e[s] = t;
550
+ }), e;
551
+ }
552
+ function ye(a) {
553
+ return new Proxy({}, {
554
+ get(e, t) {
555
+ const s = a.get(t);
556
+ return s instanceof d.Map ? ye(s) : s instanceof d.Array ? Ue(s) : s;
557
+ },
558
+ set(e, t, s) {
559
+ if (Array.isArray(s)) {
560
+ const n = new d.Array();
561
+ n.push(s), a.set(t, n);
562
+ } else if (s && typeof s == "object") {
563
+ let n = a.get(t);
564
+ n instanceof d.Map || (n = new d.Map(), a.set(t, n)), te(n, s);
565
+ } else
566
+ a.set(t, s);
567
+ return !0;
568
+ },
569
+ deleteProperty(e, t) {
570
+ return a.delete(t), !0;
571
+ },
572
+ has(e, t) {
573
+ return a.has(t);
574
+ },
575
+ ownKeys() {
576
+ return Array.from(a.keys());
577
+ },
578
+ getOwnPropertyDescriptor(e, t) {
579
+ if (a.has(t))
580
+ return { configurable: !0, enumerable: !0, writable: !0, value: a.get(t) };
581
+ }
582
+ });
583
+ }
584
+ function Ue(a) {
585
+ return new Proxy([], {
586
+ get(e, t) {
587
+ if (t === "push")
588
+ return (...i) => (a.push(i), a.length);
589
+ if (t === "length") return a.length;
590
+ if (t === Symbol.iterator) return () => a.toArray()[Symbol.iterator]();
591
+ if (typeof t == "string" && !isNaN(Number(t)))
592
+ return a.get(Number(t));
593
+ const s = a.toArray(), n = s[t];
594
+ return typeof n == "function" ? n.bind(s) : n;
595
+ }
596
+ });
597
+ }
598
+ function te(a, e) {
599
+ for (const [t, s] of Object.entries(e))
600
+ if (Array.isArray(s)) {
601
+ const n = new d.Array();
602
+ n.push(s), a.set(t, n);
603
+ } else if (s && typeof s == "object") {
604
+ let n = a.get(t);
605
+ n instanceof d.Map || (n = new d.Map(), a.set(t, n)), te(n, s);
606
+ } else
607
+ a.set(t, s);
608
+ }
609
+ function je(a, e) {
610
+ const t = a.getMap("data");
611
+ te(t, e);
612
+ }
613
+ const K = class K {
614
+ constructor(e) {
615
+ y(this, "identity");
616
+ y(this, "messaging");
617
+ y(this, "groupKeyService");
618
+ y(this, "metadataStorage");
619
+ y(this, "compactStore");
620
+ y(this, "vault");
621
+ y(this, "spaceFilter");
622
+ y(this, "spaces", /* @__PURE__ */ new Map());
623
+ y(this, "spaceListeners", /* @__PURE__ */ new Set());
624
+ y(this, "memberChangeListeners", /* @__PURE__ */ new Set());
625
+ y(this, "vaultSchedulers", /* @__PURE__ */ new Map());
626
+ y(this, "compactSchedulers", /* @__PURE__ */ new Map());
627
+ y(this, "vaultSeqs", /* @__PURE__ */ new Map());
628
+ /** Cache 404 responses from Vault to avoid repeated requests for non-existent docs */
629
+ y(this, "vault404Cache", /* @__PURE__ */ new Map());
630
+ // 5 minutes
631
+ y(this, "unsubMessage", null);
632
+ y(this, "unsubStateChange", null);
633
+ y(this, "started", !1);
634
+ y(this, "sentMessageIds", /* @__PURE__ */ new Set());
635
+ // Buffer for content messages that arrive before the space is known (multi-device timing)
636
+ y(this, "pendingMessages", /* @__PURE__ */ new Map());
637
+ // 60s
638
+ y(this, "flushPersonalDoc");
639
+ y(this, "refreshPersonalDocFromVault");
640
+ this.identity = e.identity, this.messaging = e.messaging, this.groupKeyService = e.groupKeyService, this.metadataStorage = e.metadataStorage, this.compactStore = e.compactStore, this.spaceFilter = e.spaceFilter, this.flushPersonalDoc = e.flushPersonalDoc, this.refreshPersonalDocFromVault = e.refreshPersonalDocFromVault, e.vault ? this.vault = e.vault : e.vaultUrl && (this.vault = new ae(e.vaultUrl, e.identity));
641
+ }
642
+ async start() {
643
+ this.started || (this.started = !0, this.unsubMessage = this.messaging.onMessage(async (e) => {
644
+ if (this.sentMessageIds.has(e.id)) {
645
+ this.sentMessageIds.delete(e.id);
646
+ return;
647
+ }
648
+ if (e.signature && !await Me(e)) {
649
+ console.warn("[YjsReplication] Rejected message with invalid signature from", e.fromDid);
650
+ return;
651
+ }
652
+ switch (e.type) {
653
+ case "content":
654
+ await this.handleContentMessage(e);
655
+ break;
656
+ case "space-invite":
657
+ await this.handleSpaceInvite(e);
658
+ break;
659
+ case "member-update":
660
+ await this.handleMemberUpdate(e);
661
+ break;
662
+ case "group-key-rotation":
663
+ await this.handleGroupKeyRotation(e);
664
+ break;
665
+ case "space-sync-request":
666
+ await this.handleSpaceSyncRequest(e);
667
+ break;
668
+ }
669
+ }), await this.restoreSpacesFromMetadata(), console.debug(`[YjsReplication] after restoreSpacesFromMetadata: ${this.spaces.size} spaces`, Array.from(this.spaces.keys())), await this._sendFullStateAllSpaces(), console.debug(`[YjsReplication] before _pullAllFromVault: ${this.spaces.size} spaces`), await this._pullAllFromVault(), console.debug(`[YjsReplication] after _pullAllFromVault: ${this.spaces.size} spaces`), "onStateChange" in this.messaging && typeof this.messaging.onStateChange == "function" && (this.unsubStateChange = this.messaging.onStateChange((e) => {
670
+ e === "connected" && this.started && (this._sendFullStateAllSpaces().catch(() => {
671
+ }), this._pullAllFromVault().catch(() => {
672
+ }));
673
+ })));
674
+ }
675
+ async stop() {
676
+ var e, t, s;
677
+ (e = this.unsubMessage) == null || e.call(this), this.unsubMessage = null, (t = this.unsubStateChange) == null || t.call(this), this.unsubStateChange = null, this.pendingMessages.clear();
678
+ for (const [, n] of this.vaultSchedulers) n.destroy();
679
+ for (const [, n] of this.compactSchedulers) n.destroy();
680
+ this.vaultSchedulers.clear(), this.compactSchedulers.clear();
681
+ for (const [, n] of this.spaces) {
682
+ (s = n.unsubUpdate) == null || s.call(n);
683
+ for (const i of n.handles) i.close();
684
+ n.doc.destroy();
685
+ }
686
+ this.spaces.clear(), this.started = !1;
687
+ }
688
+ getState() {
689
+ return this.started ? "syncing" : "idle";
690
+ }
691
+ async createSpace(e, t, s) {
692
+ const n = crypto.randomUUID(), i = (/* @__PURE__ */ new Date()).toISOString(), o = this.identity.getDid(), r = {
693
+ id: n,
694
+ type: e,
695
+ name: s == null ? void 0 : s.name,
696
+ description: s == null ? void 0 : s.description,
697
+ modules: s == null ? void 0 : s.modules,
698
+ appTag: s == null ? void 0 : s.appTag,
699
+ members: [o],
700
+ createdAt: i
701
+ }, c = new d.Doc();
702
+ c.transact(() => {
703
+ if (je(c, t), s != null && s.name || s != null && s.description || s != null && s.modules) {
704
+ const l = c.getMap("_meta");
705
+ s.name && l.set("name", s.name), s.description && l.set("description", s.description), s.modules && l.set("modules", s.modules);
706
+ }
707
+ }, "local"), await this.groupKeyService.createKey(n);
708
+ const f = await this.identity.getEncryptionPublicKeyBytes(), u = {
709
+ info: r,
710
+ doc: c,
711
+ handles: /* @__PURE__ */ new Set(),
712
+ memberEncryptionKeys: /* @__PURE__ */ new Map([[this.identity.getDid(), f]]),
713
+ unsubUpdate: null
714
+ };
715
+ if (this.spaces.set(n, u), this.setupSpaceSync(u), await this._saveToCompactStore(u), this.metadataStorage) {
716
+ await this.metadataStorage.saveSpaceMetadata({
717
+ info: r,
718
+ documentId: n,
719
+ documentUrl: `yjs:${n}`,
720
+ memberEncryptionKeys: {}
721
+ });
722
+ const l = this.groupKeyService.getCurrentKey(n), g = this.groupKeyService.getCurrentGeneration(n);
723
+ l && await this.metadataStorage.saveGroupKey({ spaceId: n, generation: g, key: l });
724
+ }
725
+ this.notifySpaceListeners();
726
+ const p = this.groupKeyService.getCurrentKey(n);
727
+ if (p) {
728
+ const l = this.identity.getDid(), g = d.encodeStateAsUpdate(c), m = this.groupKeyService.getCurrentGeneration(n), w = await D.encryptChange(
729
+ g,
730
+ p,
731
+ n,
732
+ m,
733
+ l
734
+ ), b = {
735
+ spaceId: n,
736
+ generation: m,
737
+ ciphertext: Array.from(w.ciphertext),
738
+ nonce: Array.from(w.nonce)
739
+ }, S = {
740
+ v: 1,
741
+ id: crypto.randomUUID(),
742
+ type: "content",
743
+ fromDid: l,
744
+ toDid: l,
745
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
746
+ encoding: "json",
747
+ payload: JSON.stringify(b),
748
+ signature: ""
749
+ }, M = await O(S, (I) => this.identity.sign(I));
750
+ this.sentMessageIds.add(M.id), setTimeout(() => this.sentMessageIds.delete(M.id), 3e4);
751
+ try {
752
+ await this.messaging.send(M);
753
+ } catch {
754
+ }
755
+ }
756
+ return this._scheduleVaultImmediate(u), r;
757
+ }
758
+ async openSpace(e) {
759
+ const t = this.spaces.get(e);
760
+ if (!t) throw new Error(`Space ${e} not found`);
761
+ return this.ensureSchedulers(t), new Oe(t, this);
762
+ }
763
+ async getSpace(e) {
764
+ var t;
765
+ return ((t = this.spaces.get(e)) == null ? void 0 : t.info) ?? null;
766
+ }
767
+ async getSpaces() {
768
+ return Array.from(this.spaces.values()).map((e) => e.info);
769
+ }
770
+ watchSpaces() {
771
+ let e = Array.from(this.spaces.values()).map((t) => t.info);
772
+ return {
773
+ subscribe: (t) => {
774
+ const s = (n) => {
775
+ e = n, t(n);
776
+ };
777
+ return this.spaceListeners.add(s), () => {
778
+ this.spaceListeners.delete(s);
779
+ };
780
+ },
781
+ getValue: () => e
782
+ };
783
+ }
784
+ async addMember(e, t, s) {
785
+ const n = this.spaces.get(e);
786
+ if (!n) throw new Error(`Space ${e} not found`);
787
+ const i = this.identity.getDid();
788
+ n.memberEncryptionKeys.set(t, s), n.info.members.includes(t) || (n.info.members = [...n.info.members, t]);
789
+ const o = this.groupKeyService.getCurrentKey(e);
790
+ if (!o) throw new Error(`No group key for space ${e}`);
791
+ const r = this.groupKeyService.getCurrentGeneration(e), c = await this.identity.encryptForRecipient(o, s), f = d.encodeStateAsUpdate(n.doc), u = await D.encryptChange(f, o, e, r, i), p = {
792
+ spaceId: e,
793
+ spaceInfo: n.info,
794
+ documentUrl: `yjs:${e}`,
795
+ encryptedGroupKey: {
796
+ ciphertext: Array.from(c.ciphertext),
797
+ nonce: Array.from(c.nonce),
798
+ ephemeralPublicKey: Array.from(c.ephemeralPublicKey)
799
+ },
800
+ generation: r,
801
+ encryptedDoc: {
802
+ ciphertext: Array.from(u.ciphertext),
803
+ nonce: Array.from(u.nonce)
804
+ }
805
+ }, l = {
806
+ v: 1,
807
+ id: crypto.randomUUID(),
808
+ type: "space-invite",
809
+ fromDid: i,
810
+ toDid: t,
811
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
812
+ encoding: "json",
813
+ payload: JSON.stringify(p),
814
+ signature: ""
815
+ }, g = await O(l, (m) => this.identity.sign(m));
816
+ this.sentMessageIds.add(g.id), setTimeout(() => this.sentMessageIds.delete(g.id), 3e4), await this.messaging.send(g), await this.sendMemberUpdate(e, t, "added"), await this.saveSpaceMetadata(n);
817
+ for (const m of this.memberChangeListeners)
818
+ m({ spaceId: e, did: t, action: "added" });
819
+ this.notifySpaceListeners();
820
+ }
821
+ async removeMember(e, t) {
822
+ const s = this.spaces.get(e);
823
+ if (!s) return;
824
+ const n = this.identity.getDid();
825
+ s.memberEncryptionKeys.delete(t), s.info.members = s.info.members.filter((p) => p !== t), await this.groupKeyService.rotateKey(e);
826
+ const i = this.groupKeyService.getCurrentKey(e), o = this.groupKeyService.getCurrentGeneration(e);
827
+ this.metadataStorage && await this.metadataStorage.saveGroupKey({
828
+ spaceId: e,
829
+ generation: o,
830
+ key: i
831
+ }), this.flushPersonalDoc && await this.flushPersonalDoc();
832
+ for (const [p, l] of s.memberEncryptionKeys) {
833
+ const g = await this.identity.encryptForRecipient(i, l), m = {
834
+ spaceId: e,
835
+ encryptedGroupKey: {
836
+ ciphertext: Array.from(g.ciphertext),
837
+ nonce: Array.from(g.nonce),
838
+ ephemeralPublicKey: Array.from(g.ephemeralPublicKey)
839
+ },
840
+ generation: o
841
+ }, w = {
842
+ v: 1,
843
+ id: crypto.randomUUID(),
844
+ type: "group-key-rotation",
845
+ fromDid: this.identity.getDid(),
846
+ toDid: p,
847
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
848
+ encoding: "json",
849
+ payload: JSON.stringify(m),
850
+ signature: ""
851
+ }, b = await O(w, (S) => this.identity.sign(S));
852
+ this.sentMessageIds.add(b.id), setTimeout(() => this.sentMessageIds.delete(b.id), 3e4), await this.messaging.send(b);
853
+ }
854
+ const r = o - 1, c = this.groupKeyService.getKeyByGeneration(e, r), f = [...s.info.members, t], u = {
855
+ spaceId: e,
856
+ memberDid: t,
857
+ action: "removed",
858
+ members: s.info.members
859
+ };
860
+ for (const p of f) {
861
+ if (p === n) continue;
862
+ let l;
863
+ if (c) {
864
+ const w = new TextEncoder().encode(JSON.stringify(u)), b = await D.encryptChange(
865
+ w,
866
+ c,
867
+ e,
868
+ r,
869
+ n
870
+ );
871
+ l = JSON.stringify({
872
+ encrypted: !0,
873
+ spaceId: e,
874
+ generation: r,
875
+ ciphertext: Array.from(b.ciphertext),
876
+ nonce: Array.from(b.nonce)
877
+ });
878
+ } else
879
+ l = JSON.stringify(u);
880
+ const g = {
881
+ v: 1,
882
+ id: crypto.randomUUID(),
883
+ type: "member-update",
884
+ fromDid: n,
885
+ toDid: p,
886
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
887
+ encoding: "json",
888
+ payload: l,
889
+ signature: ""
890
+ }, m = await O(g, (w) => this.identity.sign(w));
891
+ try {
892
+ await this.messaging.send(m);
893
+ } catch {
894
+ }
895
+ }
896
+ await this.saveSpaceMetadata(s), this._scheduleVaultImmediate(s);
897
+ for (const p of this.memberChangeListeners)
898
+ p({ spaceId: e, did: t, action: "removed" });
899
+ this.notifySpaceListeners();
900
+ }
901
+ onMemberChange(e) {
902
+ return this.memberChangeListeners.add(e), () => {
903
+ this.memberChangeListeners.delete(e);
904
+ };
905
+ }
906
+ /** Leave a space: clean up local state, metadata, group keys, compact store */
907
+ async leaveSpace(e) {
908
+ var s, n, i;
909
+ const t = this.spaces.get(e);
910
+ t && ((s = t.unsubUpdate) == null || s.call(t), t.doc.destroy(), this.spaces.delete(e)), (n = this.vaultSchedulers.get(e)) == null || n.destroy(), this.vaultSchedulers.delete(e), (i = this.compactSchedulers.get(e)) == null || i.destroy(), this.compactSchedulers.delete(e), this.metadataStorage && (await this.metadataStorage.deleteSpaceMetadata(e), await this.metadataStorage.deleteGroupKeys(e)), this.compactStore && "delete" in this.compactStore && await this.compactStore.delete(e), this.vault && await this.vault.deleteDoc(e).catch(() => {
911
+ }), this.flushPersonalDoc && await this.flushPersonalDoc(), this.notifySpaceListeners();
912
+ }
913
+ async requestSync(e) {
914
+ if (e === "__all__") {
915
+ await this.restoreSpacesFromMetadata();
916
+ for (const [t, s] of this.pendingMessages)
917
+ if (this.spaces.has(t) && s.length > 0) {
918
+ this.pendingMessages.delete(t);
919
+ const n = Date.now();
920
+ for (const { envelope: i, receivedAt: o } of s)
921
+ n - o < K.PENDING_TTL && await this.handleContentMessage(i).catch(() => {
922
+ });
923
+ }
924
+ await this._pullAllFromVault(), await this._sendFullStateAllSpaces();
925
+ } else {
926
+ const t = this.spaces.get(e);
927
+ t && await this._pullFromVault(t).catch(
928
+ (s) => console.warn(`[YjsReplication] Vault pull failed for ${e}:`, s)
929
+ );
930
+ }
931
+ }
932
+ /** Pull from Vault for all spaces with concurrency limit */
933
+ async _pullAllFromVault() {
934
+ const e = Array.from(this.spaces.entries());
935
+ await this._runWithConcurrency(e, async ([t, s]) => {
936
+ await this._pullFromVault(s).catch(
937
+ (n) => console.warn(`[YjsReplication] Vault pull failed for ${t}:`, n)
938
+ );
939
+ }, K.VAULT_PULL_CONCURRENCY);
940
+ }
941
+ /**
942
+ * Pull the latest snapshot from the Vault and merge into the local Y.Doc.
943
+ * This ensures multi-device sync even when devices were not online simultaneously.
944
+ * If decryption fails (missing key after rotation), tries to refresh the PersonalDoc
945
+ * from the Vault to get the new key, then retries.
946
+ */
947
+ async _pullFromVault(e, t = !1) {
948
+ if (!this.vault) return;
949
+ const s = this.vault404Cache.get(e.info.id);
950
+ if (s && Date.now() - s < K.VAULT_404_TTL)
951
+ return;
952
+ const n = this.groupKeyService.getCurrentKey(e.info.id);
953
+ if (!n)
954
+ return !t && this.refreshPersonalDocFromVault && await this.refreshPersonalDocFromVault() ? (await this._reloadGroupKeys(e.info.id), this._pullFromVault(e, !0)) : void 0;
955
+ const i = await this.vault.getDocInfo(e.info.id);
956
+ if (!i) {
957
+ this.vault404Cache.set(e.info.id, Date.now());
958
+ return;
959
+ }
960
+ if (i.snapshotSeq !== null) {
961
+ const l = this.vaultSeqs.get(e.info.id) ?? -1;
962
+ if (i.snapshotSeq === l) return;
963
+ this.vaultSeqs.set(e.info.id, i.snapshotSeq);
964
+ }
965
+ const o = await this.vault.getChanges(e.info.id);
966
+ if (!o.snapshot) return;
967
+ const r = B(o.snapshot.data), c = r[0], f = r.slice(1, 1 + c), u = r.slice(1 + c), p = this.groupKeyService.getCurrentGeneration(e.info.id);
968
+ try {
969
+ const l = await D.decryptChange({
970
+ ciphertext: u,
971
+ nonce: f,
972
+ spaceId: e.info.id,
973
+ generation: p,
974
+ fromDid: this.identity.getDid()
975
+ }, n);
976
+ d.applyUpdate(e.doc, l, "remote"), this.vaultSeqs.set(e.info.id, o.snapshot.upToSeq);
977
+ } catch {
978
+ if (this.vaultSeqs.delete(e.info.id), !t && this.refreshPersonalDocFromVault && await this.refreshPersonalDocFromVault())
979
+ return await this._reloadGroupKeys(e.info.id), this._pullFromVault(e, !0);
980
+ }
981
+ }
982
+ /** Reload group keys from metadata storage into the GroupKeyService */
983
+ async _reloadGroupKeys(e) {
984
+ if (!this.metadataStorage) return;
985
+ const t = await this.metadataStorage.loadGroupKeys(e);
986
+ for (const s of t)
987
+ this.groupKeyService.importKey(s.spaceId, s.key, s.generation);
988
+ }
989
+ /**
990
+ * Send full Y.Doc state of all spaces to own DID (multi-device sync).
991
+ * Other devices of the same identity merge the state via Y.applyUpdate.
992
+ * Analogous to YjsPersonalSyncAdapter.sendFullState().
993
+ */
994
+ async _sendFullStateAllSpaces() {
995
+ const e = this.identity.getDid();
996
+ for (const [t, s] of this.spaces) {
997
+ const n = this.groupKeyService.getCurrentKey(t);
998
+ if (!n) continue;
999
+ const i = d.encodeStateAsUpdate(s.doc);
1000
+ if (i.length <= 2) continue;
1001
+ const o = this.groupKeyService.getCurrentGeneration(t), r = await D.encryptChange(
1002
+ i,
1003
+ n,
1004
+ t,
1005
+ o,
1006
+ e
1007
+ ), c = {
1008
+ spaceId: t,
1009
+ generation: o,
1010
+ ciphertext: Array.from(r.ciphertext),
1011
+ nonce: Array.from(r.nonce)
1012
+ }, f = {
1013
+ v: 1,
1014
+ id: crypto.randomUUID(),
1015
+ type: "content",
1016
+ fromDid: e,
1017
+ toDid: e,
1018
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1019
+ encoding: "json",
1020
+ payload: JSON.stringify(c),
1021
+ signature: ""
1022
+ }, u = await O(f, (p) => this.identity.sign(p));
1023
+ this.sentMessageIds.add(u.id), setTimeout(() => this.sentMessageIds.delete(u.id), 3e4);
1024
+ try {
1025
+ await this.messaging.send(u);
1026
+ } catch {
1027
+ }
1028
+ }
1029
+ }
1030
+ getKeyGeneration(e) {
1031
+ return this.groupKeyService.getCurrentGeneration(e);
1032
+ }
1033
+ async updateSpace(e, t) {
1034
+ const s = this.spaces.get(e);
1035
+ if (!s) throw new Error(`Space ${e} not found`);
1036
+ s.doc.transact(() => {
1037
+ const n = s.doc.getMap("_meta");
1038
+ t.name !== void 0 && n.set("name", t.name), t.description !== void 0 && n.set("description", t.description), t.image !== void 0 && n.set("image", t.image), t.modules !== void 0 && n.set("modules", t.modules);
1039
+ }, "local"), this._scheduleCompactImmediate(s), this._scheduleVaultImmediate(s);
1040
+ }
1041
+ // --- Restore from metadata ---
1042
+ async restoreSpacesFromMetadata() {
1043
+ if (!this.metadataStorage) return;
1044
+ const e = await this.metadataStorage.loadAllSpaceMetadata();
1045
+ console.debug(`[YjsReplication] restoreSpacesFromMetadata: ${e.length} spaces from metadata, ${this.spaces.size} already loaded`);
1046
+ for (const s of e) {
1047
+ if (console.debug(`[YjsReplication] space: ${s.info.id} name=${s.info.name} type=${s.info.type}`), this.spaces.has(s.info.id) || this.spaceFilter && !this.spaceFilter(s.info)) continue;
1048
+ const n = await this.metadataStorage.loadGroupKeys(s.info.id);
1049
+ for (const S of n)
1050
+ this.groupKeyService.importKey(S.spaceId, S.key, S.generation);
1051
+ let i = null;
1052
+ this.compactStore && (i = await this.compactStore.load(s.info.id));
1053
+ const o = !i || i.length <= 2, r = this.groupKeyService.getCurrentKey(s.info.id) !== null, c = s.info.createdAt ? Date.now() - new Date(s.info.createdAt).getTime() : 0;
1054
+ if (!r && o && c > 10 * 6e4) {
1055
+ console.debug(`[YjsReplication] Removing ghost space ${s.info.id} (no key, empty doc, age ${(c / 6e4).toFixed(0)}min)`), await this.metadataStorage.deleteSpaceMetadata(s.info.id), await this.metadataStorage.deleteGroupKeys(s.info.id), this.compactStore && "delete" in this.compactStore && await this.compactStore.delete(s.info.id);
1056
+ continue;
1057
+ }
1058
+ const f = new d.Doc();
1059
+ i && d.applyUpdate(f, i);
1060
+ const u = f.getMap("_meta"), p = u.get("name"), l = u.get("description"), g = u.get("image"), m = u.get("modules");
1061
+ p !== void 0 && (s.info.name = p), l !== void 0 && (s.info.description = l), g !== void 0 && (s.info.image = g), m !== void 0 && (s.info.modules = m);
1062
+ const w = {
1063
+ info: s.info,
1064
+ doc: f,
1065
+ handles: /* @__PURE__ */ new Set(),
1066
+ memberEncryptionKeys: new Map(
1067
+ Object.entries(s.memberEncryptionKeys).map(([S, M]) => [S, new Uint8Array(M)])
1068
+ ),
1069
+ unsubUpdate: null
1070
+ };
1071
+ this.spaces.set(s.info.id, w), this.setupSpaceSync(w);
1072
+ const b = this.pendingMessages.get(s.info.id);
1073
+ if (b) {
1074
+ this.pendingMessages.delete(s.info.id);
1075
+ const S = Date.now();
1076
+ for (const { envelope: M, receivedAt: I } of b)
1077
+ S - I < K.PENDING_TTL && await this.handleContentMessage(M).catch(() => {
1078
+ });
1079
+ }
1080
+ this.sendSpaceSyncRequest(s.info.id).catch(() => {
1081
+ });
1082
+ }
1083
+ const t = Date.now();
1084
+ for (const [s, n] of this.pendingMessages) {
1085
+ const i = n.filter((o) => t - o.receivedAt < K.PENDING_TTL);
1086
+ i.length === 0 ? this.pendingMessages.delete(s) : this.pendingMessages.set(s, i);
1087
+ }
1088
+ this.notifySpaceListeners();
1089
+ }
1090
+ // --- Internal: Encrypted Space Sync ---
1091
+ setupSpaceSync(e) {
1092
+ const t = (i, o) => {
1093
+ o !== "remote" && this.sendEncryptedUpdate(e.info.id, i);
1094
+ };
1095
+ e.doc.on("update", t);
1096
+ const s = e.doc.getMap("_meta"), n = () => {
1097
+ const i = s.get("name"), o = s.get("description"), r = s.get("image");
1098
+ let c = !1;
1099
+ i !== void 0 && i !== e.info.name && (e.info = { ...e.info, name: i }, c = !0), o !== void 0 && o !== e.info.description && (e.info = { ...e.info, description: o }, c = !0), r !== void 0 && r !== e.info.image && (e.info = { ...e.info, image: r }, c = !0);
1100
+ const f = s.get("modules");
1101
+ f !== void 0 && JSON.stringify(f) !== JSON.stringify(e.info.modules) && (e.info = { ...e.info, modules: f }, c = !0), c && (this.saveSpaceMetadata(e), this.notifySpaceListeners());
1102
+ };
1103
+ s.observe(n), e.unsubUpdate = () => {
1104
+ e.doc.off("update", t), s.unobserve(n);
1105
+ };
1106
+ }
1107
+ async sendEncryptedUpdate(e, t) {
1108
+ const s = this.groupKeyService.getCurrentKey(e);
1109
+ if (!s) return;
1110
+ const n = this.groupKeyService.getCurrentGeneration(e), i = this.identity.getDid(), o = await D.encryptChange(t, s, e, n, i), r = {
1111
+ spaceId: e,
1112
+ generation: n,
1113
+ ciphertext: Array.from(o.ciphertext),
1114
+ nonce: Array.from(o.nonce)
1115
+ }, c = this.spaces.get(e);
1116
+ if (c)
1117
+ for (const f of c.info.members) {
1118
+ const u = {
1119
+ v: 1,
1120
+ id: crypto.randomUUID(),
1121
+ type: "content",
1122
+ fromDid: i,
1123
+ toDid: f,
1124
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1125
+ encoding: "json",
1126
+ payload: JSON.stringify(r),
1127
+ signature: ""
1128
+ }, p = await O(u, (l) => this.identity.sign(l));
1129
+ this.sentMessageIds.add(p.id), setTimeout(() => this.sentMessageIds.delete(p.id), 3e4);
1130
+ try {
1131
+ await this.messaging.send(p);
1132
+ } catch {
1133
+ }
1134
+ }
1135
+ }
1136
+ async handleContentMessage(e) {
1137
+ try {
1138
+ const t = JSON.parse(e.payload), s = t.spaceId, n = this.spaces.get(s);
1139
+ if (!n) {
1140
+ const r = this.pendingMessages.get(s) ?? [];
1141
+ r.push({ envelope: e, receivedAt: Date.now() }), this.pendingMessages.set(s, r);
1142
+ return;
1143
+ }
1144
+ const i = this.groupKeyService.getKeyByGeneration(s, t.generation);
1145
+ if (!i) {
1146
+ const r = this.pendingMessages.get(s) ?? [];
1147
+ r.push({ envelope: e, receivedAt: Date.now() }), this.pendingMessages.set(s, r);
1148
+ return;
1149
+ }
1150
+ const o = await D.decryptChange({
1151
+ ciphertext: new Uint8Array(t.ciphertext),
1152
+ nonce: new Uint8Array(t.nonce),
1153
+ spaceId: s,
1154
+ generation: t.generation,
1155
+ fromDid: e.fromDid
1156
+ }, i);
1157
+ d.applyUpdate(n.doc, o, "remote"), this._scheduleCompactDebounced(n);
1158
+ } catch (t) {
1159
+ console.debug("[YjsReplication] Failed to handle content message:", t);
1160
+ }
1161
+ }
1162
+ async handleSpaceInvite(e) {
1163
+ try {
1164
+ const t = JSON.parse(e.payload), s = t.spaceId, n = await this.identity.decryptForMe({
1165
+ ciphertext: new Uint8Array(t.encryptedGroupKey.ciphertext),
1166
+ nonce: new Uint8Array(t.encryptedGroupKey.nonce),
1167
+ ephemeralPublicKey: new Uint8Array(t.encryptedGroupKey.ephemeralPublicKey)
1168
+ });
1169
+ this.groupKeyService.importKey(s, n, t.generation);
1170
+ const i = await D.decryptChange({
1171
+ ciphertext: new Uint8Array(t.encryptedDoc.ciphertext),
1172
+ nonce: new Uint8Array(t.encryptedDoc.nonce),
1173
+ spaceId: s,
1174
+ generation: t.generation,
1175
+ fromDid: e.fromDid
1176
+ }, n), o = this.spaces.get(s);
1177
+ if (o) {
1178
+ d.applyUpdate(o.doc, i, "remote"), this._scheduleCompactDebounced(o);
1179
+ return;
1180
+ }
1181
+ const r = new d.Doc();
1182
+ d.applyUpdate(r, i, "remote");
1183
+ const c = t.spaceInfo || {
1184
+ id: s,
1185
+ type: "shared",
1186
+ members: [e.fromDid, this.identity.getDid()],
1187
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1188
+ };
1189
+ c.members.includes(this.identity.getDid()) || (c.members = [...c.members, this.identity.getDid()]);
1190
+ const f = r.getMap("_meta"), u = f.get("name"), p = f.get("description"), l = f.get("image");
1191
+ u && (c.name = u), p && (c.description = p), l && (c.image = l);
1192
+ const g = {
1193
+ info: c,
1194
+ doc: r,
1195
+ handles: /* @__PURE__ */ new Set(),
1196
+ memberEncryptionKeys: /* @__PURE__ */ new Map(),
1197
+ unsubUpdate: null
1198
+ };
1199
+ this.spaces.set(s, g), this.setupSpaceSync(g), await this._saveToCompactStore(g), await this.saveSpaceMetadata(g), this.metadataStorage && await this.metadataStorage.saveGroupKey({
1200
+ spaceId: s,
1201
+ generation: t.generation,
1202
+ key: n
1203
+ });
1204
+ const m = this.pendingMessages.get(s);
1205
+ if (m) {
1206
+ this.pendingMessages.delete(s);
1207
+ for (const { envelope: w, receivedAt: b } of m)
1208
+ Date.now() - b < K.PENDING_TTL && await this.handleContentMessage(w).catch(() => {
1209
+ });
1210
+ }
1211
+ this.notifySpaceListeners();
1212
+ } catch (t) {
1213
+ console.debug("[YjsReplication] Failed to handle space invite:", t);
1214
+ }
1215
+ }
1216
+ async handleMemberUpdate(e) {
1217
+ var t, s, n;
1218
+ try {
1219
+ let i = JSON.parse(e.payload);
1220
+ if (i.encrypted && i.ciphertext) {
1221
+ const f = this.groupKeyService.getKeyByGeneration(i.spaceId ?? "", i.generation);
1222
+ if (f) {
1223
+ const u = await D.decryptChange({
1224
+ ciphertext: new Uint8Array(i.ciphertext),
1225
+ nonce: new Uint8Array(i.nonce),
1226
+ spaceId: i.spaceId ?? "",
1227
+ generation: i.generation,
1228
+ fromDid: e.fromDid
1229
+ }, f);
1230
+ i = JSON.parse(new TextDecoder().decode(u));
1231
+ } else {
1232
+ console.debug("[YjsReplication] Cannot decrypt member-update: no key for gen", i.generation);
1233
+ return;
1234
+ }
1235
+ }
1236
+ const o = this.spaces.get(i.spaceId);
1237
+ if (!o) return;
1238
+ if (i.action === "removed") {
1239
+ if (e.fromDid !== o.info.members[0]) {
1240
+ console.warn("[YjsReplication] Rejected member removal from non-creator:", e.fromDid);
1241
+ return;
1242
+ }
1243
+ } else if (!o.info.members.includes(e.fromDid)) {
1244
+ console.warn("[YjsReplication] Rejected member-update from non-member:", e.fromDid);
1245
+ return;
1246
+ }
1247
+ const r = this.identity.getDid();
1248
+ if (i.action === "removed" && i.memberDid === r && i.members && !i.members.includes(r)) {
1249
+ for (const f of o.handles) f.close();
1250
+ (t = o.unsubUpdate) == null || t.call(o), o.doc.destroy(), this.spaces.delete(i.spaceId), (s = this.compactSchedulers.get(i.spaceId)) == null || s.destroy(), this.compactSchedulers.delete(i.spaceId), (n = this.vaultSchedulers.get(i.spaceId)) == null || n.destroy(), this.vaultSchedulers.delete(i.spaceId), this.metadataStorage && (await this.metadataStorage.deleteSpaceMetadata(i.spaceId), await this.metadataStorage.deleteGroupKeys(i.spaceId));
1251
+ } else i.action === "added" && !o.info.members.includes(i.memberDid) ? (o.info.members = [...o.info.members, i.memberDid], await this.saveSpaceMetadata(o)) : i.action === "removed" && (o.info.members = o.info.members.filter((f) => f !== i.memberDid), await this.saveSpaceMetadata(o));
1252
+ for (const f of this.memberChangeListeners)
1253
+ f({ spaceId: i.spaceId, did: i.memberDid, action: i.action });
1254
+ this.notifySpaceListeners();
1255
+ } catch (i) {
1256
+ console.debug("[YjsReplication] Failed to handle member update:", i);
1257
+ }
1258
+ }
1259
+ async handleGroupKeyRotation(e) {
1260
+ try {
1261
+ const t = JSON.parse(e.payload), s = await this.identity.decryptForMe({
1262
+ ciphertext: new Uint8Array(t.encryptedGroupKey.ciphertext),
1263
+ nonce: new Uint8Array(t.encryptedGroupKey.nonce),
1264
+ ephemeralPublicKey: new Uint8Array(t.encryptedGroupKey.ephemeralPublicKey)
1265
+ });
1266
+ this.groupKeyService.importKey(t.spaceId, s, t.generation), this.metadataStorage && await this.metadataStorage.saveGroupKey({
1267
+ spaceId: t.spaceId,
1268
+ generation: t.generation,
1269
+ key: s
1270
+ });
1271
+ const n = this.pendingMessages.get(t.spaceId);
1272
+ if (n && n.length > 0) {
1273
+ this.pendingMessages.delete(t.spaceId);
1274
+ for (const { envelope: i, receivedAt: o } of n)
1275
+ Date.now() - o < K.PENDING_TTL && await this.handleContentMessage(i).catch(() => {
1276
+ });
1277
+ }
1278
+ } catch (t) {
1279
+ console.debug("[YjsReplication] Failed to handle group key rotation:", t);
1280
+ }
1281
+ }
1282
+ /**
1283
+ * Handle sync request from another device: respond with full state for the requested space.
1284
+ */
1285
+ async handleSpaceSyncRequest(e) {
1286
+ try {
1287
+ const s = JSON.parse(e.payload).spaceId, n = this.spaces.get(s);
1288
+ if (!n) return;
1289
+ const i = this.groupKeyService.getCurrentKey(s);
1290
+ if (!i) return;
1291
+ const o = d.encodeStateAsUpdate(n.doc), r = this.groupKeyService.getCurrentGeneration(s), c = this.identity.getDid(), f = await D.encryptChange(
1292
+ o,
1293
+ i,
1294
+ s,
1295
+ r,
1296
+ c
1297
+ ), u = {
1298
+ spaceId: s,
1299
+ generation: r,
1300
+ ciphertext: Array.from(f.ciphertext),
1301
+ nonce: Array.from(f.nonce)
1302
+ }, p = {
1303
+ v: 1,
1304
+ id: crypto.randomUUID(),
1305
+ type: "content",
1306
+ fromDid: c,
1307
+ toDid: c,
1308
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1309
+ encoding: "json",
1310
+ payload: JSON.stringify(u),
1311
+ signature: ""
1312
+ }, l = await O(p, (g) => this.identity.sign(g));
1313
+ this.sentMessageIds.add(l.id), setTimeout(() => this.sentMessageIds.delete(l.id), 3e4);
1314
+ try {
1315
+ await this.messaging.send(l);
1316
+ } catch {
1317
+ }
1318
+ } catch (t) {
1319
+ console.debug("[YjsReplication] Failed to handle space-sync-request:", t);
1320
+ }
1321
+ }
1322
+ /**
1323
+ * Send a sync request for a specific space to own DID (multi-device).
1324
+ * Other devices that have this space will respond with their full state.
1325
+ */
1326
+ async sendSpaceSyncRequest(e) {
1327
+ const t = this.identity.getDid(), s = {
1328
+ v: 1,
1329
+ id: crypto.randomUUID(),
1330
+ type: "space-sync-request",
1331
+ fromDid: t,
1332
+ toDid: t,
1333
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1334
+ encoding: "json",
1335
+ payload: JSON.stringify({ spaceId: e }),
1336
+ signature: ""
1337
+ }, n = await O(s, (i) => this.identity.sign(i));
1338
+ this.sentMessageIds.add(n.id), setTimeout(() => this.sentMessageIds.delete(n.id), 3e4);
1339
+ try {
1340
+ await this.messaging.send(n);
1341
+ } catch {
1342
+ }
1343
+ }
1344
+ // --- Persistence ---
1345
+ async _saveToCompactStore(e) {
1346
+ if (!this.compactStore) return;
1347
+ const t = d.encodeStateAsUpdate(e.doc);
1348
+ t.length <= 2 || await this.compactStore.save(e.info.id, t);
1349
+ }
1350
+ async _pushSnapshotToVault(e) {
1351
+ if (!this.vault) return;
1352
+ const t = this.groupKeyService.getCurrentKey(e.info.id);
1353
+ if (!t) return;
1354
+ const s = d.encodeStateAsUpdate(e.doc);
1355
+ if (s.length <= 2) return;
1356
+ const n = this.groupKeyService.getCurrentGeneration(e.info.id), i = await D.encryptChange(
1357
+ s,
1358
+ t,
1359
+ e.info.id,
1360
+ n,
1361
+ this.identity.getDid()
1362
+ ), r = (this.vaultSeqs.get(e.info.id) ?? 0) + 1;
1363
+ await this.vault.putSnapshot(e.info.id, i.ciphertext, i.nonce, r), this.vaultSeqs.set(e.info.id, r), this.vault404Cache.delete(e.info.id);
1364
+ }
1365
+ ensureSchedulers(e) {
1366
+ const t = e.info.id;
1367
+ this.compactSchedulers.has(t) || this.compactSchedulers.set(t, new q({
1368
+ pushFn: () => this._saveToCompactStore(e),
1369
+ getHeadsFn: () => {
1370
+ const s = d.encodeStateVector(e.doc);
1371
+ return Array.from(s).join(",");
1372
+ },
1373
+ debounceMs: 2e3
1374
+ })), this.vault && !this.vaultSchedulers.has(t) && this.vaultSchedulers.set(t, new q({
1375
+ pushFn: () => this._pushSnapshotToVault(e),
1376
+ getHeadsFn: () => {
1377
+ const s = d.encodeStateVector(e.doc);
1378
+ return Array.from(s).join(",");
1379
+ },
1380
+ debounceMs: 5e3
1381
+ }));
1382
+ }
1383
+ // Public for YjsSpaceHandle
1384
+ _scheduleCompactImmediate(e) {
1385
+ var t;
1386
+ this.ensureSchedulers(e), (t = this.compactSchedulers.get(e.info.id)) == null || t.pushImmediate();
1387
+ }
1388
+ _scheduleCompactDebounced(e) {
1389
+ var t;
1390
+ this.ensureSchedulers(e), (t = this.compactSchedulers.get(e.info.id)) == null || t.pushDebounced();
1391
+ }
1392
+ _scheduleVaultImmediate(e) {
1393
+ var t;
1394
+ this.ensureSchedulers(e), (t = this.vaultSchedulers.get(e.info.id)) == null || t.pushImmediate();
1395
+ }
1396
+ _scheduleVaultDebounced(e) {
1397
+ var t;
1398
+ this.ensureSchedulers(e), (t = this.vaultSchedulers.get(e.info.id)) == null || t.pushDebounced();
1399
+ }
1400
+ // --- Helpers ---
1401
+ /** Run async tasks with a concurrency limit */
1402
+ async _runWithConcurrency(e, t, s) {
1403
+ let n = 0;
1404
+ const i = async () => {
1405
+ for (; n < e.length; ) {
1406
+ const o = e[n++];
1407
+ await t(o);
1408
+ }
1409
+ };
1410
+ await Promise.all(Array.from({ length: Math.min(s, e.length) }, () => i()));
1411
+ }
1412
+ async sendMemberUpdate(e, t, s) {
1413
+ const n = this.spaces.get(e);
1414
+ if (!n) return;
1415
+ const i = this.identity.getDid(), o = this.groupKeyService.getCurrentKey(e), r = this.groupKeyService.getCurrentGeneration(e), c = { spaceId: e, memberDid: t, action: s };
1416
+ for (const f of n.info.members) {
1417
+ if (f === i || f === t) continue;
1418
+ let u;
1419
+ if (o) {
1420
+ const g = new TextEncoder().encode(JSON.stringify(c)), m = await D.encryptChange(
1421
+ g,
1422
+ o,
1423
+ e,
1424
+ r,
1425
+ i
1426
+ );
1427
+ u = JSON.stringify({
1428
+ encrypted: !0,
1429
+ spaceId: e,
1430
+ generation: r,
1431
+ ciphertext: Array.from(m.ciphertext),
1432
+ nonce: Array.from(m.nonce)
1433
+ });
1434
+ } else
1435
+ u = JSON.stringify(c);
1436
+ const p = {
1437
+ v: 1,
1438
+ id: crypto.randomUUID(),
1439
+ type: "member-update",
1440
+ fromDid: i,
1441
+ toDid: f,
1442
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1443
+ encoding: "json",
1444
+ payload: u,
1445
+ signature: ""
1446
+ }, l = await O(p, (g) => this.identity.sign(g));
1447
+ try {
1448
+ await this.messaging.send(l);
1449
+ } catch {
1450
+ }
1451
+ }
1452
+ }
1453
+ async saveSpaceMetadata(e) {
1454
+ this.metadataStorage && await this.metadataStorage.saveSpaceMetadata({
1455
+ info: e.info,
1456
+ documentId: e.info.id,
1457
+ documentUrl: `yjs:${e.info.id}`,
1458
+ memberEncryptionKeys: Object.fromEntries(
1459
+ Array.from(e.memberEncryptionKeys.entries()).map(([t, s]) => [t, s])
1460
+ )
1461
+ });
1462
+ }
1463
+ notifySpaceListeners() {
1464
+ const e = Array.from(this.spaces.values()).map((t) => t.info);
1465
+ for (const t of this.spaceListeners)
1466
+ try {
1467
+ t(e);
1468
+ } catch (s) {
1469
+ console.error("[YjsReplication] Space listener error:", s);
1470
+ }
1471
+ }
1472
+ };
1473
+ // spaceId → timestamp
1474
+ y(K, "VAULT_404_TTL", 5 * 6e4), y(K, "PENDING_TTL", 6e4), y(K, "VAULT_PULL_CONCURRENCY", 3);
1475
+ let ne = K;
1476
+ function z(a) {
1477
+ return {
1478
+ did: a.did,
1479
+ publicKey: a.publicKey,
1480
+ ...a.name != null ? { name: a.name } : {},
1481
+ ...a.avatar != null ? { avatar: a.avatar } : {},
1482
+ ...a.bio != null ? { bio: a.bio } : {},
1483
+ status: a.status,
1484
+ ...a.verifiedAt != null ? { verifiedAt: a.verifiedAt } : {},
1485
+ createdAt: a.createdAt,
1486
+ updatedAt: a.updatedAt
1487
+ };
1488
+ }
1489
+ function R(a) {
1490
+ return {
1491
+ id: a.id,
1492
+ from: a.fromDid,
1493
+ to: a.toDid,
1494
+ timestamp: a.timestamp,
1495
+ proof: JSON.parse(a.proofJson),
1496
+ ...a.locationJson != null ? { location: JSON.parse(a.locationJson) } : {}
1497
+ };
1498
+ }
1499
+ function Y(a) {
1500
+ return {
1501
+ id: a.attestationId ?? a.id,
1502
+ from: a.fromDid,
1503
+ to: a.toDid,
1504
+ claim: a.claim,
1505
+ ...a.tagsJson != null ? { tags: JSON.parse(a.tagsJson) } : {},
1506
+ ...a.context != null ? { context: a.context } : {},
1507
+ createdAt: a.createdAt,
1508
+ proof: JSON.parse(a.proofJson)
1509
+ };
1510
+ }
1511
+ class Je {
1512
+ constructor(e) {
1513
+ y(this, "cachedIdentity", null);
1514
+ this.did = e;
1515
+ }
1516
+ // --- Identity ---
1517
+ async createIdentity(e, t) {
1518
+ const s = (/* @__PURE__ */ new Date()).toISOString(), n = { did: e, profile: t, createdAt: s, updatedAt: s };
1519
+ return x((i) => {
1520
+ var o, r;
1521
+ i.profile = {
1522
+ did: e,
1523
+ name: t.name || null,
1524
+ bio: t.bio || null,
1525
+ avatar: t.avatar || null,
1526
+ offersJson: (o = t.offers) != null && o.length ? JSON.stringify(t.offers) : null,
1527
+ needsJson: (r = t.needs) != null && r.length ? JSON.stringify(t.needs) : null,
1528
+ createdAt: s,
1529
+ updatedAt: s
1530
+ };
1531
+ }), this.cachedIdentity = n, n;
1532
+ }
1533
+ async getIdentity() {
1534
+ if (this.cachedIdentity) return this.cachedIdentity;
1535
+ const e = v();
1536
+ if (!e.profile) return null;
1537
+ const t = this.profileFromDoc(e), s = {
1538
+ did: this.did,
1539
+ profile: t,
1540
+ createdAt: e.profile.createdAt ?? "",
1541
+ updatedAt: e.profile.updatedAt ?? ""
1542
+ };
1543
+ return this.cachedIdentity = s, s;
1544
+ }
1545
+ async updateIdentity(e) {
1546
+ e.updatedAt = (/* @__PURE__ */ new Date()).toISOString(), x((t) => {
1547
+ var s, n, i;
1548
+ t.profile = {
1549
+ did: e.did,
1550
+ name: e.profile.name || null,
1551
+ bio: e.profile.bio || null,
1552
+ avatar: e.profile.avatar || null,
1553
+ offersJson: (s = e.profile.offers) != null && s.length ? JSON.stringify(e.profile.offers) : null,
1554
+ needsJson: (n = e.profile.needs) != null && n.length ? JSON.stringify(e.profile.needs) : null,
1555
+ createdAt: ((i = t.profile) == null ? void 0 : i.createdAt) ?? e.createdAt,
1556
+ updatedAt: e.updatedAt
1557
+ };
1558
+ }), this.cachedIdentity = e;
1559
+ }
1560
+ profileFromDoc(e) {
1561
+ return e.profile ? {
1562
+ name: e.profile.name ?? "",
1563
+ ...e.profile.bio != null ? { bio: e.profile.bio } : {},
1564
+ ...e.profile.avatar != null ? { avatar: e.profile.avatar } : {},
1565
+ ...e.profile.offersJson != null ? { offers: JSON.parse(e.profile.offersJson) } : {},
1566
+ ...e.profile.needsJson != null ? { needs: JSON.parse(e.profile.needsJson) } : {}
1567
+ } : { name: "" };
1568
+ }
1569
+ // --- Contacts ---
1570
+ async addContact(e) {
1571
+ x((t) => {
1572
+ t.contacts[e.did] = {
1573
+ did: e.did,
1574
+ publicKey: e.publicKey,
1575
+ name: e.name || null,
1576
+ avatar: e.avatar || null,
1577
+ bio: e.bio || null,
1578
+ status: e.status,
1579
+ verifiedAt: e.verifiedAt || null,
1580
+ createdAt: e.createdAt,
1581
+ updatedAt: e.updatedAt
1582
+ };
1583
+ });
1584
+ }
1585
+ async getContacts() {
1586
+ const e = v();
1587
+ return Object.values(e.contacts).map(z);
1588
+ }
1589
+ async getContact(e) {
1590
+ const s = v().contacts[e];
1591
+ return s ? z(s) : null;
1592
+ }
1593
+ async updateContact(e) {
1594
+ x((t) => {
1595
+ var s;
1596
+ t.contacts[e.did] = {
1597
+ did: e.did,
1598
+ publicKey: e.publicKey,
1599
+ name: e.name || null,
1600
+ avatar: e.avatar || null,
1601
+ bio: e.bio || null,
1602
+ status: e.status,
1603
+ verifiedAt: e.verifiedAt || null,
1604
+ createdAt: ((s = t.contacts[e.did]) == null ? void 0 : s.createdAt) ?? e.createdAt,
1605
+ updatedAt: e.updatedAt
1606
+ };
1607
+ }, { background: !0 });
1608
+ }
1609
+ async removeContact(e) {
1610
+ x((t) => {
1611
+ delete t.contacts[e];
1612
+ });
1613
+ }
1614
+ // --- Verifications ---
1615
+ async saveVerification(e) {
1616
+ x((t) => {
1617
+ for (const [s, n] of Object.entries(t.verifications))
1618
+ n.fromDid === e.from && n.toDid === e.to && s !== e.id && delete t.verifications[s];
1619
+ t.verifications[e.id] = {
1620
+ id: e.id,
1621
+ fromDid: e.from,
1622
+ toDid: e.to,
1623
+ timestamp: e.timestamp,
1624
+ proofJson: JSON.stringify(e.proof),
1625
+ locationJson: e.location ? JSON.stringify(e.location) : null
1626
+ };
1627
+ });
1628
+ }
1629
+ async getReceivedVerifications() {
1630
+ const e = v();
1631
+ return Object.values(e.verifications).filter((t) => t.toDid === this.did).map(R);
1632
+ }
1633
+ async getAllVerifications() {
1634
+ const e = v();
1635
+ return Object.values(e.verifications).filter((t) => t.fromDid === this.did || t.toDid === this.did).map(R);
1636
+ }
1637
+ async getVerification(e) {
1638
+ const s = v().verifications[e];
1639
+ return s ? R(s) : null;
1640
+ }
1641
+ // --- Attestations ---
1642
+ async saveAttestation(e) {
1643
+ x((t) => {
1644
+ t.attestations[e.id] = {
1645
+ id: e.id,
1646
+ attestationId: e.id,
1647
+ fromDid: e.from,
1648
+ toDid: e.to,
1649
+ claim: e.claim,
1650
+ tagsJson: e.tags ? JSON.stringify(e.tags) : null,
1651
+ context: e.context || null,
1652
+ createdAt: e.createdAt,
1653
+ proofJson: JSON.stringify(e.proof)
1654
+ }, t.attestationMetadata[e.id] || (t.attestationMetadata[e.id] = {
1655
+ attestationId: e.id,
1656
+ accepted: !1,
1657
+ acceptedAt: null,
1658
+ deliveryStatus: null
1659
+ });
1660
+ });
1661
+ }
1662
+ async getReceivedAttestations() {
1663
+ const e = v();
1664
+ return Object.values(e.attestations).filter((t) => t.toDid === this.did).map(Y);
1665
+ }
1666
+ async getAttestation(e) {
1667
+ const s = v().attestations[e];
1668
+ return s ? Y(s) : null;
1669
+ }
1670
+ // --- Attestation Metadata ---
1671
+ async getAttestationMetadata(e) {
1672
+ const s = v().attestationMetadata[e];
1673
+ return s ? {
1674
+ attestationId: s.attestationId,
1675
+ accepted: s.accepted,
1676
+ ...s.acceptedAt != null ? { acceptedAt: s.acceptedAt } : {}
1677
+ } : null;
1678
+ }
1679
+ async setAttestationAccepted(e, t) {
1680
+ x((s) => {
1681
+ s.attestationMetadata[e] ? (s.attestationMetadata[e].accepted = t, s.attestationMetadata[e].acceptedAt = t ? (/* @__PURE__ */ new Date()).toISOString() : null) : s.attestationMetadata[e] = {
1682
+ attestationId: e,
1683
+ accepted: t,
1684
+ acceptedAt: t ? (/* @__PURE__ */ new Date()).toISOString() : null,
1685
+ deliveryStatus: null
1686
+ };
1687
+ });
1688
+ }
1689
+ async setDeliveryStatus(e, t) {
1690
+ x((s) => {
1691
+ s.attestationMetadata[e] ? s.attestationMetadata[e].deliveryStatus = t : s.attestationMetadata[e] = {
1692
+ attestationId: e,
1693
+ accepted: !1,
1694
+ acceptedAt: null,
1695
+ deliveryStatus: t
1696
+ };
1697
+ }, { background: !0 });
1698
+ }
1699
+ async getAllDeliveryStatuses() {
1700
+ const e = v(), t = /* @__PURE__ */ new Map();
1701
+ for (const s of Object.values(e.attestationMetadata))
1702
+ s.deliveryStatus && t.set(s.attestationId, s.deliveryStatus);
1703
+ return t;
1704
+ }
1705
+ // --- Lifecycle ---
1706
+ async init() {
1707
+ }
1708
+ async clear() {
1709
+ this.cachedIdentity = null;
1710
+ }
1711
+ // --- Reactive (ReactiveStorageAdapter) ---
1712
+ watchIdentity() {
1713
+ const e = this.did, t = this, s = () => {
1714
+ const o = v();
1715
+ if (!o.profile) return null;
1716
+ const r = t.profileFromDoc(o), c = t.cachedIdentity;
1717
+ return {
1718
+ did: e,
1719
+ profile: r,
1720
+ createdAt: (c == null ? void 0 : c.createdAt) ?? o.profile.createdAt ?? "",
1721
+ updatedAt: (c == null ? void 0 : c.updatedAt) ?? o.profile.updatedAt ?? ""
1722
+ };
1723
+ };
1724
+ let n = s(), i = JSON.stringify(n == null ? void 0 : n.profile);
1725
+ return {
1726
+ subscribe: (o) => T(() => {
1727
+ const r = s(), c = JSON.stringify(r == null ? void 0 : r.profile);
1728
+ c !== i && (n = r, i = c, n && (t.cachedIdentity = n), o(n));
1729
+ }),
1730
+ getValue: () => n
1731
+ };
1732
+ }
1733
+ watchContacts() {
1734
+ const e = () => {
1735
+ const n = v();
1736
+ return Object.values(n.contacts).map(z);
1737
+ };
1738
+ let t = e(), s = JSON.stringify(t);
1739
+ return {
1740
+ subscribe: (n) => T(() => {
1741
+ const i = e(), o = JSON.stringify(i);
1742
+ o !== s && (t = i, s = o, n(t));
1743
+ }),
1744
+ getValue: () => t
1745
+ };
1746
+ }
1747
+ watchAllVerifications() {
1748
+ const e = this.did, t = () => {
1749
+ const i = v();
1750
+ return Object.values(i.verifications).filter((o) => o.fromDid === e || o.toDid === e).map(R);
1751
+ };
1752
+ let s = t(), n = JSON.stringify(s);
1753
+ return {
1754
+ subscribe: (i) => T(() => {
1755
+ const o = t(), r = JSON.stringify(o);
1756
+ r !== n && (s = o, n = r, i(s));
1757
+ }),
1758
+ getValue: () => s
1759
+ };
1760
+ }
1761
+ watchReceivedVerifications() {
1762
+ const e = this.did, t = () => {
1763
+ const i = v();
1764
+ return Object.values(i.verifications).filter((o) => o.toDid === e).map(R);
1765
+ };
1766
+ let s = t(), n = JSON.stringify(s);
1767
+ return {
1768
+ subscribe: (i) => T(() => {
1769
+ const o = t(), r = JSON.stringify(o);
1770
+ r !== n && (s = o, n = r, i(s));
1771
+ }),
1772
+ getValue: () => s
1773
+ };
1774
+ }
1775
+ watchAllAttestations() {
1776
+ const e = this.did, t = () => {
1777
+ const i = v();
1778
+ return Object.values(i.attestations).filter((o) => o.fromDid === e || o.toDid === e).map(Y);
1779
+ };
1780
+ let s = t(), n = JSON.stringify(s);
1781
+ return {
1782
+ subscribe: (i) => T(() => {
1783
+ const o = t(), r = JSON.stringify(o);
1784
+ r !== n && (s = o, n = r, i(s));
1785
+ }),
1786
+ getValue: () => s
1787
+ };
1788
+ }
1789
+ watchReceivedAttestations() {
1790
+ const e = this.did, t = () => {
1791
+ const i = v();
1792
+ return Object.values(i.attestations).filter((o) => o.toDid === e).map(Y);
1793
+ };
1794
+ let s = t(), n = JSON.stringify(s);
1795
+ return {
1796
+ subscribe: (i) => T(() => {
1797
+ const o = t(), r = JSON.stringify(o);
1798
+ r !== n && (s = o, n = r, i(s));
1799
+ }),
1800
+ getValue: () => s
1801
+ };
1802
+ }
1803
+ }
1804
+ export {
1805
+ Ae as YjsPersonalSyncAdapter,
1806
+ ne as YjsReplicationAdapter,
1807
+ Je as YjsStorageAdapter,
1808
+ x as changeYjsPersonalDoc,
1809
+ Fe as deleteYjsPersonalDocDB,
1810
+ Ne as flushYjsPersonalDoc,
1811
+ v as getYjsPersonalDoc,
1812
+ Ie as initYjsPersonalDoc,
1813
+ T as onYjsPersonalDocChange,
1814
+ Pe as refreshYjsPersonalDocFromVault,
1815
+ Ce as resetYjsPersonalDoc
1816
+ };