@perkos/shared-client
v0.1.1
Published
Shared client lib for PerkOS apps: wallet auth, API client, Firebase init, React hooks.
Maintainers
Readme
@perkos/shared-client
Shared client library for PerkOS apps. Bundles the wallet sign-in flow, an auth-aware API client, Firebase init helpers, format utilities, Zod validators, and React hooks that glue everything together so App, Admin, Desktop, and future PerkOS surfaces don't each reimplement them.
The package is framework-agnostic at the core (works from CLI / Tauri /
plain Node) and ships React hooks under a separate @perkos/shared-client/hooks
entry so consumers without React can avoid the peer dep.
Install
npm install @perkos/shared-client firebase viem
# plus react if you want the hooks
npm install reactPeer dependencies
| Peer | Required? | Why |
|---|---|---|
| firebase (^10 || ^11) | yes | Auth + Firestore handles returned by initFirebase. |
| viem (^2) | optional | Only needed if the consumer types its address as viem's Address (the package itself uses `0x${string}` literals). |
| react (^18 || ^19) | optional | Only needed when importing from @perkos/shared-client/hooks. |
| @perkos/shared-types (^0.1) | optional | Once published, supplies ApiError, WalletSigninResponse, etc. Until then this package ships inline fallback declarations under ./dist/types.*. |
Usage
1. Initialise Firebase (once at app startup)
import { initFirebase } from "@perkos/shared-client";
const { app, auth, db } = initFirebase({
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN!,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID!,
});initFirebase is idempotent — call it from your root layout / provider and
re-call getFirebase() anywhere else.
2. Sign in with a wallet (no React required)
import { signInWithWallet, initFirebase } from "@perkos/shared-client";
import { signInWithCustomToken } from "firebase/auth";
const { auth } = initFirebase(firebaseConfig);
const session = await signInWithWallet({
address: "0xAbC…",
signMessage: (msg) => wallet.signMessage(msg),
apiBase: "https://api.perkos.xyz",
});
await signInWithCustomToken(auth, session.token);The helper performs the three-step handshake (nonce → wallet signature →
custom-token exchange) and returns the server response. Calling
signInWithCustomToken is left to the consumer so it can run extra logic
(analytics, role checks, etc.) before finalising the Firebase session.
3. Use the React hook in Next.js or any React app
"use client";
import { useWalletSession } from "@perkos/shared-client/hooks";
import { useAccount, useSignMessage } from "wagmi";
const { address } = useAccount();
const { signMessageAsync } = useSignMessage();
const session = useWalletSession({
apiBase: "https://api.perkos.xyz",
address,
signMessage: (m) => signMessageAsync({ message: m }),
auth, // from initFirebase
requireRole: null, // or "super_admin" for the Admin app
requireAccess: true, // ignore on CLI tools that allow anyone
});
switch (session.status) {
case "loading": return <Spinner />;
case "signed-out": return <ConnectButton />;
case "signing": return <Spinner label="Signing in…" />;
case "not-allowlisted": return <AccessGate />;
case "wrong-role": return <Unauthorized />;
case "error": return <Retry onClick={session.retry} />;
case "signed-in": return <App />;
}4. Call the API with the user's Firebase ID token attached automatically
import { createApiClient, initFirebase } from "@perkos/shared-client";
const { auth } = initFirebase(firebaseConfig);
const api = createApiClient({
baseUrl: "https://api.perkos.xyz",
getIdToken: () => auth.currentUser?.getIdToken() ?? Promise.resolve(null),
});
const me = await api.get<{ uid: string; role: string }>("/v1/users/me");Any non-2xx response throws ApiError with the parsed body attached.
Configuration
The package does not read process.env itself. Consumers pass config
explicitly so the same lib works under Next.js, Vite, Electron, Tauri, or a
plain Node CLI. For Next.js the typical env vars to expose to the browser
are:
NEXT_PUBLIC_FIREBASE_API_KEY=…
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=…
NEXT_PUBLIC_FIREBASE_PROJECT_ID=…
NEXT_PUBLIC_FIREBASE_APP_ID=…
NEXT_PUBLIC_PERKOS_API_BASE=https://api.perkos.xyzWire them into initFirebase({...}) and createApiClient({ baseUrl }) at
startup.
Versioning
This package uses SemVer. The 0.x line allows
breaking changes between minor releases until the platform-level API
(api.perkos.xyz) stabilises. Until 1.0, pin the exact version in
consumers.
Related packages
@perkos/shared-types— TypeScript types and Zod schemas shared with the PerkOS-API server (peer dep; once published it provides the realApiError/WalletSigninResponsesymbols re-exported here).@perkos/perkos-a2a— A2A protocol bridge plugin (independent of this package).
License
MIT (c) 2026 PerkOS.