feat: delegate keyless mode to SDK, autoclaim on authenticated init#267
feat: delegate keyless mode to SDK, autoclaim on authenticated init#267rafa-thayto wants to merge 1 commit intomainfrom
Conversation
…crumb on init clerk init no longer calls createAccountlessApp() for unauthenticated users — the SDK handles keyless mode natively at runtime. When an authenticated user re-runs clerk init (without --app), the CLI reads the SDK's breadcrumb at .clerk/.tmp/keyless.json, claims the temporary app, links it, and pulls real keys — eliminating the need for a separate clerk auth login step.
|
📝 WalkthroughWalkthroughThis PR extends the Clerk CLI's keyless authentication flow to support breadcrumbs created by the Clerk SDK at Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli-core/src/commands/init/index.ts`:
- Around line 104-116: tryInitAutoclaim currently returns a result object but
the code treats any status === "claimed" as fully done; change the flow to
inspect the full result from tryInitAutoclaim/attemptAutoclaim and only skip
authenticateAndLink()/pull() when result.status === "claimed" AND
result.envPulled === true (set autoclaimPulled = true only in that case); if
envPulled is false (or missing) treat it as not fully claimed and proceed to
call authenticateAndLink(ctx.cwd, ...) and later pull() so local linking/envs
are completed; apply the same adjustment to the other tryInitAutoclaim usage
sites (the other blocks that currently set autoclaimPulled on any "claimed"
result).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5138e676-8dc0-4ef2-a35a-51c16ece8551
📒 Files selected for processing (8)
packages/cli-core/src/commands/auth/README.mdpackages/cli-core/src/commands/init/README.mdpackages/cli-core/src/commands/init/index.test.tspackages/cli-core/src/commands/init/index.tspackages/cli-core/src/lib/autoclaim.test.tspackages/cli-core/src/lib/autoclaim.tspackages/cli-core/src/lib/keyless.test.tspackages/cli-core/src/lib/keyless.ts
| let autoclaimPulled = false; | ||
| if (!keyless && !manualSetup) { | ||
| bar(); | ||
| const createIfMissing = agent | ||
| ? await deriveProjectName(ctx.cwd, bootstrap?.projectName) | ||
| : undefined; | ||
| await authenticateAndLink(ctx.cwd, options.app, createIfMissing); | ||
|
|
||
| const claimed = !options.app && authed && (await tryInitAutoclaim(ctx.cwd)); | ||
| if (!claimed) { | ||
| const createIfMissing = agent | ||
| ? await deriveProjectName(ctx.cwd, bootstrap?.projectName) | ||
| : undefined; | ||
| await authenticateAndLink(ctx.cwd, options.app, createIfMissing); | ||
| } else { | ||
| autoclaimPulled = true; | ||
| } |
There was a problem hiding this comment.
Handle partial autoclaim success before skipping normal link/env pull
tryInitAutoclaim treats every status: "claimed" as fully complete, but attemptAutoclaim can return { status: "claimed", envPulled: false } when local linking or env pull failed. The current flow then skips both authenticateAndLink() and the later pull(), which can leave the project not fully configured.
Suggested fix
- let autoclaimPulled = false;
+ let autoclaimPulled = false;
if (!keyless && !manualSetup) {
bar();
- const claimed = !options.app && authed && (await tryInitAutoclaim(ctx.cwd));
- if (!claimed) {
+ const autoclaim = !options.app && authed ? await tryInitAutoclaim(ctx.cwd) : { claimed: false, envPulled: false };
+ autoclaimPulled = autoclaim.envPulled;
+ if (!autoclaim.claimed || !autoclaim.envPulled) {
const createIfMissing = agent
? await deriveProjectName(ctx.cwd, bootstrap?.projectName)
: undefined;
await authenticateAndLink(ctx.cwd, options.app, createIfMissing);
- } else {
- autoclaimPulled = true;
}
}-async function tryInitAutoclaim(cwd: string): Promise<boolean> {
+async function tryInitAutoclaim(
+ cwd: string,
+): Promise<{ claimed: boolean; envPulled: boolean }> {
const result = await attemptAutoclaim(cwd);
if (result.status === "claimed") {
const label = result.app.name || result.app.application_id;
- log.success(`Claimed and linked \`${label}\``);
- return true;
+ if (result.envPulled) {
+ log.success(`Claimed and linked \`${label}\``);
+ } else {
+ log.warn(`Claimed \`${label}\`, but local setup was incomplete; continuing setup.`);
+ }
+ return { claimed: true, envPulled: result.envPulled };
}
if (result.status !== "not_keyless") {
log.debug(`init: autoclaim returned '${result.status}', falling through to link`);
}
- return false;
+ return { claimed: false, envPulled: false };
}Also applies to: 138-139, 322-333
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli-core/src/commands/init/index.ts` around lines 104 - 116,
tryInitAutoclaim currently returns a result object but the code treats any
status === "claimed" as fully done; change the flow to inspect the full result
from tryInitAutoclaim/attemptAutoclaim and only skip
authenticateAndLink()/pull() when result.status === "claimed" AND
result.envPulled === true (set autoclaimPulled = true only in that case); if
envPulled is false (or missing) treat it as not fully claimed and proceed to
call authenticateAndLink(ctx.cwd, ...) and later pull() so local linking/envs
are completed; apply the same adjustment to the other tryInitAutoclaim usage
sites (the other blocks that currently set autoclaimPulled on any "claimed"
result).
Summary
Stop writing keys during keyless bootstrap:
clerk initfor unauthenticated users no longer callscreateAccountlessApp()or writes temporary keys to.env.local. The@clerk/nextjsSDK handles keyless mode natively at runtime — when no keys are present, the SDK creates an accountless app and shows a "Configure your application" widget.Read SDK breadcrumbs: The CLI now reads the SDK's keyless breadcrumb at
.clerk/.tmp/keyless.json(in addition to the legacy CLI breadcrumb at.clerk/keyless.json). A unifiedreadAnyKeylessBreadcrumb()reader tries the SDK path first and normalizes both formats to{ claimToken, source }.Autoclaim during
clerk init: When an authenticated user runsclerk initwithout--app, the CLI checks for an SDK keyless breadcrumb before falling through toauthenticateAndLink. If found, it claims the temporary app, links it, and pulls real keys — all in one step.Test plan
bun run typecheckpassesbun run lintpassesbun run format:checkpassesbun test packages/cli-core/src/lib/keyless.test.ts— 28 tests pass (17 new SDK breadcrumb + unified reader tests)bun test packages/cli-core/src/lib/autoclaim.test.ts— 11 tests pass (updated for dual breadcrumb clearing)bun test packages/cli-core/src/commands/init/index.test.ts— 46 tests pass (5 new autoclaim-in-init tests)clerk init --starter --framework next --yesunauthenticated → app scaffolds without keys → run the app → SDK enters keyless mode and writes.clerk/.tmp/keyless.json→ authenticate withclerk auth login→ re-runclerk init→ autoclaim kicks in, real keys are pulled