@agent-p2p/peer 0.0.1
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/events.d.ts +12 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +26 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/permissions/index.d.ts +2 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +2 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/room-permissions.d.ts +30 -0
- package/dist/permissions/room-permissions.d.ts.map +1 -0
- package/dist/permissions/room-permissions.js +105 -0
- package/dist/permissions/room-permissions.js.map +1 -0
- package/dist/radio-peer.d.ts +30 -0
- package/dist/radio-peer.d.ts.map +1 -0
- package/dist/radio-peer.js +153 -0
- package/dist/radio-peer.js.map +1 -0
- package/dist/transport/index.d.ts +3 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +3 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/indexeddb.d.ts +4 -0
- package/dist/transport/indexeddb.d.ts.map +1 -0
- package/dist/transport/indexeddb.js +5 -0
- package/dist/transport/indexeddb.js.map +1 -0
- package/dist/transport/trystero-provider.d.ts +29 -0
- package/dist/transport/trystero-provider.d.ts.map +1 -0
- package/dist/transport/trystero-provider.js +141 -0
- package/dist/transport/trystero-provider.js.map +1 -0
- package/dist/transport/webrtc.d.ts +9 -0
- package/dist/transport/webrtc.d.ts.map +1 -0
- package/dist/transport/webrtc.js +10 -0
- package/dist/transport/webrtc.js.map +1 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/yjs/awareness.d.ts +9 -0
- package/dist/yjs/awareness.d.ts.map +1 -0
- package/dist/yjs/awareness.js +17 -0
- package/dist/yjs/awareness.js.map +1 -0
- package/dist/yjs/channel-array.d.ts +16 -0
- package/dist/yjs/channel-array.d.ts.map +1 -0
- package/dist/yjs/channel-array.js +50 -0
- package/dist/yjs/channel-array.js.map +1 -0
- package/dist/yjs/doc-manager.d.ts +13 -0
- package/dist/yjs/doc-manager.d.ts.map +1 -0
- package/dist/yjs/doc-manager.js +30 -0
- package/dist/yjs/doc-manager.js.map +1 -0
- package/dist/yjs/index.d.ts +4 -0
- package/dist/yjs/index.d.ts.map +1 -0
- package/dist/yjs/index.js +4 -0
- package/dist/yjs/index.js.map +1 -0
- package/package.json +31 -0
- package/src/events.ts +30 -0
- package/src/index.ts +23 -0
- package/src/permissions/index.ts +1 -0
- package/src/permissions/room-permissions.ts +125 -0
- package/src/radio-peer.ts +187 -0
- package/src/transport/index.ts +2 -0
- package/src/transport/indexeddb.ts +9 -0
- package/src/transport/trystero-provider.ts +173 -0
- package/src/types.ts +31 -0
- package/src/yjs/awareness.ts +25 -0
- package/src/yjs/channel-array.ts +60 -0
- package/src/yjs/doc-manager.ts +35 -0
- package/src/yjs/index.ts +3 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Awareness, applyAwarenessUpdate, encodeAwarenessUpdate, removeAwarenessStates } from "y-protocols/awareness";
|
|
2
|
+
import * as syncProtocol from "y-protocols/sync";
|
|
3
|
+
import * as encoding from "lib0/encoding";
|
|
4
|
+
import * as decoding from "lib0/decoding";
|
|
5
|
+
const MSG_SYNC = 0;
|
|
6
|
+
const MSG_AWARENESS = 1;
|
|
7
|
+
export class TrysteroProvider {
|
|
8
|
+
doc;
|
|
9
|
+
awareness;
|
|
10
|
+
roomName;
|
|
11
|
+
connected;
|
|
12
|
+
_room = null;
|
|
13
|
+
_send = null;
|
|
14
|
+
_peers = new Set();
|
|
15
|
+
_destroyed = false;
|
|
16
|
+
_onDocUpdate;
|
|
17
|
+
constructor(doc, roomName, config = {}) {
|
|
18
|
+
this.doc = doc;
|
|
19
|
+
this.roomName = roomName;
|
|
20
|
+
this.awareness = new Awareness(doc);
|
|
21
|
+
this._onDocUpdate = (update, origin) => {
|
|
22
|
+
if (origin === this)
|
|
23
|
+
return;
|
|
24
|
+
const encoder = encoding.createEncoder();
|
|
25
|
+
encoding.writeVarUint(encoder, MSG_SYNC);
|
|
26
|
+
syncProtocol.writeUpdate(encoder, update);
|
|
27
|
+
this._broadcast(encoding.toUint8Array(encoder));
|
|
28
|
+
};
|
|
29
|
+
this.connected = this._connect(config);
|
|
30
|
+
}
|
|
31
|
+
async _connect(config) {
|
|
32
|
+
const backend = config.backend ?? "torrent";
|
|
33
|
+
let joinRoom;
|
|
34
|
+
switch (backend) {
|
|
35
|
+
case "torrent": {
|
|
36
|
+
const mod = await import("trystero/torrent");
|
|
37
|
+
joinRoom = mod.joinRoom;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case "nostr": {
|
|
41
|
+
const mod = await import("trystero/nostr");
|
|
42
|
+
joinRoom = mod.joinRoom;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case "mqtt": {
|
|
46
|
+
const mod = await import("trystero/mqtt");
|
|
47
|
+
joinRoom = mod.joinRoom;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const roomConfig = {
|
|
52
|
+
appId: config.appId ?? "agent-p2p",
|
|
53
|
+
};
|
|
54
|
+
if (config.password)
|
|
55
|
+
roomConfig.password = config.password;
|
|
56
|
+
if (config.relayUrls)
|
|
57
|
+
roomConfig.relayUrls = config.relayUrls;
|
|
58
|
+
if (this._destroyed)
|
|
59
|
+
return;
|
|
60
|
+
const room = joinRoom(roomConfig, this.roomName);
|
|
61
|
+
this._room = room;
|
|
62
|
+
const [send, receive] = room.makeAction("yjs-sync");
|
|
63
|
+
this._send = send;
|
|
64
|
+
receive((data, peerId) => {
|
|
65
|
+
this._handleMessage(new Uint8Array(data), peerId);
|
|
66
|
+
});
|
|
67
|
+
room.onPeerJoin((peerId) => {
|
|
68
|
+
this._peers.add(peerId);
|
|
69
|
+
this._sendSyncStep1(peerId);
|
|
70
|
+
this._sendAwareness(peerId);
|
|
71
|
+
});
|
|
72
|
+
room.onPeerLeave((peerId) => {
|
|
73
|
+
this._peers.delete(peerId);
|
|
74
|
+
});
|
|
75
|
+
this.doc.on("update", this._onDocUpdate);
|
|
76
|
+
this.awareness.on("update", ({ added, updated, removed }) => {
|
|
77
|
+
const changedClients = [...added, ...updated, ...removed];
|
|
78
|
+
const encoder = encoding.createEncoder();
|
|
79
|
+
encoding.writeVarUint(encoder, MSG_AWARENESS);
|
|
80
|
+
encoding.writeVarUint8Array(encoder, encodeAwarenessUpdate(this.awareness, changedClients));
|
|
81
|
+
this._broadcast(encoding.toUint8Array(encoder));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
_sendSyncStep1(peerId) {
|
|
85
|
+
const encoder = encoding.createEncoder();
|
|
86
|
+
encoding.writeVarUint(encoder, MSG_SYNC);
|
|
87
|
+
syncProtocol.writeSyncStep1(encoder, this.doc);
|
|
88
|
+
this._sendTo(encoding.toUint8Array(encoder), peerId);
|
|
89
|
+
}
|
|
90
|
+
_sendAwareness(peerId) {
|
|
91
|
+
const clients = Array.from(this.awareness.getStates().keys());
|
|
92
|
+
if (clients.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
const encoder = encoding.createEncoder();
|
|
95
|
+
encoding.writeVarUint(encoder, MSG_AWARENESS);
|
|
96
|
+
encoding.writeVarUint8Array(encoder, encodeAwarenessUpdate(this.awareness, clients));
|
|
97
|
+
this._sendTo(encoding.toUint8Array(encoder), peerId);
|
|
98
|
+
}
|
|
99
|
+
_handleMessage(data, peerId) {
|
|
100
|
+
const decoder = decoding.createDecoder(data);
|
|
101
|
+
const msgType = decoding.readVarUint(decoder);
|
|
102
|
+
switch (msgType) {
|
|
103
|
+
case MSG_SYNC: {
|
|
104
|
+
const encoder = encoding.createEncoder();
|
|
105
|
+
encoding.writeVarUint(encoder, MSG_SYNC);
|
|
106
|
+
syncProtocol.readSyncMessage(decoder, encoder, this.doc, this);
|
|
107
|
+
if (encoding.length(encoder) > 1) {
|
|
108
|
+
this._sendTo(encoding.toUint8Array(encoder), peerId);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case MSG_AWARENESS: {
|
|
113
|
+
const update = decoding.readVarUint8Array(decoder);
|
|
114
|
+
applyAwarenessUpdate(this.awareness, update, peerId);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
_broadcast(data) {
|
|
120
|
+
if (this._send && this._peers.size > 0) {
|
|
121
|
+
this._send(data.buffer);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
_sendTo(data, peerId) {
|
|
125
|
+
if (this._send) {
|
|
126
|
+
this._send(data.buffer, peerId);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
destroy() {
|
|
130
|
+
if (this._destroyed)
|
|
131
|
+
return;
|
|
132
|
+
this._destroyed = true;
|
|
133
|
+
removeAwarenessStates(this.awareness, [this.doc.clientID], "provider destroyed");
|
|
134
|
+
this.doc.off("update", this._onDocUpdate);
|
|
135
|
+
this._room?.leave();
|
|
136
|
+
this._room = null;
|
|
137
|
+
this._send = null;
|
|
138
|
+
this._peers.clear();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=trystero-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trystero-provider.js","sourceRoot":"","sources":["../../src/transport/trystero-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { WebrtcProvider } from "y-webrtc";
|
|
2
|
+
import type * as Y from "yjs";
|
|
3
|
+
export interface WebRTCTransportOptions {
|
|
4
|
+
signalingServers?: string[];
|
|
5
|
+
password?: string;
|
|
6
|
+
peerOpts?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createWebRTCProvider(doc: Y.Doc, roomName: string, opts?: WebRTCTransportOptions): WebrtcProvider;
|
|
9
|
+
//# sourceMappingURL=webrtc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webrtc.d.ts","sourceRoot":"","sources":["../../src/transport/webrtc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,KAAK,KAAK,CAAC,MAAM,KAAK,CAAC;AAI9B,MAAM,WAAW,sBAAsB;IACtC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,sBAA2B,GAC/B,cAAc,CAMhB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WebrtcProvider } from "y-webrtc";
|
|
2
|
+
const DEFAULT_SIGNALING = ["ws://localhost:4444", "wss://signaling.yjs.dev", "wss://y-webrtc-signaling-eu.herokuapp.com"];
|
|
3
|
+
export function createWebRTCProvider(doc, roomName, opts = {}) {
|
|
4
|
+
return new WebrtcProvider(roomName, doc, {
|
|
5
|
+
signaling: opts.signalingServers ?? DEFAULT_SIGNALING,
|
|
6
|
+
password: opts.password ?? undefined,
|
|
7
|
+
peerOpts: opts.peerOpts,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=webrtc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webrtc.js","sourceRoot":"","sources":["../../src/transport/webrtc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,iBAAiB,GAAG,CAAC,qBAAqB,EAAE,yBAAyB,EAAE,2CAA2C,CAAC,CAAC;AAQ1H,MAAM,UAAU,oBAAoB,CACnC,GAAU,EACV,QAAgB,EAChB,OAA+B,EAAE;IAEjC,OAAO,IAAI,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxC,SAAS,EAAE,IAAI,CAAC,gBAAgB,IAAI,iBAAiB;QACrD,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS;QACpC,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SignalEnvelope, Keypair } from "@agent-p2p/core";
|
|
2
|
+
export type SignalingBackend = "torrent" | "nostr" | "mqtt";
|
|
3
|
+
export interface TransportConfig {
|
|
4
|
+
backend?: SignalingBackend;
|
|
5
|
+
/** Relay/tracker URLs (BitTorrent trackers, Nostr relays, or MQTT brokers) */
|
|
6
|
+
relayUrls?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface RadioPeerOptions {
|
|
9
|
+
password?: string;
|
|
10
|
+
maxSignalsPerChannel?: number;
|
|
11
|
+
enablePersistence?: boolean;
|
|
12
|
+
keypair?: Keypair;
|
|
13
|
+
transport?: TransportConfig;
|
|
14
|
+
}
|
|
15
|
+
export interface PeerInfo {
|
|
16
|
+
peerId: string;
|
|
17
|
+
joinedAt: number;
|
|
18
|
+
}
|
|
19
|
+
export type PeerEventMap = {
|
|
20
|
+
signal: SignalEnvelope;
|
|
21
|
+
"peer:join": PeerInfo;
|
|
22
|
+
"peer:leave": PeerInfo;
|
|
23
|
+
"permission:denied": {
|
|
24
|
+
topic: string;
|
|
25
|
+
action: "publish" | "read";
|
|
26
|
+
};
|
|
27
|
+
"roles:changed": {
|
|
28
|
+
peerId: string;
|
|
29
|
+
role: string;
|
|
30
|
+
};
|
|
31
|
+
status: "connecting" | "connected" | "disconnected";
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC/B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,QAAQ,CAAC;IACtB,YAAY,EAAE,QAAQ,CAAC;IACvB,mBAAmB,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAA;KAAE,CAAC;IACnE,eAAe,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;CACpD,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PeerInfo } from "../types.js";
|
|
2
|
+
export interface AwarenessLike {
|
|
3
|
+
setLocalStateField(field: string, value: unknown): void;
|
|
4
|
+
getStates(): Map<number, Record<string, unknown>>;
|
|
5
|
+
on(event: string, fn: (...args: unknown[]) => void): void;
|
|
6
|
+
}
|
|
7
|
+
export declare function setLocalPeer(awareness: AwarenessLike, peerId: string): void;
|
|
8
|
+
export declare function getConnectedPeers(awareness: AwarenessLike): PeerInfo[];
|
|
9
|
+
//# sourceMappingURL=awareness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/yjs/awareness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC7B,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACxD,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CAC1D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAK3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,aAAa,GAAG,QAAQ,EAAE,CAStE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function setLocalPeer(awareness, peerId) {
|
|
2
|
+
awareness.setLocalStateField("peer", {
|
|
3
|
+
peerId,
|
|
4
|
+
joinedAt: Date.now(),
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export function getConnectedPeers(awareness) {
|
|
8
|
+
const peers = [];
|
|
9
|
+
for (const [, state] of awareness.getStates()) {
|
|
10
|
+
const peer = state.peer;
|
|
11
|
+
if (peer) {
|
|
12
|
+
peers.push(peer);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return peers;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=awareness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness.js","sourceRoot":"","sources":["../../src/yjs/awareness.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,YAAY,CAAC,SAAwB,EAAE,MAAc;IACpE,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE;QACpC,MAAM;QACN,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;KACpB,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAwB;IACzD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,SAAS,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,IAA4B,CAAC;QAChD,IAAI,IAAI,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import type { SignalEnvelope } from "@agent-p2p/core";
|
|
3
|
+
export type PublishGuard = (peerId: string, topic: string) => boolean;
|
|
4
|
+
export declare class ChannelArray {
|
|
5
|
+
readonly array: Y.Array<SignalEnvelope>;
|
|
6
|
+
readonly topic: string;
|
|
7
|
+
private _maxSignals;
|
|
8
|
+
private _guard?;
|
|
9
|
+
constructor(array: Y.Array<SignalEnvelope>, topic: string, maxSignals?: number, guard?: PublishGuard);
|
|
10
|
+
push(signal: SignalEnvelope): void;
|
|
11
|
+
getAll(): SignalEnvelope[];
|
|
12
|
+
get length(): number;
|
|
13
|
+
observe(fn: (signals: SignalEnvelope[]) => void, filter?: (signal: SignalEnvelope) => boolean): () => void;
|
|
14
|
+
private trim;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=channel-array.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-array.d.ts","sourceRoot":"","sources":["../../src/yjs/channel-array.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAEtE,qBAAa,YAAY;IACxB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAe;gBAElB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,SAAO,EAAE,KAAK,CAAC,EAAE,YAAY;IAOlG,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAQlC,MAAM,IAAI,cAAc,EAAE;IAI1B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,GAAG,MAAM,IAAI;IAmB1G,OAAO,CAAC,IAAI;CAMZ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class ChannelArray {
|
|
2
|
+
array;
|
|
3
|
+
topic;
|
|
4
|
+
_maxSignals;
|
|
5
|
+
_guard;
|
|
6
|
+
constructor(array, topic, maxSignals = 1000, guard) {
|
|
7
|
+
this.array = array;
|
|
8
|
+
this.topic = topic;
|
|
9
|
+
this._maxSignals = maxSignals;
|
|
10
|
+
this._guard = guard;
|
|
11
|
+
}
|
|
12
|
+
push(signal) {
|
|
13
|
+
if (this._guard && !this._guard(signal.provenance.peer_id, this.topic)) {
|
|
14
|
+
throw new Error(`Permission denied: cannot publish to "${this.topic}"`);
|
|
15
|
+
}
|
|
16
|
+
this.array.push([signal]);
|
|
17
|
+
this.trim();
|
|
18
|
+
}
|
|
19
|
+
getAll() {
|
|
20
|
+
return this.array.toArray();
|
|
21
|
+
}
|
|
22
|
+
get length() {
|
|
23
|
+
return this.array.length;
|
|
24
|
+
}
|
|
25
|
+
observe(fn, filter) {
|
|
26
|
+
const handler = (event) => {
|
|
27
|
+
const added = [];
|
|
28
|
+
for (const item of event.changes.added) {
|
|
29
|
+
for (const content of item.content.getContent()) {
|
|
30
|
+
const signal = content;
|
|
31
|
+
if (!filter || filter(signal)) {
|
|
32
|
+
added.push(signal);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (added.length > 0) {
|
|
37
|
+
fn(added);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
this.array.observe(handler);
|
|
41
|
+
return () => this.array.unobserve(handler);
|
|
42
|
+
}
|
|
43
|
+
trim() {
|
|
44
|
+
if (this.array.length > this._maxSignals) {
|
|
45
|
+
const excess = this.array.length - this._maxSignals;
|
|
46
|
+
this.array.delete(0, excess);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=channel-array.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-array.js","sourceRoot":"","sources":["../../src/yjs/channel-array.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,YAAY;IACf,KAAK,CAA0B;IAC/B,KAAK,CAAS;IACf,WAAW,CAAS;IACpB,MAAM,CAAgB;IAE9B,YAAY,KAA8B,EAAE,KAAa,EAAE,UAAU,GAAG,IAAI,EAAE,KAAoB;QACjG,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,MAAsB;QAC1B,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED,MAAM;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED,OAAO,CAAC,EAAuC,EAAE,MAA4C;QAC5F,MAAM,OAAO,GAAG,CAAC,KAAoC,EAAE,EAAE;YACxD,MAAM,KAAK,GAAqB,EAAE,CAAC;YACnC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACxC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;oBACjD,MAAM,MAAM,GAAG,OAAyB,CAAC;oBACzC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC/B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACpB,CAAC;gBACF,CAAC;YACF,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,EAAE,CAAC,KAAK,CAAC,CAAC;YACX,CAAC;QACF,CAAC,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEO,IAAI;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;YACpD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC;IACF,CAAC;CACD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { ChannelArray, type PublishGuard } from "./channel-array.js";
|
|
3
|
+
export declare class DocManager {
|
|
4
|
+
readonly doc: Y.Doc;
|
|
5
|
+
private _channels;
|
|
6
|
+
private _maxSignals;
|
|
7
|
+
private _guard?;
|
|
8
|
+
constructor(maxSignals?: number, guard?: PublishGuard);
|
|
9
|
+
getChannel(topic: string): ChannelArray;
|
|
10
|
+
getTopics(): string[];
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=doc-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-manager.d.ts","sourceRoot":"","sources":["../../src/yjs/doc-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,qBAAa,UAAU;IACtB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAe;gBAElB,UAAU,SAAO,EAAE,KAAK,CAAC,EAAE,YAAY;IAMnD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAUvC,SAAS,IAAI,MAAM,EAAE;IAIrB,OAAO,IAAI,IAAI;CAIf"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { ChannelArray } from "./channel-array.js";
|
|
3
|
+
export class DocManager {
|
|
4
|
+
doc;
|
|
5
|
+
_channels = new Map();
|
|
6
|
+
_maxSignals;
|
|
7
|
+
_guard;
|
|
8
|
+
constructor(maxSignals = 1000, guard) {
|
|
9
|
+
this.doc = new Y.Doc();
|
|
10
|
+
this._maxSignals = maxSignals;
|
|
11
|
+
this._guard = guard;
|
|
12
|
+
}
|
|
13
|
+
getChannel(topic) {
|
|
14
|
+
let ch = this._channels.get(topic);
|
|
15
|
+
if (!ch) {
|
|
16
|
+
const arr = this.doc.getArray(`ch:${topic}`);
|
|
17
|
+
ch = new ChannelArray(arr, topic, this._maxSignals, this._guard);
|
|
18
|
+
this._channels.set(topic, ch);
|
|
19
|
+
}
|
|
20
|
+
return ch;
|
|
21
|
+
}
|
|
22
|
+
getTopics() {
|
|
23
|
+
return Array.from(this._channels.keys());
|
|
24
|
+
}
|
|
25
|
+
destroy() {
|
|
26
|
+
this._channels.clear();
|
|
27
|
+
this.doc.destroy();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=doc-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-manager.js","sourceRoot":"","sources":["../../src/yjs/doc-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EAAE,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAErE,MAAM,OAAO,UAAU;IACb,GAAG,CAAQ;IACZ,SAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC5C,WAAW,CAAS;IACpB,MAAM,CAAgB;IAE9B,YAAY,UAAU,GAAG,IAAI,EAAE,KAAoB;QAClD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,UAAU,CAAC,KAAa;QACvB,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,EAAE,CAAC;YACT,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAiB,MAAM,KAAK,EAAE,CAAC,CAAC;YAC7D,EAAE,GAAG,IAAI,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,CAAC;IACX,CAAC;IAED,SAAS;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO;QACN,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/yjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/yjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-p2p/peer",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "P2P peer transport for agent-p2p — Yjs + trystero (serverless WebRTC)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"bun": "./src/index.ts",
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": ["src", "dist"],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@agent-p2p/core": "^0.0.1",
|
|
19
|
+
"yjs": "^13.6",
|
|
20
|
+
"y-protocols": "^1.0",
|
|
21
|
+
"y-indexeddb": "^9.0",
|
|
22
|
+
"lib0": "^0.2",
|
|
23
|
+
"trystero": "^0.20"
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/luisfreitas/radio.ag",
|
|
29
|
+
"directory": "packages/peer"
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type Listener<T> = (data: T) => void;
|
|
2
|
+
|
|
3
|
+
export class TypedEmitter<EventMap extends { [key: string]: unknown }> {
|
|
4
|
+
private _listeners = new Map<keyof EventMap, Set<Listener<never>>>();
|
|
5
|
+
|
|
6
|
+
on<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): () => void {
|
|
7
|
+
if (!this._listeners.has(event)) {
|
|
8
|
+
this._listeners.set(event, new Set());
|
|
9
|
+
}
|
|
10
|
+
const set = this._listeners.get(event)!;
|
|
11
|
+
set.add(fn as Listener<never>);
|
|
12
|
+
return () => set.delete(fn as Listener<never>);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
off<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): void {
|
|
16
|
+
this._listeners.get(event)?.delete(fn as Listener<never>);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected emit<K extends keyof EventMap>(event: K, data: EventMap[K]): void {
|
|
20
|
+
const set = this._listeners.get(event);
|
|
21
|
+
if (!set) return;
|
|
22
|
+
for (const fn of set) {
|
|
23
|
+
(fn as Listener<EventMap[K]>)(data);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
removeAllListeners(): void {
|
|
28
|
+
this._listeners.clear();
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { RadioPeer } from "./radio-peer.js";
|
|
2
|
+
export { TypedEmitter } from "./events.js";
|
|
3
|
+
export { RoomPermissions } from "./permissions/index.js";
|
|
4
|
+
export type { RadioPeerOptions, PeerInfo, PeerEventMap, SignalingBackend, TransportConfig } from "./types.js";
|
|
5
|
+
export { TrysteroProvider, type TrysteroConfig } from "./transport/trystero-provider.js";
|
|
6
|
+
export { DocManager, ChannelArray, type PublishGuard } from "./yjs/index.js";
|
|
7
|
+
|
|
8
|
+
// Re-export core essentials
|
|
9
|
+
export {
|
|
10
|
+
type SignalEnvelope,
|
|
11
|
+
type Keypair,
|
|
12
|
+
type RoomRole,
|
|
13
|
+
type ChannelPolicy,
|
|
14
|
+
type RoomConfig,
|
|
15
|
+
ROLE_WEIGHT,
|
|
16
|
+
SignalBuilder,
|
|
17
|
+
generateKeypair,
|
|
18
|
+
peerId,
|
|
19
|
+
exportKeypair,
|
|
20
|
+
importKeypair,
|
|
21
|
+
signSignal,
|
|
22
|
+
verifySignal,
|
|
23
|
+
} from "@agent-p2p/core";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RoomPermissions } from "./room-permissions.js";
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { type RoomRole, type ChannelPolicy, ROLE_WEIGHT } from "@agent-p2p/core";
|
|
3
|
+
|
|
4
|
+
export interface RoomPermissionsEvents {
|
|
5
|
+
"roles:changed": { peerId: string; role: RoomRole };
|
|
6
|
+
"config:changed": void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class RoomPermissions {
|
|
10
|
+
private _configMap: Y.Map<unknown>;
|
|
11
|
+
private _rolesMap: Y.Map<RoomRole>;
|
|
12
|
+
|
|
13
|
+
constructor(doc: Y.Doc) {
|
|
14
|
+
this._configMap = doc.getMap("room:config");
|
|
15
|
+
this._rolesMap = doc.getMap("room:roles");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get ownerId(): string | undefined {
|
|
19
|
+
return this._configMap.get("owner_id") as string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get isInitialized(): boolean {
|
|
23
|
+
return this._configMap.has("owner_id");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
initializeAsOwner(peerId: string): void {
|
|
27
|
+
if (this.isInitialized) return;
|
|
28
|
+
this._configMap.doc!.transact(() => {
|
|
29
|
+
this._configMap.set("owner_id", peerId);
|
|
30
|
+
this._configMap.set("created_at", new Date().toISOString());
|
|
31
|
+
this._configMap.set("default_publish_role", "member");
|
|
32
|
+
this._configMap.set("default_read_role", "viewer");
|
|
33
|
+
this._configMap.set("channel_policies", {});
|
|
34
|
+
this._rolesMap.set(peerId, "owner");
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
acceptExisting(peerId: string): void {
|
|
39
|
+
if (!this._rolesMap.has(peerId)) {
|
|
40
|
+
this._rolesMap.set(peerId, "member");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getRole(peerId: string): RoomRole {
|
|
45
|
+
return this._rolesMap.get(peerId) ?? "viewer";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private _getRoleWeight(peerId: string): number {
|
|
49
|
+
return ROLE_WEIGHT[this.getRole(peerId)];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private _getMinPublishRole(topic: string): RoomRole {
|
|
53
|
+
const policies = this._configMap.get("channel_policies") as Record<string, ChannelPolicy> | undefined;
|
|
54
|
+
return policies?.[topic]?.min_publish_role ?? (this._configMap.get("default_publish_role") as RoomRole) ?? "member";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private _getMinReadRole(topic: string): RoomRole {
|
|
58
|
+
const policies = this._configMap.get("channel_policies") as Record<string, ChannelPolicy> | undefined;
|
|
59
|
+
return policies?.[topic]?.min_read_role ?? (this._configMap.get("default_read_role") as RoomRole) ?? "viewer";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
canPublish(peerId: string, topic: string): boolean {
|
|
63
|
+
return this._getRoleWeight(peerId) >= ROLE_WEIGHT[this._getMinPublishRole(topic)];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
canRead(peerId: string, topic: string): boolean {
|
|
67
|
+
return this._getRoleWeight(peerId) >= ROLE_WEIGHT[this._getMinReadRole(topic)];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
promotePeer(actorId: string, targetId: string, newRole: RoomRole): boolean {
|
|
71
|
+
const actorWeight = this._getRoleWeight(actorId);
|
|
72
|
+
const targetWeight = ROLE_WEIGHT[newRole];
|
|
73
|
+
|
|
74
|
+
// Must be at least moderator to promote
|
|
75
|
+
if (actorWeight < ROLE_WEIGHT.moderator) return false;
|
|
76
|
+
// Cannot promote above own role
|
|
77
|
+
if (targetWeight > actorWeight) return false;
|
|
78
|
+
// Cannot change the owner's role
|
|
79
|
+
if (targetId === this.ownerId && actorId !== this.ownerId) return false;
|
|
80
|
+
|
|
81
|
+
this._rolesMap.set(targetId, newRole);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setChannelPolicy(actorId: string, topic: string, policy: Partial<Pick<ChannelPolicy, "min_publish_role" | "min_read_role">>): boolean {
|
|
86
|
+
if (this._getRoleWeight(actorId) < ROLE_WEIGHT.moderator) return false;
|
|
87
|
+
|
|
88
|
+
const policies = (this._configMap.get("channel_policies") as Record<string, ChannelPolicy>) ?? {};
|
|
89
|
+
const existing = policies[topic];
|
|
90
|
+
policies[topic] = {
|
|
91
|
+
topic,
|
|
92
|
+
min_publish_role: existing?.min_publish_role ?? "member",
|
|
93
|
+
min_read_role: existing?.min_read_role ?? "viewer",
|
|
94
|
+
...policy,
|
|
95
|
+
};
|
|
96
|
+
this._configMap.set("channel_policies", policies);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
observeRoles(fn: (peerId: string, role: RoomRole) => void): () => void {
|
|
101
|
+
const handler = (event: Y.YMapEvent<RoomRole>) => {
|
|
102
|
+
for (const [key, change] of event.changes.keys) {
|
|
103
|
+
if (change.action === "add" || change.action === "update") {
|
|
104
|
+
fn(key, this._rolesMap.get(key)!);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
this._rolesMap.observe(handler);
|
|
109
|
+
return () => this._rolesMap.unobserve(handler);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
observeConfig(fn: () => void): () => void {
|
|
113
|
+
const handler = () => fn();
|
|
114
|
+
this._configMap.observe(handler);
|
|
115
|
+
return () => this._configMap.unobserve(handler);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getAllRoles(): Map<string, RoomRole> {
|
|
119
|
+
const result = new Map<string, RoomRole>();
|
|
120
|
+
for (const [key, value] of this._rolesMap.entries()) {
|
|
121
|
+
result.set(key, value);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
}
|