feat: bootstrap Supabase CLI auth with loopback signup#2
Conversation
WalkthroughAdds a TypeScript CLI for Listee with auth commands, a Supabase-based auth service and types, tests, project/tooling files (.env.example, package.json, tsconfig, biome), README and .gitignore updates, implementing signup via a temporary loopback callback, login, token refresh, status, logout, and keychain storage. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as "listee CLI"
participant AuthCmd as "auth command"
participant Loopback as "loopback server"
participant Browser
participant Service as "auth service"
participant Supabase
User->>CLI: listee auth signup
CLI->>AuthCmd: start signupAction
AuthCmd->>Service: ensureSupabaseConfig()
AuthCmd->>Loopback: start temporary server (/callback)
AuthCmd->>Browser: open signup URL
Browser->>Supabase: complete signup (form)
Supabase-->>Browser: redirect to loopback with fragment (#...)
Browser-->>Loopback: GET /callback#fragment
Loopback->>Service: completeSignupFromFragment(fragment)
Service->>Service: parse fragment → decode token → store refresh token
Service-->>Loopback: parsed result
Loopback-->>AuthCmd: success
AuthCmd-->>User: signup completed
sequenceDiagram
autonumber
actor User
participant CLI as "listee CLI"
participant AuthCmd as "auth command"
participant Service as "auth service"
participant Keychain
participant Supabase
User->>CLI: listee auth login --email
CLI->>AuthCmd: loginAction(email,password)
AuthCmd->>Service: login(email,password)
Service->>Supabase: POST /token (password grant)
Supabase-->>Service: access_token + refresh_token
Service->>Keychain: store refresh token
Service-->>AuthCmd: AccessTokenResult
AuthCmd-->>User: login success
User->>CLI: listee auth status
CLI->>Service: status()
Service->>Keychain: list stored accounts
Service-->>CLI: AuthStatus
CLI-->>User: status output
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tsconfig.json (1)
6-6: Consider whether DOM lib is needed for a CLI.The configuration includes
"DOM"in the lib array. For a CLI application, this is typically unnecessary unless dependencies require DOM types. Consider removing it if not needed.Apply this diff if DOM types are not required:
- "lib": ["ES2022", "DOM"], + "lib": ["ES2022"],src/types/auth.ts (1)
16-19: Consider clarifying the StoredCredential.password field.If the
passwordfield stores a refresh token (as suggested by the PR's keychain storage context), consider renaming it torefreshTokenorsecretfor clarity.If this field stores refresh tokens, apply this diff:
export type StoredCredential = { account: string; - password: string; + refreshToken: string; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
.env.example(1 hunks).gitignore(1 hunks)README.md(2 hunks)biome.json(1 hunks)package.json(1 hunks)src/commands/auth.ts(1 hunks)src/index.ts(1 hunks)src/services/auth-service.test.ts(1 hunks)src/services/auth-service.ts(1 hunks)src/types/auth.ts(1 hunks)tsconfig.json(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.ts : Extend Supabase JWT verification (createSupabaseAuthentication using .well-known/jwks.json) only via dedicated modules to keep caching and claim validation centralized
Applied to files:
src/services/auth-service.test.tssrc/services/auth-service.ts
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to {tsconfig.json,biome.json,vitest.config.ts,bun.lock} : Review cross-package impact before changing root tooling files: tsconfig.json, biome.json, vitest.config.ts, bun.lock
Applied to files:
biome.json
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.{ts,tsx} : Place runtime-specific authentication adapters under packages/auth/src/authentication/ (e.g., header.ts, supabase.ts, shared utilities, errors.ts)
Applied to files:
src/types/auth.ts
🧬 Code graph analysis (5)
src/index.ts (1)
src/commands/auth.ts (1)
registerAuthCommand(346-392)
src/services/auth-service.test.ts (2)
src/services/auth-service.ts (3)
ensureSupabaseConfig(112-115)AccessTokenResult(12-12)parseSignupFragment(259-262)src/types/auth.ts (1)
AccessTokenResult(21-25)
src/commands/auth.ts (2)
src/services/auth-service.ts (7)
SignupRedirect(12-12)status(405-417)completeSignupFromFragment(419-425)AuthStatus(12-12)ensureSupabaseConfig(112-115)signup(323-337)logout(401-403)src/types/auth.ts (4)
SignupRedirect(37-40)RawModeCapableInput(35-35)AuthStatus(27-29)EmailOption(31-33)
src/types/auth.ts (1)
src/services/auth-service.ts (3)
AccessTokenResult(12-12)AuthStatus(12-12)SignupRedirect(12-12)
src/services/auth-service.ts (1)
src/types/auth.ts (6)
SupabaseErrorPayload(8-14)SupabaseTokenResponse(1-6)StoredCredential(16-19)SignupRedirect(37-40)AccessTokenResult(21-25)AuthStatus(27-29)
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 2-2: [UnorderedKey] The SUPABASE_PUBLISHABLE_KEY key should go before the SUPABASE_URL key
(UnorderedKey)
🔇 Additional comments (12)
biome.json (1)
1-28: LGTM!The Biome configuration is well-structured for a new TypeScript CLI project. The formatter, linter, and import organization settings align with best practices.
package.json (2)
1-27: LGTM for overall package structure.The package configuration is well-organized with appropriate scripts for build, dev, lint, and test workflows. The binary entry point and module type settings are correct.
17-17: @napi-rs/keyring@^1.2.0 is published on npm. Version 1.2.0 exists; the dependency constraint is valid..gitignore (1)
1-20: LGTM!The .gitignore patterns appropriately cover environment files, build outputs, and common artifacts for a TypeScript CLI project.
tsconfig.json (1)
1-28: LGTM for TypeScript configuration.The tsconfig.json is well-configured with strict mode, modern module resolution, and appropriate compiler options for a Node.js CLI project.
src/types/auth.ts (1)
1-40: LGTM for type definitions.The authentication types are well-structured with appropriate discriminated unions and type composition. They provide a solid foundation for the auth service.
.env.example (1)
1-3: LGTM!The environment template clearly documents the required Supabase configuration variables for the authentication service.
README.md (2)
37-37: LGTM!The documentation clearly explains the loopback callback flow for the signup command, helping users understand that they need to keep the CLI running while confirming their email.
52-52: LGTM on filename alignment.The service filename change from
authService.tstoauth-service.tsaligns with kebab-case naming conventions.src/index.ts (3)
1-1: LGTM on environment loading.Loading dotenv via
import "dotenv/config"at the top of the entry point ensures environment variables are available before any other code executes.Based on learnings
16-27: LGTM on error handling.The error handling pattern correctly catches errors, logs them, and sets the exit code without throwing, which is appropriate for a CLI application.
1-29: LGTM for CLI entry point structure.The entry point follows best practices: early environment loading, structured command registration, and robust error handling with graceful exit.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/commands/auth.ts (3)
86-96: DirectinnerHTMLassignment is a code smell.Line 93 assigns the server response directly to
document.body.innerHTML. While safe in this specific context (the server controls the response viasuccessPage()), this pattern could introduce XSS vulnerabilities if copied to other contexts where the response source is less trusted.Consider using safer DOM manipulation (e.g.,
textContentfor messages) to establish a more defensible pattern, or add a comment explaining whyinnerHTMLis safe here to prevent cargo-culting.
170-176: Timeout doesn't await server close.Line 175 calls
server.close()with thevoidoperator, meaning the timeout callback doesn't wait for the server to finish closing. While acceptable since the signup has failed and the process will likely exit soon, this could leave the port briefly occupied if cleanup is delayed.If you want more deterministic cleanup, await the close:
const timeout = setTimeout(() => { if (!settled) { settled = true; rejectResult?.(new Error("Signup confirmation timed out.")); } - void server.close(); + void (async () => { + await new Promise<void>((resolve) => server.close(() => resolve())); + })(); }, LOOPBACK_TIMEOUT_MS);
309-309: Unused_tokenvariable could be removed.The
_tokenresult fromlogin()is assigned but never used (underscore prefix indicates intentional). If the token is automatically stored in the keychain by theloginservice and doesn't need to be returned, consider removing the assignment entirely for clarity.Apply this diff to remove the unused variable:
- const _token = await login(email, password); + await login(email, password); console.log("✅ Logged in.");
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/commands/auth.ts(1 hunks)
🔇 Additional comments (5)
src/commands/auth.ts (5)
21-27: LGTM!The
ensureNonEmptyhelper is appropriate for validating and normalizing email addresses. The previous issue regarding password trimming has been correctly addressed—passwords no longer use this function and preserve whitespace as required.
118-121: Request body accumulation without size limit.The POST handler accumulates request data without enforcing a size limit, which could theoretically allow a malicious local process to exhaust memory. However, since this server only binds to
127.0.0.1(line 161) and runs briefly during signup, the risk is minimal and the simplicity trade-off is reasonable.If you want to add defense-in-depth, consider enforcing a modest body size limit (e.g., 10 KB) and rejecting oversized payloads with a 413 status.
202-211: Past issue correctly resolved: passwords preserve whitespace.The previous concern about password trimming has been properly addressed. The code now validates emptiness without mutating the input (line 205) and resolves with the original
answer(line 209), preserving any leading or trailing whitespace as required by Supabase.
238-247: Past issue correctly resolved: raw-mode path also preserves whitespace.This section also correctly addresses the previous password trimming concern. The password is validated for emptiness without mutation (line 242) and resolved with the original collected value (line 246), preserving whitespace in the TTY/raw-mode path as well.
313-339: LGTM! Robust signup flow with proper cleanup.The signup action demonstrates good practices:
- Signal handlers registered with
process.once()prevent duplicate handler invocationfinallyblock ensures server shutdown even on errors (line 337)- Signal handlers are properly removed after use (lines 335-336)
- The loopback server lifecycle is well-managed with timeout protection
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/commands/auth.ts(1 hunks)src/services/auth-service.ts(1 hunks)src/types/auth.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.{ts,tsx} : Place runtime-specific authentication adapters under packages/auth/src/authentication/ (e.g., header.ts, supabase.ts, shared utilities, errors.ts)
Applied to files:
src/types/auth.tssrc/services/auth-service.ts
📚 Learning: 2025-10-02T12:40:33.718Z
Learnt from: CR
PR: listee-dev/listee-libs#0
File: AGENTS.md:0-0
Timestamp: 2025-10-02T12:40:33.718Z
Learning: Applies to packages/auth/src/authentication/**/*.ts : Extend Supabase JWT verification (createSupabaseAuthentication using .well-known/jwks.json) only via dedicated modules to keep caching and claim validation centralized
Applied to files:
src/types/auth.tssrc/services/auth-service.ts
🧬 Code graph analysis (2)
src/commands/auth.ts (2)
src/services/auth-service.ts (8)
SignupRedirect(12-12)status(405-417)completeSignupFromFragment(419-425)AuthStatus(12-12)ensureSupabaseConfig(112-115)login(339-364)signup(323-337)logout(401-403)src/types/auth.ts (4)
SignupRedirect(37-40)RawModeCapableInput(35-35)AuthStatus(27-29)EmailOption(31-33)
src/services/auth-service.ts (1)
src/types/auth.ts (6)
SupabaseErrorPayload(8-14)SupabaseTokenResponse(1-6)StoredCredential(16-19)SignupRedirect(37-40)AccessTokenResult(21-25)AuthStatus(27-29)
Testing
Summary by CodeRabbit
New Features
Documentation
Tests
Chores