Installation
Install
Section titled “Install”npm install @muhkoo/connect@alpha pnpm add @muhkoo/connect@alpha yarn add @muhkoo/connect@alpha Optional peer dependency: snarkjs
Section titled “Optional peer dependency: snarkjs”ZK login generates a Groth16 proof, which needs snarkjs. It’s imported
lazily — you only need it installed if your app calls
client.auth.zk.login() / register():
npm install snarkjsApps that only read public data or act as a relay don’t need it.
Runtime support
Section titled “Runtime support”@muhkoo/connect ships three builds, selected automatically by your bundler
via the package’s exports map:
| Environment | Notes |
|---|---|
| Browser | The primary target. Needs WebCrypto (every modern browser). |
| Node 20+ | globalThis.fetch + WebCrypto are built in. |
| Edge / serverless runtimes | A trimmed build (the edge can’t run snarkjs); use it for verification + relay logic, not ZK proof generation. Selected by the workerd export condition, or import @muhkoo/connect/workers explicitly. It exports far fewer symbols than the browser and Node builds, so check its type declarations before relying on one. |
Bundling for the browser (Vite)
Section titled “Bundling for the browser (Vite)”The browser build reaches for a few Node globals (Buffer, process) on its
crypto paths. In a Vite app with no polyfills, the build succeeds and the app
loads, then throws process is not defined the first time one of those paths
runs, such as hosted sign-in. Add vite-plugin-node-polyfills:
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({ plugins: [ nodePolyfills({ include: ["buffer", "process", "util", "stream"], globals: { Buffer: true, process: true, global: true }, }), ],});The browser build is large (several MB before compression). If first paint
matters, load it with a dynamic import("@muhkoo/connect") so visitors who never
sign in never download it.
Configure the client
Section titled “Configure the client”import { Client } from "@muhkoo/connect";
const client = new Client({ apiKey: "mk_test_pk_…", // app / publishable key // baseUrl is optional — it defaults to the hosted accelerator // (https://api.muhkoo.dev). Set it only to target staging or self-hosting.});| Option | Type | Required | Description |
|---|---|---|---|
apiKey | string | recommended | App key. Authenticates + meters the app. See app keys. |
accessToken | string | no | A scoped, expiring access token (mk_<env>_at_…) for server-side and CI callers. Takes precedence over apiKey. |
baseUrl | string | no | Absolute URL of the accelerator. Defaults to the hosted accelerator (https://api.muhkoo.dev). |
authBaseUrl | string | no | The hosted sign-in app used by client.auth.hosted. Defaults to https://auth.muhkoo.dev. |
functionsHostSuffix | string | no | Zone HTTP functions are served from, used by client.functions.invoke. Defaults to fns.muhkoo.dev. |
circuits | CircuitUrls | no | ZK circuit assets (wasmUrl, zkeyUrl, plus pinned SHA-256 digests). Defaults to ${baseUrl}/circuits/build/preimagePoK_js/preimagePoK.wasm and ${baseUrl}/circuits/build/preimagePoK_0001.zkey. |
sessionStore | SessionStore | no | Token persistence. Defaults to localStorage in a browser, and in-memory everywhere else. |
offline | { enabled?, store?, cacheShards?, maxQueueBytes? } | no | Offline support. On by default in browsers, a no-op elsewhere. |
p2p | { enabled?, workerFactory?, iceServers?, maxPeers?, debug? } | no | Opt-in peer-to-peer file-block exchange between Space members (browser only). |
fetch | typeof fetch | no | Custom fetch (tests, proxies). |
logLevel | string | no | SDK log verbosity. |
Persisting sessions across reloads
Section titled “Persisting sessions across reloads”In a browser the session is kept in localStorage (under keys starting
muhkoo.session.) by default, so users stay signed in across reloads. Outside a
browser, or where localStorage is blocked (private windows, sandboxed iframes),
it falls back to memory for the life of the process. Pass your own
sessionStore to change where it lives. The SDK exports
LocalStorageSessionStore and MemorySessionStore, or you can write one:
import { Client, type SessionStore, type StoredSession } from "@muhkoo/connect";
const localStorageStore: SessionStore = { load: () => { const raw = localStorage.getItem("muhkoo.session"); return raw ? (JSON.parse(raw) as StoredSession) : null; }, save: (s) => localStorage.setItem("muhkoo.session", JSON.stringify(s)), clear: () => localStorage.removeItem("muhkoo.session"),};
const client = new Client({ apiKey, sessionStore: localStorageStore });On boot, call await client.auth.zk.restore() on boot — see
Authentication.