# Getting Started

> Install, configure, and make your first commit through the gitapp stack.

Source: https://gitapp.n.yatsyk.com/docs/core/getting-started

# Getting Started

End-to-end: install the stack, build a `DocStore` against a GitHub repo,
and run a transaction. The same shape works for Node CLIs, browser apps,
and React Native apps — only the adapter changes.

## 1. Install

```bash
pnpm add @dev-bench/docstore @dev-bench/git-fs @dev-bench/gitapp
```

For the UI layer (optional):

```bash
pnpm add @dev-bench/gitapp-ui
# Peer deps if you don't already have them:
pnpm add react react-native react-native-svg
```

## 2. Build a `DocStore`

`createGitAppDocStore` takes three things: a `GitFs` (storage), a
`RepoManagement` (REST provider), and a `RepoRef` (which repo / branch).

```ts
import { createBrowserGitFs } from "@dev-bench/git-fs/adapters/browser";
import { githubManagement } from "@dev-bench/git-fs/mgmt/github";
import { createGitAppDocStore } from "@dev-bench/gitapp";

const docStore = createGitAppDocStore({
  gitFs: createBrowserGitFs({ dbName: "myapp" }),
  mgmt: githubManagement({
    proxyBase: "https://cors.example.com/github",
  }),
  repoRef: {
    provider: "github",
    owner: "octocat",
    name: "notes",
    branch: "main",
    proxyBase: "https://cors.example.com/github",
  },
  // Token lookup is a function so the docstore picks up fresh tokens
  // when the user re-auths without needing reconstruction.
  getToken: () => ({ kind: "present", token: process.env.GITHUB_TOKEN! }),
  author: {
    name: "Octocat",
    email: "octocat@github.com",
    timestampISO: () => new Date().toISOString(),
  },
});
```

> **Why a CORS proxy?** Browsers can't talk to `github.com` directly for
> git smart-http or REST. In Node, swap `createBrowserGitFs` for
> `createNodeGitFs` and drop `proxyBase`.

## 3. Read

```ts
import { match } from "ts-pattern";

const r = await docStore.read("todos/1.md");
match(r)
  .with({ kind: "found" }, ({ content, versionToken }) => {
    console.log(content);
    return versionToken; // pass back as ifMatch for safe updates
  })
  .with({ kind: "missing" }, () => console.log("no such doc"))
  .exhaustive();
```

Reads never throw on user-recoverable conditions; they return a
discriminated union. Same for `list`, `runTransaction`, `syncIn`.

## 4. Write a transaction

```ts
const result = await docStore.runTransaction({
  mutations: [
    {
      kind: "put",
      path: "todos/1.md",
      content: "# buy milk\n\nstatus: open\n",
      ifMatch: { kind: "absent" }, // create-only; fails if path exists
    },
  ],
  message: "todo: add buy milk",
  onConflict: { kind: "rebase-mutations", maxAttempts: 3 },
});

match(result)
  .with({ kind: "ok" }, ({ commitOid }) => console.log("ok", commitOid))
  .with({ kind: "conflict" }, ({ paths }) => console.warn("conflict", paths))
  .with({ kind: "rejected" }, ({ reason }) => console.warn(reason))
  .with({ kind: "network" }, ({ message }) => console.warn(message))
  .exhaustive();
```

Available mutation kinds (v1):

* `put` — create or update a doc.
* `delete` — remove a doc.
* `json-patch` — RFC 6902 patch on a JSON doc.
* `upsert-frontmatter` — merge YAML frontmatter on a markdown doc.

## 5. Watch

```ts
const unsub = docStore.watch("todos/", (event) => {
  // Fires on remote-driven changes only — local writes don't echo.
  console.log("remote changed:", event);
});

await docStore.syncIn(); // force a pull-then-emit cycle
unsub();
```

## 6. UI (optional)

`@dev-bench/gitapp-ui` provides view-model-driven components — every
async control surfaces idle / loading / ready / error explicitly.

```tsx
import { ThemeProvider, defaultLightTheme, ConnectionPanel } from "@dev-bench/gitapp-ui";

export function App() {
  return (
    <ThemeProvider theme={defaultLightTheme}>
      <ConnectionPanel model={connectionModel} />
    </ThemeProvider>
  );
}
```

The component takes a `connectionModel` (a thin view-model the host app
implements). See [API](./api.mdx) for the full set.

## Tests

For unit tests, swap the adapter:

```ts
import { createInMemoryGitFs, createInMemoryRemote } from "@dev-bench/git-fs/adapters/in-memory";

const remote = createInMemoryRemote("test-remote");
const gitFs = createInMemoryGitFs({ remote });
// ... build docStore as above; no network involved.
```
