Operational facts about this repository: ports, env vars, package behaviors, and build quirks. Read this file when you need a specific detail. For philosophy, principles, and coding conventions, see AGENTS.md.
Use pnpm. Do not use npm.
| App | Port | Command |
|---|---|---|
apps/emulator |
3000 | pnpm exec turbo dev --filter=@farcaster/snap-emulator |
template/ |
3003 | pnpm dev (inside template/) |
examples/* |
3010+ | Distinct port per example app |
- GET: send
Accept: application/vnd.farcaster.snap+json; example servers typically expose JSON on/snap, not on bare/. - POST: body must be a JFS compact string (
header.payload.signature). The payload must be base64url-encoded.
registerSnapHandler skips JFS signature verification when NODE_ENV is not production, but POST bodies must still be JFS-shaped JSON (header / payload / signature), including from apps/emulator.
- Set
SKIP_JFS_VERIFICATION=noto require verification anyway - Set
SKIP_JFS_VERIFICATION=yesor=1to force bypass in production (dev-only) - The handler option is
skipJFSVerification(exact property name) - There is no
maxSkewSecondsoption on the handler — post time skew is handled inside@farcaster/snapserver parsing
| Variable | Where | Description |
|---|---|---|
SNAP_PUBLIC_BASE_URL |
Snap server | Canonical HTTPS origin (no trailing slash) so page.buttons[].target URLs resolve correctly |
SKIP_JFS_VERIFICATION |
Snap server | yes/1 to bypass JFS verification; do not use in production |
FARCASTER_HUB_URL |
Snap server | Hub URL with port, e.g. https://rho.farcaster.xyz:3381 |
TURSO_DATABASE_URL |
@farcaster/snap-turso |
Turso database URL (e.g. libsql://…) |
TURSO_AUTH_TOKEN |
@farcaster/snap-turso |
Turso database auth token |
Snap hub verification uses the Hubble HTTP API only (no gRPC). URL helpers accept http/https with an explicit port or bare host:port; grpc:/grpcs: are invalid.
In apps/emulator, link buttons first GET /api/snap?url=… for the resolved target; if the response is valid snap JSON, the emulator replaces the preview and syncs the Snap URL field, otherwise it opens the link in a new tab.
For local dev on Next.js 16+, use next dev -p 3000 --webpack when forcing the Webpack dev server (supported flag). Do not use undocumented flags such as --no-turbopack.
This repo sets link-workspace-packages=false in .npmrc, so plain semver ranges resolve from npm. Use workspace:* only when you intentionally want the in-repo package.
For apps installed or copied outside this monorepo, prefer published semver ranges for @farcaster/snap and @farcaster/snap-hono on npm.
The json-render catalog for snaps lives in pkgs/snap/src/ui/. It is exported as @farcaster/snap/ui and per-component sub-paths (e.g., @farcaster/snap/ui/button). The emulator imports snapJsonRenderCatalog from @farcaster/snap/ui.
Opt-in data persistence lives in @farcaster/snap-turso:
- Types:
DataStore,DataStoreValue,SnapFunctionWithDataStore - Helpers:
createInMemoryDataStore(),createTursoDataStore(url, token) - when hosted via Neynar, uses db-backed storage; otherwise in-memory (for local dev)
Snap POST authentication uses verifyJFSRequestBody from @farcaster/snap/server as the single verification path; legacy header/signing verification flows were removed.
- POST bodies must be a JFS envelope — either JSON
{ header, payload, signature }or the same compact dot-separated string form (BASE64URL(header).BASE64URL(payload).BASE64URL(signature)); both are accepted byparseRequestandregisterSnapHandler - Hub/Node-dependent code lives under
pkgs/snap/src/server/ - The main
@farcaster/snapentry does not depend on@farcaster/hub-nodejs(safe for browser bundles that only need schemas/validation) @farcaster/snap-honouses an internalpayloadToResponsehelper when buildingResponses fromregisterSnapHandler; it is not part of the package's public exports
parseRequest (@farcaster/snap/server) decodes the JFS payload and validates it with payloadSchema (Zod). No manual coercion is applied — fields that don't match the schema are rejected. Coverage in pkgs/snap/tests/parseRequest.test.ts.
pkgs/snapuses a post-build ESM import rewrite (tsc-alias --resolve-full-paths --resolve-full-extension .js) so Node ESM consumers can resolvedist/*imports- Turbo wires
dependsOn: ["^build"]ontest,typecheck, anddevso workspace packages build before dependents apps/emulatorrunsbuild:workspace-depsinpredevandprebuildfor@farcaster/snap