From 34fb47f9a385c302570406fe9bf8e811dcb8b15e Mon Sep 17 00:00:00 2001 From: crowlbot <280062030+crowlbot@users.noreply.github.com> Date: Tue, 2 Jun 2026 02:25:04 +0000 Subject: [PATCH] feat(whoami): consume account.me to populate user identity The deployng `account.me` tRPC procedure has landed, so `deno deploy whoami` can now identify the principal behind the token rather than just listing reachable orgs. - Calls `account.me` in parallel with `orgs.list` (no extra round trip). - JSON output: `user` field is now populated for user-backed tokens (`{ id, name, email, avatarUrl, githubLogin }`) and `null` for org-scoped (`ddo_`) tokens. A new `tokenType` field carries the raw token type from the backend in both cases. - Human output: the "Authenticated" line now names the principal (`@github-login`, falling back to email/name/id, or `org-scoped token (...)` for non-user tokens). Existing agent consumers reading `authenticated` and `orgs[]` keep working; only added fields. --- deploy/mod.ts | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/deploy/mod.ts b/deploy/mod.ts index a409722..27eaf6e 100644 --- a/deploy/mod.ts +++ b/deploy/mod.ts @@ -246,6 +246,17 @@ interface WhoamiOrg { plan: string | null; } +interface AccountMe { + user: { + id: string; + name: string | null; + email: string | null; + avatarUrl: string | null; + githubLogin: string | null; + } | null; + tokenType: string; +} + const whoamiCommand = new Command() .description( "Verify the current Deno Deploy token and list reachable organizations", @@ -260,16 +271,16 @@ const whoamiCommand = new Command() // AUTH_INVALID_TOKEN envelope from the errorLink if the token is bad, // without ever calling `requireInteractive()` or opening a browser. const trpcClient = createTrpcClient(options); - const orgs = await trpcClient.query("orgs.list") as WhoamiOrg[]; + const [me, orgs] = await Promise.all([ + trpcClient.query("account.me") as Promise, + trpcClient.query("orgs.list") as Promise, + ]); if (options.json) { writeJsonResult({ authenticated: true, - // The deployng tRPC router does not currently expose user identity, - // so we surface what we can (orgs the token can reach). When that - // procedure lands, this output will gain a `user` field; existing - // consumers reading `authenticated` / `orgs[]` keep working. - user: null, + user: me.user, + tokenType: me.tokenType, orgs: orgs.map((org) => ({ id: org.id, slug: org.slug, @@ -280,8 +291,15 @@ const whoamiCommand = new Command() return; } + const who = me.user + ? (me.user.githubLogin + ? `@${me.user.githubLogin}` + : me.user.email ?? me.user.name ?? me.user.id) + : `org-scoped token (${me.tokenType})`; console.log( - `${green("✔")} Authenticated. ${orgs.length} reachable organization${ + `${ + green("✔") + } Authenticated as ${who}. ${orgs.length} reachable organization${ orgs.length === 1 ? "" : "s" }:`, );