Vest: the relayed login binds itself to an unset Vest firm

A Vest firm's credential is the wallet of the login it trades. It no longer
has to be typed or clicked in: when the extension relays a Vest tab's
session and a Vest firm here has no credential, that wallet is saved as the
credential (lib/vest-wallet.ts), the client starts, and the backup is
pushed.

- A saved wallet is never replaced. When the tab is signed in to another
  login, the firm now says which one and how to switch: sign in as the
  saved wallet, or remove the credential.
- With two logins relayed at once nothing binds itself; the one-click form
  decides.
- Extension 0.17.1 re-posts the session every minute even when it hasn't
  changed. The dashboard holds it in memory only, so a restart there was
  unauthenticated until the tab's next renewal (up to ~15 min); now it is
  back within a minute, and a firm created later binds within a minute too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-26 14:42:01 -05:00
co-authored by Claude Opus 5.5
parent 96fdd9ca23
commit 769d96883f
8 changed files with 79 additions and 15 deletions
+7 -2
View File
@@ -1,5 +1,6 @@
import { NextRequest } from 'next/server';
import { putVestSession, listVestSessions } from '@/lib/vest-session';
import { autoBindVestWallet } from '@/lib/vest-wallet';
import { getTradableFirms } from '@/lib/firm-catalog';
import { getClients } from '@/lib/clients';
import { corsJson, corsPreflight } from '../../autobuyer/cors';
@@ -15,7 +16,10 @@ function wantedWallets(): string[] {
/**
* The extension's Vest relay (lib/vest-session.ts): POST the access token the
* signed-in Vest tab just renewed — { accessToken, expiresAt, primaryAddr,
* userId } — and it is held in memory for this machine's Vest client. GET
* userId } — and it is held in memory for this machine's Vest client. A Vest
* firm here with no credential yet is bound to that login's wallet
* (lib/vest-wallet.ts). The extension posts again every minute, so a restart
* here is back on the session within a minute. GET
* lists what has been relayed (never the tokens) and which wallets this
* machine wants, so the extension knows whether to keep a Vest tab open and
* the dashboard can offer the address as the firm's credential.
@@ -38,6 +42,7 @@ export async function POST(req: NextRequest) {
});
if (refused) return corsJson({ ok: false, reason: refused }, { status: 400 });
const bound = autoBindVestWallet();
const wanted = wantedWallets();
const addr = String(body.primaryAddr).toLowerCase();
// A client waiting on this wallet's session syncs now, not at its next poll.
@@ -45,7 +50,7 @@ export async function POST(req: NextRequest) {
const vest = client as { onVestSession?: (wallet: string) => void };
vest.onVestSession?.(addr);
}
return corsJson({ ok: true, used: wanted.includes(addr), wanted });
return corsJson({ ok: true, used: wanted.includes(addr), wanted, bound });
}
export async function GET() {