Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
Update naming of project(s) to repo(s)
Sebastian Martinez committed 1 year ago
commit cf08c83913c94f6c53d39916e8bcb47a7234c24c
parent 4fda686
67 files changed +891 -921
modified http-client/index.ts
@@ -2,9 +2,9 @@ import type { BaseUrl } from "./lib/fetcher.js";
import type {
  Blob,
  DiffResponse,
-
  Project,
-
  ProjectListQuery,
  Remote,
+
  Repo,
+
  RepoListQuery,
  Tree,
  TreeStats,
} from "./lib/project.js";
@@ -41,7 +41,7 @@ import type { ZodSchema } from "zod";

import { z, array, literal, number, object, string, union } from "zod";

-
import * as project from "./lib/project.js";
+
import * as repo from "./lib/project.js";
import { Fetcher } from "./lib/fetcher.js";
import {
  nodeConfigSchema,
@@ -73,15 +73,15 @@ export type {
  Merge,
  Patch,
  PatchState,
-
  Project,
-
  ProjectListQuery,
  Reaction,
  Remote,
+
  Repo,
+
  RepoListQuery,
  Review,
  Revision,
  SeedingPolicy,
-
  TreeStats,
  Tree,
+
  TreeStats,
  Verdict,
};

@@ -156,13 +156,13 @@ export class HttpdClient {
  #fetcher: Fetcher;

  public baseUrl: BaseUrl;
-
  public project: project.Client;
+
  public repo: repo.Client;

  public constructor(baseUrl: BaseUrl) {
    this.baseUrl = baseUrl;
    this.#fetcher = new Fetcher(this.baseUrl);

-
    this.project = new project.Client(this.#fetcher);
+
    this.repo = new repo.Client(this.#fetcher);
  }

  public changePort(port: number): void {
@@ -213,14 +213,14 @@ export class HttpdClient {
    );
  }

-
  public async getPolicyById(
-
    id: string,
+
  public async getPolicyByRid(
+
    rid: string,
    options?: RequestOptions,
  ): Promise<SeedingPolicy> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `node/policies/repos/${id}`,
+
        path: `node/policies/repos/${rid}`,
        options,
      },
      seedingPolicySchema,
@@ -239,13 +239,13 @@ export class HttpdClient {
  }

  public async getNodeIdentity(
-
    id: string,
+
    nid: string,
    options?: RequestOptions,
  ): Promise<NodeIdentity> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `nodes/${id}`,
+
        path: `nodes/${nid}`,
        options,
      },
      nodeIdentitySchema,
@@ -253,13 +253,13 @@ export class HttpdClient {
  }

  public async getNodeInventory(
-
    id: string,
+
    nid: string,
    options?: RequestOptions,
  ): Promise<string[]> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `nodes/${id}/inventory`,
+
        path: `nodes/${nid}/inventory`,
        options,
      },
      array(string()),
modified http-client/lib/project.ts
@@ -27,11 +27,13 @@ import {
import { issueSchema, issuesSchema } from "./project/issue.js";
import { patchSchema, patchesSchema } from "./project/patch.js";

-
const projectSchema = object({
-
  id: string(),
-
  name: string(),
-
  description: string(),
-
  defaultBranch: string(),
+
const repoSchema = object({
+
  rid: string(),
+
  "xyz.radicle.project": object({
+
    name: string(),
+
    description: string(),
+
    defaultBranch: string(),
+
  }),
  delegates: array(object({ id: string(), alias: optional(string()) })),
  head: string(),
  threshold: number(),
@@ -51,9 +53,9 @@ const projectSchema = object({
  }),
  seeding: number(),
});
-
const projectsSchema = array(projectSchema);
+
const reposSchema = array(repoSchema);

-
export type Project = z.infer<typeof projectSchema>;
+
export type Repo = z.infer<typeof repoSchema>;

const activitySchema = object({
  activity: array(number()),
@@ -116,7 +118,7 @@ const diffResponseSchema = object({
  files: record(string(), diffBlobSchema),
});

-
export type ProjectListQuery = {
+
export type RepoListQuery = {
  page?: number;
  perPage?: number;
  show?: "pinned" | "all";
@@ -130,54 +132,54 @@ export class Client {

  public async getByDelegate(
    delegateId: string,
-
    query?: ProjectListQuery,
+
    query?: RepoListQuery,
    options?: RequestOptions,
-
  ): Promise<Project[]> {
+
  ): Promise<Repo[]> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `delegates/${delegateId}/projects`,
+
        path: `delegates/${delegateId}/repos`,
        query,
        options,
      },
-
      projectsSchema,
+
      reposSchema,
    );
  }

-
  public async getById(id: string, options?: RequestOptions): Promise<Project> {
+
  public async getByRid(rid: string, options?: RequestOptions): Promise<Repo> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}`,
+
        path: `repos/${rid}`,
        options,
      },
-
      projectSchema,
+
      repoSchema,
    );
  }

  public async getAll(
-
    query?: ProjectListQuery,
+
    query?: RepoListQuery,
    options?: RequestOptions,
-
  ): Promise<Project[]> {
+
  ): Promise<Repo[]> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: "projects",
+
        path: "repos",
        query,
        options,
      },
-
      projectsSchema,
+
      reposSchema,
    );
  }

  public async getActivity(
-
    id: string,
+
    rid: string,
    options?: RequestOptions,
  ): Promise<Activity> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/activity`,
+
        path: `repos/${rid}/activity`,
        options,
      },
      activitySchema,
@@ -185,14 +187,14 @@ export class Client {
  }

  public async getReadme(
-
    id: string,
+
    rid: string,
    sha: string,
    options?: RequestOptions,
  ): Promise<Blob> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/readme/${sha}`,
+
        path: `repos/${rid}/readme/${sha}`,
        options,
      },
      blobSchema,
@@ -200,7 +202,7 @@ export class Client {
  }

  public async getBlob(
-
    id: string,
+
    rid: string,
    sha: string,
    path: string,
    options?: RequestOptions,
@@ -208,7 +210,7 @@ export class Client {
    const blob = await this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/blob/${sha}/${path}`,
+
        path: `repos/${rid}/blob/${sha}/${path}`,
        options,
      },
      blobSchema,
@@ -217,7 +219,7 @@ export class Client {
  }

  public async getTree(
-
    id: string,
+
    rid: string,
    sha: string,
    path?: string,
    options?: RequestOptions,
@@ -225,7 +227,7 @@ export class Client {
    const tree = await this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/tree/${sha}/${path ?? ""}`,
+
        path: `repos/${rid}/tree/${sha}/${path ?? ""}`,
        options,
      },
      treeSchema,
@@ -234,14 +236,14 @@ export class Client {
  }

  public async getTreeStatsBySha(
-
    id: string,
+
    rid: string,
    sha: string,
    options?: RequestOptions,
  ): Promise<TreeStats> {
    const tree = await this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/stats/tree/${sha}`,
+
        path: `repos/${rid}/stats/tree/${sha}`,
        options,
      },
      treeStatsSchema,
@@ -250,13 +252,13 @@ export class Client {
  }

  public async getAllRemotes(
-
    id: string,
+
    rid: string,
    options?: RequestOptions,
  ): Promise<Remote[]> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/remotes`,
+
        path: `repos/${rid}/remotes`,
        options,
      },
      remotesSchema,
@@ -264,14 +266,14 @@ export class Client {
  }

  public async getRemoteByPeer(
-
    id: string,
+
    rid: string,
    peer: string,
    options?: RequestOptions,
  ): Promise<Remote> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/remotes/${peer}`,
+
        path: `repos/${rid}/remotes/${peer}`,
        options,
      },
      remoteSchema,
@@ -279,7 +281,7 @@ export class Client {
  }

  public async getAllCommits(
-
    id: string,
+
    rid: string,
    query?: {
      parent?: string;
      since?: number;
@@ -292,7 +294,7 @@ export class Client {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/commits`,
+
        path: `repos/${rid}/commits`,
        query,
        options,
      },
@@ -301,14 +303,14 @@ export class Client {
  }

  public async getCommitBySha(
-
    id: string,
+
    rid: string,
    sha: string,
    options?: RequestOptions,
  ): Promise<Commit> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/commits/${sha}`,
+
        path: `repos/${rid}/commits/${sha}`,
        options,
      },
      commitSchema,
@@ -316,7 +318,7 @@ export class Client {
  }

  public async getDiff(
-
    id: string,
+
    rid: string,
    revisionBase: string,
    revisionOid: string,
    options?: RequestOptions,
@@ -324,7 +326,7 @@ export class Client {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/diff/${revisionBase}/${revisionOid}`,
+
        path: `repos/${rid}/diff/${revisionBase}/${revisionOid}`,
        options,
      },
      diffResponseSchema,
@@ -332,14 +334,14 @@ export class Client {
  }

  public async getIssueById(
-
    id: string,
+
    rid: string,
    issueId: string,
    options?: RequestOptions,
  ): Promise<Issue> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/issues/${issueId}`,
+
        path: `repos/${rid}/issues/${issueId}`,
        options,
      },
      issueSchema,
@@ -347,7 +349,7 @@ export class Client {
  }

  public async getAllIssues(
-
    id: string,
+
    rid: string,
    query?: {
      page?: number;
      perPage?: number;
@@ -358,7 +360,7 @@ export class Client {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/issues`,
+
        path: `repos/${rid}/issues`,
        query,
        options,
      },
@@ -367,14 +369,14 @@ export class Client {
  }

  public async getPatchById(
-
    id: string,
+
    rid: string,
    patchId: string,
    options?: RequestOptions,
  ): Promise<Patch> {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/patches/${patchId}`,
+
        path: `repos/${rid}/patches/${patchId}`,
        options,
      },
      patchSchema,
@@ -382,7 +384,7 @@ export class Client {
  }

  public async getAllPatches(
-
    id: string,
+
    rid: string,
    query?: {
      page?: number;
      perPage?: number;
@@ -393,7 +395,7 @@ export class Client {
    return this.#fetcher.fetchOk(
      {
        method: "GET",
-
        path: `projects/${id}/patches`,
+
        path: `repos/${rid}/patches`,
        query,
        options,
      },
modified http-client/tests/project.test.ts
@@ -9,7 +9,7 @@ import {
  sourceBrowsingRid,
} from "@tests/support/fixtures.js";

-
describe("project", () => {
+
describe("repo", () => {
  const api = new HttpdClient({
    hostname: "127.0.0.1",
    port: defaultHttpdPort,
@@ -17,59 +17,56 @@ describe("project", () => {
  });

  test("#getByDelegate(delegateId)", async () => {
-
    await api.project.getByDelegate(aliceRemote);
+
    await api.repo.getByDelegate(aliceRemote);
  });

  test("#getAll()", async () => {
-
    await api.project.getAll();
+
    await api.repo.getAll();
  });

-
  test("#getById(id)", async () => {
-
    await api.project.getById(sourceBrowsingRid);
+
  test("#getByRid(rid)", async () => {
+
    await api.repo.getByRid(sourceBrowsingRid);
  });

-
  test("#getActivity(id)", async () => {
-
    await api.project.getActivity(sourceBrowsingRid);
+
  test("#getActivity(rid)", async () => {
+
    await api.repo.getActivity(sourceBrowsingRid);
  });

-
  test("#getReadme(id, sha)", async () => {
-
    await api.project.getReadme(sourceBrowsingRid, aliceMainHead);
+
  test("#getReadme(rid, sha)", async () => {
+
    await api.repo.getReadme(sourceBrowsingRid, aliceMainHead);
  });

-
  test("#getBlob(id, sha, path)", async () => {
-
    await api.project.getBlob(sourceBrowsingRid, aliceMainHead, "src/true.c");
+
  test("#getBlob(rid, sha, path)", async () => {
+
    await api.repo.getBlob(sourceBrowsingRid, aliceMainHead, "src/true.c");
  });

-
  test("#getTree(id, sha)", async () => {
-
    await api.project.getTree(sourceBrowsingRid, aliceMainHead);
+
  test("#getTree(rid, sha)", async () => {
+
    await api.repo.getTree(sourceBrowsingRid, aliceMainHead);
  });

-
  test("#getTreeStats(id, sha)", async () => {
-
    await api.project.getTreeStatsBySha(sourceBrowsingRid, aliceMainHead);
+
  test("#getTreeStats(rid, sha)", async () => {
+
    await api.repo.getTreeStatsBySha(sourceBrowsingRid, aliceMainHead);
  });

-
  test("#getTree(id, sha, path)", async () => {
-
    await api.project.getTree(sourceBrowsingRid, aliceMainHead, "src");
+
  test("#getTree(rid, sha, path)", async () => {
+
    await api.repo.getTree(sourceBrowsingRid, aliceMainHead, "src");
  });

-
  test("#getAllRemotes(id)", async () => {
-
    await api.project.getAllRemotes(sourceBrowsingRid);
+
  test("#getAllRemotes(rid)", async () => {
+
    await api.repo.getAllRemotes(sourceBrowsingRid);
  });

-
  test("#getRemoteByPeer(id, peer)", async () => {
-
    await api.project.getRemoteByPeer(
-
      sourceBrowsingRid,
-
      aliceRemote.substring(8),
-
    );
+
  test("#getRemoteByPeer(rid, peer)", async () => {
+
    await api.repo.getRemoteByPeer(sourceBrowsingRid, aliceRemote.substring(8));
  });

-
  test("#getAllCommits(id)", async () => {
-
    await api.project.getAllCommits(sourceBrowsingRid);
+
  test("#getAllCommits(rid)", async () => {
+
    await api.repo.getAllCommits(sourceBrowsingRid);
  });

  // TODO: test since/until properly.
-
  test("#getAllCommits(id, {parent, since, until, page, perPage})", async () => {
-
    await api.project.getAllCommits(sourceBrowsingRid, {
+
  test("#getAllCommits(rid, {parent, since, until, page, perPage})", async () => {
+
    await api.repo.getAllCommits(sourceBrowsingRid, {
      parent: aliceMainHead,
      since: 1679065819581,
      until: 1679065819590,
@@ -78,41 +75,41 @@ describe("project", () => {
    });
  });

-
  test("#getCommitBySha(id, sha)", async () => {
-
    await api.project.getCommitBySha(sourceBrowsingRid, aliceMainHead);
+
  test("#getCommitBySha(rid, sha)", async () => {
+
    await api.repo.getCommitBySha(sourceBrowsingRid, aliceMainHead);
  });

-
  test("#getDiff(id, revisionBase, revisionOid)", async () => {
-
    await api.project.getDiff(
+
  test("#getDiff(rid, revisionBase, revisionOid)", async () => {
+
    await api.repo.getDiff(
      sourceBrowsingRid,
      "90f6d058ece12f75f349bc7bbe88142187fe0379",
      aliceMainHead,
    );
  });

-
  test("#getIssueById(id, issueId)", async () => {
-
    await api.project.getIssueById(
+
  test("#getIssueById(rid, issueId)", async () => {
+
    await api.repo.getIssueById(
      cobRid,
      "d481fe6e562dd78129589d4738f171a8380fcb19",
    );
  });

-
  test("#getAllIssues(id)", async () => {
-
    await api.project.getAllIssues(cobRid, {
+
  test("#getAllIssues(rid)", async () => {
+
    await api.repo.getAllIssues(cobRid, {
      page: 0,
      perPage: 5,
      status: "open",
    });
  });

-
  test("#getPatchById(id, patchId)", async () => {
-
    await api.project.getPatchById(
+
  test("#getPatchByOid(rid, patchId)", async () => {
+
    await api.repo.getPatchById(
      cobRid,
      "59a0821edc73630bce540596cffc7854da557365",
    );
  });

-
  test("#getAllPatches(id)", async () => {
-
    await api.project.getAllPatches(cobRid);
+
  test("#getAllPatches(rid)", async () => {
+
    await api.repo.getAllPatches(cobRid);
  });
});
modified http-client/tests/support/support.ts
@@ -12,7 +12,7 @@ export async function assertIssue(
) {
  expect(
    //@prettier-ignore looks more readable than what prettier suggests.
-
    isMatch(await api.project.getIssueById(cobRid, oid), change),
+
    isMatch(await api.repo.getIssueById(cobRid, oid), change),
  ).toBe(true);
}

@@ -23,6 +23,6 @@ export async function assertPatch(
) {
  expect(
    //@prettier-ignore looks more readable than what prettier suggests.
-
    isMatch(await api.project.getPatchById(cobRid, oid), change),
+
    isMatch(await api.repo.getPatchById(cobRid, oid), change),
  ).toBe(true);
}
modified playwright.config.ts
@@ -87,7 +87,7 @@ const config: PlaywrightTestConfig = {
      command: "npm run start -- --strictPort --port 3001",
      port: 3001,
    },
-
    // Required by test tests/e2e/project/commits.spec.ts "loading more commits, adds them to the commits list"
+
    // Required by test tests/e2e/repo/commits.spec.ts "loading more commits, adds them to the commits list"
    {
      command: "npm run start -- --strictPort --port 3002",
      port: 3002,
modified src/App.svelte
@@ -63,19 +63,19 @@
  <Nodes {...$activeRouteStore.params} />
{:else if $activeRouteStore.resource === "users"}
  <Users {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.source"}
+
{:else if $activeRouteStore.resource === "repo.source"}
  <Source {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.history"}
+
{:else if $activeRouteStore.resource === "repo.history"}
  <History {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.commit"}
+
{:else if $activeRouteStore.resource === "repo.commit"}
  <Commit {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.issues"}
+
{:else if $activeRouteStore.resource === "repo.issues"}
  <Issues {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.issue"}
+
{:else if $activeRouteStore.resource === "repo.issue"}
  <Issue {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.patches"}
+
{:else if $activeRouteStore.resource === "repo.patches"}
  <Patches {...$activeRouteStore.params} />
-
{:else if $activeRouteStore.resource === "project.patch"}
+
{:else if $activeRouteStore.resource === "repo.patch"}
  <Patch {...$activeRouteStore.params} />
{:else if $activeRouteStore.resource === "error"}
  <Error {...$activeRouteStore.params} />
modified src/components/Markdown.svelte
@@ -134,7 +134,7 @@
    }

    // Iterate over all images, and replace the source with a canonicalized URL
-
    // pointing at the projects /raw endpoint.
+
    // pointing at the repos /raw endpoint.
    for (const i of container.querySelectorAll("img")) {
      const imagePath = i.getAttribute("src");

modified src/components/ProjectCard.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { ProjectInfo } from "./ProjectCard";
+
  import type { RepoInfo } from "./ProjectCard";

  import {
    absoluteTimestamp,
@@ -14,15 +14,16 @@
  import Link from "@app/components/Link.svelte";

  export let compact = false;
-
  export let projectInfo: ProjectInfo;
+
  export let repoInfo: RepoInfo;

-
  $: project = projectInfo.project;
-
  $: baseUrl = projectInfo.baseUrl;
-
  $: isPrivate = project.visibility?.type === "private";
+
  $: repo = repoInfo.repo;
+
  $: project = repoInfo.repo["xyz.radicle.project"];
+
  $: baseUrl = repoInfo.baseUrl;
+
  $: isPrivate = repo.visibility?.type === "private";
</script>

<style>
-
  .project-card {
+
  .repo-card {
    height: 10rem;
    border: 1px solid var(--color-border-default);
    border-radius: var(--border-radius-small);
@@ -35,11 +36,11 @@
    overflow: hidden;
  }

-
  .project-card.compact {
+
  .repo-card.compact {
    height: 8rem;
  }

-
  .project-card:hover {
+
  .repo-card:hover {
    background-color: var(--color-fill-float-hover);
  }

@@ -64,7 +65,7 @@
    );
  }

-
  .project-card:hover .fadeout-overlay {
+
  .repo-card:hover .fadeout-overlay {
    background: linear-gradient(
      to right,
      var(--color-fill-float-hover) 20%,
@@ -129,18 +130,18 @@

<Link
  route={{
-
    resource: "project.source",
-
    project: project.id,
+
    resource: "repo.source",
+
    repo: repo.rid,
    node: baseUrl,
  }}>
-
  <div class="project-card" class:compact>
+
  <div class="repo-card" class:compact>
    <div class="activity">
      <div class="fadeout-overlay" />
      <ActivityDiagram
-
        id={project.id}
+
        id={repo.rid}
        viewBoxHeight={200}
        styleColor="var(--color-foreground-primary"
-
        activity={projectInfo.activity} />
+
        activity={repoInfo.activity} />
    </div>
    <div class="title">
      <div class="headline-and-badges">
@@ -160,32 +161,32 @@
            size="tiny"
            style="padding: 0 0.372rem; gap: 0.125rem;">
            <Icon name="seedling" />
-
            {projectInfo.project.seeding}
+
            {repoInfo.repo.seeding}
          </Badge>
        </div>
      </div>
-
      <p class="txt-small" use:twemoji>{project.description}</p>
+
      <p class="txt-small" use:twemoji>
+
        {project.description}
+
      </p>
    </div>
    <div>
      <div class="stats-row txt-tiny" style:color="var(--color-foreground-dim)">
        <Icon name="issue" />
-
        {project.issues.open} ·
+
        {repo.issues.open} ·
        <Icon name="patch" />
        <span
          style:overflow="hidden"
          style:text-overflow="ellipsis"
-
          title={absoluteTimestamp(
-
            projectInfo.lastCommit.commit.committer.time,
-
          )}>
-
          {project.patches.open} · Updated {formatTimestamp(
-
            projectInfo.lastCommit.commit.committer.time,
+
          title={absoluteTimestamp(repoInfo.lastCommit.commit.committer.time)}>
+
          {repo.patches.open} · Updated {formatTimestamp(
+
            repoInfo.lastCommit.commit.committer.time,
          )}
        </span>
        <span
-
          title={project.id}
+
          title={repo.rid}
          style:color="var(--color-foreground-emphasized)"
          style:margin-left="auto">
-
          {formatRepositoryId(project.id)}
+
          {formatRepositoryId(repo.rid)}
        </span>
      </div>
    </div>
modified src/components/ProjectCard.ts
@@ -1,40 +1,35 @@
-
import type { ProjectListQuery } from "@http-client";
+
import type { Repo, RepoListQuery } from "@http-client";

-
import { loadProjectActivity, type WeeklyActivity } from "@app/lib/commit";
-
import {
-
  HttpdClient,
-
  type BaseUrl,
-
  type Commit,
-
  type Project,
-
} from "@http-client";
+
import { loadRepoActivity, type WeeklyActivity } from "@app/lib/commit";
+
import { HttpdClient, type BaseUrl, type Commit } from "@http-client";

-
export interface ProjectInfo {
-
  project: Project;
+
export interface RepoInfo {
+
  repo: Repo;
  baseUrl: BaseUrl;
  activity: WeeklyActivity[];
  lastCommit: Commit;
}

-
export async function fetchProjectInfos(
+
export async function fetchRepoInfos(
  baseUrl: BaseUrl,
-
  query?: ProjectListQuery,
+
  query?: RepoListQuery,
  delegate?: string,
-
): Promise<ProjectInfo[]> {
+
): Promise<RepoInfo[]> {
  const api = new HttpdClient(baseUrl);
-
  let projects: Project[];
+
  let repos: Repo[];

  if (delegate) {
-
    projects = await api.project.getByDelegate(delegate, query);
+
    repos = await api.repo.getByDelegate(delegate, query);
  } else {
-
    projects = await api.project.getAll(query);
+
    repos = await api.repo.getAll(query);
  }
  const info = await Promise.all(
-
    projects.map(async project => {
+
    repos.map(async repo => {
      const [activity, lastCommit] = await Promise.all([
-
        loadProjectActivity(project.id, baseUrl),
-
        api.project.getCommitBySha(project.id, project.head),
+
        loadRepoActivity(repo.rid, baseUrl),
+
        api.repo.getCommitBySha(repo.rid, repo.head),
      ]);
-
      return { project, activity, lastCommit, baseUrl };
+
      return { repo, activity, lastCommit, baseUrl };
    }),
  );

modified src/lib/commit.ts
@@ -110,9 +110,9 @@ function groupCommitsByWeek(commits: number[]): WeeklyActivity[] {
  return groupedCommits;
}

-
export async function loadProjectActivity(id: string, baseUrl: BaseUrl) {
+
export async function loadRepoActivity(id: string, baseUrl: BaseUrl) {
  const api = new HttpdClient(baseUrl);
-
  const commits = await api.project.getActivity(id);
+
  const commits = await api.repo.getActivity(id);

  return groupCommitsByWeek(commits.activity);
}
modified src/lib/markdown.ts
@@ -71,7 +71,7 @@ export class Renderer extends BaseRenderer {
      return `<a ${title ? `title="${title}"` : ""} href="${href.toLowerCase()}">${text}</a>`;
    }

-
    if (this.#route.resource === "project.source" && !isUrl(href)) {
+
    if (this.#route.resource === "repo.source" && !isUrl(href)) {
      href = routeToPath({
        ...this.#route,
        path: canonicalize(href, this.#route.path || "README.md"),
modified src/lib/router.ts
@@ -7,9 +7,9 @@ import * as mutexExecutor from "@app/lib/mutexExecutor";
import * as utils from "@app/lib/utils";
import config from "virtual:config";
import {
-
  projectRouteToPath,
-
  projectTitle,
-
  resolveProjectRoute,
+
  repoRouteToPath,
+
  repoTitle,
+
  resolveRepoRoute,
} from "@app/views/projects/router";
import { loadRoute } from "@app/lib/router/definitions";
import { nodePath } from "@app/views/nodes/router";
@@ -119,15 +119,15 @@ function setTitle(loadedRoute: LoadedRoute) {
    title.push("Page not found");
    title.push("Radicle");
  } else if (
-
    loadedRoute.resource === "project.source" ||
-
    loadedRoute.resource === "project.history" ||
-
    loadedRoute.resource === "project.commit" ||
-
    loadedRoute.resource === "project.issue" ||
-
    loadedRoute.resource === "project.issues" ||
-
    loadedRoute.resource === "project.patches" ||
-
    loadedRoute.resource === "project.patch"
+
    loadedRoute.resource === "repo.source" ||
+
    loadedRoute.resource === "repo.history" ||
+
    loadedRoute.resource === "repo.commit" ||
+
    loadedRoute.resource === "repo.issue" ||
+
    loadedRoute.resource === "repo.issues" ||
+
    loadedRoute.resource === "repo.patches" ||
+
    loadedRoute.resource === "repo.patch"
  ) {
-
    title.push(...projectTitle(loadedRoute));
+
    title.push(...repoTitle(loadedRoute));
  } else if (loadedRoute.resource === "nodes") {
    title.push(loadedRoute.params.baseUrl.hostname);
  } else {
@@ -196,11 +196,11 @@ function urlToRoute(url: URL): Route | null {
          }
          return null;
        } else if (id) {
-
          return resolveProjectRoute(baseUrl, id, segments, url.search);
+
          return resolveRepoRoute(baseUrl, id, segments, url.search);
        } else {
          return {
            resource: "nodes",
-
            params: { baseUrl, projectPageIndex: 0 },
+
            params: { baseUrl, repoPageIndex: 0 },
          };
        }
      } else {
@@ -229,15 +229,15 @@ export function routeToPath(route: Route): string {
  } else if (route.resource === "users") {
    return userRouteToPath(route);
  } else if (
-
    route.resource === "project.source" ||
-
    route.resource === "project.history" ||
-
    route.resource === "project.commit" ||
-
    route.resource === "project.issues" ||
-
    route.resource === "project.issue" ||
-
    route.resource === "project.patches" ||
-
    route.resource === "project.patch"
+
    route.resource === "repo.source" ||
+
    route.resource === "repo.history" ||
+
    route.resource === "repo.commit" ||
+
    route.resource === "repo.issues" ||
+
    route.resource === "repo.issue" ||
+
    route.resource === "repo.patches" ||
+
    route.resource === "repo.patch"
  ) {
-
    return projectRouteToPath(route);
+
    return repoRouteToPath(route);
  } else if (
    route.resource === "booting" ||
    route.resource === "notFound" ||
modified src/lib/router/definitions.ts
@@ -2,16 +2,13 @@ import type {
  ResponseError,
  ResponseParseError,
} from "@http-client/lib/fetcher";
-
import type {
-
  ProjectLoadedRoute,
-
  ProjectRoute,
-
} from "@app/views/projects/router";
+
import type { RepoLoadedRoute, RepoRoute } from "@app/views/projects/router";
import type { UserLoadedRoute, UserRoute } from "@app/views/users/router";
import type { NodesRoute, NodesLoadedRoute } from "@app/views/nodes/router";
import type { ComponentProps } from "svelte";
import type IconLarge from "@app/components/IconLarge.svelte";

-
import { loadProjectRoute } from "@app/views/projects/router";
+
import { loadRepoRoute } from "@app/views/projects/router";
import { loadUserRoute } from "@app/views/users/router";
import { loadNodeRoute } from "@app/views/nodes/router";

@@ -41,7 +38,7 @@ export type Route =
  | UserRoute
  | ErrorRoute
  | NotFoundRoute
-
  | ProjectRoute
+
  | RepoRoute
  | NodesRoute;

export type LoadedRoute =
@@ -49,7 +46,7 @@ export type LoadedRoute =
  | UserLoadedRoute
  | ErrorRoute
  | NotFoundRoute
-
  | ProjectLoadedRoute
+
  | RepoLoadedRoute
  | NodesLoadedRoute;

export async function loadRoute(
@@ -61,15 +58,15 @@ export async function loadRoute(
  } else if (route.resource === "users") {
    return await loadUserRoute(route);
  } else if (
-
    route.resource === "project.source" ||
-
    route.resource === "project.history" ||
-
    route.resource === "project.commit" ||
-
    route.resource === "project.issues" ||
-
    route.resource === "project.issue" ||
-
    route.resource === "project.patches" ||
-
    route.resource === "project.patch"
+
    route.resource === "repo.source" ||
+
    route.resource === "repo.history" ||
+
    route.resource === "repo.commit" ||
+
    route.resource === "repo.issues" ||
+
    route.resource === "repo.issue" ||
+
    route.resource === "repo.patches" ||
+
    route.resource === "repo.patch"
  ) {
-
    return await loadProjectRoute(route, previousLoaded);
+
    return await loadRepoRoute(route, previousLoaded);
  } else {
    return route;
  }
modified src/views/nodes/SeedSelector.svelte
@@ -59,7 +59,7 @@
      }
      void push({
        resource: "nodes",
-
        params: { baseUrl: seed, projectPageIndex: 0 },
+
        params: { baseUrl: seed, repoPageIndex: 0 },
      });
      selectedSeed.set(seed);
    }
@@ -72,7 +72,7 @@
    seedAddressInput = seed.hostname;
    void push({
      resource: "nodes",
-
      params: { baseUrl: seed, projectPageIndex: 0 },
+
      params: { baseUrl: seed, repoPageIndex: 0 },
    });
  }
</script>
modified src/views/nodes/View.svelte
@@ -3,7 +3,7 @@

  import * as router from "@app/lib/router";
  import { baseUrlToString } from "@app/lib/utils";
-
  import { fetchProjectInfos } from "@app/components/ProjectCard";
+
  import { fetchRepoInfos } from "@app/components/ProjectCard";
  import { handleError } from "@app/views/nodes/error";

  import Settings from "@app/App/Settings.svelte";
@@ -18,7 +18,7 @@
  import MobileFooter from "@app/App/MobileFooter.svelte";
  import Placeholder from "@app/components/Placeholder.svelte";
  import Popover from "@app/components/Popover.svelte";
-
  import ProjectCard from "@app/components/ProjectCard.svelte";
+
  import RepoCard from "@app/components/ProjectCard.svelte";

  import PolicyExplainer from "./PolicyExplainer.svelte";
  import SeedSelector from "./SeedSelector.svelte";
@@ -135,10 +135,10 @@
    width: 100%;
    margin-top: 1rem;
  }
-
  .projects {
+
  .repos {
    margin-top: 0;
  }
-
  .project-grid {
+
  .repo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr));
    gap: 1rem;
@@ -208,7 +208,7 @@
    .container {
      padding: 0;
    }
-
    .projects {
+
    .repos {
      margin-top: 3rem;
    }
    .mobile-footer {
@@ -406,21 +406,21 @@
            </div>
          {/if}

-
          <div class="projects">
-
            {#await fetchProjectInfos( baseUrl, { show: "pinned", perPage: stats.repos.total }, )}
+
          <div class="repos">
+
            {#await fetchRepoInfos( baseUrl, { show: "pinned", perPage: stats.repos.total }, )}
              <div style:height="35vh">
                <Loading small center />
              </div>
-
            {:then projectInfos}
-
              {#if projectInfos.length > 0}
-
                <div class="project-grid">
-
                  {#each projectInfos as projectInfo}
-
                    <ProjectCard {projectInfo} />
+
            {:then repoInfos}
+
              {#if repoInfos.length > 0}
+
                <div class="repo-grid">
+
                  {#each repoInfos as repoInfo}
+
                    <RepoCard {repoInfo} />
                  {/each}
                </div>
                <div class="subtitle">
-
                  {projectInfos.length}
-
                  pinned {projectInfos.length === 1
+
                  {repoInfos.length}
+
                  pinned {repoInfos.length === 1
                    ? "repository"
                    : "repositories"}
                </div>
modified src/views/nodes/router.ts
@@ -12,7 +12,7 @@ import { determineSeed } from "./SeedSelector";
export type NodesRouteParams =
  | {
      baseUrl: BaseUrl;
-
      projectPageIndex: number;
+
      repoPageIndex: number;
    }
  | undefined;

modified src/views/projects/Changeset.svelte
@@ -10,7 +10,7 @@
  export let diff: Diff;
  export let files: Record<string, CommitBlob>;
  export let baseUrl: BaseUrl;
-
  export let projectId: string;
+
  export let repoId: string;
  export let revision: string;

  let expanded = true;
@@ -102,7 +102,7 @@
      <div use:intersection={observer} id={"observer:" + path}>
        {#if "diff" in file}
          <FileDiff
-
            {projectId}
+
            {repoId}
            {baseUrl}
            {revision}
            {expanded}
@@ -120,7 +120,7 @@
            headerBadgeCaption={file.state}
            oldPath={file.oldPath}
            newPath={file.newPath}
-
            {projectId}
+
            {repoId}
            {baseUrl}
            {revision} />
        {/if}
modified src/views/projects/Changeset/FileDiff.svelte
@@ -31,7 +31,7 @@
  export let headerBadgeCaption: ChangesetWithDiff["state"];
  export let revision: string | undefined = undefined;
  export let baseUrl: BaseUrl;
-
  export let projectId: string;
+
  export let repoId: string;
  export let visible: boolean = false;
  export let expanded: boolean = true;

@@ -434,8 +434,8 @@
        {/if}
        <Link
          route={{
-
            resource: "project.source",
-
            project: projectId,
+
            resource: "repo.source",
+
            repo: repoId,
            node: baseUrl,
            path: filePath,
            revision,
modified src/views/projects/Changeset/FileLocationChange.svelte
@@ -12,7 +12,7 @@
  export let oldPath: string;
  export let revision: string | undefined = undefined;
  export let baseUrl: BaseUrl;
-
  export let projectId: string;
+
  export let repoId: string;
</script>

<style>
@@ -54,8 +54,8 @@
    <div style:margin-left="auto">
      <Link
        route={{
-
          resource: "project.source",
-
          project: projectId,
+
          resource: "repo.source",
+
          repo: repoId,
          node: baseUrl,
          path: newPath,
          revision,
modified src/views/projects/Cob/CobCommitTeaser.svelte
@@ -13,7 +13,7 @@

  export let baseUrl: BaseUrl;
  export let commit: CommitHeader;
-
  export let projectId: string;
+
  export let repoId: string;

  let commitMessageVisible = false;
</script>
@@ -62,8 +62,8 @@
    <div class="message">
      <Link
        route={{
-
          resource: "project.commit",
-
          project: projectId,
+
          resource: "repo.commit",
+
          repo: repoId,
          node: baseUrl,
          commit: commit.id,
        }}>
@@ -102,8 +102,8 @@
      <IconButton title="Browse repo at this commit">
        <Link
          route={{
-
            resource: "project.source",
-
            project: projectId,
+
            resource: "repo.source",
+
            repo: repoId,
            node: baseUrl,
            revision: commit.id,
          }}>
modified src/views/projects/Cob/Revision.svelte
@@ -37,7 +37,7 @@
  export let rawPath: (commit?: string) => string;
  export let patchId: string;
  export let patchState: PatchState;
-
  export let projectId: string;
+
  export let repoId: string;
  export let revisionBase: string;
  export let revisionId: string;
  export let revisionEdits: Revision["edits"];
@@ -107,7 +107,7 @@
      loading = true;
      response = await cachedGetDiff(
        api.baseUrl,
-
        projectId,
+
        repoId,
        fromCommit,
        revisionOid,
      );
@@ -293,8 +293,8 @@
              fromCommit,
            )}..{utils.formatCommit(revisionOid)}"
            route={{
-
              resource: "project.patch",
-
              project: projectId,
+
              resource: "repo.patch",
+
              repo: repoId,
              node: baseUrl,
              patch: patchId,
              view: { name: "diff", fromCommit, toCommit: revisionOid },
@@ -329,8 +329,8 @@
                revisionOid,
              )}"
              route={{
-
                resource: "project.patch",
-
                project: projectId,
+
                resource: "repo.patch",
+
                repo: repoId,
                node: baseUrl,
                patch: patchId,
                view: {
@@ -439,7 +439,7 @@
            {#each response.commits.reverse() as commit}
              <div class="commit" style:position="relative">
                <div class="commit-dot" />
-
                <CobCommitTeaser {commit} {baseUrl} {projectId} />
+
                <CobCommitTeaser {commit} {baseUrl} {repoId} />
              </div>
            {/each}
          </div>
modified src/views/projects/Commit.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { BaseUrl, Commit, Project, SeedingPolicy } from "@http-client";
+
  import type { BaseUrl, Commit, Repo, SeedingPolicy } from "@http-client";

  import { formatObjectId } from "@app/lib/utils";

@@ -17,7 +17,7 @@
  export let baseUrl: BaseUrl;
  export let seedingPolicy: SeedingPolicy;
  export let commit: Commit;
-
  export let project: Project;
+
  export let repo: Repo;
  export let nodeAvatarUrl: string | undefined;

  $: header = commit.commit;
@@ -49,13 +49,13 @@
  }
</style>

-
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {project}>
+
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {repo}>
  <svelte:fragment slot="breadcrumb">
    <Separator />
    <Link
      route={{
-
        resource: "project.history",
-
        project: project.id,
+
        resource: "repo.history",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Commits
@@ -78,8 +78,8 @@
          <div class="button-container">
            <Link
              route={{
-
                resource: "project.source",
-
                project: project.id,
+
                resource: "repo.source",
+
                repo: repo.rid,
                node: baseUrl,
                path: "/",
                revision: commit.commit.id,
@@ -101,7 +101,7 @@
    </div>
    <Changeset
      {baseUrl}
-
      projectId={project.id}
+
      repoId={repo.rid}
      files={commit.files}
      diff={commit.diff}
      revision={commit.commit.id} />
modified src/views/projects/Commit/CommitTeaser.svelte
@@ -13,7 +13,7 @@

  export let baseUrl: BaseUrl;
  export let commit: CommitHeader;
-
  export let projectId: string;
+
  export let repoId: string;

  let commitMessageVisible = false;
</script>
@@ -79,8 +79,8 @@
    <div class="message">
      <Link
        route={{
-
          resource: "project.commit",
-
          project: projectId,
+
          resource: "repo.commit",
+
          repo: repoId,
          node: baseUrl,
          commit: commit.id,
        }}>
@@ -112,8 +112,8 @@
      <IconButton title="Browse repo at this commit">
        <Link
          route={{
-
            resource: "project.source",
-
            project: projectId,
+
            resource: "repo.source",
+
            repo: repoId,
            node: baseUrl,
            revision: commit.id,
          }}>
modified src/views/projects/DiffStatBadgeLoader.svelte
@@ -8,13 +8,13 @@
  import Link from "@app/components/Link.svelte";
  import Loading from "@app/components/Loading.svelte";

-
  export let projectId: string;
+
  export let repoId: string;
  export let baseUrl: BaseUrl;
  export let patch: Patch;
  export let latestRevision: Revision;
</script>

-
{#await cachedGetDiff(baseUrl, projectId, latestRevision.base, latestRevision.oid)}
+
{#await cachedGetDiff(baseUrl, repoId, latestRevision.base, latestRevision.oid)}
  <Loading small />
{:then { diff }}
  <Link
@@ -22,8 +22,8 @@
      latestRevision.oid,
    )}"
    route={{
-
      resource: "project.patch",
-
      project: projectId,
+
      resource: "repo.patch",
+
      repo: repoId,
      node: baseUrl,
      patch: patch.id,
      view: {
modified src/views/projects/Header.svelte
@@ -3,7 +3,7 @@
</script>

<script lang="ts">
-
  import type { BaseUrl, Project } from "@http-client";
+
  import type { BaseUrl, Repo } from "@http-client";

  import Link from "@app/components/Link.svelte";
  import Button from "@app/components/Button.svelte";
@@ -11,7 +11,7 @@

  export let baseUrl: BaseUrl;
  export let activeTab: ActiveTab = undefined;
-
  export let project: Project;
+
  export let repo: Repo;
</script>

<style>
@@ -49,8 +49,8 @@
<div class="container">
  <Link
    route={{
-
      resource: "project.source",
-
      project: project.id,
+
      resource: "repo.source",
+
      repo: repo.rid,
      node: baseUrl,
      path: "/",
    }}>
@@ -65,8 +65,8 @@
  </Link>
  <Link
    route={{
-
      resource: "project.issues",
-
      project: project.id,
+
      resource: "repo.issues",
+
      repo: repo.rid,
      node: baseUrl,
    }}>
    <Button
@@ -82,7 +82,7 @@
          class="counter"
          class:selected={activeTab === "issues"}
          class:hover={hover && activeTab !== "issues"}>
-
          {project.issues.open}
+
          {repo.issues.open}
        </span>
      </div>
    </Button>
@@ -90,8 +90,8 @@

  <Link
    route={{
-
      resource: "project.patches",
-
      project: project.id,
+
      resource: "repo.patches",
+
      repo: repo.rid,
      node: baseUrl,
    }}>
    <Button
@@ -107,7 +107,7 @@
          class="counter"
          class:hover={hover && activeTab !== "patches"}
          class:selected={activeTab === "patches"}>
-
          {project.patches.open}
+
          {repo.patches.open}
        </span>
      </div>
    </Button>
modified src/views/projects/Header/SeedButton.svelte
@@ -5,7 +5,7 @@
  import Icon from "@app/components/Icon.svelte";
  import Popover from "@app/components/Popover.svelte";

-
  export let projectId: string;
+
  export let repoId: string;
  export let seedCount: number;
  export let disabled: boolean = false;
</script>
@@ -66,6 +66,6 @@
        Radicle CLI
      </ExternalLink> to start seeding this repository.
    </span>
-
    <Command command={`rad seed ${projectId}`} />
+
    <Command command={`rad seed ${repoId}`} />
  </div>
</Popover>
modified src/views/projects/History.svelte
@@ -2,12 +2,12 @@
  import type {
    BaseUrl,
    CommitHeader,
-
    Project,
+
    Repo,
    Remote,
    SeedingPolicy,
    Tree,
  } from "@http-client";
-
  import type { ProjectRoute } from "./router";
+
  import type { RepoRoute } from "./router";

  import config from "virtual:config";
  import { HttpdClient } from "@http-client";
@@ -22,7 +22,7 @@
  import Link from "@app/components/Link.svelte";
  import List from "@app/components/List.svelte";
  import Loading from "@app/components/Loading.svelte";
-
  import ProjectNameHeader from "./Source/ProjectNameHeader.svelte";
+
  import RepoNameHeader from "./Source/ProjectNameHeader.svelte";
  import Separator from "./Separator.svelte";

  export let baseUrl: BaseUrl;
@@ -31,7 +31,7 @@
  export let commitHeaders: CommitHeader[];
  export let peer: string | undefined;
  export let peers: Remote[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let revision: string | undefined;
  export let tree: Tree;
  export let nodeAvatarUrl: string | undefined;
@@ -45,10 +45,10 @@
  let allCommitHeaders: CommitHeader[];

  $: baseRoute = {
-
    resource: "project.history",
+
    resource: "repo.history",
    node: baseUrl,
-
    project: project.id,
-
  } as Extract<ProjectRoute, { resource: "project.history" }>;
+
    repo: repo.rid,
+
  } as Extract<RepoRoute, { resource: "repo.history" }>;
  $: {
    allCommitHeaders = commitHeaders;
    page = 0;
@@ -58,7 +58,7 @@
    loading = true;
    page += 1;
    try {
-
      const response = await api.project.getAllCommits(project.id, {
+
      const response = await api.repo.getAllCommits(repo.rid, {
        parent: allCommitHeaders[0].id,
        page,
        perPage: config.source.commitsPerPage,
@@ -92,19 +92,19 @@
  }
</style>

-
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {project} activeTab="source">
+
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {repo} activeTab="source">
  <svelte:fragment slot="breadcrumb">
    <Separator />
    <Link
      route={{
-
        resource: "project.history",
-
        project: project.id,
+
        resource: "repo.history",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Commits
    </Link>
  </svelte:fragment>
-
  <ProjectNameHeader {project} {baseUrl} slot="header" />
+
  <RepoNameHeader {repo} {baseUrl} slot="header" />

  <div style:margin="1rem" slot="subheader">
    <Header
@@ -112,7 +112,7 @@
      {commit}
      {peers}
      {peer}
-
      {project}
+
      {repo}
      {revision}
      {tree}
      node={baseUrl}
@@ -127,14 +127,14 @@
        <CommitTeaser
          slot="item"
          let:item
-
          projectId={project.id}
+
          repoId={repo.rid}
          {baseUrl}
          commit={item} />
      </List>
    {/each}
  </div>

-
  {#await api.project.getTreeStatsBySha(project.id, commit)}
+
  {#await api.repo.getTreeStatsBySha(repo.rid, commit)}
    <div class="more">
      <Loading small center />
    </div>
modified src/views/projects/Issue.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { BaseUrl, Issue, Project, SeedingPolicy } from "@http-client";
+
  import type { BaseUrl, Issue, Repo, SeedingPolicy } from "@http-client";

  import capitalize from "lodash/capitalize";
  import uniqBy from "lodash/uniqBy";
@@ -26,7 +26,7 @@
  export let baseUrl: BaseUrl;
  export let seedingPolicy: SeedingPolicy;
  export let issue: Issue;
-
  export let project: Project;
+
  export let repo: Repo;
  export let rawPath: (commit?: string) => string;
  export let nodeAvatarUrl: string | undefined;

@@ -128,7 +128,7 @@
<Layout
  {baseUrl}
  {nodeAvatarUrl}
-
  {project}
+
  {repo}
  {seedingPolicy}
  activeTab="issues"
  stylePaddingBottom="0">
@@ -136,8 +136,8 @@
    <Separator />
    <Link
      route={{
-
        resource: "project.issues",
-
        project: project.id,
+
        resource: "repo.issues",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Issues
@@ -215,7 +215,7 @@
            <Markdown
              breaks
              content={issue.discussion[0].body}
-
              rawPath={rawPath(project.head)} />
+
              rawPath={rawPath(repo.head)} />
          {:else}
            <span class="txt-missing">No description</span>
          {/if}
@@ -234,7 +234,7 @@
              <ThreadComponent
                {baseUrl}
                {thread}
-
                rawPath={rawPath(project.head)} />
+
                rawPath={rawPath(repo.head)} />
              {#if i < threads.length - 1}
                <div class="connector" />
              {/if}
modified src/views/projects/Issue/IssueTeaser.svelte
@@ -13,7 +13,7 @@

  export let baseUrl: BaseUrl;
  export let issue: Issue;
-
  export let projectId: string;
+
  export let repoId: string;

  $: commentCount = issue.discussion.reduce((acc, _curr, index) => {
    if (index !== 0) {
@@ -84,8 +84,8 @@
        <Link
          styleHoverState
          route={{
-
            resource: "project.issue",
-
            project: projectId,
+
            resource: "repo.issue",
+
            repo: repoId,
            node: baseUrl,
            issue: issue.id,
          }}>
modified src/views/projects/Issues.svelte
@@ -3,7 +3,7 @@
    BaseUrl,
    Issue,
    IssueState,
-
    Project,
+
    Repo,
    SeedingPolicy,
  } from "@http-client";

@@ -31,7 +31,7 @@
  export let baseUrl: BaseUrl;
  export let seedingPolicy: SeedingPolicy;
  export let issues: Issue[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let status: IssueState["status"];
  export let nodeAvatarUrl: string | undefined;

@@ -52,7 +52,7 @@
    loading = true;
    page += 1;
    try {
-
      const response = await api.project.getAllIssues(project.id, {
+
      const response = await api.repo.getAllIssues(repo.rid, {
        status,
        page,
        perPage: ISSUES_PER_PAGE,
@@ -72,7 +72,7 @@
  };

  $: showMoreButton =
-
    !loading && !error && allIssues.length < project.issues[status];
+
    !loading && !error && allIssues.length < repo.issues[status];
</script>

<style>
@@ -117,13 +117,13 @@
  }
</style>

-
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {project} activeTab="issues">
+
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {repo} activeTab="issues">
  <svelte:fragment slot="breadcrumb">
    <Separator />
    <Link
      route={{
-
        resource: "project.issues",
-
        project: project.id,
+
        resource: "repo.issues",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Issues
@@ -146,7 +146,7 @@
        </div>
        {capitalize(status)}
        <div class="dropdown-button-counter">
-
          {project.issues[status]}
+
          {repo.issues[status]}
        </div>
        <Icon name={expanded ? "chevron-up" : "chevron-down"} />
      </Button>
@@ -157,8 +157,8 @@
          slot="item"
          let:item
          route={{
-
            resource: "project.issues",
-
            project: project.id,
+
            resource: "repo.issues",
+
            repo: repo.rid,
            node: baseUrl,
            status: item,
          }}>
@@ -172,7 +172,7 @@
              <div
                class="dropdown-list-counter"
                class:selected={item === status}>
-
                {project.issues[item]}
+
                {repo.issues[item]}
              </div>
            </div>
          </DropdownListItem>
@@ -188,7 +188,7 @@
      slot="item"
      let:item
      {baseUrl}
-
      projectId={project.id}
+
      repoId={repo.rid}
      issue={item} />
  </List>

@@ -201,7 +201,7 @@
      {error} />
  {/if}

-
  {#if project.issues[status] === 0}
+
  {#if repo.issues[status] === 0}
    <div class="placeholder">
      <Placeholder iconName="no-issues" caption={`No ${status} issues`} />
    </div>
modified src/views/projects/Layout.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
  import type { ActiveTab } from "./Header.svelte";
-
  import type { BaseUrl, Project, SeedingPolicy } from "@http-client";
+
  import type { BaseUrl, Repo, SeedingPolicy } from "@http-client";

  import Button from "@app/components/Button.svelte";
  import Icon from "@app/components/Icon.svelte";
@@ -12,7 +12,7 @@
  export let activeTab: ActiveTab | undefined = undefined;
  export let seedingPolicy: SeedingPolicy;
  export let baseUrl: BaseUrl;
-
  export let project: Project;
+
  export let repo: Repo;
  export let stylePaddingBottom: string = "2.5rem";
  export let nodeAvatarUrl: string | undefined;
</script>
@@ -109,7 +109,7 @@
              resource: "nodes",
              params: {
                baseUrl,
-
                projectPageIndex: 0,
+
                repoPageIndex: 0,
              },
            }}>
            <img
@@ -126,15 +126,15 @@

        <Separator />

-
        <span class="breadcrumb" title={project.id}>
+
        <span class="breadcrumb" title={repo.rid}>
          <Link
            route={{
-
              resource: "project.source",
-
              project: project.id,
+
              resource: "repo.source",
+
              repo: repo.rid,
              node: baseUrl,
            }}>
            <div class="breadcrumb">
-
              {project.name}
+
              {repo["xyz.radicle.project"].name}
            </div>
          </Link>
        </span>
@@ -157,11 +157,11 @@
  </div>

  <div class="sidebar global-hide-on-medium-desktop-down">
-
    <Sidebar {seedingPolicy} {activeTab} {baseUrl} {project} />
+
    <Sidebar {seedingPolicy} {activeTab} {baseUrl} {repo} />
  </div>

  <div class="sidebar global-hide-on-mobile-down global-hide-on-desktop-up">
-
    <Sidebar {seedingPolicy} {activeTab} {baseUrl} {project} collapsedOnly />
+
    <Sidebar {seedingPolicy} {activeTab} {baseUrl} {repo} collapsedOnly />
  </div>

  <div class="content" style:padding-bottom={stylePaddingBottom}>
@@ -176,8 +176,8 @@
        <Link
          title="Home"
          route={{
-
            resource: "project.source",
-
            project: project.id,
+
            resource: "repo.source",
+
            repo: repo.rid,
            node: baseUrl,
            path: "/",
          }}>
@@ -191,10 +191,10 @@

      <div style:width="100%">
        <Link
-
          title={`${project.issues.open} Issues`}
+
          title={`${repo.issues.open} Issues`}
          route={{
-
            resource: "project.issues",
-
            project: project.id,
+
            resource: "repo.issues",
+
            repo: repo.rid,
            node: baseUrl,
          }}>
          <Button
@@ -207,10 +207,10 @@

      <div style:width="100%">
        <Link
-
          title={`${project.patches.open} Patches`}
+
          title={`${repo.patches.open} Patches`}
          route={{
-
            resource: "project.patches",
-
            project: project.id,
+
            resource: "repo.patches",
+
            repo: repo.rid,
            node: baseUrl,
          }}>
          <Button
modified src/views/projects/Patch.svelte
@@ -3,7 +3,7 @@
    Comment,
    Review,
    Merge,
-
    Project,
+
    Repo,
    Revision,
    Diff,
    SeedingPolicy,
@@ -79,7 +79,7 @@
  export let patch: Patch;
  export let stats: Diff["stats"];
  export let rawPath: (commit?: string) => string;
-
  export let project: Project;
+
  export let repo: Repo;
  export let view: PatchView;
  export let nodeAvatarUrl: string | undefined;

@@ -102,8 +102,8 @@
  let tabs: Record<Tab, { icon: ComponentProps<Icon>["name"]; route: Route }>;
  $: {
    const baseRoute = {
-
      resource: "project.patch",
-
      project: project.id,
+
      resource: "repo.patch",
+
      repo: repo.rid,
      node: baseUrl,
      patch: patch.id,
    } as const;
@@ -294,7 +294,7 @@

<Layout
  {baseUrl}
-
  {project}
+
  {repo}
  {nodeAvatarUrl}
  {seedingPolicy}
  activeTab="patches"
@@ -303,8 +303,8 @@
    <Separator />
    <Link
      route={{
-
        resource: "project.patches",
-
        project: project.id,
+
        resource: "repo.patches",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Patches
@@ -344,8 +344,8 @@
          </Badge>
          <Link
            route={{
-
              resource: "project.patch",
-
              project: project.id,
+
              resource: "repo.patch",
+
              repo: repo.rid,
              node: baseUrl,
              patch: patch.id,
              view: { name: "changes", revision: latestRevision.id },
@@ -423,7 +423,7 @@
          <div
            class="global-hide-on-mobile-down"
            style="margin-left: auto; margin-top: -0.5rem;">
-
            <RevisionSelector {view} {baseUrl} {patch} {project} />
+
            <RevisionSelector {view} {baseUrl} {patch} {repo} />
          </div>
        {/if}
        {#if view.name === "diff"}
@@ -446,7 +446,7 @@
            style:padding="0 1rem"
            style:display="flex"
            class="global-hide-on-small-desktop-up">
-
            <RevisionSelector {view} {baseUrl} {patch} {project} />
+
            <RevisionSelector {view} {baseUrl} {patch} {repo} />
          </div>
        {/if}
        {#if view.name === "diff"}
@@ -461,7 +461,7 @@
          </div>
          <Changeset
            {baseUrl}
-
            projectId={project.id}
+
            repoId={repo.rid}
            revision={view.toCommit}
            files={view.files}
            diff={view.diff} />
@@ -472,7 +472,7 @@
            <RevisionComponent
              {baseUrl}
              {rawPath}
-
              projectId={project.id}
+
              repoId={repo.rid}
              {timelines}
              {...revision}
              first={index === 0}
@@ -492,7 +492,7 @@
        {:else if view.name === "changes"}
          <Changeset
            {baseUrl}
-
            projectId={project.id}
+
            repoId={repo.rid}
            revision={view.oid}
            files={view.files}
            diff={view.diff} />
modified src/views/projects/Patch/PatchTeaser.svelte
@@ -13,7 +13,7 @@
  import Link from "@app/components/Link.svelte";
  import NodeId from "@app/components/NodeId.svelte";

-
  export let projectId: string;
+
  export let repoId: string;
  export let baseUrl: BaseUrl;
  export let patch: Patch;

@@ -99,8 +99,8 @@
      <Link
        styleHoverState
        route={{
-
          resource: "project.patch",
-
          project: projectId,
+
          resource: "repo.patch",
+
          repo: repoId,
          node: baseUrl,
          patch: patch.id,
        }}>
@@ -118,7 +118,7 @@
          {#if commentCount > 0}
            <CommentCounter {commentCount} />
          {/if}
-
          <DiffStatBadgeLoader {projectId} {baseUrl} {patch} {latestRevision} />
+
          <DiffStatBadgeLoader {repoId} {baseUrl} {patch} {latestRevision} />
        </div>
      </div>
    </div>
modified src/views/projects/Patch/RevisionSelector.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
  import type { PatchView } from "../router";
-
  import type { BaseUrl, Patch, Project } from "@http-client";
+
  import type { BaseUrl, Patch, Repo } from "@http-client";
  import * as utils from "@app/lib/utils";

  import Button from "@app/components/Button.svelte";
@@ -14,7 +14,7 @@
  export let view: Extract<PatchView, { name: "changes" }>;
  export let baseUrl: BaseUrl;
  export let patch: Patch;
-
  export let project: Project;
+
  export let repo: Repo;
</script>

<Popover
@@ -48,8 +48,8 @@
      <Link
        on:afterNavigate={closeFocused}
        route={{
-
          resource: "project.patch",
-
          project: project.id,
+
          resource: "repo.patch",
+
          repo: repo.rid,
          node: baseUrl,
          patch: patch.id,
          view: {
modified src/views/projects/Patches.svelte
@@ -3,7 +3,7 @@
    BaseUrl,
    Patch,
    PatchState,
-
    Project,
+
    Repo,
    SeedingPolicy,
  } from "@http-client";

@@ -31,7 +31,7 @@
  export let baseUrl: BaseUrl;
  export let seedingPolicy: SeedingPolicy;
  export let patches: Patch[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let status: PatchState["status"];
  export let nodeAvatarUrl: string | undefined;

@@ -52,7 +52,7 @@
    loading = true;
    page += 1;
    try {
-
      const response = await api.project.getAllPatches(project.id, {
+
      const response = await api.repo.getAllPatches(repo.rid, {
        status,
        page,
        perPage: PATCHES_PER_PAGE,
@@ -80,7 +80,7 @@
  };

  $: showMoreButton =
-
    !loading && !error && allPatches.length < project.patches[status];
+
    !loading && !error && allPatches.length < repo.patches[status];
</script>

<style>
@@ -125,13 +125,13 @@
  }
</style>

-
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {project} activeTab="patches">
+
<Layout {nodeAvatarUrl} {seedingPolicy} {baseUrl} {repo} activeTab="patches">
  <svelte:fragment slot="breadcrumb">
    <Separator />
    <Link
      route={{
-
        resource: "project.patches",
-
        project: project.id,
+
        resource: "repo.patches",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      Patches
@@ -154,7 +154,7 @@
        </div>
        {capitalize(status)}
        <div class="dropdown-button-counter">
-
          {project.patches[status]}
+
          {repo.patches[status]}
        </div>
        <Icon name={expanded ? "chevron-up" : "chevron-down"} />
      </Button>
@@ -164,8 +164,8 @@
          let:item
          on:afterNavigate={() => closeFocused()}
          route={{
-
            resource: "project.patches",
-
            project: project.id,
+
            resource: "repo.patches",
+
            repo: repo.rid,
            node: baseUrl,
            search: `status=${item}`,
          }}>
@@ -179,7 +179,7 @@
              <div
                class="dropdown-list-counter"
                class:selected={item === status}>
-
                {project.patches[item]}
+
                {repo.patches[item]}
              </div>
            </div>
          </DropdownListItem>
@@ -195,7 +195,7 @@
      slot="item"
      let:item
      {baseUrl}
-
      projectId={project.id}
+
      repoId={repo.rid}
      patch={item} />
  </List>

@@ -208,7 +208,7 @@
      {error} />
  {/if}

-
  {#if project.patches[status] === 0}
+
  {#if repo.patches[status] === 0}
    <div class="placeholder">
      <Placeholder iconName="no-patches" caption={`No ${status} patches`} />
    </div>
modified src/views/projects/Sidebar.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
  import type { ActiveTab } from "./Header.svelte";
-
  import type { BaseUrl, Project, SeedingPolicy } from "@http-client";
+
  import type { BaseUrl, Repo, SeedingPolicy } from "@http-client";

  import Button from "@app/components/Button.svelte";
  import ContextRepo from "@app/views/projects/Sidebar/ContextRepo.svelte";
@@ -15,7 +15,7 @@
  export let activeTab: ActiveTab | undefined = undefined;
  export let seedingPolicy: SeedingPolicy;
  export let baseUrl: BaseUrl;
-
  export let project: Project;
+
  export let repo: Repo;
  export let collapsedOnly = false;

  let expanded = collapsedOnly ? false : loadSidebarState();
@@ -64,7 +64,7 @@
  .sidebar.expanded {
    width: 22.5rem;
  }
-
  .project-navigation {
+
  .repo-navigation {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
@@ -163,12 +163,12 @@

<div class="sidebar" class:expanded>
  <!-- Top Navigation Items -->
-
  <div class="project-navigation">
+
  <div class="repo-navigation">
    <Link
      title="Source"
      route={{
-
        resource: "project.source",
-
        project: project.id,
+
        resource: "repo.source",
+
        repo: repo.rid,
        node: baseUrl,
        path: "/",
      }}>
@@ -183,10 +183,10 @@
      </Button>
    </Link>
    <Link
-
      title={`${project.issues.open} Issues`}
+
      title={`${repo.issues.open} Issues`}
      route={{
-
        resource: "project.issues",
-
        project: project.id,
+
        resource: "repo.issues",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      <Button
@@ -203,17 +203,17 @@
            class="counter"
            class:selected={activeTab === "issues"}
            class:hover={hover && activeTab !== "issues"}>
-
            {project.issues.open}
+
            {repo.issues.open}
          </span>
        </div>
      </Button>
    </Link>

    <Link
-
      title={`${project.patches.open} Patches`}
+
      title={`${repo.patches.open} Patches`}
      route={{
-
        resource: "project.patches",
-
        project: project.id,
+
        resource: "repo.patches",
+
        repo: repo.rid,
        node: baseUrl,
      }}>
      <Button
@@ -230,7 +230,7 @@
            class="counter"
            class:hover={hover && activeTab !== "patches"}
            class:selected={activeTab === "patches"}>
-
            {project.patches.open}
+
            {repo.patches.open}
          </span>
        </div>
      </Button>
@@ -241,8 +241,8 @@
    <div class="repo box" class:expanded>
      <ContextRepo
        {baseUrl}
-
        projectThreshold={project.threshold}
-
        projectDelegates={project.delegates}
+
        repoThreshold={repo.threshold}
+
        repoDelegates={repo.delegates}
        {seedingPolicy} />
    </div>
    <div class="vertical-buttons" class:expanded style:gap="0.5rem">
@@ -288,8 +288,8 @@
        <div slot="popover" class="txt-small" style:width="18rem">
          <ContextRepo
            {baseUrl}
-
            projectThreshold={project.threshold}
-
            projectDelegates={project.delegates}
+
            repoThreshold={repo.threshold}
+
            repoDelegates={repo.delegates}
            {seedingPolicy} />
        </div>
      </Popover>
modified src/views/projects/Sidebar/ContextRepo.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { BaseUrl, Project, SeedingPolicy } from "@http-client";
+
  import type { BaseUrl, Repo, SeedingPolicy } from "@http-client";

  import capitalize from "lodash/capitalize";

@@ -8,8 +8,8 @@
  import NodeId from "@app/components/NodeId.svelte";

  export let baseUrl: BaseUrl;
-
  export let projectThreshold: number;
-
  export let projectDelegates: Project["delegates"];
+
  export let repoThreshold: number;
+
  export let repoDelegates: Repo["delegates"];
  export let seedingPolicy: SeedingPolicy;

  let delegateExpanded = false;
@@ -40,7 +40,7 @@
  <span>Delegates</span>
  <div class="global-flex-item">
    <span class="txt-bold">
-
      {projectThreshold}/{projectDelegates.length}
+
      {repoThreshold}/{repoDelegates.length}
    </span>
    <IconButton on:click={() => (delegateExpanded = !delegateExpanded)}>
      <Icon name={delegateExpanded ? "chevron-up" : "chevron-down"} />
@@ -49,16 +49,16 @@
</div>
{#if delegateExpanded}
  <div style:color="var(--color-foreground-dim" style:margin-bottom="1rem">
-
    {#if projectDelegates.length === 1}
+
    {#if repoDelegates.length === 1}
      Any changes accepted by the sole delegate will be included in the
      canonical branch.
    {:else}
-
      {projectThreshold} out of {projectDelegates.length} delegates have to accept
-
      changes to be included in the canonical branch.
+
      {repoThreshold} out of {repoDelegates.length} delegates have to accept changes
+
      to be included in the canonical branch.
    {/if}
  </div>
  <div class="delegates">
-
    {#each projectDelegates as delegate}
+
    {#each repoDelegates as delegate}
      <div class="nid">
        <NodeId {baseUrl} nodeId={delegate.id} alias={delegate.alias} />
      </div>
modified src/views/projects/Source.svelte
@@ -1,12 +1,12 @@
<script lang="ts">
  import type {
    BaseUrl,
-
    Project,
+
    Repo,
    Remote,
    SeedingPolicy,
    Tree,
  } from "@http-client";
-
  import type { BlobResult, ProjectRoute } from "./router";
+
  import type { BlobResult, RepoRoute } from "./router";

  import { HttpdClient } from "@http-client";

@@ -17,7 +17,7 @@

  import BlobComponent from "./Source/Blob.svelte";
  import FilePath from "@app/components/FilePath.svelte";
-
  import ProjectNameHeader from "./Source/ProjectNameHeader.svelte";
+
  import RepoNameHeader from "./Source/ProjectNameHeader.svelte";
  import Separator from "./Separator.svelte";
  import TreeComponent from "./Source/Tree.svelte";

@@ -27,7 +27,7 @@
  export let path: string;
  export let peer: string | undefined;
  export let peers: Remote[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let rawPath: (commit?: string) => string;
  export let revision: string | undefined;
  export let seedingPolicy: SeedingPolicy;
@@ -39,26 +39,24 @@
  const api = new HttpdClient(baseUrl);

  const fetchTree = async (path: string) => {
-
    return api.project
-
      .getTree(project.id, tree.lastCommit.id, path)
-
      .catch(() => {
-
        blobResult = {
-
          ok: false,
-
          error: {
-
            message: "Not able to expand directory",
-
            path,
-
          },
-
        };
-
        return undefined;
-
      });
+
    return api.repo.getTree(repo.rid, tree.lastCommit.id, path).catch(() => {
+
      blobResult = {
+
        ok: false,
+
        error: {
+
          message: "Not able to expand directory",
+
          path,
+
        },
+
      };
+
      return undefined;
+
    });
  };

  $: baseRoute = {
-
    resource: "project.source",
+
    resource: "repo.source",
    node: baseUrl,
-
    project: project.id,
+
    repo: repo.rid,
    path: "/",
-
  } as Extract<ProjectRoute, { resource: "project.source" }>;
+
  } as Extract<RepoRoute, { resource: "repo.source" }>;
</script>

<style>
@@ -122,7 +120,7 @@
<Layout
  {baseUrl}
  {nodeAvatarUrl}
-
  {project}
+
  {repo}
  {seedingPolicy}
  activeTab="source"
  stylePaddingBottom="0">
@@ -132,7 +130,7 @@
      <FilePath filenameWithPath={path} />
    {/if}
  </svelte:fragment>
-
  <ProjectNameHeader {project} {baseUrl} slot="header" />
+
  <RepoNameHeader {repo} {baseUrl} slot="header" />

  <div style:margin="1rem" slot="subheader">
    <Header
@@ -143,7 +141,7 @@
      {baseRoute}
      {peers}
      {peer}
-
      {project}
+
      {repo}
      {revision}
      {tree} />
  </div>
@@ -164,7 +162,7 @@
      {#if mobileFileTree}
        <div class="layout-mobile" style:margin="1rem">
          <TreeComponent
-
            projectId={project.id}
+
            repoId={repo.rid}
            {revision}
            {baseUrl}
            {fetchTree}
@@ -184,7 +182,7 @@
      <div class="column-left global-hide-on-small-desktop-down">
        <div class="source-tree sticky">
          <TreeComponent
-
            projectId={project.id}
+
            repoId={repo.rid}
            {revision}
            {baseUrl}
            {fetchTree}
@@ -198,7 +196,7 @@
          <BlobComponent
            {path}
            {baseUrl}
-
            projectId={project.id}
+
            repoId={repo.rid}
            blob={blobResult.blob}
            highlighted={blobResult.highlighted}
            rawPath={rawPath(tree.lastCommit.id)} />
modified src/views/projects/Source/Blob.svelte
@@ -18,7 +18,7 @@
  import Radio from "@app/components/Radio.svelte";

  export let baseUrl: BaseUrl;
-
  export let projectId: string;
+
  export let repoId: string;
  export let path: string;
  export let blob: Blob;
  export let highlighted: Syntax.Root | undefined;
@@ -151,7 +151,7 @@
<File sticky={false}>
  <FilePath slot="left-header" filenameWithPath={blob.path} />
  <svelte:fragment slot="right-header">
-
    <CommitButton {projectId} {baseUrl} commit={lastCommit} />
+
    <CommitButton {repoId} {baseUrl} commit={lastCommit} />
    <div class="global-hide-on-mobile-down teaser-buttons">
      {#if enablePreview}
        <Radio ariaLabel="Toggle render method">
modified src/views/projects/Source/Header.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
-
  import type { ProjectRoute } from "../router";
-
  import type { BaseUrl, Project, Remote, Tree } from "@http-client";
+
  import type { RepoRoute } from "../router";
+
  import type { BaseUrl, Repo, Remote, Tree } from "@http-client";
  import type { ComponentProps } from "svelte";

  import { HttpdClient } from "@http-client";
@@ -18,10 +18,10 @@
  export let node: BaseUrl;
  export let peer: string | undefined;
  export let peers: Remote[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let baseRoute: Extract<
-
    ProjectRoute,
-
    { resource: "project.source" } | { resource: "project.history" }
+
    RepoRoute,
+
    { resource: "repo.source" } | { resource: "repo.history" }
  >;
  export let revision: string | undefined;
  export let tree: Tree;
@@ -36,11 +36,13 @@
  $: if (revision === lastCommit.id) {
    selectedBranch = undefined;
  } else {
-
    selectedBranch = revision || project.defaultBranch;
+
    selectedBranch = revision || repo["xyz.radicle.project"].defaultBranch;
  }

  $: lastCommit = tree.lastCommit;
-
  $: onCanonical = Boolean(!peer && selectedBranch === project.defaultBranch);
+
  $: onCanonical = Boolean(
+
    !peer && selectedBranch === repo["xyz.radicle.project"].defaultBranch,
+
  );
  $: if (onCanonical) {
    commitButtonVariant = "right";
  } else if (!selectedBranch) {
@@ -106,7 +108,7 @@
      {peer}
      {baseRoute}
      {onCanonical}
-
      {project}
+
      {repo}
      {selectedBranch} />
  {/if}
  <div class="global-flex-item txt-overflow" style:gap="1px">
@@ -115,7 +117,7 @@
      styleMinWidth="0"
      styleWidth="100%"
      hideSummaryOnMobile={false}
-
      projectId={project.id}
+
      repoId={repo.rid}
      commit={lastCommit}
      baseUrl={node} />
    {#if !onCanonical}
@@ -134,8 +136,8 @@
  <div style="display: flex; gap: 0.375rem;">
    <Link
      route={{
-
        resource: "project.source",
-
        project: project.id,
+
        resource: "repo.source",
+
        repo: repo.rid,
        node: node,
        peer,
        revision,
@@ -147,8 +149,8 @@

    <Link
      route={{
-
        resource: "project.history",
-
        project: project.id,
+
        resource: "repo.history",
+
        repo: repo.rid,
        node: node,
        peer,
        revision,
@@ -157,7 +159,7 @@
        <Icon name="commit" />
        <div class="title-counter">
          Commits
-
          {#await api.project.getTreeStatsBySha(project.id, commit)}
+
          {#await api.repo.getTreeStatsBySha(repo.rid, commit)}
            <Loading small center noDelay grayscale />
          {:then stats}
            <div class="counter" class:selected={historyLinkActive}>
modified src/views/projects/Source/PeerBranchSelector.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
-
  import type { ProjectRoute } from "@app/views/projects/router";
-
  import type { Project, Remote } from "@http-client";
+
  import type { RepoRoute } from "@app/views/projects/router";
+
  import type { Repo, Remote } from "@http-client";

  import fuzzysort from "fuzzysort";
  import orderBy from "lodash/orderBy";
@@ -17,13 +17,13 @@
  import Avatar from "@app/components/Avatar.svelte";

  export let baseRoute: Extract<
-
    ProjectRoute,
-
    { resource: "project.source" } | { resource: "project.history" }
+
    RepoRoute,
+
    { resource: "repo.source" } | { resource: "repo.history" }
  >;
  export let onCanonical: boolean;
  export let peer: string | undefined;
  export let peers: Remote[];
-
  export let project: Project;
+
  export let repo: Repo;
  export let selectedBranch: string | undefined;

  const subgridStyle =
@@ -37,8 +37,8 @@
  const searchElements = [
    {
      peer: undefined,
-
      revision: project.defaultBranch,
-
      head: project.head,
+
      revision: repo["xyz.radicle.project"].defaultBranch,
+
      head: repo.head,
    },
    ...peers.flatMap(peer =>
      Object.entries(peer.heads).map(([name, head]) => ({
@@ -252,7 +252,7 @@
              style={`${subgridStyle} gap: inherit;`}>
              <div class="global-flex-item">
                <Icon name="branch" />
-
                {project.defaultBranch}
+
                {repo["xyz.radicle.project"].defaultBranch}
                <Badge title="Canonical branch" variant="foreground-emphasized">
                  Canonical
                </Badge>
@@ -260,7 +260,7 @@
              <div
                class="txt-monospace"
                style="color: var(--color-foreground-dim);">
-
                {formatCommit(project.head)}
+
                {formatCommit(repo.head)}
              </div>
            </DropdownListItem>
          </Link>
modified src/views/projects/Source/PeerBranchSelector/Peer.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { ProjectRoute } from "@app/views/projects/router";
+
  import type { RepoRoute } from "@app/views/projects/router";
  import type { Remote } from "@http-client";

  import { closeFocused } from "@app/components/Popover.svelte";
@@ -14,8 +14,8 @@
  import NodeId from "@app/components/NodeId.svelte";

  export let baseRoute: Extract<
-
    ProjectRoute,
-
    { resource: "project.source" } | { resource: "project.history" }
+
    RepoRoute,
+
    { resource: "repo.source" } | { resource: "repo.history" }
  >;
  export let peer: { remote: Remote; selected: boolean };
  export let revision: string | undefined = undefined;
modified src/views/projects/Source/ProjectNameHeader.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-
  import type { BaseUrl, Project } from "@http-client";
+
  import type { BaseUrl, Repo } from "@http-client";

  import dompurify from "dompurify";
  import { markdownWithExtensions } from "@app/lib/markdown";
@@ -13,7 +13,7 @@
  import SeedButton from "@app/views/projects/Header/SeedButton.svelte";
  import Share from "@app/views/projects/Share.svelte";

-
  export let project: Project;
+
  export let repo: Repo;
  export let baseUrl: BaseUrl;

  function render(content: string): string {
@@ -21,6 +21,8 @@
      markdownWithExtensions.parseInline(content) as string,
    );
  }
+

+
  $: project = repo["xyz.radicle.project"];
</script>

<style>
@@ -38,10 +40,10 @@
  .description {
    padding: 0 1rem 1rem 1rem;
  }
-
  .project-name {
+
  .repo-name {
    font-weight: var(--font-weight-semibold);
  }
-
  .project-name:hover {
+
  .repo-name:hover {
    color: inherit;
  }
  .description :global(a) {
@@ -66,16 +68,16 @@
    <span class="txt-overflow">
      <Link
        route={{
-
          resource: "project.source",
-
          project: project.id,
+
          resource: "repo.source",
+
          repo: repo.rid,
          node: baseUrl,
        }}>
-
        <span class="project-name">
+
        <span class="repo-name">
          {project.name}
        </span>
      </Link>
    </span>
-
    {#if project.visibility && project.visibility.type === "private"}
+
    {#if repo.visibility && repo.visibility.type === "private"}
      <Badge variant="yellow" size="tiny">
        <Icon name="lock" />
        Private
@@ -87,22 +89,19 @@
        style:display="flex"
        style:gap="0.5rem"
        class="global-hide-on-mobile-down">
-
        <CloneButton {baseUrl} id={project.id} name={project.name} />
-
        <SeedButton seedCount={project.seeding} projectId={project.id} />
+
        <CloneButton {baseUrl} id={repo.rid} name={project.name} />
+
        <SeedButton seedCount={repo.seeding} repoId={repo.rid} />
      </div>
      <div
        style:display="flex"
        style:gap="0.5rem"
        class="global-hide-on-small-desktop-up">
-
        <SeedButton
-
          disabled
-
          seedCount={project.seeding}
-
          projectId={project.id} />
+
        <SeedButton disabled seedCount={repo.seeding} repoId={repo.rid} />
      </div>
    </div>
  </div>
  <div class="id">
-
    <Id shorten={false} id={project.id} ariaLabel="project-id" />
+
    <Id shorten={false} id={repo.rid} ariaLabel="repo-id" />
  </div>
</div>
<div class="description" use:twemoji>
modified src/views/projects/Source/Tree.svelte
@@ -12,7 +12,7 @@
  export let fetchTree: (path: string) => Promise<Tree | undefined>;
  export let path: string;
  export let peer: string | undefined;
-
  export let projectId: string;
+
  export let repoId: string;
  export let revision: string | undefined;
  export let tree: Tree;

@@ -32,15 +32,15 @@
      {baseUrl}
      {fetchTree}
      {peer}
-
      {projectId}
+
      {repoId}
      {revision} />
  {:else if entry.kind === "submodule"}
    <Submodule name={entry.name} oid={entry.oid} />
  {:else}
    <Link
      route={{
-
        resource: "project.source",
-
        project: projectId,
+
        resource: "repo.source",
+
        repo: repoId,
        node: baseUrl,
        path: entry.path,
        peer,
modified src/views/projects/Source/Tree/Folder.svelte
@@ -16,7 +16,7 @@
  export let name: string;
  export let peer: string | undefined;
  export let prefix: string;
-
  export let projectId: string;
+
  export let repoId: string;
  export let revision: string | undefined;

  $: expanded = currentPath.indexOf(prefix) === 0;
@@ -111,15 +111,15 @@
              {currentPath}
              {fetchTree}
              {peer}
-
              {projectId}
+
              {repoId}
              {revision} />
          {:else if entry.kind === "submodule"}
            <Submodule name={entry.name} oid={entry.oid} />
          {:else}
            <Link
              route={{
-
                resource: "project.source",
-
                project: projectId,
+
                resource: "repo.source",
+
                repo: repoId,
                node: baseUrl,
                path: entry.path,
                peer,
modified src/views/projects/components/CommitButton.svelte
@@ -8,7 +8,7 @@
  export let variant: "standalone" | "right" | "center" | "left" = "standalone";
  export let styleMinWidth: string | undefined = undefined;
  export let styleWidth: "100%" | undefined = undefined;
-
  export let projectId: string;
+
  export let repoId: string;
  export let baseUrl: BaseUrl;
  export let hideSummaryOnMobile: boolean = true;
  export let commit: Commit["commit"];
@@ -47,8 +47,8 @@
<Link
  styleTextOverflow
  route={{
-
    resource: "project.commit",
-
    project: projectId,
+
    resource: "repo.commit",
+
    repo: repoId,
    node: baseUrl,
    commit: commit.id,
  }}>
modified src/views/projects/error.ts
@@ -1,22 +1,22 @@
import type { ErrorRoute, NotFoundRoute } from "@app/lib/router/definitions";
-
import type { ProjectRoute } from "@app/views/projects/router";
+
import type { RepoRoute } from "@app/views/projects/router";

import { baseUrlToString } from "@app/lib/utils";
import { ResponseParseError, ResponseError } from "@http-client/lib/fetcher";

export function handleError(
  error: Error | ResponseParseError | ResponseError,
-
  route: ProjectRoute,
+
  route: RepoRoute,
): NotFoundRoute | ErrorRoute {
  const url = baseUrlToString(route.node);
  if (error instanceof ResponseError && error.status === 404) {
    let subject;

-
    if (route.resource === "project.commit") {
+
    if (route.resource === "repo.commit") {
      subject = "Commit";
-
    } else if (route.resource === "project.issue") {
+
    } else if (route.resource === "repo.issue") {
      subject = "Issue";
-
    } else if (route.resource === "project.patch") {
+
    } else if (route.resource === "repo.patch") {
      subject = "Patch";
    } else {
      subject = "Repository";
modified src/views/projects/router.ts
@@ -16,7 +16,7 @@ import type {
  Node,
  Patch,
  PatchState,
-
  Project,
+
  Repo,
  Remote,
  Revision,
  SeedingPolicy,
@@ -35,56 +35,56 @@ import { nodePath } from "@app/views/nodes/router";
export const PATCHES_PER_PAGE = 10;
export const ISSUES_PER_PAGE = 10;

-
export type ProjectRoute =
-
  | ProjectTreeRoute
-
  | ProjectHistoryRoute
+
export type RepoRoute =
+
  | RepoTreeRoute
+
  | RepoHistoryRoute
  | {
-
      resource: "project.commit";
+
      resource: "repo.commit";
      node: BaseUrl;
-
      project: string;
+
      repo: string;
      commit: string;
    }
-
  | ProjectIssuesRoute
-
  | ProjectIssueRoute
-
  | ProjectPatchesRoute
-
  | ProjectPatchRoute;
+
  | RepoIssuesRoute
+
  | RepoIssueRoute
+
  | RepoPatchesRoute
+
  | RepoPatchRoute;

-
interface ProjectIssuesRoute {
-
  resource: "project.issues";
+
interface RepoIssuesRoute {
+
  resource: "repo.issues";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  status?: "open" | "closed";
}

-
interface ProjectIssueRoute {
-
  resource: "project.issue";
+
interface RepoIssueRoute {
+
  resource: "repo.issue";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  issue: string;
}

-
interface ProjectTreeRoute {
-
  resource: "project.source";
+
interface RepoTreeRoute {
+
  resource: "repo.source";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  path?: string;
  peer?: string;
  revision?: string;
  route?: string;
}

-
interface ProjectHistoryRoute {
-
  resource: "project.history";
+
interface RepoHistoryRoute {
+
  resource: "repo.history";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  peer?: string;
  revision?: string;
}

-
interface ProjectPatchRoute {
-
  resource: "project.patch";
+
interface RepoPatchRoute {
+
  resource: "repo.patch";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  patch: string;
  view?:
    | {
@@ -101,21 +101,21 @@ interface ProjectPatchRoute {
      };
}

-
interface ProjectPatchesRoute {
-
  resource: "project.patches";
+
interface RepoPatchesRoute {
+
  resource: "repo.patches";
  node: BaseUrl;
-
  project: string;
+
  repo: string;
  search?: string;
}

-
export type ProjectLoadedRoute =
+
export type RepoLoadedRoute =
  | {
-
      resource: "project.source";
+
      resource: "repo.source";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
        commit: string;
-
        project: Project;
+
        repo: Repo;
        peers: Remote[];
        peer: string | undefined;
        revision: string | undefined;
@@ -127,12 +127,12 @@ export type ProjectLoadedRoute =
      };
    }
  | {
-
      resource: "project.history";
+
      resource: "repo.history";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
        commit: string;
-
        project: Project;
+
        repo: Repo;
        peers: Remote[];
        peer: string | undefined;
        revision: string | undefined;
@@ -142,54 +142,54 @@ export type ProjectLoadedRoute =
      };
    }
  | {
-
      resource: "project.commit";
+
      resource: "repo.commit";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
-
        project: Project;
+
        repo: Repo;
        commit: Commit;
        nodeAvatarUrl: string | undefined;
      };
    }
  | {
-
      resource: "project.issue";
+
      resource: "repo.issue";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
-
        project: Project;
+
        repo: Repo;
        rawPath: (commit?: string) => string;
        issue: Issue;
        nodeAvatarUrl: string | undefined;
      };
    }
  | {
-
      resource: "project.issues";
+
      resource: "repo.issues";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
-
        project: Project;
+
        repo: Repo;
        issues: Issue[];
        status: IssueState["status"];
        nodeAvatarUrl: string | undefined;
      };
    }
  | {
-
      resource: "project.patches";
+
      resource: "repo.patches";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
-
        project: Project;
+
        repo: Repo;
        patches: Patch[];
        status: PatchState["status"];
        nodeAvatarUrl: string | undefined;
      };
    }
  | {
-
      resource: "project.patch";
+
      resource: "repo.patch";
      params: {
        baseUrl: BaseUrl;
        seedingPolicy: SeedingPolicy;
-
        project: Project;
+
        repo: Repo;
        rawPath: (commit?: string) => string;
        patch: Patch;
        stats: Diff["stats"];
@@ -231,7 +231,7 @@ function isOid(input: string): boolean {
export const cachedGetDiff = cached(
  async (baseUrl: BaseUrl, rid: string, base: string, oid: string) => {
    const api = new HttpdClient(baseUrl);
-
    return await api.project.getDiff(rid, base, oid);
+
    return await api.repo.getDiff(rid, base, oid);
  },
  (...args) => JSON.stringify(args),
  { max: 200 },
@@ -258,10 +258,10 @@ function parseRevisionToOid(
  }
}

-
export async function loadProjectRoute(
-
  route: ProjectRoute,
+
export async function loadRepoRoute(
+
  route: RepoRoute,
  previousLoaded: LoadedRoute,
-
): Promise<ProjectLoadedRoute | ErrorRoute | NotFoundRoute> {
+
): Promise<RepoLoadedRoute | ErrorRoute | NotFoundRoute> {
  if (
    import.meta.env.PROD &&
    isLocal(`${route.node.hostname}:${route.node.port}`)
@@ -278,35 +278,35 @@ export async function loadProjectRoute(
  const api = new HttpdClient(route.node);

  try {
-
    if (route.resource === "project.source") {
+
    if (route.resource === "repo.source") {
      return await loadTreeView(route, previousLoaded);
-
    } else if (route.resource === "project.history") {
+
    } else if (route.resource === "repo.history") {
      return await loadHistoryView(route, previousLoaded);
-
    } else if (route.resource === "project.commit") {
-
      const [project, commit, seedingPolicy, node] = await Promise.all([
-
        api.project.getById(route.project),
-
        api.project.getCommitBySha(route.project, route.commit),
-
        api.getPolicyById(route.project),
+
    } else if (route.resource === "repo.commit") {
+
      const [repo, commit, seedingPolicy, node] = await Promise.all([
+
        api.repo.getByRid(route.repo),
+
        api.repo.getCommitBySha(route.repo, route.commit),
+
        api.getPolicyByRid(route.repo),
        api.getNode(),
      ]);

      return {
-
        resource: "project.commit",
+
        resource: "repo.commit",
        params: {
          baseUrl: route.node,
          seedingPolicy,
-
          project,
+
          repo,
          commit,
          nodeAvatarUrl: node.avatarUrl,
        },
      };
-
    } else if (route.resource === "project.issue") {
+
    } else if (route.resource === "repo.issue") {
      return await loadIssueView(route);
-
    } else if (route.resource === "project.patch") {
+
    } else if (route.resource === "repo.patch") {
      return await loadPatchView(route, previousLoaded);
-
    } else if (route.resource === "project.issues") {
+
    } else if (route.resource === "repo.issues") {
      return await loadIssuesView(route);
-
    } else if (route.resource === "project.patches") {
+
    } else if (route.resource === "repo.patches") {
      return await loadPatchesView(route);
    } else {
      return unreachable(route);
@@ -325,108 +325,108 @@ export async function loadProjectRoute(
}

async function loadPatchesView(
-
  route: ProjectPatchesRoute,
-
): Promise<ProjectLoadedRoute> {
+
  route: RepoPatchesRoute,
+
): Promise<RepoLoadedRoute> {
  const api = new HttpdClient(route.node);
  const searchParams = new URLSearchParams(route.search || "");
  const status = (searchParams.get("status") as PatchState["status"]) || "open";

-
  const [project, patches, seedingPolicy, node] = await Promise.all([
-
    api.project.getById(route.project),
-
    api.project.getAllPatches(route.project, {
+
  const [repo, patches, seedingPolicy, node] = await Promise.all([
+
    api.repo.getByRid(route.repo),
+
    api.repo.getAllPatches(route.repo, {
      status,
      page: 0,
      perPage: PATCHES_PER_PAGE,
    }),
-
    api.getPolicyById(route.project),
+
    api.getPolicyByRid(route.repo),
    api.getNode(),
  ]);

  return {
-
    resource: "project.patches",
+
    resource: "repo.patches",
    params: {
      baseUrl: route.node,
      seedingPolicy,
      patches,
      status,
-
      project,
+
      repo,
      nodeAvatarUrl: node.avatarUrl,
    },
  };
}

async function loadIssuesView(
-
  route: ProjectIssuesRoute,
-
): Promise<ProjectLoadedRoute> {
+
  route: RepoIssuesRoute,
+
): Promise<RepoLoadedRoute> {
  const api = new HttpdClient(route.node);
  const status = route.status || "open";

-
  const [project, issues, seedingPolicy, node] = await Promise.all([
-
    api.project.getById(route.project),
-
    api.project.getAllIssues(route.project, {
+
  const [repo, issues, seedingPolicy, node] = await Promise.all([
+
    api.repo.getByRid(route.repo),
+
    api.repo.getAllIssues(route.repo, {
      status,
      page: 0,
      perPage: ISSUES_PER_PAGE,
    }),
-
    api.getPolicyById(route.project),
+
    api.getPolicyByRid(route.repo),
    api.getNode(),
  ]);

  return {
-
    resource: "project.issues",
+
    resource: "repo.issues",
    params: {
      baseUrl: route.node,
      seedingPolicy,
      issues,
      status,
-
      project,
+
      repo,
      nodeAvatarUrl: node.avatarUrl,
    },
  };
}

async function loadTreeView(
-
  route: ProjectTreeRoute,
+
  route: RepoTreeRoute,
  previousLoaded: LoadedRoute,
-
): Promise<ProjectLoadedRoute | NotFoundRoute> {
+
): Promise<RepoLoadedRoute | NotFoundRoute> {
  const api = new HttpdClient(route.node);
  const rawPath = (commit?: string) =>
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
-
      route.project
+
      route.repo
    }${commit ? `/${commit}` : ""}`;

-
  let projectPromise: Promise<Project>;
+
  let repoPromise: Promise<Repo>;
  let seedingPolicyPromise: Promise<SeedingPolicy>;
  let peersPromise: Promise<Remote[]>;
  let nodePromise: Promise<Partial<Node>>;
  if (
-
    (previousLoaded.resource === "project.source" ||
-
      previousLoaded.resource === "project.history") &&
-
    previousLoaded.params.project.id === route.project &&
+
    (previousLoaded.resource === "repo.source" ||
+
      previousLoaded.resource === "repo.history") &&
+
    previousLoaded.params.repo.rid === route.repo &&
    previousLoaded.params.peer === route.peer
  ) {
-
    projectPromise = Promise.resolve(previousLoaded.params.project);
+
    repoPromise = Promise.resolve(previousLoaded.params.repo);
    peersPromise = Promise.resolve(previousLoaded.params.peers);
    seedingPolicyPromise = Promise.resolve(previousLoaded.params.seedingPolicy);
    nodePromise = Promise.resolve({
      avatarUrl: previousLoaded.params.nodeAvatarUrl,
    });
  } else {
-
    projectPromise = api.project.getById(route.project);
-
    peersPromise = api.project.getAllRemotes(route.project);
-
    seedingPolicyPromise = api.getPolicyById(route.project);
+
    repoPromise = api.repo.getByRid(route.repo);
+
    peersPromise = api.repo.getAllRemotes(route.repo);
+
    seedingPolicyPromise = api.getPolicyByRid(route.repo);
    nodePromise = api.getNode();
  }

-
  const [project, peers, seedingPolicy, node] = await Promise.all([
-
    projectPromise,
+
  const [repo, peers, seedingPolicy, node] = await Promise.all([
+
    repoPromise,
    peersPromise,
    seedingPolicyPromise,
    nodePromise,
  ]);

  let branchMap: Record<string, string> = {
-
    [project.defaultBranch]: project.head,
+
    [repo["xyz.radicle.project"].defaultBranch]: repo.head,
  };
  if (route.peer) {
    const peer = peers.find(peer => peer.id === route.peer);
@@ -448,21 +448,21 @@ async function loadTreeView(

  const commit = parseRevisionToOid(
    route.revision,
-
    project.defaultBranch,
+
    repo["xyz.radicle.project"].defaultBranch,
    branchMap,
  );
  const path = route.path || "/";
  const [tree, blobResult] = await Promise.all([
-
    api.project.getTree(route.project, commit),
-
    loadBlob(api, project.id, commit, path),
+
    api.repo.getTree(route.repo, commit),
+
    loadBlob(api, repo.rid, commit, path),
  ]);
  return {
-
    resource: "project.source",
+
    resource: "repo.source",
    params: {
      baseUrl: route.node,
      seedingPolicy,
      commit,
-
      project,
+
      repo,
      peers: peers.filter(remote => Object.keys(remote.heads).length > 0),
      peer: route.peer,
      rawPath,
@@ -477,16 +477,16 @@ async function loadTreeView(

async function loadBlob(
  api: HttpdClient,
-
  project: string,
+
  repo: string,
  commit: string,
  path: string,
): Promise<BlobResult> {
  try {
    let blob: Blob;
    if (path === "" || path === "/") {
-
      blob = await api.project.getReadme(project, commit);
+
      blob = await api.repo.getReadme(repo, commit);
    } else {
-
      blob = await api.project.getBlob(project, commit, path);
+
      blob = await api.repo.getBlob(repo, commit, path);
    }
    return {
      ok: true,
@@ -525,39 +525,39 @@ async function loadBlob(
  }
}
async function loadHistoryView(
-
  route: ProjectHistoryRoute,
+
  route: RepoHistoryRoute,
  previousLoaded: LoadedRoute,
-
): Promise<ProjectLoadedRoute> {
+
): Promise<RepoLoadedRoute> {
  const api = new HttpdClient(route.node);

-
  let projectPromise: Promise<Project>;
+
  let repoPromise: Promise<Repo>;
  let seedingPolicyPromise: Promise<SeedingPolicy>;
  let peersPromise: Promise<Remote[]>;
  let nodePromise: Promise<Partial<Node>>;
  if (
-
    (previousLoaded.resource === "project.source" ||
-
      previousLoaded.resource === "project.history") &&
-
    previousLoaded.params.project.id === route.project &&
+
    (previousLoaded.resource === "repo.source" ||
+
      previousLoaded.resource === "repo.history") &&
+
    previousLoaded.params.repo.rid === route.repo &&
    previousLoaded.params.peer === route.peer
  ) {
-
    projectPromise = Promise.resolve(previousLoaded.params.project);
+
    repoPromise = Promise.resolve(previousLoaded.params.repo);
    peersPromise = Promise.resolve(previousLoaded.params.peers);
    seedingPolicyPromise = Promise.resolve(previousLoaded.params.seedingPolicy);
    nodePromise = Promise.resolve({
      avatarUrl: previousLoaded.params.nodeAvatarUrl,
    });
  } else {
-
    projectPromise = api.project.getById(route.project);
-
    peersPromise = api.project.getAllRemotes(route.project);
-
    seedingPolicyPromise = api.getPolicyById(route.project);
+
    repoPromise = api.repo.getByRid(route.repo);
+
    peersPromise = api.repo.getAllRemotes(route.repo);
+
    seedingPolicyPromise = api.getPolicyByRid(route.repo);
    nodePromise = api.getNode();
  }

-
  const [project, peers, seedingPolicy, branchMap, node] = await Promise.all([
-
    projectPromise,
+
  const [repo, peers, seedingPolicy, branchMap, node] = await Promise.all([
+
    repoPromise,
    peersPromise,
    seedingPolicyPromise,
-
    getPeerBranches(api, route.project, route.peer),
+
    getPeerBranches(api, route.repo, route.peer),
    nodePromise,
  ]);

@@ -565,33 +565,34 @@ async function loadHistoryView(
  if (route.revision && isOid(route.revision)) {
    commitId = route.revision;
  } else if (branchMap) {
-
    commitId = branchMap[route.revision || project.defaultBranch];
+
    commitId =
+
      branchMap[route.revision || repo["xyz.radicle.project"].defaultBranch];
  } else if (!route.revision) {
-
    commitId = project.head;
+
    commitId = repo.head;
  }

  if (!commitId) {
    throw new Error(
-
      `Revision ${route.revision} not found for project ${project.id}`,
+
      `Revision ${route.revision} not found for repo ${repo.rid}`,
    );
  }

  let treePromise: Promise<Tree>;

  if (
-
    (previousLoaded.resource === "project.source" ||
-
      previousLoaded.resource === "project.history") &&
-
    previousLoaded.params.project.id === route.project &&
+
    (previousLoaded.resource === "repo.source" ||
+
      previousLoaded.resource === "repo.history") &&
+
    previousLoaded.params.repo.rid === route.repo &&
    previousLoaded.params.commit === commitId
  ) {
    treePromise = Promise.resolve(previousLoaded.params.tree);
  } else {
-
    treePromise = api.project.getTree(route.project, commitId);
+
    treePromise = api.repo.getTree(route.repo, commitId);
  }

  const [tree, commitHeaders] = await Promise.all([
    treePromise,
-
    api.project.getAllCommits(project.id, {
+
    api.repo.getAllCommits(repo.rid, {
      parent: commitId,
      page: 0,
      perPage: config.source.commitsPerPage,
@@ -599,12 +600,12 @@ async function loadHistoryView(
  ]);

  return {
-
    resource: "project.history",
+
    resource: "repo.history",
    params: {
      baseUrl: route.node,
      seedingPolicy,
      commit: commitId,
-
      project,
+
      repo,
      peers: peers.filter(remote => Object.keys(remote.heads).length > 0),
      peer: route.peer,
      revision: route.revision,
@@ -615,27 +616,25 @@ async function loadHistoryView(
  };
}

-
async function loadIssueView(
-
  route: ProjectIssueRoute,
-
): Promise<ProjectLoadedRoute> {
+
async function loadIssueView(route: RepoIssueRoute): Promise<RepoLoadedRoute> {
  const api = new HttpdClient(route.node);
  const rawPath = (commit?: string) =>
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
-
      route.project
+
      route.repo
    }${commit ? `/${commit}` : ""}`;

-
  const [project, issue, seedingPolicy, node] = await Promise.all([
-
    api.project.getById(route.project),
-
    api.project.getIssueById(route.project, route.issue),
-
    api.getPolicyById(route.project),
+
  const [repo, issue, seedingPolicy, node] = await Promise.all([
+
    api.repo.getByRid(route.repo),
+
    api.repo.getIssueById(route.repo, route.issue),
+
    api.getPolicyByRid(route.repo),
    api.getNode(),
  ]);
  return {
-
    resource: "project.issue",
+
    resource: "repo.issue",
    params: {
      baseUrl: route.node,
      seedingPolicy,
-
      project,
+
      repo,
      rawPath,
      issue,
      nodeAvatarUrl: node.avatarUrl,
@@ -644,39 +643,39 @@ async function loadIssueView(
}

async function loadPatchView(
-
  route: ProjectPatchRoute,
+
  route: RepoPatchRoute,
  previousLoaded: LoadedRoute,
-
): Promise<ProjectLoadedRoute> {
+
): Promise<RepoLoadedRoute> {
  const api = new HttpdClient(route.node);
  const rawPath = (commit?: string) =>
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
-
      route.project
+
      route.repo
    }${commit ? `/${commit}` : ""}`;

-
  let projectPromise: Promise<Project>;
+
  let repoPromise: Promise<Repo>;
  let patchPromise: Promise<Patch>;
  let nodePromise: Promise<Partial<Node>>;
  let seedingPolicyPromise: Promise<SeedingPolicy>;

  if (
-
    previousLoaded.resource === "project.patch" &&
-
    previousLoaded.params.project.id === route.project &&
+
    previousLoaded.resource === "repo.patch" &&
+
    previousLoaded.params.repo.rid === route.repo &&
    previousLoaded.params.patch.id === route.patch
  ) {
-
    projectPromise = Promise.resolve(previousLoaded.params.project);
+
    repoPromise = Promise.resolve(previousLoaded.params.repo);
    patchPromise = Promise.resolve(previousLoaded.params.patch);
    seedingPolicyPromise = Promise.resolve(previousLoaded.params.seedingPolicy);
    nodePromise = Promise.resolve({
      avatarUrl: previousLoaded.params.nodeAvatarUrl,
    });
  } else {
-
    projectPromise = api.project.getById(route.project);
-
    patchPromise = api.project.getPatchById(route.project, route.patch);
-
    seedingPolicyPromise = api.getPolicyById(route.project);
+
    repoPromise = api.repo.getByRid(route.repo);
+
    patchPromise = api.repo.getPatchById(route.repo, route.patch);
+
    seedingPolicyPromise = api.getPolicyByRid(route.repo);
    nodePromise = api.getNode();
  }
-
  const [project, patch, seedingPolicy, { avatarUrl }] = await Promise.all([
-
    projectPromise,
+
  const [repo, patch, seedingPolicy, { avatarUrl }] = await Promise.all([
+
    repoPromise,
    patchPromise,
    seedingPolicyPromise,
    nodePromise,
@@ -687,7 +686,7 @@ async function loadPatchView(
    diff: { stats },
  } = await cachedGetDiff(
    api.baseUrl,
-
    route.project,
+
    route.repo,
    latestRevision.base,
    latestRevision.oid,
  );
@@ -710,7 +709,7 @@ async function loadPatchView(
      }
      const { diff, commits, files } = await cachedGetDiff(
        api.baseUrl,
-
        route.project,
+
        route.repo,
        revision.base,
        revision.oid,
      );
@@ -728,7 +727,7 @@ async function loadPatchView(
      const { fromCommit, toCommit } = route.view;
      const { diff, files } = await cachedGetDiff(
        api.baseUrl,
-
        route.project,
+
        route.repo,
        fromCommit,
        toCommit,
      );
@@ -738,11 +737,11 @@ async function loadPatchView(
    }
  }
  return {
-
    resource: "project.patch",
+
    resource: "repo.patch",
    params: {
      baseUrl: route.node,
      seedingPolicy,
-
      project,
+
      repo,
      rawPath,
      patch,
      stats,
@@ -752,13 +751,9 @@ async function loadPatchView(
  };
}

-
async function getPeerBranches(
-
  api: HttpdClient,
-
  project: string,
-
  peer?: string,
-
) {
+
async function getPeerBranches(api: HttpdClient, repo: string, peer?: string) {
  if (peer) {
-
    return (await api.project.getRemoteByPeer(project, peer)).heads;
+
    return (await api.repo.getRemoteByPeer(repo, peer)).heads;
  } else {
    return undefined;
  }
@@ -797,12 +792,12 @@ function sanitizeQueryString(queryString: string): string {
  return queryString.startsWith("?") ? queryString.substring(1) : queryString;
}

-
export function resolveProjectRoute(
+
export function resolveRepoRoute(
  node: BaseUrl,
-
  project: string,
+
  repo: string,
  segments: string[],
  urlSearch: string,
-
): ProjectRoute | null {
+
): RepoRoute | null {
  let content = segments.shift();
  let peer;
  if (content === "remotes") {
@@ -812,9 +807,9 @@ export function resolveProjectRoute(

  if (!content || content === "tree") {
    return {
-
      resource: "project.source",
+
      resource: "repo.source",
      node,
-
      project,
+
      repo,
      peer,
      path: undefined,
      revision: undefined,
@@ -822,26 +817,26 @@ export function resolveProjectRoute(
    };
  } else if (content === "history") {
    return {
-
      resource: "project.history",
+
      resource: "repo.history",
      node,
-
      project,
+
      repo,
      peer,
      revision: segments.join("/"),
    };
  } else if (content === "commits") {
    return {
-
      resource: "project.commit",
+
      resource: "repo.commit",
      node,
-
      project,
+
      repo,
      commit: segments[0],
    };
  } else if (content === "issues") {
    const issueOrAction = segments.shift();
    if (issueOrAction) {
      return {
-
        resource: "project.issue",
+
        resource: "repo.issue",
        node,
-
        project,
+
        repo,
        issue: issueOrAction,
      };
    } else {
@@ -853,14 +848,14 @@ export function resolveProjectRoute(
        status = rawStatus;
      }
      return {
-
        resource: "project.issues",
+
        resource: "repo.issues",
        node,
-
        project,
+
        repo,
        status,
      };
    }
  } else if (content === "patches") {
-
    return resolvePatchesRoute(node, project, segments, urlSearch);
+
    return resolvePatchesRoute(node, repo, segments, urlSearch);
  } else {
    return null;
  }
@@ -868,19 +863,19 @@ export function resolveProjectRoute(

function resolvePatchesRoute(
  node: BaseUrl,
-
  project: string,
+
  repo: string,
  segments: string[],
  urlSearch: string,
-
): ProjectPatchRoute | ProjectPatchesRoute {
+
): RepoPatchRoute | RepoPatchesRoute {
  const patch = segments.shift();
  const revision = segments.shift();
  if (patch) {
    const searchParams = new URLSearchParams(sanitizeQueryString(urlSearch));
    const tab = searchParams.get("tab");
    const base = {
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project,
+
      repo,
      patch,
    } as const;
    const diff = searchParams.get("diff");
@@ -909,20 +904,20 @@ function resolvePatchesRoute(
    }
  } else {
    return {
-
      resource: "project.patches",
+
      resource: "repo.patches",
      node,
-
      project,
+
      repo,
      search: sanitizeQueryString(urlSearch),
    };
  }
}

-
export function projectRouteToPath(route: ProjectRoute): string {
+
export function repoRouteToPath(route: RepoRoute): string {
  const node = nodePath(route.node);

-
  const pathSegments = [node, route.project];
+
  const pathSegments = [node, route.repo];

-
  if (route.resource === "project.source") {
+
  if (route.resource === "repo.source") {
    if (route.peer) {
      pathSegments.push("remotes", route.peer);
    }
@@ -949,7 +944,7 @@ export function projectRouteToPath(route: ProjectRoute): string {
    }

    return pathSegments.join("/");
-
  } else if (route.resource === "project.history") {
+
  } else if (route.resource === "repo.history") {
    if (route.peer) {
      pathSegments.push("remotes", route.peer);
    }
@@ -960,9 +955,9 @@ export function projectRouteToPath(route: ProjectRoute): string {
      pathSegments.push(route.revision);
    }
    return pathSegments.join("/");
-
  } else if (route.resource === "project.commit") {
+
  } else if (route.resource === "repo.commit") {
    return [...pathSegments, "commits", route.commit].join("/");
-
  } else if (route.resource === "project.issues") {
+
  } else if (route.resource === "repo.issues") {
    let url = [...pathSegments, "issues"].join("/");
    const searchParams = new URLSearchParams();
    if (route.status) {
@@ -972,25 +967,25 @@ export function projectRouteToPath(route: ProjectRoute): string {
      url += `?${searchParams}`;
    }
    return url;
-
  } else if (route.resource === "project.issue") {
+
  } else if (route.resource === "repo.issue") {
    return [...pathSegments, "issues", route.issue].join("/");
-
  } else if (route.resource === "project.patches") {
+
  } else if (route.resource === "repo.patches") {
    let url = [...pathSegments, "patches"].join("/");
    if (route.search) {
      url += `?${route.search}`;
    }
    return url;
-
  } else if (route.resource === "project.patch") {
+
  } else if (route.resource === "repo.patch") {
    return patchRouteToPath(route);
  } else {
    return unreachable(route);
  }
}

-
function patchRouteToPath(route: ProjectPatchRoute): string {
+
function patchRouteToPath(route: RepoPatchRoute): string {
  const node = nodePath(route.node);

-
  const pathSegments = [node, route.project];
+
  const pathSegments = [node, route.repo];

  pathSegments.push("patches", route.patch);
  if (route.view?.name === "changes") {
@@ -1018,31 +1013,31 @@ function patchRouteToPath(route: ProjectPatchRoute): string {
  }
}

-
export function projectTitle(loadedRoute: ProjectLoadedRoute) {
+
export function repoTitle(loadedRoute: RepoLoadedRoute) {
  const title: string[] = [];

-
  if (loadedRoute.resource === "project.source") {
-
    title.push(loadedRoute.params.project.name);
-
    if (loadedRoute.params.project.description.length > 0) {
-
      title.push(loadedRoute.params.project.description);
+
  if (loadedRoute.resource === "repo.source") {
+
    title.push(loadedRoute.params.repo["xyz.radicle.project"].name);
+
    if (loadedRoute.params.repo["xyz.radicle.project"].description.length > 0) {
+
      title.push(loadedRoute.params.repo["xyz.radicle.project"].description);
    }
-
  } else if (loadedRoute.resource === "project.commit") {
+
  } else if (loadedRoute.resource === "repo.commit") {
    title.push(loadedRoute.params.commit.commit.summary);
    title.push("commit");
-
  } else if (loadedRoute.resource === "project.history") {
-
    title.push(loadedRoute.params.project.name);
+
  } else if (loadedRoute.resource === "repo.history") {
+
    title.push(loadedRoute.params.repo["xyz.radicle.project"].name);
    title.push("history");
-
  } else if (loadedRoute.resource === "project.issue") {
+
  } else if (loadedRoute.resource === "repo.issue") {
    title.push(loadedRoute.params.issue.title);
    title.push("issue");
-
  } else if (loadedRoute.resource === "project.issues") {
-
    title.push(loadedRoute.params.project.name);
+
  } else if (loadedRoute.resource === "repo.issues") {
+
    title.push(loadedRoute.params.repo["xyz.radicle.project"].name);
    title.push("issues");
-
  } else if (loadedRoute.resource === "project.patch") {
+
  } else if (loadedRoute.resource === "repo.patch") {
    title.push(loadedRoute.params.patch.title);
    title.push("patch");
-
  } else if (loadedRoute.resource === "project.patches") {
-
    title.push(loadedRoute.params.project.name);
+
  } else if (loadedRoute.resource === "repo.patches") {
+
    title.push(loadedRoute.params.repo["xyz.radicle.project"].name);
    title.push("patches");
  } else {
    return unreachable(loadedRoute);
modified src/views/users/View.svelte
@@ -3,7 +3,7 @@

  import * as router from "@app/lib/router";
  import * as utils from "@app/lib/utils";
-
  import { fetchProjectInfos } from "@app/components/ProjectCard";
+
  import { fetchRepoInfos } from "@app/components/ProjectCard";
  import { handleError } from "@app/views/nodes/error";

  import Avatar from "@app/components/Avatar.svelte";
@@ -19,7 +19,7 @@
  import MobileFooter from "@app/App/MobileFooter.svelte";
  import Placeholder from "@app/components/Placeholder.svelte";
  import Popover from "@app/components/Popover.svelte";
-
  import ProjectCard from "@app/components/ProjectCard.svelte";
+
  import RepoCard from "@app/components/ProjectCard.svelte";
  import Separator from "@app/views/projects/Separator.svelte";
  import Settings from "@app/App/Settings.svelte";
  import UserAddress from "@app/views/users/UserAddress.svelte";
@@ -216,7 +216,7 @@
            resource: "nodes",
            params: {
              baseUrl,
-
              projectPageIndex: 0,
+
              repoPageIndex: 0,
            },
          }}>
          <img
@@ -352,15 +352,15 @@
        </div>
      </div>

-
      {#await fetchProjectInfos(baseUrl, { show: "all", perPage: stats.repos.total }, utils.formatDid(did))}
+
      {#await fetchRepoInfos(baseUrl, { show: "all", perPage: stats.repos.total }, utils.formatDid(did))}
        <div class="loading">
          <Loading small center />
        </div>
      {:then repos}
        {#if repos.length > 0}
          <div class="repo-grid">
-
            {#each repos as projectInfo}
-
              <ProjectCard {projectInfo}>
+
            {#each repos as repoInfo}
+
              <RepoCard {repoInfo}>
                <svelte:fragment slot="delegate">
                  <Badge
                    title={`${node.alias || utils.formatNodeId(did.pubkey)} is a delegate of this repository`}
@@ -371,7 +371,7 @@
                    <Icon name="badge" />
                  </Badge>
                </svelte:fragment>
-
              </ProjectCard>
+
              </RepoCard>
            {/each}
          </div>
          <div class="subtitle">
modified tests/e2e/clipboard.spec.ts
@@ -30,9 +30,9 @@ test("copy to clipboard", async ({ page, browserName, context }) => {
  // Reset system clipboard to a known state.
  await page.evaluate<string>("navigator.clipboard.writeText('')");

-
  // Project ID.
+
  // Repo ID.
  {
-
    await page.getByLabel("project-id").click();
+
    await page.getByLabel("repo-id").click();
    const clipboardContent = await page.evaluate<string>(
      "navigator.clipboard.readText()",
    );
modified tests/e2e/node.spec.ts
@@ -25,27 +25,27 @@ test("node metadata", async ({ page, peerManager }) => {
  await expect(page.getByText("/radicle:1.0.0-rc.13/")).toBeVisible();
});

-
test("node projects", async ({ page }) => {
+
test("node repos", async ({ page }) => {
  await page.goto("/nodes/radicle.local");
-
  const project = page
-
    .locator(".project-card", { hasText: "source-browsing" })
+
  const repo = page
+
    .locator(".repo-card", { hasText: "source-browsing" })
    .nth(0);

-
  // Project metadata.
+
  // Repo metadata.
  {
-
    await expect(project.getByText("source-browsing")).toBeVisible();
+
    await expect(repo.getByText("source-browsing")).toBeVisible();
    await expect(
-
      project.getByText("Git repository for source browsing tests"),
+
      repo.getByText("Git repository for source browsing tests"),
    ).toBeVisible();
  }
});

test("show pinned repositories", async ({ page }) => {
  await page.goto("/");
-
  // Shows pinned project name.
+
  // Shows pinned repo name.
  await expect(page.getByText("source-browsing")).toBeVisible();
  //
-
  // Shows pinned project description.
+
  // Shows pinned repo description.
  await expect(
    page.getByText("Git repository for source browsing tests"),
  ).toBeVisible();
modified tests/e2e/project.spec.ts
@@ -12,10 +12,10 @@ import {
  sourceBrowsingUrl,
  test,
} from "@tests/support/fixtures.js";
-
import { changeBranch, createProject } from "@tests/support/project";
+
import { changeBranch, createRepo } from "@tests/support/project";
import { expectUrlPersistsReload } from "@tests/support/router";

-
test("navigate to project", async ({ page }) => {
+
test("navigate to repo", async ({ page }) => {
  await page.goto(sourceBrowsingUrl);

  // Header.
@@ -31,7 +31,7 @@ test("navigate to project", async ({ page }) => {
    await expect(description).toBeVisible();
  }

-
  // Project menu shows default selected branch and commit and contributor counts.
+
  // Repo menu shows default selected branch and commit and contributor counts.
  {
    await expect(page.getByTitle("Change branch")).toBeVisible();
    await expect(
@@ -48,7 +48,7 @@ test("navigate to project", async ({ page }) => {
    ).toBeVisible();
  }

-
  // Navigate to the project README.md by default.
+
  // Navigate to the repo README.md by default.
  await expect(page.locator(".filename")).toContainText("README.md");

  // Show a commit teaser.
@@ -58,8 +58,8 @@ test("navigate to project", async ({ page }) => {
  await expect(page.getByText("Git test repository")).toBeVisible();
});

-
test("project description", async ({ page, peer }) => {
-
  const { rid } = await createProject(peer, {
+
test("repo description", async ({ page, peer }) => {
+
  const { rid } = await createRepo(peer, {
    name: "heartwood",
    description: "Radicle Heartwood Protocol & Stack",
  });
@@ -356,7 +356,7 @@ test("peer and branch switching", async ({ page }) => {
    }
  }

-
  // Reset the source browser by clicking the project title.
+
  // Reset the source browser by clicking the repo title.
  {
    await page.getByRole("link", { name: "source-browsing" }).nth(1).click();

@@ -429,7 +429,7 @@ test.describe("browser error handling", () => {
    await page.route(
      ({ pathname }) =>
        pathname.startsWith(
-
          `/api/v1/projects/${sourceBrowsingRid}/tree/${aliceMainHead}/src`,
+
          `/api/v1/repos/${sourceBrowsingRid}/tree/${aliceMainHead}/src`,
        ),
      route => route.fulfill({ status: 500 }),
    );
@@ -445,7 +445,7 @@ test.describe("browser error handling", () => {
    await page.route(
      ({ pathname }) =>
        pathname ===
-
        `/api/v1/projects/${sourceBrowsingRid}/blob/${aliceMainHead}/.hidden`,
+
        `/api/v1/repos/${sourceBrowsingRid}/blob/${aliceMainHead}/.hidden`,
      route => route.fulfill({ status: 500 }),
    );

@@ -458,7 +458,7 @@ test.describe("browser error handling", () => {
    await page.route(
      ({ pathname }) =>
        pathname ===
-
        `/api/v1/projects/${sourceBrowsingRid}/readme/${aliceMainHead}`,
+
        `/api/v1/repos/${sourceBrowsingRid}/readme/${aliceMainHead}`,
      route => route.fulfill({ status: 500 }),
    );

@@ -469,7 +469,7 @@ test.describe("browser error handling", () => {
    await page.route(
      ({ pathname }) =>
        pathname ===
-
        `/api/v1/projects/${sourceBrowsingRid}/blob/${aliceMainHead}/.hidden`,
+
        `/api/v1/repos/${sourceBrowsingRid}/blob/${aliceMainHead}/.hidden`,
      route => route.fulfill({ status: 500 }),
    );

modified tests/e2e/project/commits.spec.ts
@@ -9,7 +9,7 @@ import {
  sourceBrowsingUrl,
  test,
} from "@tests/support/fixtures.js";
-
import { changeBranch, createProject } from "@tests/support/project";
+
import { changeBranch, createRepo } from "@tests/support/project";
import sinon from "sinon";

test("peer and branch switching", async ({ page }) => {
@@ -183,7 +183,7 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
  });
  await alice.startNode();
  await alice.startHttpd();
-
  const { rid, projectFolder } = await createProject(alice, {
+
  const { rid, repoFolder } = await createRepo(alice, {
    name: "alice-project",
  });
  await page.goto(`${alice.uiUrl()}/${rid}`);
@@ -191,10 +191,10 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
  await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);

  await alice.git(["commit", "--allow-empty", "--message", "first change"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await alice.git(["push", "rad", "main"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await page.reload();
  await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);
@@ -219,11 +219,11 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
      "after clicking the project title",
    ],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );
  await alice.git(["push", "rad", "main"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await page.reload();
  await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);
modified tests/e2e/project/issues.spec.ts
@@ -1,5 +1,5 @@
import { test, cobUrl, expect } from "@tests/support/fixtures.js";
-
import { createProject } from "@tests/support/project";
+
import { createRepo } from "@tests/support/project";

test("navigate issue listing", async ({ page }) => {
  await page.goto(cobUrl);
@@ -12,7 +12,7 @@ test("navigate issue listing", async ({ page }) => {
});

test("issue counters", async ({ page, peer }) => {
-
  const { rid, projectFolder } = await createProject(peer, {
+
  const { rid, repoFolder } = await createRepo(peer, {
    name: "issue-counters",
  });
  await peer.rad(
@@ -24,7 +24,7 @@ test("issue counters", async ({ page, peer }) => {
      "--description",
      "Let's see",
    ],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await page.goto(`${peer.uiUrl()}/${rid}/issues`);
  await peer.rad(
@@ -36,7 +36,7 @@ test("issue counters", async ({ page, peer }) => {
      "--description",
      "Let's see",
    ],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await page.getByRole("button", { name: "filter-dropdown" }).first().click();
  await page.locator(".dropdown-item").getByText("Open 1").click();
modified tests/e2e/project/patches.spec.ts
@@ -1,5 +1,5 @@
import { test, cobUrl, expect } from "@tests/support/fixtures.js";
-
import { createProject } from "@tests/support/project";
+
import { createRepo } from "@tests/support/project";

test("navigate patch listing", async ({ page }) => {
  await page.goto(cobUrl);
@@ -15,30 +15,30 @@ test("navigate patch listing", async ({ page }) => {
});

test("patches counters", async ({ page, peer }) => {
-
  const { rid, projectFolder, defaultBranch } = await createProject(peer, {
+
  const { rid, repoFolder, defaultBranch } = await createRepo(peer, {
    name: "patch-counters",
  });
  await peer.git(["switch", "-c", "feature-1"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.git(["commit", "--allow-empty", "-m", "1th"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.git(["push", "rad", "HEAD:refs/patches"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await page.goto(`${peer.uiUrl()}/${rid}/patches`);
  await peer.git(["switch", defaultBranch], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.git(["switch", "-c", "feature-2"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.git(["commit", "--allow-empty", "-m", "2nd"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.git(["push", "rad", "HEAD:refs/patches"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await page.getByRole("button", { name: "filter-dropdown" }).first().click();
  await page.locator(".dropdown-item").getByText("Open 1").click();
modified tests/e2e/router.ts
@@ -6,13 +6,13 @@ import {
  sourceBrowsingUrl,
  test,
} from "@tests/support/fixtures.js";
-
import { createProject } from "@tests/support/project";
+
import { createRepo } from "@tests/support/project";
import {
  expectBackAndForwardNavigationWorks,
  expectUrlPersistsReload,
} from "@tests/support/router.js";

-
test("navigate between landing and project page", async ({ page }) => {
+
test("navigate between landing and repo page", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveURL("/");

@@ -23,13 +23,13 @@ test("navigate between landing and project page", async ({ page }) => {
  await expectUrlPersistsReload(page);
});

-
test("navigation between node and project pages", async ({ page }) => {
+
test("navigation between node and repo pages", async ({ page }) => {
  await page.goto("/nodes/radicle.local");

-
  const project = page
-
    .locator(".project-card", { hasText: "source-browsing" })
+
  const repo = page
+
    .locator(".repo-card", { hasText: "source-browsing" })
    .nth(0);
-
  await project.click();
+
  await repo.click();
  await expect(page).toHaveURL(sourceBrowsingUrl);

  await expectBackAndForwardNavigationWorks("/nodes/radicle.local", page);
@@ -39,30 +39,30 @@ test("navigation between node and project pages", async ({ page }) => {
  await expect(page).toHaveURL("/nodes/127.0.0.1");
});

-
test.describe("project page navigation", () => {
+
test.describe("repo page navigation", () => {
  test("navigation between commit history and single commit", async ({
    page,
  }) => {
-
    const projectHistoryURL = `${sourceBrowsingUrl}/history/${aliceMainHead}`;
-
    await page.goto(projectHistoryURL);
+
    const repoHistoryURL = `${sourceBrowsingUrl}/history/${aliceMainHead}`;
+
    await page.goto(repoHistoryURL);

    await page.getByText("Add README.md").click();
    await expect(page).toHaveURL(
      `${sourceBrowsingUrl}/commits/${aliceMainHead}`,
    );

-
    await expectBackAndForwardNavigationWorks(projectHistoryURL, page);
+
    await expectBackAndForwardNavigationWorks(repoHistoryURL, page);
    await expectUrlPersistsReload(page);
  });

  test("navigate between tree and commit history", async ({ page }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
+
    const repoTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;

-
    await page.goto(projectTreeURL);
+
    await page.goto(repoTreeURL);
    await page
      .getByRole("progressbar", { name: "Page loading" })
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
+
    await expect(page).toHaveURL(repoTreeURL);

    await page
      .getByRole("link", { name: `Commits ${aliceMainCommitCount}` })
@@ -72,23 +72,23 @@ test.describe("project page navigation", () => {
      `${sourceBrowsingUrl}/history/${aliceMainHead}`,
    );

-
    await expectBackAndForwardNavigationWorks(projectTreeURL, page);
+
    await expectBackAndForwardNavigationWorks(repoTreeURL, page);
    await expectUrlPersistsReload(page);
  });

  test("navigate between tree and commit history while a file is selected", async ({
    page,
  }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}`;
+
    const repoTreeURL = `${sourceBrowsingUrl}`;

-
    await page.goto(projectTreeURL);
+
    await page.goto(repoTreeURL);
    await page
      .getByRole("progressbar", { name: "Page loading" })
      .waitFor({ state: "hidden" });
-
    await expect(page).toHaveURL(projectTreeURL);
+
    await expect(page).toHaveURL(repoTreeURL);

    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/tree/.hidden`);

    await page
      .getByRole("link", { name: `Commits ${aliceMainCommitCount}` })
@@ -96,23 +96,20 @@ test.describe("project page navigation", () => {
    await expect(page).toHaveURL(`${sourceBrowsingUrl}/history`);
  });

-
  test("navigate project paths", async ({ page }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;
+
  test("navigate repo paths", async ({ page }) => {
+
    const repoTreeURL = `${sourceBrowsingUrl}/tree/${aliceMainHead}`;

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
+
    await page.goto(repoTreeURL);
+
    await expect(page).toHaveURL(repoTreeURL);

    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/.hidden`);

    await page.getByText("bin").click();
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/bin/true`);

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
+
    await expectBackAndForwardNavigationWorks(`${repoTreeURL}/.hidden`, page);
    await expectUrlPersistsReload(page);
  });

@@ -126,68 +123,62 @@ test.describe("project page navigation", () => {
    );
  });

-
  test("page title on project with empty description", async ({
-
    page,
-
    peer,
-
  }) => {
-
    const { rid } = await createProject(peer, {
-
      name: "ProjectWithNoDescription",
+
  test("page title on repo with empty description", async ({ page, peer }) => {
+
    const { rid } = await createRepo(peer, {
+
      name: "RepoWithNoDescription",
    });
    await page.goto(peer.ridUrl(rid), {
      waitUntil: "networkidle",
    });
    const title = await page.title();
-
    expect(title).toBe("ProjectWithNoDescription");
+
    expect(title).toBe("RepoWithNoDescription");
  });

-
  test("navigate project paths with an explicitly selected peer", async ({
+
  test("navigate repo paths with an explicitly selected peer", async ({
    page,
  }) => {
-
    // If a branch isn't explicitly specified, the code assumes the project
+
    // If a branch isn't explicitly specified, the code assumes the repo
    // default branch is selected. We omit showing the default branch in the URL.

-
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
+
    const repoTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
      8,
    )}`;

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
+
    await page.goto(repoTreeURL);
+
    await expect(page).toHaveURL(repoTreeURL);

    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/.hidden`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/tree/.hidden`);

    await page.getByText("bin").click();
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/tree/bin/true`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/tree/bin/true`);

    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/tree/.hidden`,
+
      `${repoTreeURL}/tree/.hidden`,
      page,
    );
    await expectUrlPersistsReload(page);
  });

-
  test("navigate project paths with an explicitly selected peer and branch", async ({
+
  test("navigate repo paths with an explicitly selected peer and branch", async ({
    page,
  }) => {
-
    const projectTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
+
    const repoTreeURL = `${sourceBrowsingUrl}/remotes/${aliceRemote.substring(
      8,
    )}/tree/main`;

-
    await page.goto(projectTreeURL);
-
    await expect(page).toHaveURL(projectTreeURL);
+
    await page.goto(repoTreeURL);
+
    await expect(page).toHaveURL(repoTreeURL);

    await page.getByText(".hidden").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/.hidden`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/.hidden`);

    await page.getByText("bin").click();
    await page.getByText("true").click();
-
    await expect(page).toHaveURL(`${projectTreeURL}/bin/true`);
+
    await expect(page).toHaveURL(`${repoTreeURL}/bin/true`);

-
    await expectBackAndForwardNavigationWorks(
-
      `${projectTreeURL}/.hidden`,
-
      page,
-
    );
+
    await expectBackAndForwardNavigationWorks(`${repoTreeURL}/.hidden`, page);
    await expectUrlPersistsReload(page);
  });
});
modified tests/support/fixtures.ts
@@ -14,7 +14,7 @@ import * as logLabel from "@tests/support/logPrefix.js";
import * as patch from "@tests/support/cobs/patch.js";
import { createOptions, supportDir, tmpDir } from "@tests/support/support.js";
import { createPeerManager } from "@tests/support/peerManager.js";
-
import { createProject } from "@tests/support/project.js";
+
import { createRepo } from "@tests/support/project.js";
import { formatCommit } from "@app/lib/utils.js";

export { expect };
@@ -169,12 +169,12 @@ export async function createSourceBrowsingFixture(
  peerManager: PeerManager,
  palm: RadiclePeer,
) {
-
  const projectName = "source-browsing";
-
  const sourceBrowsingDir = Path.join(tmpDir, "repos", projectName);
+
  const repoName = "source-browsing";
+
  const sourceBrowsingDir = Path.join(tmpDir, "repos", repoName);
  await Fs.mkdir(sourceBrowsingDir, { recursive: true });
  await execa("tar", [
    "-xf",
-
    Path.join(fixturesDir, `repos/${projectName}.tar.bz2`),
+
    Path.join(fixturesDir, `repos/${repoName}.tar.bz2`),
    "-C",
    sourceBrowsingDir,
  ]);
@@ -183,12 +183,12 @@ export async function createSourceBrowsingFixture(
    name: "alice",
    gitOptions: gitOptions["alice"],
  });
-
  const aliceProjectPath = Path.join(alice.checkoutPath, "source-browsing");
+
  const aliceRepoPath = Path.join(alice.checkoutPath, "source-browsing");
  const bob = await peerManager.createPeer({
    name: "bob",
    gitOptions: gitOptions["bob"],
  });
-
  const bobProjectPath = Path.join(bob.checkoutPath, "source-browsing");
+
  const bobRepoPath = Path.join(bob.checkoutPath, "source-browsing");
  await alice.startNode({
    node: {
      ...defaultConfig.node,
@@ -203,24 +203,24 @@ export async function createSourceBrowsingFixture(
  await palm.waitForEvent({ type: "peerConnected", nid: bob.nodeId }, 1000);

  await alice.git(["clone", sourceBrowsingDir], { cwd: alice.checkoutPath });
-
  await alice.git(["checkout", "feature/branch"], { cwd: aliceProjectPath });
+
  await alice.git(["checkout", "feature/branch"], { cwd: aliceRepoPath });
  await alice.git(["checkout", "feature/move-copy-files"], {
-
    cwd: aliceProjectPath,
+
    cwd: aliceRepoPath,
  });
-
  await alice.git(["checkout", "orphaned-branch"], { cwd: aliceProjectPath });
-
  await alice.git(["checkout", "main"], { cwd: aliceProjectPath });
+
  await alice.git(["checkout", "orphaned-branch"], { cwd: aliceRepoPath });
+
  await alice.git(["checkout", "main"], { cwd: aliceRepoPath });
  await alice.rad(
    [
      "init",
      "--name",
-
      projectName,
+
      repoName,
      "--default-branch",
      "main",
      "--description",
      "Git repository for source browsing tests",
      "--public",
    ],
-
    { cwd: aliceProjectPath },
+
    { cwd: aliceRepoPath },
  );
  await alice.waitForEvent(
    {
@@ -232,7 +232,7 @@ export async function createSourceBrowsingFixture(
  );

  // Needed due to rad init not pushing all branches.
-
  await alice.git(["push", "rad", "--all"], { cwd: aliceProjectPath });
+
  await alice.git(["push", "rad", "--all"], { cwd: aliceRepoPath });
  await alice.stopNode();

  await bob.waitForEvent(
@@ -250,7 +250,7 @@ export async function createSourceBrowsingFixture(
    Path.join(bob.checkoutPath, "source-browsing", "README.md"),
    "Updated readme",
  );
-
  await bob.git(["add", "README.md"], { cwd: bobProjectPath });
+
  await bob.git(["add", "README.md"], { cwd: bobRepoPath });
  await bob.git(
    [
      "commit",
@@ -259,16 +259,16 @@ export async function createSourceBrowsingFixture(
      "--date",
      "Mon Dec 21 14:00 2022 +0100",
    ],
-
    { cwd: bobProjectPath },
+
    { cwd: bobRepoPath },
  );
-
  await bob.git(["push", "rad"], { cwd: bobProjectPath });
+
  await bob.git(["push", "rad"], { cwd: bobRepoPath });
  await bob.stopNode();
}

export async function createCobsFixture(peer: RadiclePeer) {
  await peer.rad(["follow", peer.nodeId, "--alias", "palm"]);
  await Fs.mkdir(Path.join(tmpDir, "repos", "cobs"));
-
  const { projectFolder, defaultBranch } = await createProject(peer, {
+
  const { repoFolder, defaultBranch } = await createRepo(peer, {
    name: "cobs",
  });
  const issueOne = await issue.create(
@@ -276,23 +276,23 @@ export async function createCobsFixture(peer: RadiclePeer) {
    "This `title` has **markdown**",
    "This is a description\nWith some multiline text.",
    ["bug", "feature-request"],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    ["issue", "react", issueOne, "--emoji", "👍", "--to", issueOne],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );
  await peer.rad(
    ["issue", "react", issueOne, "--emoji", "🎉", "--to", issueOne],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );
  await peer.rad(
    ["issue", "assign", issueOne, "--add", `did:key:${peer.nodeId}`],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );
  const { stdout: commentIssueOne } = await peer.rad(
    [
@@ -303,12 +303,12 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "This is a multiline comment\n\nWith some more text.",
      "--quiet",
    ],
-
    createOptions(projectFolder, 2),
+
    createOptions(repoFolder, 2),
  );
  await peer.rad(
    ["issue", "react", issueOne, "--emoji", "🙏", "--to", commentIssueOne],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );
  const { stdout: replyIssueOne } = await peer.rad(
@@ -322,12 +322,12 @@ export async function createCobsFixture(peer: RadiclePeer) {
      commentIssueOne,
      "--quiet",
    ],
-
    createOptions(projectFolder, 3),
+
    createOptions(repoFolder, 3),
  );
  await peer.rad(
    ["issue", "react", issueOne, "--emoji", "🚀", "--to", replyIssueOne],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );
  await peer.rad(
@@ -339,7 +339,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "A root level comment after a reply, for margins sake.",
      "--quiet",
    ],
-
    createOptions(projectFolder, 4),
+
    createOptions(repoFolder, 4),
  );

  const issueTwo = await issue.create(
@@ -347,11 +347,11 @@ export async function createCobsFixture(peer: RadiclePeer) {
    "A closed issue",
    "This issue has been closed\n\nsource: [link](https://radicle.xyz)",
    [],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    ["issue", "state", issueTwo, "--closed"],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );

  const issueThree = await issue.create(
@@ -359,20 +359,20 @@ export async function createCobsFixture(peer: RadiclePeer) {
    "A solved issue",
    "This issue has been solved\n\n```js\nconsole.log('hello world')\nconsole.log(\"\")\n```",
    [],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    ["issue", "state", issueThree, "--solved"],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );

  const patchOne = await patch.create(
    peer,
    ["Add README", "This commit adds more information to the README"],
    "feature/add-readme",
-
    () => Fs.writeFile(Path.join(projectFolder, "README.md"), "# Cobs Repo"),
+
    () => Fs.writeFile(Path.join(repoFolder, "README.md"), "# Cobs Repo"),
    ["Let's add a README", "This repo needed a README"],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  const { stdout: commentPatchOne } = await peer.rad(
    [
@@ -384,7 +384,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "--quiet",
      "--no-announce",
    ],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );
  await peer.rad(
    [
@@ -397,7 +397,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      commentPatchOne,
      "--quiet",
    ],
-
    createOptions(projectFolder, 2),
+
    createOptions(repoFolder, 2),
  );
  await peer.rad(
    [
@@ -410,7 +410,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      commentPatchOne,
      "--quiet",
    ],
-
    createOptions(projectFolder, 3),
+
    createOptions(repoFolder, 3),
  );
  const { stdout: commentTwo } = await peer.rad(
    [
@@ -422,7 +422,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "--quiet",
      "--no-announce",
    ],
-
    createOptions(projectFolder, 4),
+
    createOptions(repoFolder, 4),
  );
  await peer.rad(
    [
@@ -435,27 +435,26 @@ export async function createCobsFixture(peer: RadiclePeer) {
      commentTwo,
      "--quiet",
    ],
-
    createOptions(projectFolder, 5),
+
    createOptions(repoFolder, 5),
  );
  await peer.rad(
    ["patch", "review", patchOne, "-m", "LGTM", "--accept"],
-
    createOptions(projectFolder, 6),
+
    createOptions(repoFolder, 6),
  );
  await patch.merge(
    peer,
    defaultBranch,
    "feature/add-readme",
-
    createOptions(projectFolder, 7),
+
    createOptions(repoFolder, 7),
  );

  const patchTwo = await patch.create(
    peer,
    ["Add subtitle to README"],
    "feature/add-more-text",
-
    () =>
-
      Fs.appendFile(Path.join(projectFolder, "README.md"), "\n\n## Subtitle"),
+
    () => Fs.appendFile(Path.join(repoFolder, "README.md"), "\n\n## Subtitle"),
    [],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    [
@@ -466,7 +465,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "Not the README we are looking for",
      "--reject",
    ],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );

  const patchThree = await patch.create(
@@ -477,29 +476,28 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "Blazingly fast",
    ],
    "feature/better-subtitle",
-
    () =>
-
      Fs.appendFile(Path.join(projectFolder, "README.md"), "\n\n## Better?"),
+
    () => Fs.appendFile(Path.join(repoFolder, "README.md"), "\n\n## Better?"),
    [
      "Taking another stab at the README",
      "This is a big improvement over the last one",
      "Hopefully **this** is the last time",
    ],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    ["patch", "label", patchThree, "--add", "documentation"],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );
  await peer.rad(
    ["patch", "review", patchThree, "-m", "This looks better"],
-
    createOptions(projectFolder, 2),
+
    createOptions(repoFolder, 2),
  );
  await Fs.appendFile(
-
    Path.join(projectFolder, "README.md"),
+
    Path.join(repoFolder, "README.md"),
    "\n\nHad to push a new revision",
  );
-
  await peer.git(["add", "."], { cwd: projectFolder });
-
  await peer.git(["commit", "-m", "Add more text"], { cwd: projectFolder });
+
  await peer.git(["add", "."], { cwd: repoFolder });
+
  await peer.git(["commit", "-m", "Add more text"], { cwd: repoFolder });
  await peer.git(
    [
      "push",
@@ -510,7 +508,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "rad",
      "feature/better-subtitle",
    ],
-
    createOptions(projectFolder, 3),
+
    createOptions(repoFolder, 3),
  );
  await peer.rad(
    [
@@ -521,17 +519,16 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "No this doesn't look better",
      "--reject",
    ],
-
    createOptions(projectFolder, 2),
+
    createOptions(repoFolder, 2),
  );

  const patchFour = await patch.create(
    peer,
    ["This patch is going to be archived"],
    "feature/archived",
-
    () =>
-
      Fs.writeFile(Path.join(projectFolder, "CONTRIBUTING.md"), "# Archived"),
+
    () => Fs.writeFile(Path.join(repoFolder, "CONTRIBUTING.md"), "# Archived"),
    [],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    [
@@ -541,24 +538,21 @@ export async function createCobsFixture(peer: RadiclePeer) {
      "-m",
      "No review due to patch being archived.",
    ],
-
    createOptions(projectFolder, 1),
-
  );
-
  await peer.rad(
-
    ["patch", "archive", patchFour],
-
    createOptions(projectFolder, 2),
+
    createOptions(repoFolder, 1),
  );
+
  await peer.rad(["patch", "archive", patchFour], createOptions(repoFolder, 2));

  const patchFive = await patch.create(
    peer,
    ["This patch is going to be reverted to draft"],
    "feature/draft",
-
    () => Fs.writeFile(Path.join(projectFolder, "LICENSE"), "Draft"),
+
    () => Fs.writeFile(Path.join(repoFolder, "LICENSE"), "Draft"),
    [],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
  await peer.rad(
    ["patch", "ready", patchFive, "--undo"],
-
    createOptions(projectFolder, 1),
+
    createOptions(repoFolder, 1),
  );
}

@@ -570,12 +564,12 @@ export async function createMarkdownFixture(peer: RadiclePeer) {
    "-C",
    Path.join(tmpDir, "repos", "markdown"),
  ]);
-
  const { projectFolder } = await createProject(peer, { name: "markdown" });
-
  await Fs.cp(Path.join(tmpDir, "repos", "markdown"), projectFolder, {
+
  const { repoFolder } = await createRepo(peer, { name: "markdown" });
+
  await Fs.cp(Path.join(tmpDir, "repos", "markdown"), repoFolder, {
    recursive: true,
  });

-
  await peer.git(["add", "."], { cwd: projectFolder });
+
  await peer.git(["add", "."], { cwd: repoFolder });
  const commitMessage = `Add Markdown cheat sheet

  Borrowed from [Adam Pritchard][ap].
@@ -583,15 +577,15 @@ export async function createMarkdownFixture(peer: RadiclePeer) {

  [ap]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet`;
  await peer.git(["commit", "-m", commitMessage], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
-
  await peer.git(["push", "rad"], { cwd: projectFolder });
+
  await peer.git(["push", "rad"], { cwd: repoFolder });
  await issue.create(
    peer,
    "This `title` has **markdown**",
    'This is a description\n\nWith some multiline text.\n\n```\n23-11-06 10:19 ➜  radicle-jetbrains-plugin git:(main) rad id update --title "Godify jchrist" --description "where jchrist ascends to a god of this project" --delegate did:key:z6MkpaATbhkGbSMysNomYTFVvKG5bnNKYZ2cCamfoHzX9SnL --threshold 1\n\n✓ Identity revision 029837dde8f5c49704e50a19cd709473ac66a456 created\n```',
    ["bug", "feature-request"],
-
    { cwd: projectFolder },
+
    { cwd: repoFolder },
  );
}

@@ -613,7 +607,6 @@ export const markdownRid = "rad:z2tchH2Ti4LxRKdssPQYs6VHE5rsg";
export const sourceBrowsingUrl = `/nodes/127.0.0.1/${sourceBrowsingRid}`;
export const cobUrl = `/nodes/127.0.0.1/${cobRid}`;
export const markdownUrl = `/nodes/127.0.0.1/${markdownRid}`;
-
export const nodeRemote = "z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S";
export const shortNodeRemote = "z6MktU…1xB22S";
export const defaultHttpdPort = 8081;
export const gitOptions = {
modified tests/support/project.ts
@@ -10,8 +10,8 @@ export async function changeBranch(peer: string, branch: string, page: Page) {
  await page.getByRole("button", { name: branch }).click();
}

-
// Create a project using the rad CLI.
-
export async function createProject(
+
// Create a repo using the rad CLI.
+
export async function createRepo(
  peer: RadiclePeer,
  {
    name,
@@ -24,14 +24,14 @@ export async function createProject(
    defaultBranch?: string;
    visibility?: "public" | "private";
  },
-
): Promise<{ rid: string; projectFolder: string; defaultBranch: string }> {
-
  const projectFolder = Path.join(peer.checkoutPath, name);
+
): Promise<{ rid: string; repoFolder: string; defaultBranch: string }> {
+
  const repoFolder = Path.join(peer.checkoutPath, name);

  await peer.git(["init", name, "--initial-branch", defaultBranch], {
    cwd: peer.checkoutPath,
  });
  await peer.git(["commit", "--allow-empty", "--message", "initial commit"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });
  await peer.rad(
    [
@@ -45,15 +45,15 @@ export async function createProject(
      `--${visibility}`,
    ],
    {
-
      cwd: projectFolder,
+
      cwd: repoFolder,
    },
  );

  const { stdout: rid } = await peer.rad(["inspect"], {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
  });

-
  return { rid, projectFolder, defaultBranch };
+
  return { rid, repoFolder, defaultBranch };
}

export function extractPatchId(cmdOutput: { stderr: string }) {
modified tests/support/radicle-httpd-release
@@ -1 +1 @@
-
0.15.0

\ No newline at end of file
+
0.16.0

\ No newline at end of file
modified tests/support/support.ts
@@ -11,9 +11,9 @@ export function randomTag(): string {
  return Crypto.randomBytes(8).toString("hex");
}

-
export function createOptions(projectFolder: string, days: number): Options {
+
export function createOptions(repoFolder: string, days: number): Options {
  return {
-
    cwd: projectFolder,
+
    cwd: repoFolder,
    // eslint-disable-next-line @typescript-eslint/naming-convention
    env: { RAD_LOCAL_TIME: (1671211684 + days * 86400).toString() },
  };
modified tests/unit/router.test.ts
@@ -19,35 +19,35 @@ describe("route invariant when parsed", () => {
      params: {
        // TODO: This only works with the value 0. The value is not actually
        // extract.
-
        projectPageIndex: 0,
+
        repoPageIndex: 0,
        baseUrl: node,
      },
    });
  });
-
  test("projects.tree", () => {
+
  test("repos.tree", () => {
    expectParsingInvariant({
-
      resource: "project.source",
+
      resource: "repo.source",
      node,
-
      project: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
+
      repo: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
      route: "",
    });
  });

-
  test("projects.tree with peer", () => {
+
  test("repos.tree with peer", () => {
    expectParsingInvariant({
-
      resource: "project.source",
+
      resource: "repo.source",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      peer: "PEER",
      route: "",
    });
  });

-
  test("projects.tree with peer and revision", () => {
+
  test("repos.tree with peer and revision", () => {
    const route: Route = {
-
      resource: "project.source",
+
      resource: "repo.source",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      peer: "PEER",
      revision: "REVISION",
      route: "",
@@ -58,11 +58,11 @@ describe("route invariant when parsed", () => {
    expect(testExports.urlToRoute(new URL(path, origin))).toEqual(route);
  });

-
  test("projects.tree with peer and revision and path", () => {
+
  test("repos.tree with peer and revision and path", () => {
    const route: Route = {
-
      resource: "project.source",
+
      resource: "repo.source",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      peer: "PEER",
      path: "PATH",
      revision: "REVISION",
@@ -75,121 +75,121 @@ describe("route invariant when parsed", () => {
    expect(testExports.urlToRoute(new URL(path, origin))).toEqual(route);
  });

-
  test("projects.history", () => {
+
  test("repos.history", () => {
    expectParsingInvariant({
-
      resource: "project.history",
+
      resource: "repo.history",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      revision: "",
    });
  });

-
  test("projects.history with revision", () => {
+
  test("repos.history with revision", () => {
    expectParsingInvariant({
-
      resource: "project.history",
+
      resource: "repo.history",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      revision: "REVISION",
    });
  });

-
  test("projects.commits", () => {
+
  test("repos.commits", () => {
    expectParsingInvariant({
-
      resource: "project.commit",
+
      resource: "repo.commit",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      commit: "COMMIT",
    });
  });

-
  test("projects.issues", () => {
+
  test("repos.issues", () => {
    expectParsingInvariant({
-
      resource: "project.issues",
+
      resource: "repo.issues",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
    });
  });

-
  test("projects.issues with status", () => {
+
  test("repos.issues with status", () => {
    expectParsingInvariant({
-
      resource: "project.issues",
+
      resource: "repo.issues",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      status: "closed",
    });
  });

-
  test("projects.issue", () => {
+
  test("repos.issue", () => {
    expectParsingInvariant({
-
      resource: "project.issue",
+
      resource: "repo.issue",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      issue: "ISSUE",
    });
  });

-
  test("projects.patches", () => {
+
  test("repos.patches", () => {
    expectParsingInvariant({
-
      resource: "project.patches",
+
      resource: "repo.patches",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      search: "SEARCH",
    });
  });

-
  test("projects.patches with search", () => {
+
  test("repos.patches with search", () => {
    expectParsingInvariant({
-
      resource: "project.patches",
+
      resource: "repo.patches",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      search: "SEARCH",
    });
  });

-
  test("projects.patch default view", () => {
+
  test("repos.patch default view", () => {
    expectParsingInvariant({
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      patch: "PATCH",
    });
  });

-
  test("projects.patch activity", () => {
+
  test("repos.patch activity", () => {
    expectParsingInvariant({
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      patch: "PATCH",
      view: { name: "activity" },
    });
  });

-
  test("projects.patch changes", () => {
+
  test("repos.patch changes", () => {
    expectParsingInvariant({
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      patch: "PATCH",
      view: { name: "changes" },
    });
  });

-
  test("projects.patch changes with revision", () => {
+
  test("repos.patch changes with revision", () => {
    expectParsingInvariant({
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      patch: "PATCH",
      view: { name: "changes", revision: "REVISION" },
    });
  });

-
  test("projects.patch diff", () => {
+
  test("repos.patch diff", () => {
    expectParsingInvariant({
-
      resource: "project.patch",
+
      resource: "repo.patch",
      node,
-
      project: "PROJECT",
+
      repo: "REPO",
      patch: "PATCH",
      view: {
        name: "diff",
@@ -219,44 +219,44 @@ describe("pathToRoute", () => {
          scheme: "http",
          port: defaultHttpdPort,
        },
-
        projectPageIndex: 0,
+
        repoPageIndex: 0,
      },
    });
  });

-
  test("project with trailing slash", () => {
+
  test("repo with trailing slash", () => {
    expectPathToRoute(
      "/nodes/example.node.tld/rad:zKtT7DmF9H34KkvcKj9PHW19WzjT/",
      {
-
        resource: "project.source",
+
        resource: "repo.source",
        node: {
          hostname: "example.node.tld",
          scheme: "http",
          port: defaultHttpdPort,
        },
-
        project: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
+
        repo: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
        route: "",
      },
    );
  });

-
  test("project without trailing slash", () => {
+
  test("repo without trailing slash", () => {
    expectPathToRoute(
      "/nodes/example.node.tld/rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
      {
-
        resource: "project.source",
+
        resource: "repo.source",
        node: {
          hostname: "example.node.tld",
          scheme: "http",
          port: defaultHttpdPort,
        },
-
        project: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
+
        repo: "rad:zKtT7DmF9H34KkvcKj9PHW19WzjT",
        route: "",
      },
    );
  });

-
  test("non-existent project route", () => {
+
  test("non-existent repo route", () => {
    expectPathToRoute(
      "/nodes/example.node.tld/rad:zKtT7DmF9H34KkvcKj9PHW19WzjT/nope",
      null,
modified tests/visual/desktop/cob.spec.ts
@@ -90,7 +90,7 @@ test("failed diff loading for a specific revision", async ({ page }) => {
  await page.route(
    ({ pathname }) =>
      pathname ===
-
      "/api/v1/projects/rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe/diff/38c225e2a0b47ba59def211f4e4825c31d9463ec/9898da6155467adad511f63bf0fb5aa4156b92ef",
+
      "/api/v1/repos/rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe/diff/38c225e2a0b47ba59def211f4e4825c31d9463ec/9898da6155467adad511f63bf0fb5aa4156b92ef",
    route => route.fulfill({ status: 500 }),
  );

modified tests/visual/desktop/landingPage.spec.ts
@@ -1,7 +1,7 @@
import { test, expect } from "@tests/support/fixtures.js";
import sinon from "sinon";

-
test("pinned projects", async ({ page }) => {
+
test("pinned repos", async ({ page }) => {
  await page.addInitScript(() => {
    localStorage.setItem(
      "configuredPreferredSeeds",
@@ -18,7 +18,7 @@ test("pinned projects", async ({ page }) => {
  await expect(page).toHaveScreenshot();
});

-
test("load projects error", async ({ page }) => {
+
test("load repos error", async ({ page }) => {
  await page.addInitScript(() => {
    localStorage.setItem(
      "configuredPreferredSeeds",
@@ -32,7 +32,7 @@ test("load projects error", async ({ page }) => {
  });

  await page.route(
-
    ({ pathname }) => pathname === "/api/v1/projects",
+
    ({ pathname }) => pathname === "/api/v1/repos",
    route => route.fulfill({ status: 500 }),
  );

@@ -47,7 +47,7 @@ test("response parse error", async ({ page }) => {
      JSON.stringify([{ hostname: "127.0.0.1", port: 8081, scheme: "http" }]),
    );
  });
-
  await page.route("*/**/v1/projects*", route => {
+
  await page.route("*/**/v1/repos*", route => {
    return route.fulfill({
      json: [{ name: 1337 }],
    });
@@ -63,7 +63,7 @@ test("response error", async ({ page }) => {
      JSON.stringify([{ hostname: "127.0.0.1", port: 8081, scheme: "http" }]),
    );
  });
-
  await page.route("*/**/v1/projects*", route => {
+
  await page.route("*/**/v1/repos*", route => {
    return route.fulfill({
      status: 500,
      body: "There is an error in the response",
modified tests/visual/desktop/node.spec.ts
@@ -14,10 +14,10 @@ test("node page", async ({ page }) => {
  await expect(page).toHaveScreenshot();
});

-
test("empty pinned projects", async ({ page }) => {
+
test("empty pinned repos", async ({ page }) => {
  await page.route(
    ({ hostname, pathname }) =>
-
      pathname === "/api/v1/projects" && hostname === "127.0.0.1",
+
      pathname === "/api/v1/repos" && hostname === "127.0.0.1",
    async route => {
      await route.fulfill({
        status: 200,
@@ -40,7 +40,7 @@ test("node not found", async ({ page }) => {
});

test("response parse error", async ({ page }) => {
-
  await page.route("*/**/v1/projects*", route => {
+
  await page.route("*/**/v1/repos*", route => {
    return route.fulfill({
      json: [{ name: 1337 }],
    });
@@ -53,7 +53,7 @@ test("response parse error", async ({ page }) => {
});

test("response error", async ({ page }) => {
-
  await page.route("*/**/v1/projects*", route => {
+
  await page.route("*/**/v1/repos*", route => {
    return route.fulfill({
      status: 500,
    });
modified tests/visual/desktop/project.spec.ts
@@ -80,7 +80,7 @@ test("diff selection", async ({ page }) => {
  await expect(page).toHaveScreenshot({ fullPage: true });
});

-
test("project load error", async ({ page }) => {
+
test("repo load error", async ({ page }) => {
  await page.goto(
    `${sourceBrowsingUrl}/remotes/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz`,
    { waitUntil: "networkidle" },
@@ -88,7 +88,7 @@ test("project load error", async ({ page }) => {
  await expect(page).toHaveScreenshot();
});

-
test("project not found", async ({ page }) => {
+
test("repo not found", async ({ page }) => {
  await page.goto(`/nodes/127.0.0.1/rad:z4Vzzzzzzzzzzzzzzzzzzzzzzzzzz`, {
    waitUntil: "networkidle",
  });
@@ -97,7 +97,7 @@ test("project not found", async ({ page }) => {

test("response parse error", async ({ page }) => {
  await page.route(
-
    ({ pathname }) => pathname === `/api/v1/projects/${sourceBrowsingRid}`,
+
    ({ pathname }) => pathname === `/api/v1/repos/${sourceBrowsingRid}`,
    route => {
      return route.fulfill({
        json: [{ name: 1337 }],
@@ -110,7 +110,7 @@ test("response parse error", async ({ page }) => {

test("response error", async ({ page }) => {
  await page.route(
-
    ({ pathname }) => pathname === `/api/v1/projects/${sourceBrowsingRid}`,
+
    ({ pathname }) => pathname === `/api/v1/repos/${sourceBrowsingRid}`,
    route => {
      return route.fulfill({
        status: 500,
@@ -125,7 +125,7 @@ test("readme not found", async ({ page }) => {
  await page.route(
    ({ pathname }) =>
      pathname ===
-
      `http://127.0.0.1:8081/api/v1/projects/${sourceBrowsingRid}/readme/f591f9c3d842fdfb9e170e0f467189c6d9e950a2`,
+
      `http://127.0.0.1:8081/api/v1/repos/${sourceBrowsingRid}/readme/f591f9c3d842fdfb9e170e0f467189c6d9e950a2`,
    route => {
      return route.fulfill({
        status: 500,
modified tests/visual/desktop/user.spec.ts
@@ -21,7 +21,7 @@ test("user page", async ({ page }) => {
  await expect(page).toHaveScreenshot();
});

-
test("empty pinned projects", async ({ page }) => {
+
test("empty pinned repos", async ({ page }) => {
  await page.goto(`/nodes/radicle.local/users/${bobRemote}`, {
    waitUntil: "networkidle",
  });
modified tests/visual/mobile/user.spec.ts
@@ -21,7 +21,7 @@ test("user page", async ({ page }) => {
  await expect(page).toHaveScreenshot();
});

-
test("empty pinned projects", async ({ page }) => {
+
test("empty pinned repos", async ({ page }) => {
  await page.goto(`/nodes/radicle.local/users/${bobRemote}`, {
    waitUntil: "networkidle",
  });