@voltro/local-first 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -1,102 +1,210 @@
1
- import { c as e, i as t, n, o as r, r as i, s as a, t as o } from "./room-CzWRYppA.js";
2
- import { useCallback as s, useEffect as c, useMemo as l, useReducer as u, useRef as d, useState as f } from "react";
1
+ import { a as e, c as t, f as n, i as r, l as i, n as a, r as o, s, t as c } from "./room-wFNUwEgi.js";
2
+ import { useCallback as l, useEffect as u, useMemo as d, useReducer as f, useRef as p, useState as m } from "react";
3
3
  //#region src/react/useSyncQueue.ts
4
- var p = (t = !0) => {
5
- let [n, i] = u(e, t, r), o = s((e) => {
6
- i({
4
+ var h = (e = !0) => {
5
+ let [n, r] = f(i, e, s), a = l((e) => {
6
+ r({
7
7
  type: "enqueue",
8
8
  write: e
9
9
  });
10
- }, []), c = s((e) => {
11
- i(e ? { type: "online" } : { type: "offline" });
12
- }, []), d = s(() => i({ type: "drain-start" }), []), f = s((e) => i({
10
+ }, []), o = l((e) => {
11
+ r(e ? { type: "online" } : { type: "offline" });
12
+ }, []), c = l(() => r({ type: "drain-start" }), []), u = l((e) => r({
13
13
  type: "ack",
14
14
  id: e
15
- }), []), p = s((e, t) => {
16
- i({
15
+ }), []), p = l((e, t) => {
16
+ r({
17
17
  type: "fail",
18
18
  id: e,
19
19
  error: t
20
20
  });
21
- }, []), m = a(n);
22
- return l(() => ({
21
+ }, []), m = t(n);
22
+ return d(() => ({
23
23
  state: n,
24
24
  outstanding: m,
25
- enqueue: o,
26
- setOnline: c,
27
- drainNext: d,
28
- ack: f,
25
+ enqueue: a,
26
+ setOnline: o,
27
+ drainNext: c,
28
+ ack: u,
29
29
  fail: p
30
30
  }), [
31
31
  n,
32
32
  m,
33
+ a,
33
34
  o,
34
35
  c,
35
- d,
36
- f,
36
+ u,
37
37
  p
38
38
  ]);
39
- }, m = () => typeof navigator > "u" || navigator.onLine ? "online" : "offline", h = (e = 0) => {
40
- let [r, a] = u(n, void 0, () => t(m()));
41
- c(() => {
39
+ }, g = () => typeof navigator > "u" || navigator.onLine ? "online" : "offline", _ = (t = 0) => {
40
+ let [n, i] = f(o, void 0, () => e(g()));
41
+ u(() => {
42
42
  if (typeof window > "u") return;
43
- let e = () => a({ type: "network-up" }), t = () => a({ type: "network-down" });
43
+ let e = () => i({ type: "network-up" }), t = () => i({ type: "network-down" });
44
44
  return window.addEventListener("online", e), window.addEventListener("offline", t), () => {
45
45
  window.removeEventListener("online", e), window.removeEventListener("offline", t);
46
46
  };
47
47
  }, []);
48
- let o = s(() => a({ type: "confirmed" }), []), d = s(() => a({ type: "confirm-failed" }), []), f = i(r.phase, e);
49
- return l(() => ({
50
- state: r,
51
- phase: r.phase,
52
- status: f,
53
- confirm: o,
54
- confirmFailed: d
48
+ let a = l(() => i({ type: "confirmed" }), []), s = l(() => i({ type: "confirm-failed" }), []), c = r(n.phase, t);
49
+ return d(() => ({
50
+ state: n,
51
+ phase: n.phase,
52
+ status: c,
53
+ confirm: a,
54
+ confirmFailed: s
55
55
  }), [
56
- r,
57
- f,
58
- o,
59
- d
56
+ n,
57
+ c,
58
+ a,
59
+ s
60
60
  ]);
61
- }, g = 0, _ = () => {
61
+ }, v = 0, y = () => {
62
62
  let e = typeof crypto < "u" ? crypto : void 0;
63
- return e && typeof e.randomUUID == "function" ? e.randomUUID() : `peer_${Date.now().toString(36)}_${g += 1}`;
64
- }, v = (e, t, n) => {
65
- let { channel: r } = n, i = n.ttlMs ?? 3e4, a = n.heartbeatMs ?? 5e3, u = l(() => n.peerId ?? _(), [n.peerId]), p = d(null), [m, h] = f(0), g = d(t);
66
- g.current = t, c(() => {
67
- let t = o({
63
+ return e && typeof e.randomUUID == "function" ? e.randomUUID() : `peer_${Date.now().toString(36)}_${v += 1}`;
64
+ }, b = (e, t, n) => {
65
+ let { channel: r } = n, i = n.ttlMs ?? 3e4, a = n.heartbeatMs ?? 5e3, o = d(() => n.peerId ?? y(), [n.peerId]), s = p(null), [f, h] = m(0), g = p(t);
66
+ g.current = t, u(() => {
67
+ let t = c({
68
68
  channel: r,
69
69
  roomId: e,
70
- peerId: u,
70
+ peerId: o,
71
71
  initial: g.current,
72
72
  ttlMs: i
73
73
  });
74
- p.current = t;
75
- let n = t.onChange(() => h((e) => e + 1)), s = setInterval(() => {
74
+ s.current = t;
75
+ let n = t.onChange(() => h((e) => e + 1)), l = setInterval(() => {
76
76
  t.heartbeat(), t.sweep();
77
77
  }, a);
78
78
  return h((e) => e + 1), () => {
79
- clearInterval(s), n(), t.leave(), p.current = null;
79
+ clearInterval(l), n(), t.leave(), s.current = null;
80
80
  };
81
81
  }, [
82
82
  r,
83
83
  e,
84
- u,
84
+ o,
85
85
  i,
86
86
  a
87
87
  ]);
88
- let v = s((e) => {
89
- p.current?.update(e);
90
- }, []), y = p.current;
91
- return l(() => ({
92
- presence: y?.self() ?? g.current,
93
- others: y?.others() ?? [],
94
- setPresence: v
88
+ let _ = l((e) => {
89
+ s.current?.update(e);
90
+ }, []), v = s.current;
91
+ return d(() => ({
92
+ presence: v?.self() ?? g.current,
93
+ others: v?.others() ?? [],
94
+ setPresence: _
95
95
  }), [
96
- y,
97
96
  v,
98
- m
97
+ _,
98
+ f
99
+ ]);
100
+ }, x = (e, t) => {
101
+ if (e === t) return null;
102
+ let n = Math.min(e.length, t.length), r = 0;
103
+ for (; r < n && e[r] === t[r];) r += 1;
104
+ let i = 0;
105
+ for (; i < n - r && e[e.length - 1 - i] === t[t.length - 1 - i];) i += 1;
106
+ return {
107
+ index: r,
108
+ deleteLength: e.length - r - i,
109
+ insert: t.slice(r, t.length - i)
110
+ };
111
+ }, S = (e) => `${e.table}\u0000${e.id}\u0000${e.column}`, C = {
112
+ text: "",
113
+ state: void 0,
114
+ outstanding: 0
115
+ }, w = (e) => {
116
+ let { cell: t, remote: r, adapter: i, online: o, maxAttempts: s } = e, c = e.backend ?? n, f = S(t), h = p(e.push);
117
+ h.current = e.push;
118
+ let g = p(t);
119
+ g.current = t;
120
+ let _ = p(null), v = p(null), y = p(null), [b, w] = m(C);
121
+ u(() => {
122
+ let t = g.current, n = a({
123
+ transport: {
124
+ kind: "sync-transport",
125
+ push: async (e) => {
126
+ await h.current({
127
+ table: e.payload.table,
128
+ id: e.payload.id,
129
+ column: e.payload.column,
130
+ update: e.payload.update,
131
+ attempts: e.attempts
132
+ });
133
+ },
134
+ onRemoteState: (e) => (v.current = (n) => {
135
+ e({
136
+ ...t,
137
+ state: n
138
+ });
139
+ }, () => {
140
+ v.current = null;
141
+ })
142
+ },
143
+ ...i === void 0 ? {} : { adapter: i },
144
+ ...e.backend === void 0 ? {} : { backend: e.backend },
145
+ ...o === void 0 ? {} : { online: o },
146
+ ...s === void 0 ? {} : { maxAttempts: s }
147
+ });
148
+ _.current = n, y.current = c.createText();
149
+ let r = () => {
150
+ let e = n.getText(t), r = n.outstanding();
151
+ w((i) => i.text === e && i.outstanding === r ? i : {
152
+ text: e,
153
+ state: n.getState(t),
154
+ outstanding: r
155
+ });
156
+ }, l = n.subscribe(r);
157
+ return r(), () => {
158
+ l(), n.close(), _.current = null, y.current = null, v.current = null, w(C);
159
+ };
160
+ }, [
161
+ f,
162
+ i,
163
+ c,
164
+ e.backend,
165
+ o,
166
+ s
167
+ ]), u(() => {
168
+ r != null && v.current?.(r);
169
+ }, [f, r]);
170
+ let T = l((e) => {
171
+ let t = _.current, n = y.current;
172
+ if (t === null || n === null) return;
173
+ let r = t.getState(g.current);
174
+ r !== void 0 && n.applyState(r), e(n), t.enqueue({
175
+ ...g.current,
176
+ update: n.encodeState()
177
+ });
178
+ }, []), E = l((e, t) => {
179
+ t !== "" && T((n) => n.insert(e, t));
180
+ }, [T]), D = l((e, t) => {
181
+ t <= 0 || T((n) => n.delete(e, t));
182
+ }, [T]), O = l((e) => {
183
+ let t = _.current;
184
+ if (t === null) return;
185
+ let n = x(t.getText(g.current), e);
186
+ n !== null && T((e) => {
187
+ n.deleteLength > 0 && e.delete(n.index, n.deleteLength), n.insert !== "" && e.insert(n.index, n.insert);
188
+ });
189
+ }, [T]), k = l((e) => {
190
+ _.current?.setOnline(e);
191
+ }, []);
192
+ return d(() => ({
193
+ text: b.text,
194
+ state: b.state,
195
+ outstanding: b.outstanding,
196
+ synced: b.outstanding === 0,
197
+ insert: E,
198
+ delete: D,
199
+ setText: O,
200
+ setOnline: k
201
+ }), [
202
+ b,
203
+ E,
204
+ D,
205
+ O,
206
+ k
99
207
  ]);
100
208
  };
101
209
  //#endregion
102
- export { h as useConnectionStatus, v as usePresence, p as useSyncQueue };
210
+ export { x as crdtTextEdit, _ as useConnectionStatus, w as useCrdtText, b as usePresence, h as useSyncQueue };
@@ -0,0 +1,251 @@
1
+ import * as e from "yjs";
2
+ //#region src/crdt/yjsBackend.ts
3
+ var t = "t", n = (t) => e.encodeStateAsUpdate(t), r = (t) => {
4
+ let n = new e.Doc();
5
+ return t.length > 0 && e.applyUpdate(n, t), n;
6
+ }, i = (r) => {
7
+ let i = r.getText(t);
8
+ return {
9
+ toString: () => i.toString(),
10
+ insert: (e, t) => i.insert(e, t),
11
+ delete: (e, t) => i.delete(e, t),
12
+ encodeState: () => n(r),
13
+ applyState: (t) => {
14
+ t.length > 0 && e.applyUpdate(r, t);
15
+ }
16
+ };
17
+ }, a = {
18
+ name: "yjs",
19
+ createText: (n) => {
20
+ let r = new e.Doc();
21
+ return n !== void 0 && n.length > 0 && r.getText(t).insert(0, n), i(r);
22
+ },
23
+ merge: (t, n) => e.mergeUpdates([t, n]),
24
+ decodeText: (e) => {
25
+ let n = r(e), i = n.getText(t).toString();
26
+ return n.destroy(), i;
27
+ },
28
+ emptyState: () => n(new e.Doc())
29
+ }, o = a, s = (e, t = o) => {
30
+ let n = t.createText(e), r = {
31
+ backend: t.name,
32
+ toString: () => n.toString(),
33
+ insert: (e, t) => (n.insert(e, t), r),
34
+ delete: (e, t) => (n.delete(e, t), r),
35
+ merge: (e) => (n.applyState(e), r),
36
+ encode: () => n.encodeState()
37
+ };
38
+ return r;
39
+ }, c = (e, t, n = o) => n.merge(e, t), l = (e, t = o) => t.decodeText(e), u = (e = o) => e.emptyState(), d = (e = !0) => ({
40
+ online: e,
41
+ pending: [],
42
+ inFlight: void 0,
43
+ lastError: void 0
44
+ }), f = (e) => e.online && e.inFlight === void 0 && e.pending.length > 0, p = (e) => e.pending.length + (e.inFlight === void 0 ? 0 : 1), m = (e) => ({
45
+ ...e,
46
+ attempts: e.attempts + 1
47
+ }), h = (e, t) => {
48
+ switch (t.type) {
49
+ case "enqueue": return {
50
+ ...e,
51
+ pending: [...e.pending, t.write]
52
+ };
53
+ case "online": return e.online ? e : {
54
+ ...e,
55
+ online: !0
56
+ };
57
+ case "offline": return e.inFlight === void 0 ? e.online ? {
58
+ ...e,
59
+ online: !1
60
+ } : e : {
61
+ ...e,
62
+ online: !1,
63
+ pending: [e.inFlight, ...e.pending],
64
+ inFlight: void 0
65
+ };
66
+ case "drain-start": {
67
+ if (!f(e)) return e;
68
+ let [t, ...n] = e.pending;
69
+ return t === void 0 ? e : {
70
+ ...e,
71
+ pending: n,
72
+ inFlight: t,
73
+ lastError: void 0
74
+ };
75
+ }
76
+ case "ack": return e.inFlight === void 0 || e.inFlight.id !== t.id ? e : {
77
+ ...e,
78
+ inFlight: void 0,
79
+ lastError: void 0
80
+ };
81
+ case "fail": return e.inFlight === void 0 || e.inFlight.id !== t.id ? e : {
82
+ ...e,
83
+ pending: [m(e.inFlight), ...e.pending],
84
+ inFlight: void 0,
85
+ lastError: t.error
86
+ };
87
+ }
88
+ }, g = (e = "online") => ({
89
+ phase: e,
90
+ attempt: 0
91
+ }), _ = (e, t) => {
92
+ switch (t.type) {
93
+ case "network-down": return e.phase === "offline" ? e : {
94
+ phase: "offline",
95
+ attempt: 0
96
+ };
97
+ case "network-up": return e.phase === "online" ? e : {
98
+ phase: "reconnecting",
99
+ attempt: 0
100
+ };
101
+ case "confirmed": return e.phase === "online" ? e : {
102
+ phase: "online",
103
+ attempt: 0
104
+ };
105
+ case "confirm-failed": return e.phase === "reconnecting" ? {
106
+ phase: "reconnecting",
107
+ attempt: e.attempt + 1
108
+ } : e;
109
+ }
110
+ }, v = (e, t) => e === "offline" ? "offline" : e === "reconnecting" || t > 0 ? "syncing" : "synced", y = (e) => `${e.table}\u0000${e.id}\u0000${e.column}`, b = 0, x = () => {
111
+ let e = typeof crypto < "u" ? crypto : void 0;
112
+ return e && typeof e.randomUUID == "function" ? e.randomUUID() : `w_${Date.now().toString(36)}_${b += 1}`;
113
+ }, S = (e) => {
114
+ let { transport: t, adapter: n } = e, r = e.backend ?? o, i = e.now ?? Date.now, a = e.maxAttempts ?? 5, s = d(e.online ?? !0), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Set(), m = () => {
115
+ for (let e of u) try {
116
+ e();
117
+ } catch {}
118
+ }, g = (e, t) => {
119
+ let i = y(e), a = l.get(i), o = a === void 0 ? t : c(a, t, r);
120
+ l.set(i, o), n?.saveCrdtState(e.table, e.id, o).catch(() => void 0);
121
+ }, _ = () => {
122
+ if (n === void 0) return;
123
+ let e = s.inFlight === void 0 ? s.pending : [s.inFlight, ...s.pending];
124
+ n.saveQueue(e).catch(() => void 0);
125
+ }, v = !1, b = async () => {
126
+ if (!v) {
127
+ v = !0;
128
+ try {
129
+ for (; f(s);) {
130
+ s = h(s, { type: "drain-start" });
131
+ let e = s.inFlight;
132
+ if (e === void 0) break;
133
+ try {
134
+ await t.push(e), s = h(s, {
135
+ type: "ack",
136
+ id: e.id
137
+ }), _(), m();
138
+ } catch (t) {
139
+ if (s = h(s, {
140
+ type: "fail",
141
+ id: e.id,
142
+ error: t instanceof Error ? t.message : String(t)
143
+ }), _(), m(), e.attempts + 1 >= a) break;
144
+ }
145
+ }
146
+ } finally {
147
+ v = !1;
148
+ }
149
+ }
150
+ }, S = t.onRemoteState((e) => {
151
+ g(e, e.state), m();
152
+ });
153
+ return {
154
+ enqueue: (e) => {
155
+ g(e, e.update);
156
+ let t = {
157
+ id: x(),
158
+ payload: e,
159
+ enqueuedAt: i(),
160
+ attempts: 0
161
+ };
162
+ s = h(s, {
163
+ type: "enqueue",
164
+ write: t
165
+ }), _(), m(), b();
166
+ },
167
+ setOnline: (e) => {
168
+ s = h(s, e ? { type: "online" } : { type: "offline" }), _(), m(), e && b();
169
+ },
170
+ queueState: () => s,
171
+ outstanding: () => p(s),
172
+ getState: (e) => {
173
+ let t = l.get(y(e));
174
+ return t === void 0 ? void 0 : t.slice();
175
+ },
176
+ getText: (e) => {
177
+ let t = l.get(y(e));
178
+ return t === void 0 ? "" : r.decodeText(t);
179
+ },
180
+ subscribe: (e) => (u.add(e), () => {
181
+ u.delete(e);
182
+ }),
183
+ flush: async () => {
184
+ await b();
185
+ },
186
+ close: () => {
187
+ S(), u.clear();
188
+ }
189
+ };
190
+ }, C = (e) => {
191
+ let { channel: t, roomId: n, peerId: r, initial: i } = e, a = e.ttlMs ?? 3e4, o = e.now ?? Date.now, s = i, c = 0, l = !1, u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Set(), p = () => {
192
+ for (let e of f) try {
193
+ e();
194
+ } catch {}
195
+ }, m = (e) => {
196
+ c += 1;
197
+ let i = e === "leave" ? {
198
+ t: e,
199
+ peerId: r,
200
+ seq: c
201
+ } : {
202
+ t: e,
203
+ peerId: r,
204
+ seq: c,
205
+ presence: s
206
+ };
207
+ t.publish(n, JSON.stringify(i));
208
+ }, h = t.subscribe(n, (e) => {
209
+ if (l) return;
210
+ let t;
211
+ try {
212
+ t = JSON.parse(e);
213
+ } catch {
214
+ return;
215
+ }
216
+ if (t.peerId === r) return;
217
+ if (t.t === "leave") {
218
+ d.delete(t.peerId), u.delete(t.peerId) && p();
219
+ return;
220
+ }
221
+ let n = u.has(t.peerId);
222
+ t.seq <= (d.get(t.peerId) ?? 0) || (d.set(t.peerId, t.seq), u.set(t.peerId, {
223
+ peerId: t.peerId,
224
+ presence: t.presence,
225
+ lastSeen: o()
226
+ }), n || m("update"), p());
227
+ });
228
+ return m("update"), {
229
+ self: () => s,
230
+ others: () => Array.from(u.values()),
231
+ update: (e) => {
232
+ s = e, m("update"), p();
233
+ },
234
+ heartbeat: () => {
235
+ l || m("update");
236
+ },
237
+ sweep: () => {
238
+ let e = o() - a, t = !1;
239
+ for (let [n, r] of u) r.lastSeen < e && (u.delete(n), t = !0);
240
+ t && p();
241
+ },
242
+ onChange: (e) => (f.add(e), () => {
243
+ f.delete(e);
244
+ }),
245
+ leave: () => {
246
+ l || (l = !0, m("leave"), h(), u.clear(), d.clear(), p(), f.clear());
247
+ }
248
+ };
249
+ };
250
+ //#endregion
251
+ export { g as a, p as c, l as d, o as f, a as h, v as i, h as l, c as m, S as n, f as o, u as p, _ as r, d as s, C as t, s as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/local-first",
3
- "version": "0.32.0",
3
+ "version": "0.34.0",
4
4
  "description": "Local-first / CRDT primitives (opt-in): a Yjs-backed crdtText() field and its deterministic merge, an offline sync-queue reducer, connection-status state machine, and last-write-wins conflict policy. Library-level primitives only — client SQLite persistence, the sync wire, and the presence channel are documented seams.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -27,7 +27,8 @@
27
27
  "types": "./dist/react.d.ts",
28
28
  "import": "./dist/react.js",
29
29
  "default": "./dist/react.js"
30
- }
30
+ },
31
+ "./package.json": "./package.json"
31
32
  },
32
33
  "main": "./dist/index.js",
33
34
  "module": "./dist/index.js",
@@ -1,134 +0,0 @@
1
- //#region src/sync/queue.ts
2
- var e = (e = !0) => ({
3
- online: e,
4
- pending: [],
5
- inFlight: void 0,
6
- lastError: void 0
7
- }), t = (e) => e.online && e.inFlight === void 0 && e.pending.length > 0, n = (e) => e.pending.length + (e.inFlight === void 0 ? 0 : 1), r = (e) => ({
8
- ...e,
9
- attempts: e.attempts + 1
10
- }), i = (e, n) => {
11
- switch (n.type) {
12
- case "enqueue": return {
13
- ...e,
14
- pending: [...e.pending, n.write]
15
- };
16
- case "online": return e.online ? e : {
17
- ...e,
18
- online: !0
19
- };
20
- case "offline": return e.inFlight === void 0 ? e.online ? {
21
- ...e,
22
- online: !1
23
- } : e : {
24
- ...e,
25
- online: !1,
26
- pending: [e.inFlight, ...e.pending],
27
- inFlight: void 0
28
- };
29
- case "drain-start": {
30
- if (!t(e)) return e;
31
- let [n, ...r] = e.pending;
32
- return n === void 0 ? e : {
33
- ...e,
34
- pending: r,
35
- inFlight: n,
36
- lastError: void 0
37
- };
38
- }
39
- case "ack": return e.inFlight === void 0 || e.inFlight.id !== n.id ? e : {
40
- ...e,
41
- inFlight: void 0,
42
- lastError: void 0
43
- };
44
- case "fail": return e.inFlight === void 0 || e.inFlight.id !== n.id ? e : {
45
- ...e,
46
- pending: [r(e.inFlight), ...e.pending],
47
- inFlight: void 0,
48
- lastError: n.error
49
- };
50
- }
51
- }, a = (e = "online") => ({
52
- phase: e,
53
- attempt: 0
54
- }), o = (e, t) => {
55
- switch (t.type) {
56
- case "network-down": return e.phase === "offline" ? e : {
57
- phase: "offline",
58
- attempt: 0
59
- };
60
- case "network-up": return e.phase === "online" ? e : {
61
- phase: "reconnecting",
62
- attempt: 0
63
- };
64
- case "confirmed": return e.phase === "online" ? e : {
65
- phase: "online",
66
- attempt: 0
67
- };
68
- case "confirm-failed": return e.phase === "reconnecting" ? {
69
- phase: "reconnecting",
70
- attempt: e.attempt + 1
71
- } : e;
72
- }
73
- }, s = (e, t) => e === "offline" ? "offline" : e === "reconnecting" || t > 0 ? "syncing" : "synced", c = (e) => {
74
- let { channel: t, roomId: n, peerId: r, initial: i } = e, a = e.ttlMs ?? 3e4, o = e.now ?? Date.now, s = i, c = 0, l = !1, u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Set(), p = () => {
75
- for (let e of f) try {
76
- e();
77
- } catch {}
78
- }, m = (e) => {
79
- c += 1;
80
- let i = e === "leave" ? {
81
- t: e,
82
- peerId: r,
83
- seq: c
84
- } : {
85
- t: e,
86
- peerId: r,
87
- seq: c,
88
- presence: s
89
- };
90
- t.publish(n, JSON.stringify(i));
91
- }, h = t.subscribe(n, (e) => {
92
- if (l) return;
93
- let t;
94
- try {
95
- t = JSON.parse(e);
96
- } catch {
97
- return;
98
- }
99
- if (t.peerId === r) return;
100
- if (t.t === "leave") {
101
- d.delete(t.peerId), u.delete(t.peerId) && p();
102
- return;
103
- }
104
- let n = u.has(t.peerId);
105
- t.seq <= (d.get(t.peerId) ?? 0) || (d.set(t.peerId, t.seq), u.set(t.peerId, {
106
- peerId: t.peerId,
107
- presence: t.presence,
108
- lastSeen: o()
109
- }), n || m("update"), p());
110
- });
111
- return m("update"), {
112
- self: () => s,
113
- others: () => Array.from(u.values()),
114
- update: (e) => {
115
- s = e, m("update"), p();
116
- },
117
- heartbeat: () => {
118
- l || m("update");
119
- },
120
- sweep: () => {
121
- let e = o() - a, t = !1;
122
- for (let [n, r] of u) r.lastSeen < e && (u.delete(n), t = !0);
123
- t && p();
124
- },
125
- onChange: (e) => (f.add(e), () => {
126
- f.delete(e);
127
- }),
128
- leave: () => {
129
- l || (l = !0, m("leave"), h(), u.clear(), d.clear(), p(), f.clear());
130
- }
131
- };
132
- };
133
- //#endregion
134
- export { t as a, i as c, a as i, o as n, e as o, s as r, n as s, c as t };