Fifth library variant that keeps folder sync for offline/local use AND adds Nostr relay sync for cross-device reach via WebSocket. Both transports run simultaneously - writes go to folder AND Nostr, sync imports from both and bridges events between them. Works from file:// since Nostr uses WebSocket (not fetch/WebRTC). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
71 lines
2.2 KiB
TypeScript
71 lines
2.2 KiB
TypeScript
import { FolderSyncDB } from '../../nostr/src/index.ts';
|
|
import { initPasteApp } from '../shared.ts';
|
|
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
const db = await FolderSyncDB.open({ autoSyncIntervalMs: 3000 });
|
|
await initPasteApp(db as any, 'nostr');
|
|
|
|
// ── Nostr room UI ──────────────────────────────────────────
|
|
|
|
const roomInput = document.querySelector('#room-input') as HTMLInputElement;
|
|
const joinBtn = document.querySelector('#join-room') as HTMLButtonElement;
|
|
const nostrStatus = document.querySelector('#nostr-status')!;
|
|
|
|
function updateNostrUI(connected: boolean, room?: string) {
|
|
if (connected && room) {
|
|
nostrStatus.textContent = `Connected: ${room}`;
|
|
nostrStatus.className = 'status ok';
|
|
joinBtn.textContent = 'Leave';
|
|
roomInput.disabled = true;
|
|
} else {
|
|
nostrStatus.textContent = 'Not connected';
|
|
nostrStatus.className = 'status';
|
|
joinBtn.textContent = 'Join room';
|
|
roomInput.disabled = false;
|
|
}
|
|
}
|
|
|
|
joinBtn.addEventListener('click', async () => {
|
|
if (db.isConnected()) {
|
|
db.leaveRoom();
|
|
updateNostrUI(false);
|
|
} else {
|
|
const key = roomInput.value.trim();
|
|
if (!key) {
|
|
nostrStatus.textContent = 'Enter a room key';
|
|
nostrStatus.className = 'status err';
|
|
return;
|
|
}
|
|
try {
|
|
nostrStatus.textContent = 'Connecting...';
|
|
nostrStatus.className = 'status';
|
|
await db.joinRoom(key);
|
|
updateNostrUI(true, key);
|
|
} catch (e: unknown) {
|
|
nostrStatus.textContent = 'Error: ' + (e as Error).message;
|
|
nostrStatus.className = 'status err';
|
|
}
|
|
}
|
|
});
|
|
|
|
roomInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
if (e.key === 'Enter') joinBtn.click();
|
|
});
|
|
|
|
// Restore saved room
|
|
if (db.isConnected()) {
|
|
updateNostrUI(true, db.currentRoom ?? undefined);
|
|
roomInput.value = db.currentRoom ?? '';
|
|
} else {
|
|
updateNostrUI(false);
|
|
}
|
|
|
|
db.on('nostr:connected', (data: any) => {
|
|
updateNostrUI(true, data?.roomKey);
|
|
});
|
|
|
|
db.on('nostr:disconnected', () => {
|
|
updateNostrUI(false);
|
|
});
|
|
});
|