@joinbankroll/sdk/next is those, so they are an upgrade rather than a file you
maintain.
The entry is server-only — it imports next/headers, which throws in a
client bundle, so a mistake fails at build rather than shipping the wrong thing
to a browser. Nothing here is required: every helper is a convenience over
verifyToken and the
manifest format, both of which any stack can use directly.
The origin
host header — so preview
deployments, custom domains, and local tunnels each identify themselves
correctly with nothing configured. It is the audience a session token is minted
for and the sub a manifest claims, which is why it is never guessed: an origin
inferred from a deployment environment variable would verify tokens for
somewhere the app is not actually served from.
The session on a request
Because the audience comes from
getOrigin(), a token minted for another app
can never authenticate a user on yours, and there is no origin constant to keep
in step across environments.
Unauthorized is a plain Error subclass — map it to a 401 wherever you handle
route errors:
The manifest route
manifestRoute(app) returns the GET handler for
/.well-known/bankroll.jwt. You supply what is genuinely your app’s; it fills
in sub, aud, manifestVersion, and the capability shape.
Each is a function rather than a value because it is evaluated per request:
payments can start returning an address the moment a treasury key is set,
without a redeploy. Entries whose name or description is an empty string are
dropped rather than served, since one invalid entry would take the whole
manifest down with it.
See The manifest for what each claim means to the host, and
for building one on another stack.
The treasury
Your app’s one secret isBANKROLL_TREASURY_KEY, a base58 Solana secret key.
These read it, and are re-exported from @joinbankroll/sdk/server too:
treasuryAddress straight to manifestRoute’s payments.
An app runs fine with no treasury: it simply can’t take or send money, and says
so in its manifest. That is why the accessors answer “not configured” rather
than throwing, and only requireTreasury() — what a money path calls — fails.
pay() already defaults to this signer, so a payout needs nothing passed. Reach
for requireTreasury() when you need the signer itself — a custom instruction,
or minting an app token. See
Paying a user.