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.
Repository: github.com/le-space/orbitdb-ui
Live example (SvelteKit demo on IPFS via Storacha): gateway · CID bafybeihda6qtfj5dmpkqrwjv22dfsa3csacapygfwzzohts6wwgoebcbiy
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.
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-didConfigure your bundler to compile Svelte components from this package (same as any Svelte library).
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:
import { createWebAuthnIdentity, getWebAuthnCapabilities } from '@le-space/orbitdb-ui/identity';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:
@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.
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.
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.
<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
}}
/>Passkey identity creation: worker (ed25519) vs varsig (P-256) modes, optional skip; parent sets show={false} from oncreated / onskip.
<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 |
Optional footer chrome for OrbitDB-branded apps (export from the same package).
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).
svelte^5.0.0@le-space/orbitdb-identity-provider-webauthn-did^0.2.10
pnpm install # or npm install
pnpm run build # emits dist/
pnpm run checkFirst-time npm publish (scoped package must be public):
npm publish --access publicpackage.json includes prepublishOnly to build dist/ before pack.
MIT