wireweave 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -35
- package/package.json +14 -4
- package/src/bans.js +45 -0
- package/src/channels.js +107 -0
- package/src/chat.js +95 -0
- package/src/fsm.js +51 -0
- package/src/index.js +12 -0
- package/src/media.js +81 -0
- package/src/message.js +22 -0
- package/src/pages.js +77 -0
- package/src/roles.js +58 -0
- package/src/servers.js +103 -0
- package/src/settings.js +72 -0
- package/src/voice.js +348 -0
- package/src/wireweave.js +89 -0
- package/src/legacy/README.md +0 -71
- package/src/legacy/index.js +0 -49
- package/src/legacy/nostr-auth.js +0 -217
- package/src/legacy/nostr-bans.js +0 -59
- package/src/legacy/nostr-channels.js +0 -145
- package/src/legacy/nostr-chat.js +0 -185
- package/src/legacy/nostr-fsm.js +0 -5
- package/src/legacy/nostr-media.js +0 -97
- package/src/legacy/nostr-message.js +0 -12
- package/src/legacy/nostr-network.js +0 -182
- package/src/legacy/nostr-pages.js +0 -152
- package/src/legacy/nostr-roles.js +0 -74
- package/src/legacy/nostr-servers.js +0 -223
- package/src/legacy/nostr-settings.js +0 -97
- package/src/legacy/nostr-state-patch.js +0 -19
- package/src/legacy/nostr-voice-camera.js +0 -63
- package/src/legacy/nostr-voice-rtc.js +0 -199
- package/src/legacy/nostr-voice-sfu.js +0 -128
- package/src/legacy/nostr-voice.js +0 -257
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
var serverRoles = {
|
|
2
|
-
_store: new Map(),
|
|
3
|
-
_sub: null,
|
|
4
|
-
|
|
5
|
-
_creatorOf(serverId) {
|
|
6
|
-
return serverId ? serverId.split(':')[0] : null;
|
|
7
|
-
},
|
|
8
|
-
|
|
9
|
-
isOwner(serverId) {
|
|
10
|
-
return !!state.nostrPubkey && serverRoles._creatorOf(serverId) === state.nostrPubkey;
|
|
11
|
-
},
|
|
12
|
-
|
|
13
|
-
isAdmin(serverId) {
|
|
14
|
-
if (serverRoles.isOwner(serverId)) return true;
|
|
15
|
-
var roles = serverRoles._store.get(serverId) || {};
|
|
16
|
-
return !!(roles.admins || []).includes(state.nostrPubkey);
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
isMod(serverId) {
|
|
20
|
-
if (serverRoles.isAdmin(serverId)) return true;
|
|
21
|
-
var roles = serverRoles._store.get(serverId) || {};
|
|
22
|
-
return !!(roles.mods || []).includes(state.nostrPubkey);
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
getRole(serverId, pubkey) {
|
|
26
|
-
var creator = serverRoles._creatorOf(serverId);
|
|
27
|
-
if (pubkey === creator) return 'owner';
|
|
28
|
-
var roles = serverRoles._store.get(serverId) || {};
|
|
29
|
-
if ((roles.admins || []).includes(pubkey)) return 'admin';
|
|
30
|
-
if ((roles.mods || []).includes(pubkey)) return 'moderator';
|
|
31
|
-
return 'member';
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
async setRole(serverId, targetPubkey, role) {
|
|
35
|
-
if (!serverRoles.isOwner(serverId) && role === 'admin') throw new Error('Only owner can assign admin');
|
|
36
|
-
if (!serverRoles.isAdmin(serverId)) throw new Error('Insufficient permissions');
|
|
37
|
-
var existing = serverRoles._store.get(serverId) || { admins: [], mods: [] };
|
|
38
|
-
var admins = (existing.admins || []).filter(function(p) { return p !== targetPubkey; });
|
|
39
|
-
var mods = (existing.mods || []).filter(function(p) { return p !== targetPubkey; });
|
|
40
|
-
if (role === 'admin') admins = admins.concat([targetPubkey]);
|
|
41
|
-
else if (role === 'moderator') mods = mods.concat([targetPubkey]);
|
|
42
|
-
var next = { admins: admins, mods: mods };
|
|
43
|
-
serverRoles._store.set(serverId, next);
|
|
44
|
-
var dTag = 'zellous-roles:' + serverId;
|
|
45
|
-
var signed = await auth.sign({ kind: 30078, created_at: Math.floor(Date.now() / 1000), tags: [['d', dTag]], content: JSON.stringify(next) });
|
|
46
|
-
await nostrNet.publish(signed);
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
subscribe(serverId) {
|
|
50
|
-
if (serverRoles._sub) { nostrNet.unsubscribe(serverRoles._sub); serverRoles._sub = null; }
|
|
51
|
-
if (!serverId) return;
|
|
52
|
-
var creator = serverRoles._creatorOf(serverId);
|
|
53
|
-
if (!creator) return;
|
|
54
|
-
var dTag = 'zellous-roles:' + serverId;
|
|
55
|
-
serverRoles._sub = 'roles-' + serverId;
|
|
56
|
-
nostrNet.subscribe(serverRoles._sub,
|
|
57
|
-
[{ kinds: [30078], authors: [creator], '#d': [dTag] }],
|
|
58
|
-
function(event) {
|
|
59
|
-
if (event.pubkey !== creator) return;
|
|
60
|
-
try {
|
|
61
|
-
var data = JSON.parse(event.content);
|
|
62
|
-
serverRoles._store.set(serverId, { admins: data.admins || [], mods: data.mods || [] });
|
|
63
|
-
if (window.uiMembers) uiMembers.render();
|
|
64
|
-
} catch(e) {}
|
|
65
|
-
},
|
|
66
|
-
function() {}
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
window.__zellous.roles = serverRoles;
|
|
72
|
-
window.serverRoles = serverRoles;
|
|
73
|
-
if (!window.__debug) window.__debug = {};
|
|
74
|
-
Object.defineProperty(window.__debug, 'roles', { get: function() { return { store: Object.fromEntries(serverRoles._store), sub: serverRoles._sub }; }, configurable: true });
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
var serverManager = {
|
|
2
|
-
loadServers: function() {
|
|
3
|
-
try {
|
|
4
|
-
var raw = localStorage.getItem('zn_servers');
|
|
5
|
-
state.servers = raw ? JSON.parse(raw) : [];
|
|
6
|
-
} catch (e) { state.servers = []; }
|
|
7
|
-
|
|
8
|
-
if (state.nostrPubkey) {
|
|
9
|
-
nostrNet.subscribe(
|
|
10
|
-
'my-servers',
|
|
11
|
-
[{ kinds: [34550], authors: [state.nostrPubkey] }],
|
|
12
|
-
function(event) { serverManager._handleServerEvent(event); },
|
|
13
|
-
function() {}
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
var joined = localStorage.getItem('zn_joined_servers');
|
|
19
|
-
var joinedIds = joined ? JSON.parse(joined) : [];
|
|
20
|
-
joinedIds.forEach(function(sid) {
|
|
21
|
-
if (!state.servers.find(function(s) { return s.id === sid; })) {
|
|
22
|
-
state.servers = state.servers.concat([{ id: sid, name: sid.slice(0, 8), iconColor: '#5865F2' }]);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
// Subscribe to relay to fetch real names for joined (non-owned) servers
|
|
26
|
-
var unresolved = joinedIds.filter(function(sid) {
|
|
27
|
-
// Format: pubkey:dTag — only subscribe if not already owned by us
|
|
28
|
-
var parts = sid.split(':');
|
|
29
|
-
return parts.length === 2 && parts[0] !== state.nostrPubkey;
|
|
30
|
-
});
|
|
31
|
-
if (unresolved.length) {
|
|
32
|
-
// Group by author to minimise subscriptions
|
|
33
|
-
var byAuthor = {};
|
|
34
|
-
unresolved.forEach(function(sid) {
|
|
35
|
-
var parts = sid.split(':');
|
|
36
|
-
var author = parts[0], dTag = parts[1];
|
|
37
|
-
if (!byAuthor[author]) byAuthor[author] = [];
|
|
38
|
-
byAuthor[author].push(dTag);
|
|
39
|
-
});
|
|
40
|
-
Object.keys(byAuthor).forEach(function(author) {
|
|
41
|
-
var dTags = byAuthor[author];
|
|
42
|
-
nostrNet.subscribe(
|
|
43
|
-
'joined-server-' + author.slice(0, 8),
|
|
44
|
-
[{ kinds: [34550], authors: [author], '#d': dTags }],
|
|
45
|
-
function(event) { serverManager._handleServerEvent(event); },
|
|
46
|
-
function() {}
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {}
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
_handleServerEvent: function(event) {
|
|
54
|
-
var nameTag = event.tags.find(function(t) { return t[0] === 'name'; });
|
|
55
|
-
var colorTag = event.tags.find(function(t) { return t[0] === 'color'; });
|
|
56
|
-
var dTag = event.tags.find(function(t) { return t[0] === 'd'; });
|
|
57
|
-
if (!dTag) return;
|
|
58
|
-
var serverId = event.pubkey + ':' + dTag[1];
|
|
59
|
-
var name = nameTag ? nameTag[1] : serverId.slice(0, 8);
|
|
60
|
-
var iconColor = colorTag ? colorTag[1] : '#5865F2';
|
|
61
|
-
var existing = state.servers.find(function(s) { return s.id === serverId; });
|
|
62
|
-
if (existing) {
|
|
63
|
-
existing.name = name; existing.iconColor = iconColor; existing.ownerId = event.pubkey;
|
|
64
|
-
state.servers = state.servers.slice();
|
|
65
|
-
} else {
|
|
66
|
-
state.servers = state.servers.concat([{ id: serverId, name: name, iconColor: iconColor, ownerId: event.pubkey }]);
|
|
67
|
-
}
|
|
68
|
-
serverManager._persistServers();
|
|
69
|
-
ui.render.all();
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
create: async function(name, iconColor) {
|
|
73
|
-
var dTag = Math.random().toString(36).slice(2, 10);
|
|
74
|
-
var serverId = state.nostrPubkey + ':' + dTag;
|
|
75
|
-
var template = { kind: 34550, created_at: Math.floor(Date.now() / 1000), tags: [['d', dTag], ['name', name], ['color', iconColor || '#5865F2']], content: '' };
|
|
76
|
-
var signed = await auth.sign(template);
|
|
77
|
-
await nostrNet.publish(signed);
|
|
78
|
-
var server = { id: serverId, name: name, iconColor: iconColor || '#5865F2', ownerId: state.nostrPubkey };
|
|
79
|
-
state.servers = state.servers.concat([server]);
|
|
80
|
-
serverManager._persistServers();
|
|
81
|
-
serverManager.switchTo(serverId);
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
join: async function(serverId) {
|
|
85
|
-
try {
|
|
86
|
-
var joined = JSON.parse(localStorage.getItem('zn_joined_servers') || '[]');
|
|
87
|
-
if (!joined.includes(serverId)) { joined.push(serverId); localStorage.setItem('zn_joined_servers', JSON.stringify(joined)); }
|
|
88
|
-
} catch (e) {}
|
|
89
|
-
if (!state.servers.find(function(s) { return s.id === serverId; })) {
|
|
90
|
-
state.servers = state.servers.concat([{ id: serverId, name: serverId.slice(0, 8), iconColor: '#5865F2' }]);
|
|
91
|
-
serverManager._persistServers();
|
|
92
|
-
}
|
|
93
|
-
serverManager.switchTo(serverId);
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
delete: async function(serverId) {
|
|
97
|
-
state.servers = (state.servers || []).filter(function(s) { return s.id !== serverId; });
|
|
98
|
-
serverManager._persistServers();
|
|
99
|
-
try {
|
|
100
|
-
var joined = JSON.parse(localStorage.getItem('zn_joined_servers') || '[]');
|
|
101
|
-
localStorage.setItem('zn_joined_servers', JSON.stringify(joined.filter(function(id) { return id !== serverId; })));
|
|
102
|
-
} catch (e) {}
|
|
103
|
-
if (state.currentServerId === serverId) serverManager.switchTo(null);
|
|
104
|
-
else ui.render.all();
|
|
105
|
-
},
|
|
106
|
-
|
|
107
|
-
leave: function(serverId) { serverManager.delete(serverId); },
|
|
108
|
-
switchTo: async function(serverId) {
|
|
109
|
-
state.currentServerId = serverId;
|
|
110
|
-
state.chatMessages = []; state.channels = []; state.categories = [];
|
|
111
|
-
if (window.serverRoles) serverRoles.subscribe(serverId);
|
|
112
|
-
if (window.serverSettings) serverSettings.subscribe(serverId);
|
|
113
|
-
if (window.serverPages) serverPages.subscribe(serverId);
|
|
114
|
-
if (serverId) localStorage.setItem('zn_lastServer', serverId);
|
|
115
|
-
else localStorage.removeItem('zn_lastServer');
|
|
116
|
-
if (window.channelManager && serverId) {
|
|
117
|
-
await new Promise(function(resolve) {
|
|
118
|
-
var done = false;
|
|
119
|
-
var finish = function() { if (done) return; done = true; if (!(state.channels || []).length) channelManager._setDefaults(); resolve(); };
|
|
120
|
-
channelManager.loadChannels(serverId, finish);
|
|
121
|
-
setTimeout(finish, 3000);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
var firstText = (state.channels || []).find(function(c) { return c.type === 'text'; });
|
|
125
|
-
if (firstText && state.currentChannelId !== firstText.id) {
|
|
126
|
-
state.currentChannelId = firstText.id; state.currentChannel = firstText;
|
|
127
|
-
if (window.chat) chat.loadHistory(firstText.id);
|
|
128
|
-
}
|
|
129
|
-
ui.render.all();
|
|
130
|
-
},
|
|
131
|
-
_persistServers: function() { localStorage.setItem('zn_servers', JSON.stringify(state.servers)); },
|
|
132
|
-
init: function() {
|
|
133
|
-
serverManager.loadServers();
|
|
134
|
-
var lastServer = localStorage.getItem('zn_lastServer');
|
|
135
|
-
if (lastServer && state.servers.find(function(s) { return s.id === lastServer; })) serverManager.switchTo(lastServer);
|
|
136
|
-
else if (state.servers.length) serverManager.switchTo(state.servers[0].id);
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
_getOrder: function() { try { return JSON.parse(localStorage.getItem('zn_serverOrder') || '[]'); } catch(e) { return []; } },
|
|
140
|
-
_saveOrder: function(ids) { localStorage.setItem('zn_serverOrder', JSON.stringify(ids)); },
|
|
141
|
-
|
|
142
|
-
_sortedServers: function() {
|
|
143
|
-
var srvs = state.servers || [];
|
|
144
|
-
var order = serverManager._getOrder();
|
|
145
|
-
if (!order.length) return srvs;
|
|
146
|
-
var indexed = {};
|
|
147
|
-
order.forEach(function(id, i) { indexed[id] = i; });
|
|
148
|
-
return srvs.slice().sort(function(a, b) {
|
|
149
|
-
var ai = indexed[a.id] !== undefined ? indexed[a.id] : Infinity;
|
|
150
|
-
var bi = indexed[b.id] !== undefined ? indexed[b.id] : Infinity;
|
|
151
|
-
return ai - bi;
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
renderList: function() {
|
|
156
|
-
var container = document.getElementById('serverIcons');
|
|
157
|
-
if (!container) return;
|
|
158
|
-
var srvs = serverManager._sortedServers();
|
|
159
|
-
var current = state.currentServerId;
|
|
160
|
-
var currentServer = current && srvs.find(function(s) { return s.id === current; });
|
|
161
|
-
var headerEl = document.getElementById('serverHeaderName');
|
|
162
|
-
if (headerEl) headerEl.textContent = currentServer ? currentServer.name : 'Zellous';
|
|
163
|
-
var colors = ['#5865f2', '#57f287', '#feb347', '#fe7168', '#9b59b6', '#1abc9c', '#e67e22', '#e74c3c'];
|
|
164
|
-
var html = '';
|
|
165
|
-
srvs.forEach(function(s) {
|
|
166
|
-
var active = s.id === current ? ' active' : '';
|
|
167
|
-
var color = s.iconColor || colors[s.name.length % colors.length];
|
|
168
|
-
var initial = (s.name || '?')[0].toUpperCase();
|
|
169
|
-
html += '<div class="server-icon' + active + '" draggable="true" data-server="' + s.id + '" title="' + s.name + '" style="background:' + (active ? '' : color) + '">' +
|
|
170
|
-
'<div class="server-pill"></div>' + initial + '</div>';
|
|
171
|
-
});
|
|
172
|
-
html += '<div class="server-separator" id="serverSeparator"></div>' +
|
|
173
|
-
'<div class="server-icon add-server" id="addServerBtn" title="Add a Server"><div class="server-pill"></div>+</div>';
|
|
174
|
-
container.innerHTML = html;
|
|
175
|
-
var homeIcon = document.getElementById('homeServer');
|
|
176
|
-
if (homeIcon) {
|
|
177
|
-
homeIcon.classList.toggle('active', !current);
|
|
178
|
-
homeIcon.addEventListener('click', function() { serverManager.switchTo(null); });
|
|
179
|
-
}
|
|
180
|
-
container.querySelectorAll('[data-server]').forEach(function(el) {
|
|
181
|
-
el.addEventListener('click', function() { serverManager.switchTo(el.dataset.server); });
|
|
182
|
-
el.addEventListener('contextmenu', function(e) { e.preventDefault(); serverManager.showContextMenu(el.dataset.server, e.clientX, e.clientY); });
|
|
183
|
-
});
|
|
184
|
-
var addBtn = document.getElementById('addServerBtn');
|
|
185
|
-
if (addBtn) addBtn.addEventListener('click', function() { serverManager.showCreateModal(); });
|
|
186
|
-
serverManager._initDragDrop(container);
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
_initDragDrop: function(container) {
|
|
190
|
-
var dragId = null;
|
|
191
|
-
container.addEventListener('dragstart', function(e) {
|
|
192
|
-
var el = e.target.closest('[data-server]');
|
|
193
|
-
if (!el) return;
|
|
194
|
-
dragId = el.dataset.server; e.dataTransfer.effectAllowed = 'move';
|
|
195
|
-
setTimeout(function() { el.classList.add('dragging'); }, 0);
|
|
196
|
-
});
|
|
197
|
-
container.addEventListener('dragend', function() {
|
|
198
|
-
container.querySelectorAll('.dragging').forEach(function(el) { el.classList.remove('dragging'); });
|
|
199
|
-
container.querySelectorAll('.drag-over').forEach(function(el) { el.classList.remove('drag-over'); });
|
|
200
|
-
dragId = null;
|
|
201
|
-
});
|
|
202
|
-
container.addEventListener('dragover', function(e) {
|
|
203
|
-
e.preventDefault(); e.dataTransfer.dropEffect = 'move';
|
|
204
|
-
var target = e.target.closest('[data-server]');
|
|
205
|
-
container.querySelectorAll('.drag-over').forEach(function(el) { el.classList.remove('drag-over'); });
|
|
206
|
-
if (target && target.dataset.server !== dragId) target.classList.add('drag-over');
|
|
207
|
-
});
|
|
208
|
-
container.addEventListener('drop', function(e) {
|
|
209
|
-
e.preventDefault();
|
|
210
|
-
var target = e.target.closest('[data-server]');
|
|
211
|
-
if (!target || !dragId || target.dataset.server === dragId) return;
|
|
212
|
-
var srvs = serverManager._sortedServers();
|
|
213
|
-
var ids = srvs.map(function(s) { return s.id; });
|
|
214
|
-
var fromIdx = ids.indexOf(dragId), toIdx = ids.indexOf(target.dataset.server);
|
|
215
|
-
if (fromIdx === -1 || toIdx === -1) return;
|
|
216
|
-
ids.splice(fromIdx, 1); ids.splice(toIdx, 0, dragId);
|
|
217
|
-
serverManager._saveOrder(ids); serverManager.renderList();
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
window.__zellous.servers = serverManager;
|
|
223
|
-
window.serverManager = serverManager;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
var serverSettings = {
|
|
2
|
-
_store: new Map(),
|
|
3
|
-
_sub: null,
|
|
4
|
-
_VALID_BITRATES: [8000, 16000, 24000, 48000, 96000],
|
|
5
|
-
|
|
6
|
-
_clampBitrate(v) {
|
|
7
|
-
return serverSettings._VALID_BITRATES.reduce(function(prev, cur) {
|
|
8
|
-
return Math.abs(cur - v) < Math.abs(prev - v) ? cur : prev;
|
|
9
|
-
});
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
getBitrate(serverId) {
|
|
13
|
-
var s = serverSettings._store.get(serverId);
|
|
14
|
-
return (s && s.opusBitrate) || 24000;
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
async setBitrate(serverId, bitrate) {
|
|
18
|
-
if (!serverRoles.isOwner(serverId) && !serverRoles.isAdmin(serverId)) throw new Error('Insufficient permissions');
|
|
19
|
-
var clamped = serverSettings._clampBitrate(Number(bitrate));
|
|
20
|
-
var existing = serverSettings._store.get(serverId) || {};
|
|
21
|
-
var next = Object.assign({}, existing, { opusBitrate: clamped });
|
|
22
|
-
serverSettings._store.set(serverId, next);
|
|
23
|
-
var dTag = 'zellous-settings:' + serverId;
|
|
24
|
-
var signed = await auth.sign({ kind: 30078, created_at: Math.floor(Date.now() / 1000), tags: [['d', dTag]], content: JSON.stringify(next) });
|
|
25
|
-
await nostrNet.publish(signed);
|
|
26
|
-
if (state.audioEncoder) {
|
|
27
|
-
try { state.audioEncoder.configure({ codec: 'opus', sampleRate: config.sampleRate, numberOfChannels: 1, bitrate: clamped }); } catch(e) {}
|
|
28
|
-
}
|
|
29
|
-
return clamped;
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
getEmbedAllowlist(serverId) {
|
|
33
|
-
var s = serverSettings._store.get(serverId);
|
|
34
|
-
return (s && s.embedAllowlist) ? (typeof s.embedAllowlist === 'string' ? s.embedAllowlist.split(',').map(function(d) { return d.trim(); }).filter(Boolean) : s.embedAllowlist) : [];
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
async setEmbedAllowlist(serverId, domainsStr) {
|
|
38
|
-
if (!serverRoles.isOwner(serverId) && !serverRoles.isAdmin(serverId)) throw new Error('Insufficient permissions');
|
|
39
|
-
var domains = domainsStr.split(',').map(function(d) { return d.trim(); }).filter(Boolean);
|
|
40
|
-
var existing = serverSettings._store.get(serverId) || {};
|
|
41
|
-
var next = Object.assign({}, existing, { embedAllowlist: domains });
|
|
42
|
-
serverSettings._store.set(serverId, next);
|
|
43
|
-
var dTag = 'zellous-settings:' + serverId;
|
|
44
|
-
var signed = await auth.sign({ kind: 30078, created_at: Math.floor(Date.now() / 1000), tags: [['d', dTag]], content: JSON.stringify(next) });
|
|
45
|
-
await nostrNet.publish(signed);
|
|
46
|
-
return domains;
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
isOriginAllowed(serverId, origin) {
|
|
50
|
-
if (!origin) return false;
|
|
51
|
-
var allowlist = serverSettings.getEmbedAllowlist(serverId);
|
|
52
|
-
if (allowlist.length === 0) return true;
|
|
53
|
-
var url = {};
|
|
54
|
-
try { url = new URL(origin); } catch(e) { return false; }
|
|
55
|
-
var hostname = url.hostname;
|
|
56
|
-
return allowlist.some(function(pattern) {
|
|
57
|
-
if (pattern === '*') return true;
|
|
58
|
-
if (pattern.startsWith('*.')) {
|
|
59
|
-
var suffix = pattern.slice(2);
|
|
60
|
-
return hostname === suffix || hostname.endsWith('.' + suffix);
|
|
61
|
-
}
|
|
62
|
-
return hostname === pattern || hostname === pattern.replace('https://', '').replace('http://', '');
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
subscribe(serverId) {
|
|
67
|
-
if (serverSettings._sub) { nostrNet.unsubscribe(serverSettings._sub); serverSettings._sub = null; }
|
|
68
|
-
if (!serverId) return;
|
|
69
|
-
var creator = serverId.split(':')[0];
|
|
70
|
-
if (!creator) return;
|
|
71
|
-
var dTag = 'zellous-settings:' + serverId;
|
|
72
|
-
serverSettings._sub = 'settings-' + serverId;
|
|
73
|
-
nostrNet.subscribe(serverSettings._sub,
|
|
74
|
-
[{ kinds: [30078], authors: [creator], '#d': [dTag] }],
|
|
75
|
-
function(event) {
|
|
76
|
-
if (event.pubkey !== creator) return;
|
|
77
|
-
try {
|
|
78
|
-
var data = JSON.parse(event.content);
|
|
79
|
-
serverSettings._store.set(serverId, data);
|
|
80
|
-
} catch(e) {}
|
|
81
|
-
},
|
|
82
|
-
function() {}
|
|
83
|
-
);
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
applyToEncoder() {
|
|
87
|
-
var bitrate = serverSettings.getBitrate(state.currentServerId);
|
|
88
|
-
if (state.audioEncoder) {
|
|
89
|
-
try { state.audioEncoder.configure({ codec: 'opus', sampleRate: config.sampleRate, numberOfChannels: 1, bitrate: bitrate }); } catch(e) {}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
window.__zellous.settings = serverSettings;
|
|
95
|
-
window.serverSettings = serverSettings;
|
|
96
|
-
if (!window.__debug) window.__debug = {};
|
|
97
|
-
Object.defineProperty(window.__debug, 'settings', { get: function() { return { store: Object.fromEntries(serverSettings._store), sub: serverSettings._sub }; }, configurable: true });
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
(() => {
|
|
2
|
-
const sig = window.__signal;
|
|
3
|
-
const raw = window.stateSignals;
|
|
4
|
-
|
|
5
|
-
raw.nostrPubkey = sig('');
|
|
6
|
-
raw.nostrPrivkey = sig(null);
|
|
7
|
-
raw.nostrRelays = sig([
|
|
8
|
-
'wss://relay.damus.io',
|
|
9
|
-
'wss://relay.primal.net',
|
|
10
|
-
'wss://relay.snort.social',
|
|
11
|
-
'wss://nos.lol',
|
|
12
|
-
'wss://relay.olas.app',
|
|
13
|
-
'wss://nostr.mom'
|
|
14
|
-
]);
|
|
15
|
-
raw.nostrRelayStatus = sig(new Map());
|
|
16
|
-
raw.nostrProfile = sig(null);
|
|
17
|
-
raw.nostrSubscriptions = sig(new Map());
|
|
18
|
-
raw.currentChannelId = sig(null);
|
|
19
|
-
})();
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
var nostrVoiceCamera = {
|
|
2
|
-
_fsm: null,
|
|
3
|
-
|
|
4
|
-
_initFSM: function() {
|
|
5
|
-
var actor = XState.createActor(nostrFsm.cameraMachine);
|
|
6
|
-
actor.subscribe(function(snap) {
|
|
7
|
-
var state_val = snap.value;
|
|
8
|
-
document.getElementById('voiceCamBtn')?.classList.toggle('active', state_val === 'active');
|
|
9
|
-
});
|
|
10
|
-
actor.start();
|
|
11
|
-
nostrVoiceCamera._fsm = actor;
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
toggle() {
|
|
15
|
-
if (!nostrVoiceCamera._fsm) nostrVoiceCamera._initFSM();
|
|
16
|
-
var snap = nostrVoiceCamera._fsm.getSnapshot();
|
|
17
|
-
if (snap.matches('active')) {
|
|
18
|
-
nostrVoiceCamera.stop();
|
|
19
|
-
} else if (snap.matches('idle')) {
|
|
20
|
-
nostrVoiceCamera.start();
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
async start() {
|
|
25
|
-
if (!nostrVoiceCamera._fsm) nostrVoiceCamera._initFSM();
|
|
26
|
-
var snap = nostrVoiceCamera._fsm.getSnapshot();
|
|
27
|
-
if (!snap.can({type:'enable'})) return;
|
|
28
|
-
nostrVoiceCamera._fsm.send({type:'enable'});
|
|
29
|
-
state.cameraEnabled = true;
|
|
30
|
-
if (nostrVoice._cameraStream) {
|
|
31
|
-
var track = nostrVoice._cameraStream.getVideoTracks()[0];
|
|
32
|
-
nostrVoice._peers.forEach(function(peer) {
|
|
33
|
-
var sender = peer.pc.getSenders().find(function(s) { return s.track && s.track.kind === 'video'; });
|
|
34
|
-
if (sender) { sender.replaceTrack(track).catch(function(){}); }
|
|
35
|
-
else { peer.pc.addTrack(track, nostrVoice._cameraStream); }
|
|
36
|
-
});
|
|
37
|
-
var local = nostrVoice._participants.get('local');
|
|
38
|
-
if (local) local.hasVideo = true;
|
|
39
|
-
nostrVoiceCamera._fsm.send({type:'enabled'});
|
|
40
|
-
nostrVoice.updateParticipants();
|
|
41
|
-
} else {
|
|
42
|
-
nostrVoiceCamera._fsm.send({type:'denied'});
|
|
43
|
-
state.cameraEnabled = false;
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
stop() {
|
|
48
|
-
if (!nostrVoiceCamera._fsm) nostrVoiceCamera._initFSM();
|
|
49
|
-
if (!nostrVoiceCamera._fsm.getSnapshot().can({type:'disable'})) return;
|
|
50
|
-
nostrVoiceCamera._fsm.send({type:'disable'});
|
|
51
|
-
state.cameraEnabled = false;
|
|
52
|
-
nostrVoice._peers.forEach(function(peer) {
|
|
53
|
-
var sender = peer.pc.getSenders().find(function(s) { return s.track && s.track.kind === 'video'; });
|
|
54
|
-
if (sender) { sender.replaceTrack(null).catch(function(){}); }
|
|
55
|
-
});
|
|
56
|
-
var local = nostrVoice._participants.get('local');
|
|
57
|
-
if (local) local.hasVideo = false;
|
|
58
|
-
nostrVoice.updateParticipants();
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
window.__zellous.voiceCamera = nostrVoiceCamera;
|
|
63
|
-
window.nostrVoiceCamera = nostrVoiceCamera;
|