Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Rename tracking to seeding
Sebastian Martinez committed 2 years ago
commit bac15bfdc7eb568502b2f5c091bd2b85d5bb8682
parent e0a5e37fb7e3dbe1f23e555d598bd148bd00f16d
21 files changed +170 -149
modified httpd-client/index.ts
@@ -99,8 +99,8 @@ const nodeSchema = object({
        }),
      }),
    }),
-
    policy: union([literal("track"), literal("block")]),
-
    scope: union([literal("trusted"), literal("all")]),
+
    policy: union([literal("allow"), literal("block")]),
+
    scope: union([literal("followed"), literal("all")]),
  }).nullable(),
  state: union([literal("running"), literal("stopped")]),
});
modified httpd-client/lib/project.ts
@@ -70,7 +70,7 @@ const projectSchema = object({
    open: number(),
    closed: number(),
  }),
-
  trackings: number(),
+
  seeding: number(),
});
const projectsSchema = array(projectSchema);

modified src/views/projects/Commit.svelte
@@ -12,7 +12,7 @@
  export let baseUrl: BaseUrl;
  export let commit: Commit;
  export let project: Project;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  $: header = commit.commit;
</script>
@@ -42,7 +42,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking}>
+
<Layout {baseUrl} {project} {seeding}>
  <div class="header">
    <div class="summary">
      <div class="txt-medium txt-bold">
added src/views/projects/Header/SeedButton.svelte
@@ -0,0 +1,72 @@
+
<script lang="ts">
+
  import Button from "@app/components/Button.svelte";
+
  import Command from "@app/components/Command.svelte";
+
  import ExternalLink from "@app/components/ExternalLink.svelte";
+
  import IconSmall from "@app/components/IconSmall.svelte";
+
  import Popover from "@app/components/Popover.svelte";
+

+
  export let projectId: string;
+
  export let seedCount: number;
+
  export let seeding: boolean;
+

+
  $: buttonTitle = seeding ? "Seeding" : "Seed";
+
</script>
+

+
<style>
+
  .seed-label {
+
    display: block;
+
    font-size: var(--font-size-small);
+
    font-weight: var(--font-weight-regular);
+
    margin-bottom: 0.75rem;
+
  }
+
  code {
+
    font-family: var(--font-family-monospace);
+
    font-size: var(--font-size-small);
+
    background-color: var(--color-fill-ghost);
+
    border-radius: var(--border-radius-tiny);
+
    padding: 0.125rem 0.25rem;
+
  }
+
</style>
+

+
<Popover popoverPositionTop="3rem" popoverPositionRight="0">
+
  <Button
+
    slot="toggle"
+
    let:toggle
+
    on:click={toggle}
+
    size="large"
+
    variant={seeding ? "secondary-toggle-on" : "secondary-toggle-off"}>
+
    <IconSmall name="network" />
+
    <span>
+
      {buttonTitle}
+
      <span style:font-weight="var(--font-weight-regular)">
+
        {seedCount}
+
      </span>
+
    </span>
+
  </Button>
+

+
  <div slot="popover" style:width={seeding ? "19.5rem" : "30.5rem"}>
+
    <div class="seed-label">
+
      Use the <ExternalLink href="https://radicle.xyz/#try">
+
        Radicle CLI
+
      </ExternalLink>
+
      to {seeding ? "stop seeding" : "seed"} this project.
+
      {#if !seeding}
+
        <br />
+
        <br />
+
        The
+
        <code>seed</code>
+
        command serves a dual purpose:
+
        <ul style:padding="0 1rem" style:margin-top="0.5rem">
+
          <li>
+
            Keeps your local Radicle node in sync with updates from this
+
            project.
+
          </li>
+
          <li>
+
            Propagates them across the Radicle network to other peers like you.
+
          </li>
+
        </ul>
+
      {/if}
+
    </div>
+
    <Command command={`rad seed ${projectId} ${seeding ? "--delete" : ""}`} />
+
  </div>
+
</Popover>
deleted src/views/projects/Header/TrackButton.svelte
@@ -1,76 +0,0 @@
-
<script lang="ts">
-
  import { pluralize } from "@app/lib/pluralize";
-

-
  import Button from "@app/components/Button.svelte";
-
  import Command from "@app/components/Command.svelte";
-
  import ExternalLink from "@app/components/ExternalLink.svelte";
-
  import IconSmall from "@app/components/IconSmall.svelte";
-
  import Popover from "@app/components/Popover.svelte";
-

-
  export let projectId: string;
-
  export let trackings: number;
-
  export let tracking: boolean;
-

-
  $: buttonTitle = tracking ? "Tracking" : "Track";
-
  $: command = tracking ? "untrack" : "track";
-
</script>
-

-
<style>
-
  .track-label {
-
    display: block;
-
    font-size: var(--font-size-small);
-
    font-weight: var(--font-weight-regular);
-
    margin-bottom: 0.75rem;
-
  }
-
  code {
-
    font-family: var(--font-family-monospace);
-
    font-size: var(--font-size-small);
-
    background-color: var(--color-fill-ghost);
-
    border-radius: var(--border-radius-tiny);
-
    padding: 0.125rem 0.25rem;
-
  }
-
</style>
-

-
<Popover popoverPositionTop="3rem" popoverPositionRight="0">
-
  <Button
-
    slot="toggle"
-
    let:toggle
-
    on:click={toggle}
-
    size="large"
-
    variant={tracking ? "secondary-toggle-on" : "secondary-toggle-off"}
-
    title="Tracked by {trackings} {pluralize('node', trackings)}">
-
    <IconSmall name="network" />
-
    <span>
-
      {buttonTitle}
-
      <span style:font-weight="var(--font-weight-regular)">
-
        {trackings}
-
      </span>
-
    </span>
-
  </Button>
-

-
  <div slot="popover" style:width={tracking ? "19.5rem" : "30.5rem"}>
-
    <div class="track-label">
-
      Use the <ExternalLink href="https://radicle.xyz/#try">
-
        Radicle CLI
-
      </ExternalLink>
-
      to {command} this project.
-
      {#if command === "track"}
-
        <br />
-
        <br />
-
        The
-
        <code>track</code>
-
        command serves a dual purpose:
-
        <ul style:padding="0 1rem" style:margin-top="0.5rem">
-
          <li>
-
            Keeps your local Radicle node in sync with updates from this
-
            project.
-
          </li>
-
          <li>
-
            Propagates them across the Radicle network to other peers like you.
-
          </li>
-
        </ul>
-
      {/if}
-
    </div>
-
    <Command command={`rad ${command} ${projectId}`} />
-
  </div>
-
</Popover>
modified src/views/projects/History.svelte
@@ -29,7 +29,7 @@
  export let revision: string | undefined;
  export let totalCommitCount: number;
  export let tree: Tree;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  const api = new HttpdClient(baseUrl);

@@ -115,7 +115,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="source">
+
<Layout {baseUrl} {project} {seeding} activeTab="source">
  <svelte:fragment slot="subheader">
    <div style:margin-top="1rem">
      <Header
modified src/views/projects/Issue.svelte
@@ -47,7 +47,7 @@
  export let issue: Issue;
  export let project: Project;
  export let rawPath: (commit?: string) => string;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  const api = new HttpdClient(baseUrl);

@@ -460,7 +460,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="issues">
+
<Layout {baseUrl} {project} {seeding} activeTab="issues">
  <div class="issue">
    <div style="display: flex; flex-direction: column; gap: 1.5rem;">
      <CobHeader id={issue.id}>
modified src/views/projects/Issue/New.svelte
@@ -25,7 +25,7 @@
  export let baseUrl: BaseUrl;
  export let project: Project;
  export let rawPath: (commit?: string) => string;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  let preview: boolean = false;
  let selectionStart = 0;
@@ -144,7 +144,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="issues">
+
<Layout {baseUrl} {project} {seeding} activeTab="issues">
  <main>
    {#if session}
      <div class="form">
modified src/views/projects/Issues.svelte
@@ -25,7 +25,7 @@
  export let issues: Issue[];
  export let project: Project;
  export let state: IssueState["status"];
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  let loading = false;
  let page = 0;
@@ -79,7 +79,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="issues">
+
<Layout {baseUrl} {project} {seeding} activeTab="issues">
  <div class="issues">
    <List items={allIssues}>
      <div slot="header" style="display: flex;">
modified src/views/projects/Layout.svelte
@@ -13,12 +13,12 @@
  import CopyableId from "@app/components/CopyableId.svelte";
  import Header from "@app/views/projects/Header.svelte";
  import Link from "@app/components/Link.svelte";
-
  import TrackButton from "@app/views/projects/Header/TrackButton.svelte";
+
  import SeedButton from "@app/views/projects/Header/SeedButton.svelte";

  export let activeTab: ActiveTab = undefined;
  export let baseUrl: BaseUrl;
  export let project: Project;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  const render = (content: string): string =>
    dompurify.sanitize(markdown.parse(content) as string);
@@ -99,9 +99,9 @@
    <div
      class="layout-desktop-flex"
      style="margin-left: auto; display: flex; gap: 0.5rem;">
-
      <TrackButton
-
        {tracking}
-
        trackings={project.trackings}
+
      <SeedButton
+
        {seeding}
+
        seedCount={project.seeding}
        projectId={project.id} />
      <CloneButton {baseUrl} id={project.id} name={project.name} />
    </div>
modified src/views/projects/Patch.svelte
@@ -83,7 +83,7 @@
  export let rawPath: (commit?: string) => string;
  export let project: Project;
  export let view: PatchView;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  $: api = new HttpdClient(baseUrl);

@@ -638,7 +638,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="patches">
+
<Layout {baseUrl} {project} {seeding} activeTab="patches">
  <div class="patch">
    <div>
      <CobHeader id={patch.id}>
modified src/views/projects/Patches.svelte
@@ -22,7 +22,7 @@
  export let patches: Patch[];
  export let project: Project;
  export let state: PatchState["status"];
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  let loading = false;
  let page = 0;
@@ -84,7 +84,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="patches">
+
<Layout {baseUrl} {project} {seeding} activeTab="patches">
  <div class="patches">
    <List items={allPatches}>
      <div slot="header" style="display: flex;">
modified src/views/projects/Source.svelte
@@ -25,7 +25,7 @@
  export let project: Project;
  export let revision: string | undefined;
  export let tree: Tree;
-
  export let tracking: boolean;
+
  export let seeding: boolean;

  // Whether the mobile file tree is visible.
  let mobileFileTree = false;
@@ -136,7 +136,7 @@
  }
</style>

-
<Layout {baseUrl} {project} {tracking} activeTab="source">
+
<Layout {baseUrl} {project} {seeding} activeTab="source">
  <svelte:fragment slot="subheader">
    <div style:margin-top="1rem">
      <Header
modified src/views/projects/Source/PeerSelector.svelte
@@ -23,7 +23,7 @@
    const nodeId = formatNodeId(p.id);
    return p.delegate
      ? `${nodeId} is a delegate of this project`
-
      : `${nodeId} is a peer tracked by this node`;
+
      : `${nodeId} is a peer followed by this node`;
  }
</script>

modified src/views/projects/router.ts
@@ -115,7 +115,7 @@ export type ProjectLoadedRoute =
        path: string;
        rawPath: (commit?: string) => string;
        blobResult: BlobResult;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -130,7 +130,7 @@ export type ProjectLoadedRoute =
        tree: Tree;
        commitHeaders: CommitHeader[];
        totalCommitCount: number;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -139,7 +139,7 @@ export type ProjectLoadedRoute =
        baseUrl: BaseUrl;
        project: Project;
        commit: Commit;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -149,7 +149,7 @@ export type ProjectLoadedRoute =
        project: Project;
        rawPath: (commit?: string) => string;
        issue: Issue;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -159,7 +159,7 @@ export type ProjectLoadedRoute =
        project: Project;
        issues: Issue[];
        state: IssueState["status"];
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -168,7 +168,7 @@ export type ProjectLoadedRoute =
        baseUrl: BaseUrl;
        project: Project;
        rawPath: (commit?: string) => string;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -178,7 +178,7 @@ export type ProjectLoadedRoute =
        project: Project;
        patches: Patch[];
        state: PatchState["status"];
-
        tracking: boolean;
+
        seeding: boolean;
      };
    }
  | {
@@ -189,7 +189,7 @@ export type ProjectLoadedRoute =
        rawPath: (commit?: string) => string;
        patch: Patch;
        view: PatchView;
-
        tracking: boolean;
+
        seeding: boolean;
      };
    };

@@ -244,7 +244,7 @@ function parseRevisionToOid(
  }
}

-
async function isLocalNodeTracking(route: ProjectRoute): Promise<boolean> {
+
async function isLocalNodeSeeding(route: ProjectRoute): Promise<boolean> {
  if (isLocal(route.node.hostname)) {
    return true;
  } else {
@@ -278,10 +278,10 @@ export async function loadProjectRoute(
    } else if (route.resource === "project.history") {
      return await loadHistoryView(route);
    } else if (route.resource === "project.commit") {
-
      const [project, commit, tracking] = await Promise.all([
+
      const [project, commit, seeding] = await Promise.all([
        api.project.getById(route.project),
        api.project.getCommitBySha(route.project, route.commit),
-
        isLocalNodeTracking(route),
+
        isLocalNodeSeeding(route),
      ]);

      return {
@@ -290,14 +290,14 @@ export async function loadProjectRoute(
          baseUrl: route.node,
          project,
          commit,
-
          tracking,
+
          seeding,
        },
      };
    } else if (route.resource === "project.issue") {
-
      const [project, issue, tracking] = await Promise.all([
+
      const [project, issue, seeding] = await Promise.all([
        api.project.getById(route.project),
        api.project.getIssueById(route.project, route.issue),
-
        isLocalNodeTracking(route),
+
        isLocalNodeSeeding(route),
      ]);
      return {
        resource: "project.issue",
@@ -306,7 +306,7 @@ export async function loadProjectRoute(
          project,
          rawPath,
          issue,
-
          tracking,
+
          seeding,
        },
      };
    } else if (route.resource === "project.patch") {
@@ -314,9 +314,9 @@ export async function loadProjectRoute(
    } else if (route.resource === "project.issues") {
      return await loadIssuesView(route);
    } else if (route.resource === "project.newIssue") {
-
      const [project, tracking] = await Promise.all([
+
      const [project, seeding] = await Promise.all([
        api.project.getById(route.project),
-
        isLocalNodeTracking(route),
+
        isLocalNodeSeeding(route),
      ]);
      return {
        resource: "project.newIssue",
@@ -324,7 +324,7 @@ export async function loadProjectRoute(
          baseUrl: route.node,
          project,
          rawPath,
-
          tracking,
+
          seeding,
        },
      };
    } else if (route.resource === "project.patches") {
@@ -372,14 +372,14 @@ async function loadPatchesView(
  const searchParams = new URLSearchParams(route.search || "");
  const state = (searchParams.get("state") as PatchState["status"]) || "open";

-
  const [project, patches, tracking] = await Promise.all([
+
  const [project, patches, seeding] = await Promise.all([
    api.project.getById(route.project),
    api.project.getAllPatches(route.project, {
      state,
      page: 0,
      perPage: PATCHES_PER_PAGE,
    }),
-
    isLocalNodeTracking(route),
+
    isLocalNodeSeeding(route),
  ]);

  return {
@@ -389,7 +389,7 @@ async function loadPatchesView(
      patches,
      state,
      project,
-
      tracking,
+
      seeding,
    },
  };
}
@@ -400,14 +400,14 @@ async function loadIssuesView(
  const api = new HttpdClient(route.node);
  const state = route.state || "open";

-
  const [project, issues, tracking] = await Promise.all([
+
  const [project, issues, seeding] = await Promise.all([
    api.project.getById(route.project),
    api.project.getAllIssues(route.project, {
      state,
      page: 0,
      perPage: ISSUES_PER_PAGE,
    }),
-
    isLocalNodeTracking(route),
+
    isLocalNodeSeeding(route),
  ]);

  return {
@@ -417,7 +417,7 @@ async function loadIssuesView(
      issues,
      state,
      project,
-
      tracking,
+
      seeding,
    },
  };
}
@@ -431,11 +431,11 @@ async function loadTreeView(
      route.project
    }${commit ? `/${commit}` : ""}`;

-
  const [project, peers, branchMap, tracking] = await Promise.all([
+
  const [project, peers, branchMap, seeding] = await Promise.all([
    api.project.getById(route.project),
    api.project.getAllRemotes(route.project),
    getPeerBranches(api, route.project, route.peer),
-
    isLocalNodeTracking(route),
+
    isLocalNodeSeeding(route),
  ]);

  if (route.route) {
@@ -472,7 +472,7 @@ async function loadTreeView(
      tree,
      path,
      blobResult,
-
      tracking,
+
      seeding,
    },
  };
}
@@ -543,14 +543,14 @@ async function loadHistoryView(
    );
  }

-
  const [tree, commitsResponse, tracking] = await Promise.all([
+
  const [tree, commitsResponse, seeding] = await Promise.all([
    api.project.getTree(route.project, commitId),
    await api.project.getAllCommits(project.id, {
      parent: commitId,
      page: 0,
      perPage: COMMITS_PER_PAGE,
    }),
-
    isLocalNodeTracking(route),
+
    isLocalNodeSeeding(route),
  ]);

  return {
@@ -565,7 +565,7 @@ async function loadHistoryView(
      tree,
      commitHeaders: commitsResponse.commits.map(c => c.commit),
      totalCommitCount: commitsResponse.stats.commits,
-
      tracking,
+
      seeding,
    },
  };
}
@@ -578,10 +578,10 @@ async function loadPatchView(
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
      route.project
    }${commit ? `/${commit}` : ""}`;
-
  const [project, patch, tracking] = await Promise.all([
+
  const [project, patch, seeding] = await Promise.all([
    api.project.getById(route.project),
    api.project.getPatchById(route.project, route.patch),
-
    isLocalNodeTracking(route),
+
    isLocalNodeSeeding(route),
  ]);
  const latestRevision = patch.revisions[patch.revisions.length - 1];

@@ -637,7 +637,7 @@ async function loadPatchView(
      rawPath,
      patch,
      view,
-
      tracking,
+
      seeding,
    },
  };
}
modified tests/e2e/node.spec.ts
@@ -12,7 +12,7 @@ test("node metadata", async ({ page, peerManager }) => {
  });
  await peer.startHttpd();
  await peer.startNode({
-
    policy: "track",
+
    policy: "allow",
    scope: "all",
    alias: "palm",
    externalAddresses: ["seed.radicle.test:8123"],
modified tests/e2e/project.spec.ts
@@ -65,8 +65,8 @@ test("navigate to project", async ({ page }) => {
  // Show rendered README.md contents.
  await expect(page.getByText("Git test repository")).toBeVisible();

-
  // Number of nodes tracking this project.
-
  await expect(page.getByText("Tracking 3")).toBeVisible();
+
  // Number of nodes seeding this project.
+
  await expect(page.getByText("Seeding 3")).toBeVisible();
});

test("show source tree at specific revision", async ({ page }) => {
modified tests/support/fixtures.ts
@@ -367,7 +367,7 @@ export async function createSourceBrowsingFixture(
}

export async function createCobsFixture(peer: RadiclePeer) {
-
  await peer.rad(["track", peer.nodeId, "--alias", "palm"]);
+
  await peer.rad(["follow", peer.nodeId, "--alias", "palm"]);
  await Fs.mkdir(Path.join(tmpDir, "repos", "cobs"));
  const { projectFolder, defaultBranch } = await createProject(peer, {
    name: "cobs",
@@ -392,7 +392,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
    },
  );
  await peer.rad(
-
    ["assign", issueOne, "--to", `did:key:${peer.nodeId}`],
+
    ["issue", "assign", issueOne, "--add", `did:key:${peer.nodeId}`],
    createOptions(projectFolder, 1),
  );
  const { stdout: commentIssueOne } = await peer.rad(
@@ -537,7 +537,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
    createOptions(projectFolder, 5),
  );
  await peer.rad(
-
    ["review", patchOne, "-m", "LGTM", "--accept"],
+
    ["patch", "review", patchOne, "-m", "LGTM", "--accept"],
    createOptions(projectFolder, 6),
  );
  await patch.merge(
@@ -557,7 +557,14 @@ export async function createCobsFixture(peer: RadiclePeer) {
    { cwd: projectFolder },
  );
  await peer.rad(
-
    ["review", patchTwo, "-m", "Not the README we are looking for", "--reject"],
+
    [
+
      "patch",
+
      "review",
+
      patchTwo,
+
      "-m",
+
      "Not the README we are looking for",
+
      "--reject",
+
    ],
    createOptions(projectFolder, 1),
  );

@@ -579,11 +586,11 @@ export async function createCobsFixture(peer: RadiclePeer) {
    { cwd: projectFolder },
  );
  await peer.rad(
-
    ["patch", "label", patchThree, "--label", "documentation"],
+
    ["patch", "label", patchThree, "--add", "documentation"],
    createOptions(projectFolder, 1),
  );
  await peer.rad(
-
    ["review", patchThree, "-m", "This looks better"],
+
    ["patch", "review", patchThree, "-m", "This looks better"],
    createOptions(projectFolder, 2),
  );
  await Fs.appendFile(
@@ -605,7 +612,14 @@ export async function createCobsFixture(peer: RadiclePeer) {
    createOptions(projectFolder, 3),
  );
  await peer.rad(
-
    ["review", patchThree, "-m", "No this doesn't look better", "--reject"],
+
    [
+
      "patch",
+
      "review",
+
      patchThree,
+
      "-m",
+
      "No this doesn't look better",
+
      "--reject",
+
    ],
    createOptions(projectFolder, 2),
  );

@@ -618,7 +632,10 @@ export async function createCobsFixture(peer: RadiclePeer) {
    [],
    { cwd: projectFolder },
  );
-
  await peer.rad(["review", patchFour], createOptions(projectFolder, 1));
+
  await peer.rad(
+
    ["patch", "review", patchFour],
+
    createOptions(projectFolder, 1),
+
  );
  await peer.rad(
    ["patch", "archive", patchFour],
    createOptions(projectFolder, 2),
modified tests/support/globalSetup.ts
@@ -54,7 +54,7 @@ export default async function globalSetup(): Promise<() => void> {

  if (!process.env.SKIP_FIXTURE_CREATION) {
    await palm.startHttpd(defaultHttpdPort);
-
    await palm.startNode({ policy: "track", scope: "all", alias: "palm" });
+
    await palm.startNode({ policy: "allow", scope: "all", alias: "palm" });

    try {
      console.log("Creating source-browsing fixture");
modified tests/support/heartwood-version
@@ -1 +1 @@
-
1af9480b088c3eec800040a1bdcd09941a31bcf3
+
6ca7da276839e5217b340dbfff8cd9095d8464c5
modified tests/support/peerManager.ts
@@ -131,9 +131,13 @@ export const NodeConfigSchema = object({
      routingMaxAge: number(),
      fetchConcurrency: number(),
      gossipMaxAge: number(),
+
      rate: object({
+
        inbound: object({ fillRate: number(), capacity: number() }),
+
        outbound: object({ fillRate: number(), capacity: number() }),
+
      }),
    }),
-
    policy: union([literal("track"), literal("block")]),
-
    scope: union([literal("trusted"), literal("all")]),
+
    policy: union([literal("allow"), literal("block")]),
+
    scope: union([literal("followed"), literal("all")]),
  }),
});

@@ -297,6 +301,10 @@ export class RadiclePeer {
        routingMaxAge: 604800,
        fetchConcurrency: 1,
        gossipMaxAge: 1209600,
+
        rate: {
+
          inbound: { fillRate: 0.2, capacity: 32 },
+
          outbound: { fillRate: 1.0, capacity: 64 },
+
        },
      },
    });