Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/slick-lands-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vercel/sandbox": patch
Comment thread
gr2m marked this conversation as resolved.
---

Smarter fallback team selection for scope inference: tries `defaultTeamId` first, then the best hobby-plan OWNER team (personal team or most recently updated). Filters fallback candidates by `billing.plan === 'hobby'` to avoid selecting pro/enterprise teams. Skips teams that return 403 and shows a helpful error when no team allows sandbox creation.
31 changes: 30 additions & 1 deletion packages/sandbox/src/commands/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { output } from "../util/output";
import { default as open } from "open";
import ora from "ora";
import { acquireRelease } from "../util/disposables";
import { OAuth, pollForToken } from "@vercel/sandbox/dist/auth/index.js";
import {
OAuth,
pollForToken,
getAuth,
inferScope,
} from "@vercel/sandbox/dist/auth/index.js";
import createDebugger from "debug";

const debug = createDebugger("sandbox:login");
Expand Down Expand Up @@ -108,6 +113,30 @@ export const login = cmd.command({
spinner.succeed(
`${chalk.cyan("Congratulations!")} You are now signed in.`,
);

const auth = getAuth();
if (auth?.token) {
try {
const { teamId, teamSlug, projectId, projectSlug } =
await inferScope({
token: auth.token,
});
process.stderr.write(
chalk.dim(" │ ") +
"team: " +
chalk.cyan(teamSlug ?? teamId) +
"\n",
);
process.stderr.write(
chalk.dim(" ╰ ") +
"project: " +
chalk.cyan(projectSlug ?? projectId) +
"\n",
);
} catch {
// Scope inference is best-effort; don't fail the login
}
}
}
},
});
7 changes: 3 additions & 4 deletions packages/sandbox/src/util/infer-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,14 @@ async function inferFromJwt(jwt: string) {
}

async function inferFromToken(token: string, requestedTeam?: string) {
const { teamId, projectId } = await Auth.inferScope({
const { teamId, teamSlug, projectId, projectSlug } = await Auth.inferScope({
token,
teamId: requestedTeam,
});
// Auth.inferScope returns team slug and project name (not IDs).
return {
owner: teamId,
project: projectId,
ownerSlug: teamId,
projectSlug: projectId,
ownerSlug: teamSlug ?? teamId,
projectSlug: projectSlug ?? projectId,
};
}
2 changes: 1 addition & 1 deletion packages/vercel-sandbox/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ export type * from "./file.js";
export * from "./oauth.js";
export type * from "./oauth.js";
export { pollForToken } from "./poll-for-token.js";
export { inferScope, selectTeam } from "./project.js";
export { inferScope } from "./project.js";
Loading
Loading