Re-introduce FORCE_RELAYS setting

This commit is contained in:
Jon Staab 2024-02-02 12:25:02 -08:00
parent 4aa1a6cc0a
commit 933fce22cf
20 changed files with 86 additions and 49 deletions

2
.env

File diff suppressed because one or more lines are too long

View File

@ -58,7 +58,7 @@
<h1 class="staatliches text-4xl leading-none">{appName}</h1> <h1 class="staatliches text-4xl leading-none">{appName}</h1>
</Anchor> </Anchor>
<MenuDesktopItem path="/notes">Feed</MenuDesktopItem> <MenuDesktopItem path="/notes">Feed</MenuDesktopItem>
{#if !$env.FORCE_GROUP} {#if !$env.FORCE_GROUP && $env.FORCE_RELAYS.length === 0}
<MenuDesktopItem path="/settings/relays"> <MenuDesktopItem path="/settings/relays">
<div class="relative inline-block"> <div class="relative inline-block">
Relays Relays

View File

@ -72,7 +72,7 @@
<MenuMobileItem stopPropagation on:click={openSettings}> <MenuMobileItem stopPropagation on:click={openSettings}>
<i class="fa fa-cog" /> Settings <i class="fa fa-cog" /> Settings
</MenuMobileItem> </MenuMobileItem>
{#if !$env.FORCE_GROUP} {#if !$env.FORCE_GROUP && $env.FORCE_RELAYS.length === 0}
<MenuMobileItem href="/settings/relays"> <MenuMobileItem href="/settings/relays">
<i class="fa fa-server" /> <i class="fa fa-server" />
<div class="relative inline-block"> <div class="relative inline-block">

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {Storage} from "hurdak" import {Storage} from "hurdak"
import {uniq} from 'ramda' import {uniq} from "ramda"
import {FeedLoader} from "src/engine" import {FeedLoader} from "src/engine"
import {createScroller} from "src/util/misc" import {createScroller} from "src/util/misc"
import {LOCAL_RELAY_URL} from "src/util/nostr" import {LOCAL_RELAY_URL} from "src/util/nostr"
@ -14,6 +14,7 @@
import { import {
readable, readable,
writable, writable,
selectHints,
compileFilters, compileFilters,
searchableRelays, searchableRelays,
getRelaysFromFilters, getRelaysFromFilters,
@ -56,7 +57,7 @@
feed = new FeedLoader({ feed = new FeedLoader({
filters: compileFilters([filter], {includeReposts: true}), filters: compileFilters([filter], {includeReposts: true}),
relays: getRelays(), relays: selectHints(getRelays()),
anchor, anchor,
shouldListen, shouldListen,
shouldDefer: true, shouldDefer: true,

View File

@ -204,7 +204,7 @@
} }
} }
if (!$env.FORCE_GROUP && !note.wrap) { if (!$env.FORCE_GROUP && $env.FORCE_RELAYS.length === 0 && !note.wrap) {
actions.push({label: "Broadcast", icon: "rss", onClick: broadcast}) actions.push({label: "Broadcast", icon: "rss", onClick: broadcast})
} }
@ -318,7 +318,7 @@
{/each} {/each}
</div> </div>
{/if} {/if}
{#if note.seen_on.length > 0} {#if note.seen_on.length > 0 && $env.FORCE_RELAYS.length < 2}
<h1 class="staatliches text-2xl">Relays</h1> <h1 class="staatliches text-2xl">Relays</h1>
<p>This note was found on {quantify(note.seen_on.length, "relay")} below.</p> <p>This note was found on {quantify(note.seen_on.length, "relay")} below.</p>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">

View File

@ -13,7 +13,7 @@
import RelayCard from "src/app/shared/RelayCard.svelte" import RelayCard from "src/app/shared/RelayCard.svelte"
import GroupSummary from "src/app/shared/GroupSummary.svelte" import GroupSummary from "src/app/shared/GroupSummary.svelte"
import RelaySearch from "src/app/shared/RelaySearch.svelte" import RelaySearch from "src/app/shared/RelaySearch.svelte"
import {getGroupPublishHints, deriveGroupOptions, displayRelay} from "src/engine" import {env, getGroupPublishHints, deriveGroupOptions, displayRelay} from "src/engine"
export let hideFields = [] export let hideFields = []
export let initialValues: { export let initialValues: {
@ -98,7 +98,7 @@
</div> </div>
</Field> </Field>
{/if} {/if}
{#if !hideFields.includes("relays")} {#if !hideFields.includes("relays") && $env.FORCE_RELAYS.length === 0}
<Field icon="fa-database" label="Select which relays to publish to"> <Field icon="fa-database" label="Select which relays to publish to">
<div> <div>
{#each values.relays as url} {#each values.relays as url}

View File

@ -5,7 +5,7 @@
import Chip from "src/partials/Chip.svelte" import Chip from "src/partials/Chip.svelte"
import Subheading from "src/partials/Subheading.svelte" import Subheading from "src/partials/Subheading.svelte"
import Note from "src/app/shared/Note.svelte" import Note from "src/app/shared/Note.svelte"
import {load, getUserRelayUrls} from "src/engine" import {load, getUserHints} from "src/engine"
export let pubkey export let pubkey
@ -44,7 +44,7 @@
} }
load({ load({
relays: getUserRelayUrls("write"), relays: getUserHints("write"),
filters: [{kinds: [1985], authors: [pubkey], "#L": ["#t"]}], filters: [{kinds: [1985], authors: [pubkey], "#L": ["#t"]}],
onEvent: batch(300, chunk => { onEvent: batch(300, chunk => {
events = [...events, ...chunk] events = [...events, ...chunk]

View File

@ -15,7 +15,7 @@
import Compose from "src/app/shared/Compose.svelte" import Compose from "src/app/shared/Compose.svelte"
import {router} from "src/app/router" import {router} from "src/app/router"
import {toastProgress} from "src/app/state" import {toastProgress} from "src/app/state"
import {dereferenceNote, publishToZeroOrMoreGroups, getUserRelayUrls} from "src/engine" import {dereferenceNote, publishToZeroOrMoreGroups, getUserHints} from "src/engine"
export let address export let address
export let event export let event
@ -33,7 +33,7 @@
builder.setImageMeta(images.getValue()) builder.setImageMeta(images.getValue())
const {pubs} = await publishToZeroOrMoreGroups(values.groups, builder.template, { const {pubs} = await publishToZeroOrMoreGroups(values.groups, builder.template, {
relays: getUserRelayUrls("write"), relays: getUserHints("write"),
}) })
pubs[0].on("progress", toastProgress) pubs[0].on("progress", toastProgress)

View File

@ -24,6 +24,7 @@
displayGroup, displayGroup,
session, session,
subscribe, subscribe,
loadPubkeys,
publishGroupEntryRequest, publishGroupEntryRequest,
groupRequests, groupRequests,
deriveGroup, deriveGroup,
@ -76,6 +77,7 @@
let tabs let tabs
$: relays = relays || info.relays $: relays = relays || info.relays
$: loadPubkeys($group.members || [])
$: { $: {
tabs = ["notes"] tabs = ["notes"]

View File

@ -12,6 +12,7 @@
import SearchSelect from "src/partials/SearchSelect.svelte" import SearchSelect from "src/partials/SearchSelect.svelte"
import {router} from "src/app/router" import {router} from "src/app/router"
import { import {
env,
userLists, userLists,
searchPeople, searchPeople,
searchTopics, searchTopics,
@ -99,17 +100,19 @@
</SearchSelect> </SearchSelect>
<p slot="info">Type "@" to look for people, and "#" to look for topics.</p> <p slot="info">Type "@" to look for people, and "#" to look for topics.</p>
</Field> </Field>
<Field label="Relays"> {#if $env.FORCE_RELAYS.length === 0}
<SearchSelect multiple search={searchRelayTags} bind:value={values.relays}> <Field label="Relays">
<div slot="item" let:item> <SearchSelect multiple search={searchRelayTags} bind:value={values.relays}>
{displayRelay({url: item[1]})} <div slot="item" let:item>
</div> {displayRelay({url: item[1]})}
</SearchSelect> </div>
<p slot="info"> </SearchSelect>
Select which relays to limit this list to. If you leave this blank, your default relays <p slot="info">
will be used. Select which relays to limit this list to. If you leave this blank, your default relays
</p> will be used.
</Field> </p>
</Field>
{/if}
<Anchor button tag="button" type="submit">Save</Anchor> <Anchor button tag="button" type="submit">Save</Anchor>
</div> </div>
</FlexColumn> </FlexColumn>

View File

@ -18,7 +18,7 @@
import Compose from "src/app/shared/Compose.svelte" import Compose from "src/app/shared/Compose.svelte"
import {router} from "src/app/router" import {router} from "src/app/router"
import {toastProgress} from "src/app/state" import {toastProgress} from "src/app/state"
import {dereferenceNote, publishToZeroOrMoreGroups, getUserRelayUrls} from "src/engine" import {dereferenceNote, publishToZeroOrMoreGroups, getUserHints} from "src/engine"
export let address export let address
export let event export let event
@ -41,7 +41,7 @@
builder.setImages(images.getValue()) builder.setImages(images.getValue())
const {pubs} = await publishToZeroOrMoreGroups(values.groups, builder.template, { const {pubs} = await publishToZeroOrMoreGroups(values.groups, builder.template, {
relays: getUserRelayUrls("write"), relays: getUserHints("write"),
}) })
pubs[0].on("progress", toastProgress) pubs[0].on("progress", toastProgress)

View File

@ -306,7 +306,9 @@
<i class="fa fa-circle-nodes" /> <i class="fa fa-circle-nodes" />
{opts.groups.length} {opts.groups.length}
</span> </span>
<span><i class="fa fa-server" /> {opts.relays?.length}</span> {#if $env.FORCE_RELAYS.length === 0}
<span><i class="fa fa-server" /> {opts.relays?.length}</span>
{/if}
<span><i class="fa fa-warning" /> {opts.warning || 0}</span> <span><i class="fa fa-warning" /> {opts.warning || 0}</span>
</small> </small>
{/if} {/if}

View File

@ -4,7 +4,7 @@ import {createEvent, now} from "paravel"
import {generatePrivateKey} from "src/util/nostr" import {generatePrivateKey} from "src/util/nostr"
import {pubkey} from "src/engine/session/state" import {pubkey} from "src/engine/session/state"
import {signer, nip44, nip59} from "src/engine/session/derived" import {signer, nip44, nip59} from "src/engine/session/derived"
import {getUserRelayUrls} from "src/engine/relays/utils" import {getUserHints} from "src/engine/relays/utils"
import {Publisher} from "src/engine/network/utils" import {Publisher} from "src/engine/network/utils"
import type {Event} from "./model" import type {Event} from "./model"
import {seenIds} from "./state" import {seenIds} from "./state"
@ -20,7 +20,7 @@ export const markAsSeenPublicly = batch(5000, async idChunks => {
for (const ids of chunk(500, uniq(flatten(idChunks)))) { for (const ids of chunk(500, uniq(flatten(idChunks)))) {
Publisher.publish({ Publisher.publish({
event: await signer.get().signAsUser(createReadReceipt(ids)), event: await signer.get().signAsUser(createReadReceipt(ids)),
relays: getUserRelayUrls("write"), relays: getUserHints("write"),
}) })
} }
}) })
@ -40,7 +40,7 @@ export const markAsSeenPrivately = batch(5000, async idChunks => {
Publisher.publish({ Publisher.publish({
event: rumor.wrap, event: rumor.wrap,
relays: getUserRelayUrls("write"), relays: getUserHints("write"),
}) })
} }
}) })

View File

@ -2,7 +2,7 @@ import {now} from "paravel"
import {seconds} from "hurdak" import {seconds} from "hurdak"
import {Naddr, noteKinds, repostKinds} from "src/util/nostr" import {Naddr, noteKinds, repostKinds} from "src/util/nostr"
import {load} from "src/engine/network/utils" import {load} from "src/engine/network/utils"
import {getUserHints} from "src/engine/relays/utils" import {selectHintsWithFallback} from "src/engine/relays/utils"
import {updateCurrentSession} from "src/engine/session/commands" import {updateCurrentSession} from "src/engine/session/commands"
import {groups} from "./state" import {groups} from "./state"
import { import {
@ -44,7 +44,7 @@ export const loadGroups = async (rawAddrs: string[], relays: string[] = null) =>
if (naddrs.length > 0) { if (naddrs.length > 0) {
load({ load({
relays: relays || getUserHints("read"), relays: selectHintsWithFallback(relays),
filters: [{kinds: [34550, 35834], authors, "#d": identifiers}], filters: [{kinds: [34550, 35834], authors, "#d": identifiers}],
}) })
} }
@ -59,11 +59,11 @@ export const loadGroupMessages = async () => {
} }
for (const address of deriveUserCommunities().get()) { for (const address of deriveUserCommunities().get()) {
const info = getCommunityReqInfo(address) const {relays, ...info} = getCommunityReqInfo(address)
const kinds = [...noteKinds, ...repostKinds] const kinds = [...noteKinds, ...repostKinds]
const since = Math.max(now() - seconds(7, "day"), info.since) const since = Math.max(now() - seconds(7, "day"), info.since)
load({relays: info.relays, filters: [{kinds, "#a": [address], since}]}) load({relays, filters: [{kinds, "#a": [address], since}]})
} }
updateCurrentSession($session => { updateCurrentSession($session => {

View File

@ -5,7 +5,7 @@ import {Naddr} from "src/util/nostr"
import type {GroupStatus, Session} from "src/engine/session/model" import type {GroupStatus, Session} from "src/engine/session/model"
import {pubkey} from "src/engine/session/state" import {pubkey} from "src/engine/session/state"
import {session} from "src/engine/session/derived" import {session} from "src/engine/session/derived"
import {getUserRelayUrls, getGroupHints, mergeHints} from "src/engine/relays/utils" import {getUserHints, getGroupHints, mergeHints} from "src/engine/relays/utils"
import {groups, groupSharedKeys, groupAdminKeys} from "./state" import {groups, groupSharedKeys, groupAdminKeys} from "./state"
import {GroupAccess} from "./model" import {GroupAccess} from "./model"
import type {Group} from "./model" import type {Group} from "./model"
@ -66,7 +66,7 @@ export const getGroupReqInfo = (address = null) => {
recipients.push(key.pubkey) recipients.push(key.pubkey)
} }
const relays = mergeHints([...addresses.map(getGroupHints), getUserRelayUrls("read")]) const relays = mergeHints([...addresses.map(getGroupHints), getUserHints("read")])
return {admins, recipients, relays, since} return {admins, recipients, relays, since}
} }
@ -77,7 +77,7 @@ export const getCommunityReqInfo = (address = null) => {
return { return {
since: since - seconds(6, "hour"), since: since - seconds(6, "hour"),
relays: mergeHints([getGroupHints(address), getUserRelayUrls("read")]), relays: mergeHints([getGroupHints(address), getUserHints("read")]),
} }
} }

View File

@ -3,7 +3,7 @@ import {first} from "hurdak"
import {cached, Tags} from "paravel" import {cached, Tags} from "paravel"
import {derived} from "src/engine/core/utils" import {derived} from "src/engine/core/utils"
import {load} from "src/engine/network/utils" import {load} from "src/engine/network/utils"
import {getUserRelayUrls} from "src/engine/relays/utils" import {getUserHints} from "src/engine/relays/utils"
import {follows} from "src/engine/people/derived" import {follows} from "src/engine/people/derived"
import {handlers, handlerRecs} from "./state" import {handlers, handlerRecs} from "./state"
@ -14,7 +14,7 @@ export const deriveHandlers = cached({
const $follows = follows.get() const $follows = follows.get()
load({ load({
relays: getUserRelayUrls("read"), relays: getUserHints("read"),
filters: [ filters: [
{kinds: [31989], "#d": [String(kind)], authors: Array.from($follows)}, {kinds: [31989], "#d": [String(kind)], authors: Array.from($follows)},
{kinds: [31990], "#k": [String(kind)]}, {kinds: [31990], "#k": [String(kind)]},

View File

@ -1,10 +1,11 @@
import {max, partition, equals} from "ramda" import {max, without, uniq, partition, equals} from "ramda"
import {noop, pickVals} from "hurdak" import {noop, pickVals} from "hurdak"
import {Plex, Relays, Executor, Multi, createEvent} from "paravel" import {Plex, Relays, Executor, Multi, createEvent} from "paravel"
import {error, warn} from "src/util/logger" import {error, warn} from "src/util/logger"
import {LOCAL_RELAY_URL} from "src/util/nostr" import {LOCAL_RELAY_URL} from "src/util/nostr"
import {normalizeRelayUrl} from "src/engine/relays/utils" import {normalizeRelayUrl} from "src/engine/relays/utils"
import {pool} from "src/engine/network/state" import {pool} from "src/engine/network/state"
import {env} from "src/engine/session/state"
import {getSetting} from "src/engine/session/utils" import {getSetting} from "src/engine/session/utils"
import {signer, canSign} from "src/engine/session/derived" import {signer, canSign} from "src/engine/session/derived"
import {LocalTarget} from "./targets" import {LocalTarget} from "./targets"
@ -14,13 +15,20 @@ export const getUrls = (relays: string[]) => {
error(`Attempted to connect to zero urls`) error(`Attempted to connect to zero urls`)
} }
const urls = new Set(relays.map(normalizeRelayUrl)) const urls = uniq(relays.map(normalizeRelayUrl))
if (urls.size !== relays.length) { if (urls.length !== relays.length) {
warn(`Attempted to connect to non-unique relays`) warn(`Attempted to connect to non-unique relays`)
} }
return Array.from(urls) const {FORCE_RELAYS} = env.get()
const nonLocalRelays = without([LOCAL_RELAY_URL], urls)
if (FORCE_RELAYS.length > 0 && nonLocalRelays.some(url => !FORCE_RELAYS.includes(url))) {
warn(`Attempted to connect to something other than FORCE_RELAYS`, urls)
}
return urls
} }
export const getTarget = (urls: string[]) => { export const getTarget = (urls: string[]) => {

View File

@ -7,6 +7,7 @@ import logger from "src/util/logger"
import {getSetting} from "src/engine/session/utils" import {getSetting} from "src/engine/session/utils"
import type {Event} from "src/engine/events/model" import type {Event} from "src/engine/events/model"
import {mergeHints} from "src/engine/relays/utils" import {mergeHints} from "src/engine/relays/utils"
import {getUrls} from "src/engine/network/utils"
import type {Filter} from "../model" import type {Filter} from "../model"
import {combineFilters} from "./filters" import {combineFilters} from "./filters"
import {subscribe} from "./subscribe" import {subscribe} from "./subscribe"
@ -120,6 +121,9 @@ export const load = (request: LoadOpts) => {
const result = defer() const result = defer()
const tracker = new Tracker() const tracker = new Tracker()
// Just a dumb hack to get a warning about relay urls before we lose the stack trace
getUrls(request.relays)
execute({tracker, request, result, results: []}) execute({tracker, request, result, results: []})
return result return result

View File

@ -3,6 +3,7 @@ import {Tags, isShareableRelay, normalizeRelayUrl as normalize, fromNostrURI} fr
import {sortBy, whereEq, pluck, uniq, nth, prop, last} from "ramda" import {sortBy, whereEq, pluck, uniq, nth, prop, last} from "ramda"
import {chain, displayList, first} from "hurdak" import {chain, displayList, first} from "hurdak"
import {fuzzy} from "src/util/misc" import {fuzzy} from "src/util/misc"
import {warn} from "src/util/logger"
import {LOCAL_RELAY_URL, Naddr} from "src/util/nostr" import {LOCAL_RELAY_URL, Naddr} from "src/util/nostr"
import type {Event} from "src/engine/events/model" import type {Event} from "src/engine/events/model"
import {env} from "src/engine/session/state" import {env} from "src/engine/session/state"
@ -102,6 +103,7 @@ export const getGroupRelayUrls = address => {
// 5) Advertise relays — write and read back your own relay list // 5) Advertise relays — write and read back your own relay list
export const selectHints = (hints: Iterable<string>, limit: number = null) => { export const selectHints = (hints: Iterable<string>, limit: number = null) => {
const {FORCE_RELAYS} = env.get()
const seen = new Set() const seen = new Set()
const ok = [] const ok = []
const bad = [] const bad = []
@ -110,7 +112,7 @@ export const selectHints = (hints: Iterable<string>, limit: number = null) => {
limit = getSetting("relay_limit") limit = getSetting("relay_limit")
} }
for (const url of chain(hints, getUserRelayUrls(RelayMode.Read), env.get().DEFAULT_RELAYS)) { for (const url of FORCE_RELAYS.length > 0 ? FORCE_RELAYS : hints) {
if (seen.has(url)) { if (seen.has(url)) {
continue continue
} }
@ -135,9 +137,18 @@ export const selectHints = (hints: Iterable<string>, limit: number = null) => {
} }
// If we don't have enough hints, use the broken ones // If we don't have enough hints, use the broken ones
return ok.concat(bad).slice(0, limit) const result = ok.concat(bad).slice(0, limit)
if (result.length === 0) {
warn("No results returned from selectHints")
}
return result
} }
export const selectHintsWithFallback = (hints: Iterable<string> = null, limit = null) =>
selectHints(chain(hints || [], getUserRelayUrls(RelayMode.Read), env.get().DEFAULT_RELAYS), limit)
export class HintSelector { export class HintSelector {
constructor( constructor(
readonly generateHints, readonly generateHints,
@ -219,7 +230,7 @@ export const getPublishHints = hintSelector(function* (event: Event) {
const hintGroups = pubkeys.map(pubkey => getPubkeyRelayUrls(pubkey, RelayMode.Read)) const hintGroups = pubkeys.map(pubkey => getPubkeyRelayUrls(pubkey, RelayMode.Read))
const authorRelays = getPubkeyRelayUrls(event.pubkey, RelayMode.Write) const authorRelays = getPubkeyRelayUrls(event.pubkey, RelayMode.Write)
yield* mergeHints([...hintGroups, authorRelays, getUserRelayUrls(RelayMode.Write)]) yield* mergeHints([...hintGroups, authorRelays, getUserHints(RelayMode.Write)])
}) })
export const getInboxHints = hintSelector(function* (pubkeys: string[]) { export const getInboxHints = hintSelector(function* (pubkeys: string[]) {
@ -234,7 +245,7 @@ export const getGroupHints = hintSelector(function* (address: string) {
export const getGroupPublishHints = (addresses: string[]) => { export const getGroupPublishHints = (addresses: string[]) => {
const urls = mergeHints(addresses.map(getGroupRelayUrls)) const urls = mergeHints(addresses.map(getGroupRelayUrls))
return urls.length === 0 ? getUserRelayUrls("write") : urls return urls.length === 0 ? getUserHints("write") : urls
} }
export const mergeHints = (groups: string[][], limit: number = null) => { export const mergeHints = (groups: string[][], limit: number = null) => {

View File

@ -2,6 +2,7 @@ import "src/app.css"
import {identity} from "ramda" import {identity} from "ramda"
import {Fetch} from "hurdak" import {Fetch} from "hurdak"
import {normalizeRelayUrl} from "paravel"
import Bugsnag from "@bugsnag/js" import Bugsnag from "@bugsnag/js"
import {tryFetch} from "src/util/misc" import {tryFetch} from "src/util/misc"
import {env, saveRelay} from "src/engine" import {env, saveRelay} from "src/engine"
@ -39,11 +40,13 @@ const NIP96_URLS = fromCsv(import.meta.env.VITE_NIP96_URLS)
const FORCE_GROUP = import.meta.env.VITE_FORCE_GROUP const FORCE_GROUP = import.meta.env.VITE_FORCE_GROUP
const DVM_RELAYS = fromCsv(import.meta.env.VITE_DVM_RELAYS) const FORCE_RELAYS = fromCsv(import.meta.env.VITE_FORCE_RELAYS).map(normalizeRelayUrl)
const SEARCH_RELAYS = ["wss://relay.nostr.band", "wss://nostr.wine", "wss://search.nos.today"] const DVM_RELAYS = fromCsv(import.meta.env.VITE_DVM_RELAYS).map(normalizeRelayUrl)
const DEFAULT_RELAYS = fromCsv(import.meta.env.VITE_DEFAULT_RELAYS) const SEARCH_RELAYS = fromCsv(import.meta.env.VITE_SEARCH_RELAYS).map(normalizeRelayUrl)
const DEFAULT_RELAYS = fromCsv(import.meta.env.VITE_DEFAULT_RELAYS).map(normalizeRelayUrl)
const DEFAULT_FOLLOWS = fromCsv(import.meta.env.VITE_DEFAULT_FOLLOWS) const DEFAULT_FOLLOWS = fromCsv(import.meta.env.VITE_DEFAULT_FOLLOWS)
@ -62,6 +65,7 @@ env.set({
DUFFLEPUD_URL, DUFFLEPUD_URL,
MULTIPLEXTR_URL, MULTIPLEXTR_URL,
FORCE_GROUP, FORCE_GROUP,
FORCE_RELAYS,
DVM_RELAYS, DVM_RELAYS,
SEARCH_RELAYS, SEARCH_RELAYS,
DEFAULT_RELAYS, DEFAULT_RELAYS,