npm package: @le-space/orbitdb-ui
Description: Shared OrbitDB UI components: ConsentModal, WebAuthnSetup, and identity utilities
Latest version: 0.1.4

# `@le-space/orbitdb-ui`

Shared **Svelte 5** UI and **browser helpers** for **WebAuthn-backed OrbitDB** apps: consent flows, passkey setup (worker vs varsig modes), re-authentication, and **varsig / IPFS identity** utilities built on [`@le-space/orbitdb-identity-provider-webauthn-did`](https://www.npmjs.com/package/@le-space/orbitdb-identity-provider-webauthn-did).

**Repository:** [github.com/le-space/orbitdb-ui](https://github.com/le-space/orbitdb-ui)

**Live example (SvelteKit demo on IPFS via Storacha):** [gateway](https://storacha.link/ipfs/bafybeihda6qtfj5dmpkqrwjv22dfsa3csacapygfwzzohts6wwgoebcbiy) · CID `bafybeihda6qtfj5dmpkqrwjv22dfsa3csacapygfwzzohts6wwgoebcbiy`

---

## Why this exists

Several apps (e.g. **simple-todo**) need the same pieces: a **consent** surface, a **WebAuthn registration** flow, **“touch your passkey again”** hooks, and glue for **varsig identities** with OrbitDB. Keeping that in one package avoids copy-paste and keeps UX consistent across demos and products.

This library does **not** replace your **Helia / libp2p / OrbitDB** wiring—you still own P2P config and access controllers. It focuses on **credential UX** and **identity helpers** that pair with the WebAuthn DID provider.

**Architecture (Mermaid):** how `orbitdb-ui` sits beside **libp2p → Helia → OrbitDB** in apps like **simple-todo** is described in **[`docs/integration-architecture.md`](docs/integration-architecture.md)**.

---

## Install

```bash
npm install @le-space/orbitdb-ui @le-space/orbitdb-identity-provider-webauthn-did
# or: pnpm add @le-space/orbitdb-ui @le-space/orbitdb-identity-provider-webauthn-did
```

Configure your bundler to compile Svelte components from this package (same as any Svelte library).

### TypeScript and `@le-space/orbitdb-ui/identity`

From **v0.1.2** onward, published builds include **`.d.ts`** for the root entry and components. Import everything from `@le-space/orbitdb-ui`, or pull **identity helpers only** (separate JS entry, smaller surface) from:

```ts
import { createWebAuthnIdentity, getWebAuthnCapabilities } from '@le-space/orbitdb-ui/identity';
```

### Tailwind CSS v4

Components use **Tailwind utility classes**. Tailwind v4 does not scan `node_modules` by default, so add a **`@source`** entry in your global CSS (path relative to that file) so utilities used inside `@le-space/orbitdb-ui` are generated:

```css
@import 'tailwindcss';

@source '../node_modules/@le-space/orbitdb-ui/dist/index.js';
```

Adjust the path if your `app.css` lives elsewhere (e.g. `../../node_modules/...` from `src/styles/`).

With **pnpm** and a workspace **`file:`** dependency, `node_modules/@le-space/orbitdb-ui` may **not** exist under your app package, so that `@source` line can silently match nothing. Point **`@source`** at any on-disk path to **`dist/index.js`** (or add **`@source '…/node_modules/@le-space/orbitdb-ui/src/**/*.svelte'`** alongside it) so Tailwind still sees the class names.

Without **`@source`**, class names in the prebuilt **`dist/index.js`** never enter Tailwind’s pipeline, so positioning, flex, colors, and **arbitrary values** like `max-h-[min(90vh,40rem)]` and `z-[60]` are missing at runtime—the overlay renders **in normal document flow** (not a viewport modal) and inline **SVGs can appear huge**.

#### Modal layout (utilities used)

`ConsentModal` and `WebAuthnSetup` share the same overlay pattern:

| Layer | Role | Typical Tailwind |
| ----- | ---- | ---------------- |
| Root | Full-viewport flex portal, scroll if needed | `fixed inset-0 z-50 flex items-center justify-center overflow-y-auto p-4` |
| Backdrop | Dim everything behind the panel | `absolute inset-0 bg-slate-900/50` (`aria-hidden="true"`) |
| Panel | Dialog surface above backdrop | `relative z-10 my-auto w-full max-w-* max-h-[min(90vh,40rem)] overflow-y-auto overflow-x-hidden rounded-* border/shadow, …` |
| Toast | `ConsentModal` only, above dialog | `fixed … z-[60] -translate-x-1/2 …` |

Both dialogs set **`role="dialog"`**, **`aria-modal="true"`**, and **`aria-labelledby`** pointing at the panel title. Layout is entirely Tailwind utilities shipped as class strings in **`dist/index.js`**. If you use **`OrbitDBFooter`**, also import **`@le-space/orbitdb-ui/dist/style.css`** for its slide keyframes.

---

## Components

### `ConsentModal`

Storage / network / peer toggles and an accept action. Parent controls visibility with a plain **`show`** prop (not `bind:show` — the package ships precompiled **`dist/`** JS); the modal does not self-close.

```svelte
<script>
  import { ConsentModal } from '@le-space/orbitdb-ui';
  let show = true;
  let remember = false;
</script>

<ConsentModal
  show={show}
  bind:rememberDecision={remember}
  proceedButtonText="Accept & Continue"
  appName="My App"
  versionString="v1.0.0 [dev]"
  onproceed={({ enablePersistentStorage, enableNetworkConnection, enablePeerConnections }) => {
    show = false;
    // Start P2P / OrbitDB with these preferences
  }}
/>
```

### `WebAuthnSetup`

Passkey identity creation: **worker (ed25519)** vs **varsig (P-256)** modes, optional skip; parent sets **`show={false}`** from **`oncreated`** / **`onskip`**.

```svelte
<script>
  import { WebAuthnSetup } from '@le-space/orbitdb-ui';
  let show = true;
</script>

<WebAuthnSetup
  show={show}
  modeConfig="choice"
  defaultMode="worker"
  optional={true}
  appName="My App"
  oncreated={(detail) => {
    show = false;
    const { identity, credentialInfo, authMode } = detail;
    // Register identity with OrbitDB / Identities
  }}
  onskip={() => {
    show = false;
  }}
/>

<!-- Fixed modes -->
<!-- <WebAuthnSetup modeConfig="worker" appName="My App" /> -->
<!-- <WebAuthnSetup modeConfig="varsig" appName="My App" optional={false} /> -->
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `modeConfig` | `'choice' \| 'worker' \| 'varsig'` | `'choice'` | User picks mode, or lock to one mode |
| `defaultMode` | `'worker' \| 'varsig'` | `'worker'` | When `modeConfig='choice'` |
| `optional` | `boolean` | `true` | Show “Skip for now” |
| `appName` | `string` | `'App'` | Passkey RP display name |

### `OrbitDBFooter`

Optional footer chrome for OrbitDB-branded apps (export from the same package).

---

## Identity utilities (JS / TS)

```ts
import {
  createWebAuthnIdentity,
  useExistingWebAuthnCredential,
  authenticateWithWebAuthn,
  hasExistingCredentials,
  isWebAuthnAvailable,
  getPreferredWebAuthnMode,
  getStoredWebAuthnCredential,
  getStoredCredentialInfo,
  WEBAUTHN_AUTH_MODES,
  setOnPasskeyPrompt,
  getOrCreateVarsigIdentity,
  createWebAuthnVarsigIdentities,
  createIpfsIdentityStorage,
  wrapWithVarsigVerification
} from '@le-space/orbitdb-ui';

setOnPasskeyPrompt((msg) => console.info(msg));

const result = await createWebAuthnIdentity('My App', { mode: 'worker' });
```

Use **`authenticateWithWebAuthn`** / **`hasExistingCredentials`** before sensitive writes. Use **varsig** exports when wiring **Identities** + IPFS-backed storage (see a full app such as **simple-todo** `p2p.js`).

---

## Peer dependencies

- `svelte` ^5.0.0  
- `@le-space/orbitdb-identity-provider-webauthn-did` ^0.2.10  

---

## Develop & publish (maintainers)

```bash
pnpm install   # or npm install
pnpm run build # emits dist/
pnpm run check
```

First-time **npm** publish (scoped package must be public):

```bash
npm publish --access public
```

`package.json` includes `prepublishOnly` to build `dist/` before pack.

---

## License

MIT