# vault-client

> Self-hosted AES-256-GCM encrypted password manager — React UI plugin for MeyiConnect

## Installation

```bash
npm install vault-client
```

## MeyiConnect integration (3 steps)

### Step 1 — Add the route file

Copy to `frontend/src/routes/_authenticated/vault/$.tsx`:

```tsx
import { createFileRoute } from "@tanstack/react-router";
import { VaultApp, VaultProvider } from "vault-client";
import "vault-client/style.css";
import api from "@/services/api";
import { users } from "@/services/users";

function VaultRoute() {
  return (
    <VaultProvider
      api={api}
      getUsers={() => users.getAll().then((r) => r.data ?? r)}
    >
      <VaultApp />
    </VaultProvider>
  );
}

export const Route = createFileRoute("/_authenticated/vault/$")({
  component: VaultRoute,
});
```

### Step 2 — Add to sidebar

In `frontend/src/components/layout/data/sidebar-data.ts`:

```ts
import { vaultNavItems } from 'vault-client'
import { FolderLock } from 'lucide-react'

// Add inside navGroups array:
{
  title: 'Vault',
  items: vaultNavItems.map(item => ({ ...item, icon: FolderLock })),
},
```

### Step 3 — Done

TanStack Router auto-discovers the new route file. Run `npm run dev` and
"Vaults" appears in the sidebar.

---

## Standalone usage (any React app)

```tsx
import { VaultProvider, VaultApp } from "vault-client";
import "vault-client/style.css";
import axios from "axios";

const api = axios.create({ baseURL: "https://your-api.example.com" });

function App() {
  return (
    <VaultProvider
      api={api}
      getUsers={async () => {
        const res = await api.get("/api/v1/users");
        return res.data.users;
      }}
    >
      <VaultApp />
    </VaultProvider>
  );
}
```

---

## Composable exports

You can use individual pieces instead of the full `VaultApp`:

### Pages (you manage routing)

```tsx
import { VaultPage, GroupsPage, EntriesPage } from 'vault-client'

// VaultPage — lists all vaults
<VaultPage onNavigate={(to, vaultId) => router.push(`/vault/${vaultId}`)} />

// GroupsPage — lists domain groups inside a vault
<GroupsPage vaultId={vaultId} vaultName="Production" onNavigate={...} />

// EntriesPage — lists encrypted credentials inside a group
<EntriesPage vaultId={vaultId} groupId={groupId} onNavigate={...} />
```

### Hooks (bring your own UI)

```tsx
import { useVaults, useEntries, useCreateGrant } from "vault-client";

function MyCustomVaultUI() {
  const { data: vaults } = useVaults();
  const { data: entries } = useEntries(groupId);
  const createGrant = useCreateGrant();

  // build your own UI
}
```

### Dialogs

```tsx
import { EntryFormDialog, GrantAccessDialog } from 'vault-client'

<EntryFormDialog
  open={open}
  onOpenChange={setOpen}
  groupId={groupId}
/>

<GrantAccessDialog
  open={open}
  onOpenChange={setOpen}
  scope="vault"
  scopeId={vaultId}
  scopeLabel="Production"
/>
```

---

## VaultProvider props

| Prop       | Type                    | Required | Default  | Description                                    |
| ---------- | ----------------------- | -------- | -------- | ---------------------------------------------- |
| `api`      | `AxiosInstance`         | ✅       | —        | Host's axios instance (shares auth + base URL) |
| `getUsers` | `() => Promise<User[]>` | ✅       | —        | Fetches users for grant picker                 |
| `basePath` | `string`                | —        | `/vault` | Base path for internal navigation              |

---

## What the package does NOT include

- **Auth** — uses the host's axios instance and req.user from the server
- **Toast provider** — uses `sonner` which must be mounted by the host
- **shadcn components** — uses inline primitives; compatible with any Tailwind setup
