diff --git a/src/agent-tools.ts b/src/agent-tools.ts index d70e169..e18b707 100644 --- a/src/agent-tools.ts +++ b/src/agent-tools.ts @@ -626,7 +626,9 @@ export const NETWORKS_TOOL: Tool = { description: "For set_signaling_servers / set_stun_servers: array of URL strings. " + "For set_turn_servers: array of {url, username?, credential?} objects. " + - "Empty array clears the list (Trystero / Google defaults will be used).", + "Empty array clears the list — an empty signaling list still falls back " + + "to the default wss://myownmesh.com relay; empty STUN/TURN opts out of " + + "that helper.", }, }, required: ["action"], @@ -1054,8 +1056,9 @@ const NETWORKS_TOOL_SNIPPET: string = "(status, peers, saved networks, accepting policy, diagnostic log, " + "signaling/STUN/TURN servers, import/export of portable settings).\n\n" + "How the mesh works:\n" + - "- Devices that share a Network ID find each other through public Nostr relays " + - "(or a self-hosted one) and connect peer-to-peer over WebRTC.\n" + + "- Devices that share a Network ID find each other through the default " + + "wss://myownmesh.com relay (or your own) over Nostr, then connect " + + "peer-to-peer over WebRTC.\n" + "- Joining still requires explicit approval per device, gated by a 6-char " + "verification code that both sides should read out and confirm.\n" + "- The user can save multiple networks; exactly one is active at a time.\n" + @@ -1080,8 +1083,11 @@ const NETWORKS_TOOL_SNIPPET: string = "- `action='export_settings'` returns the same envelope for the active (or " + "named) network, ready to share to another device.\n" + "- `action='set_signaling_servers' / 'set_stun_servers' / 'set_turn_servers'` " + - "replace the respective list on a network. Empty array restores defaults " + - "(Trystero public Nostr relays / Google STUN / no TURN)."; + "replace the respective list on a network. New networks ship the MyOwnMesh " + + "defaults (signaling wss://myownmesh.com, STUN stun.myownmesh.com:3478, TURN " + + "turn.myownmesh.com:3478 with the shared guest credential). Passing an empty " + + "array clears that list — an empty signaling list still falls back to " + + "wss://myownmesh.com; empty STUN/TURN opts out of that helper."; const WEB_SEARCH_TOOL_SNIPPET: string = "## `web_search` tool — search the web\n\n" + diff --git a/src/config.ts b/src/config.ts index 8b9d24e..003bb8b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -56,18 +56,30 @@ const DEFAULT_REMOTE_UI: RemoteUiConfig = { port: 1474, }; -// Signaling is handled by Trystero over Nostr relays. The default -// per-network `signaling_servers` list is empty so the mesh client -// uses Trystero's built-in 52-relay public pool, bumped to -// redundancy 8 at connect time (see `DEFAULT_SIGNALING_REDUNDANCY` -// in mesh-client.svelte.ts). Anyone who wants to point at a -// self-hosted Nostr relay (or a private one for office/LAN use) -// adds entries from the Cloud Mesh → Addresses tab and those -// replace the default pool entirely. STUN servers default to -// Google's public pool, which is the de-facto baseline. +// Per-network transport defaults. The frontend bridges each saved +// network into the bundled `myownmesh serve` daemon (see +// `networkConfigToDaemonShape`), which owns signaling / ICE. Every +// new network is seeded with the project's semi-public MyOwnMesh +// defaults so a fresh install connects out of the box AND the user +// can see what it's using in Settings → Cloud Mesh → Addresses +// rather than staring at an empty list: +// +// - signaling → wss://myownmesh.com — the reference Nostr relay, +// reached over standard wss:// (443) so it sails through +// restrictive firewalls. The daemon resolves an empty list to +// this same relay, so seeding it explicitly is purely so the +// value is visible and editable in the UI. +// - STUN → stun.myownmesh.com:3478 — server-reflexive discovery. +// - TURN → turn.myownmesh.com:3478 with the shared guest +// credential, so symmetric-NAT / CGNAT peers (phone hotspots) +// relay out of the box. Bandwidth-capped and the credential is +// deliberately not a secret; point at your own server for +// sustained throughput. +// +// All three are overridable per-network from the Addresses tab. // // Legacy entries from earlier PeerJS-based commits get stripped -// on load so testers don't end up pointing Trystero at a +// on load so testers don't end up pointing the relay layer at a // peerjs-server URL it can't speak to. const LEGACY_PEERJS_SIGNALING_URLS = [ "wss://0.peerjs.com:443/", @@ -75,17 +87,36 @@ const LEGACY_PEERJS_SIGNALING_URLS = [ "wss://mesh.myownllm.net/signal", ]; -/** Defaults for newly-added networks. Empty signaling = Trystero's - * public Nostr relays; Google's STUN pool for NAT helpers; empty - * per-network TURN by default. Applied by `createNetwork` and by - * the legacy-config migration so a pre-multi-network install - * lands with sane per-network defaults. */ -export const DEFAULT_NETWORK_SIGNALING: string[] = []; -export const DEFAULT_NETWORK_STUN: string[] = [ +/** The pre-MyOwnMesh STUN default (Google's public pool). A network + * still carrying exactly this list never made a deliberate STUN + * choice — it's just the old baseline — so it's upgraded to the + * current default on load. A customised list (anything added or + * removed) won't match and is left untouched. */ +const LEGACY_GOOGLE_STUN: string[] = [ "stun:stun.l.google.com:19302", "stun:stun1.l.google.com:19302", ]; +/** Default signaling relay for newly-added networks: the project's + * reference relay over standard wss:// (443). The daemon resolves an + * empty list to the same relay, so this exists mainly so the value + * is visible in the UI. */ +export const DEFAULT_NETWORK_SIGNALING: string[] = ["wss://myownmesh.com"]; +/** Default STUN servers for newly-added networks — the project's + * reference STUN for server-reflexive NAT discovery. */ +export const DEFAULT_NETWORK_STUN: string[] = ["stun:stun.myownmesh.com:3478"]; +/** Default TURN servers for newly-added networks — the project's + * reference TURN with its shared semi-public guest credential, so + * symmetric-NAT / CGNAT peers relay out of the box. Bandwidth-capped; + * point at your own server for sustained throughput. */ +export const DEFAULT_NETWORK_TURN: TurnServer[] = [ + { + url: "turn:turn.myownmesh.com:3478", + username: "guest", + credential: "theguestpassword", + }, +]; + const DEFAULT_CLOUD_MESH: CloudMeshConfig = { enabled: false, networks: [], @@ -515,11 +546,26 @@ function coerceAccepting(raw: unknown): NetworkConfig["accepting"] { } /** Strip legacy PeerJS signaling URLs that may linger in old - * configs from a pre-Trystero branch commit. */ + * configs from a pre-daemon branch commit. */ function cleanSignaling(raw: string[] | undefined): string[] { return (raw ?? []).filter((s) => !LEGACY_PEERJS_SIGNALING_URLS.includes(s)); } +/** STUN list for a saved/added network. Fills the MyOwnMesh default + * when the field is absent (a fresh network) and upgrades the exact + * legacy Google default to the current one. Any other explicit list + * — including a deliberately-empty opt-out (`[]`) — is preserved. */ +function defaultedStun(raw: string[] | undefined): string[] { + if (raw === undefined) return [...DEFAULT_NETWORK_STUN]; + if ( + raw.length === LEGACY_GOOGLE_STUN.length && + raw.every((u, i) => u === LEGACY_GOOGLE_STUN[i]) + ) { + return [...DEFAULT_NETWORK_STUN]; + } + return raw; +} + /** Build a `NetworkConfig` from a partial saved entry, filling * per-network defaults. Used both for normal loads (where most * fields are present) and for the legacy single-network migration @@ -544,9 +590,18 @@ function mergeNetwork( const net: NetworkConfig = { id: raw.id || newNetworkInternalId(), network_id: raw.network_id || "", - signaling_servers: cleanSignaling(raw.signaling_servers), - stun_servers: raw.stun_servers ?? [...DEFAULT_NETWORK_STUN], - turn_servers: raw.turn_servers ?? [], + // Absent transport fields seed the MyOwnMesh defaults (a fresh + // network); an explicit list on disk — including an empty + // opt-out — is preserved. Signaling is left empty when the saved + // value is empty (the daemon resolves that to wss://myownmesh.com + // anyway), but a brand-new network gets it spelled out so it's + // visible in the Addresses tab. + signaling_servers: + raw.signaling_servers === undefined + ? [...DEFAULT_NETWORK_SIGNALING] + : cleanSignaling(raw.signaling_servers), + stun_servers: defaultedStun(raw.stun_servers), + turn_servers: raw.turn_servers ?? [...DEFAULT_NETWORK_TURN], accepting: coerceAccepting(raw.accepting), // Default to enabled so existing networks (saved before this // field existed) keep their pre-toggle "auto-sync everywhere" diff --git a/src/types.ts b/src/types.ts index 59c070d..672dd7c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -275,9 +275,13 @@ export interface NetworkConfig { auto_approve?: boolean; /** Per-network signaling / NAT settings. Each network can point * at a different relay pool — home / office / public mesh all - * configurable independently. Empty signaling = Trystero's - * built-in Nostr default pool at redundancy 8; empty stun = no - * NAT helpers; empty turn = no relay fallback. */ + * configurable independently. New networks are seeded with the + * MyOwnMesh defaults (signaling `wss://myownmesh.com`, STUN + * `stun.myownmesh.com:3478`, TURN `turn.myownmesh.com:3478` with + * the shared guest credential) so they connect out of the box; + * each list is overridable from the Addresses tab. An empty + * signaling list still resolves to `wss://myownmesh.com` in the + * daemon; an empty stun / turn list opts out of that helper. */ signaling_servers: string[]; stun_servers: string[]; turn_servers: TurnServer[]; diff --git a/src/ui/settings/AddNetworkModal.svelte b/src/ui/settings/AddNetworkModal.svelte index 93a0a79..962986b 100644 --- a/src/ui/settings/AddNetworkModal.svelte +++ b/src/ui/settings/AddNetworkModal.svelte @@ -28,7 +28,9 @@ import { onMount } from "svelte"; import { addNetwork, + DEFAULT_NETWORK_SIGNALING, DEFAULT_NETWORK_STUN, + DEFAULT_NETWORK_TURN, importNetworkSettings, tryParseNetworkSettings, type NetworkSettingsExport, @@ -55,9 +57,9 @@ // (which carries transport fields end-to-end) instead of the // simple `addNetwork` path. let advancedExpanded = $state(false); - let signalingDraft = $state([]); + let signalingDraft = $state([...DEFAULT_NETWORK_SIGNALING]); let stunDraft = $state([...DEFAULT_NETWORK_STUN]); - let turnDraft = $state([]); + let turnDraft = $state(DEFAULT_NETWORK_TURN.map((t) => ({ ...t }))); let turnEntry = $state({ url: "", username: "", credential: "" }); // Import flow state. Either a parsed blob ready to apply or null @@ -71,10 +73,10 @@ // a plain new network or applying transport overrides. let hasOverrides = $derived( importDraft !== null || - signalingDraft.some((s) => s.trim() !== "") || - // Custom STUN list = different from defaults. + // Any edit away from the seeded MyOwnMesh defaults. + JSON.stringify(signalingDraft) !== JSON.stringify(DEFAULT_NETWORK_SIGNALING) || JSON.stringify(stunDraft) !== JSON.stringify(DEFAULT_NETWORK_STUN) || - turnDraft.length > 0, + JSON.stringify(turnDraft) !== JSON.stringify(DEFAULT_NETWORK_TURN), ); onMount(() => { @@ -274,10 +276,13 @@ {#if advancedExpanded}

- Optional. Leave blank to use Trystero's public Nostr relays - and Google's STUN pool. Override here when you want a - private relay, a custom STUN, or TURN for symmetric-NAT - peers (phone hotspot / CGNAT). + Optional. These are seeded with the MyOwnMesh defaults — + signaling wss://myownmesh.com, STUN + stun.myownmesh.com, and the shared-guest TURN + relay turn.myownmesh.com — so a fresh network + connects out of the box, even for symmetric-NAT peers (phone + hotspot / CGNAT). Override here to point at a private relay, + your own STUN, or your own TURN server.

@@ -379,7 +384,7 @@
signaling
{importDraft.signaling_servers.length === 0 - ? "(default pool)" + ? "(default · wss://myownmesh.com)" : importDraft.signaling_servers.join(", ")}
STUN
diff --git a/src/ui/settings/CloudMeshAddresses.svelte b/src/ui/settings/CloudMeshAddresses.svelte index 7d28178..1466a96 100644 --- a/src/ui/settings/CloudMeshAddresses.svelte +++ b/src/ui/settings/CloudMeshAddresses.svelte @@ -357,13 +357,14 @@ {#if editing}for {editing.network_id}{/if}
- Networks use Trystero - for peer discovery — currently over Nostr relays. By default - Trystero picks from a built-in pool of public relays - maintained by the Nostr community, so MyOwnLLM operates no - signaling infrastructure of its own. Add your own relay - URLs below to use specific or self-hosted relays instead; - leave the list empty to keep the defaults. + Peers rendezvous over Nostr relays. By default a network uses + the project's reference relay + wss://myownmesh.com (standard wss:// + on 443, so it clears restrictive firewalls), with a reactive + fallback to a pool of public community relays only while the + default can't be reached. Add your own relay URLs below to pin + specific or self-hosted relays instead; leave the list empty to + keep the default.
{#each signalingRelays as _, i (i)} @@ -396,10 +397,10 @@

A Nostr relay is a tiny WebSocket service that proxies - signed messages between subscribed clients — Trystero - piggybacks on this to relay WebRTC offers/answers - between MyOwnLLM peers. The relay never sees mesh - content, only the small offer/answer envelopes during + signed messages between subscribed clients — the mesh + signaling driver piggybacks on this to relay WebRTC + offers/answers between MyOwnLLM peers. The relay never sees + mesh content, only the small offer/answer envelopes during connection setup.

@@ -426,7 +427,7 @@

More featureful, persists messages across restarts - (which Trystero doesn't need but doesn't hurt). + (which the signaling driver doesn't need but doesn't hurt).

docker run -d -p 8080:8080 scsibug/nostr-rs-relay @@ -453,8 +454,10 @@ {#if editing}for {editing.network_id}{/if}
- Public NAT-traversal helpers. Defaults to Google's public STUN - pool, which works for the majority of home networks. + Public NAT-traversal helpers. Defaults to the project's + reference STUN, stun:stun.myownmesh.com:3478, + which works for the majority of home networks. Leave the list + empty to skip STUN.
{#each stunServers as _, i (i)} @@ -483,11 +486,13 @@
Relay servers used when direct peer connections can't be - established. Required for peers behind symmetric NAT (phone + established — required for peers behind symmetric NAT (phone hotspots, carrier-grade NAT, restrictive corporate or guest - Wi-Fi) because STUN-only hole-punching can't traverse those. - TURN consumes real bandwidth, so there's no free - no-signup public service that reliably stays up. Use one of: + Wi-Fi), where STUN-only hole-punching can't traverse. New + networks default to the project's shared-guest relay + turn:turn.myownmesh.com:3478 so this works out of + the box. That relay is bandwidth-capped per connection, so for + sustained throughput point at your own: