Add standalone browser mode: no daemon required
BrowserAdapter speaks yaw/2.1 signaling + WebRTC protocol entirely in the browser (libsodium-wrappers for Ed25519/X25519). Identity stored in localStorage; peers connect via any waste/yaw2 anchor. When served from a non-localhost origin the app defaults to browser mode. On localhost the daemon adapter is tried first with a one-click switch to browser mode. config.js (gitignored, served by anchor) lets the host pre-inject signalURL and other defaults. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { create } from 'zustand'
|
||||
import type { PeerInfo, NetworkInfo, ChatMessage, FileEntry, IpcMessage } from '../types'
|
||||
import { DaemonAdapter } from '../adapter/daemon'
|
||||
import { BrowserAdapter } from '../adapter/browser'
|
||||
|
||||
type AnyAdapter = DaemonAdapter | BrowserAdapter
|
||||
|
||||
interface WasteState {
|
||||
// connection
|
||||
adapter: DaemonAdapter | null
|
||||
adapter: AnyAdapter | null
|
||||
adapterMode: 'daemon' | 'browser' | null
|
||||
daemonStatus: 'disconnected' | 'connecting' | 'connected'
|
||||
|
||||
// identity
|
||||
@@ -31,6 +35,7 @@ interface WasteState {
|
||||
|
||||
// actions
|
||||
connect: (url: string) => void
|
||||
connectBrowser: () => void
|
||||
disconnect: () => void
|
||||
send: (msg: IpcMessage) => void
|
||||
setActiveNetwork: (id: string) => void
|
||||
@@ -40,6 +45,7 @@ interface WasteState {
|
||||
|
||||
export const useWaste = create<WasteState>((set, get) => ({
|
||||
adapter: null,
|
||||
adapterMode: null,
|
||||
daemonStatus: 'disconnected',
|
||||
masterAlias: null,
|
||||
masterId: null,
|
||||
@@ -57,12 +63,22 @@ export const useWaste = create<WasteState>((set, get) => ({
|
||||
adapter.onStatusChange = (s) => set({ daemonStatus: s })
|
||||
adapter.on((msg) => get().handleEvent(msg))
|
||||
adapter.connect()
|
||||
set({ adapter })
|
||||
set({ adapter, adapterMode: 'daemon' })
|
||||
},
|
||||
|
||||
connectBrowser() {
|
||||
const adapter = new BrowserAdapter()
|
||||
adapter.onStatusChange = (s) => set({ daemonStatus: s })
|
||||
adapter.on((msg) => get().handleEvent(msg))
|
||||
adapter.connect()
|
||||
set({ adapter, adapterMode: 'browser' })
|
||||
},
|
||||
|
||||
disconnect() {
|
||||
get().adapter?.disconnect()
|
||||
set({ adapter: null, daemonStatus: 'disconnected' })
|
||||
const a = get().adapter
|
||||
if (a instanceof DaemonAdapter) a.disconnect()
|
||||
else if (a instanceof BrowserAdapter) a.disconnect()
|
||||
set({ adapter: null, adapterMode: null, daemonStatus: 'disconnected' })
|
||||
},
|
||||
|
||||
send(msg) {
|
||||
@@ -93,11 +109,13 @@ export const useWaste = create<WasteState>((set, get) => ({
|
||||
}
|
||||
case 'network_joined': {
|
||||
set(s => ({
|
||||
localPeer: s.localPeer ?? msg.local_peer ?? null,
|
||||
networks: s.networks.some(n => n.network_id === msg.network_id)
|
||||
? s.networks
|
||||
: [...s.networks, {
|
||||
network_id: msg.network_id!,
|
||||
network_name: msg.network_name!,
|
||||
local_peer: msg.local_peer,
|
||||
share_dir: msg.share_dir,
|
||||
}],
|
||||
activeNetworkId: s.activeNetworkId ?? msg.network_id!,
|
||||
|
||||
Reference in New Issue
Block a user