Skip to content

feat: bootstrap Supabase CLI auth with loopback signup#2

Merged
gentamura merged 8 commits intomainfrom
feat/auth-mvp
Oct 7, 2025
Merged

feat: bootstrap Supabase CLI auth with loopback signup#2
gentamura merged 8 commits intomainfrom
feat/auth-mvp

Conversation

@gentamura
Copy link
Member

@gentamura gentamura commented Oct 7, 2025

  • Replaced the manual confirmation flow with a loopback-based signup that starts a temporary local HTTP server, listens for Supabase’s redirect, and stores the refresh token automatically.
  • Added robust parsing/validation helpers for Supabase fragments and JWT payloads, along with new shared types and unit tests covering the fragment parsing path.
  • Updated README instructions to explain the new signup behavior and improved the confirmation HTML so users see that the window belongs to the Listee CLI.

Testing

  • bun run build
  • bun test

  • chore: initialize npm tooling
  • feat: add supabase auth commands
  • build: switch to bun tooling
  • test: cover supabase config validation
  • refactor: use kebab-case filenames
  • feat(auth): complete signup via loopback

Summary by CodeRabbit

  • New Features

    • CLI added with auth commands: signup, login, status, logout; loopback signup flow with automatic completion and secure token storage.
  • Documentation

    • Expanded signup instructions and updated project layout references.
  • Tests

    • Added tests for authentication config validation and signup fragment parsing.
  • Chores

    • Added project manifest and TypeScript/tooling configs, environment variable template, and streamlined ignore patterns.

@coderabbitai
Copy link

coderabbitai bot commented Oct 7, 2025

Walkthrough

Adds 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

Cohort / File(s) Summary
Project tooling & config
package.json, tsconfig.json, biome.json, .gitignore, .env.example
Adds Node/TypeScript project manifest and scripts, TypeScript compiler config, Biome tooling config, updated .gitignore with environment-focused rules, and .env.example entries for SUPABASE_URL and SUPABASE_PUBLISHABLE_KEY (plus commented LISTEE_CLI_KEYCHAIN_SERVICE).
Documentation
README.md
Updates README to document listee auth signup loopback callback flow and updates service filename reference to services/auth-service.ts.
CLI entry & commands
src/index.ts, src/commands/auth.ts
New CLI entrypoint and auth command with subcommands signup, login, status, logout; includes loopback signup flow, password prompt, centralized error handling, and command registration.
Auth service & types
src/services/auth-service.ts, src/types/auth.ts
New Supabase-based auth service implementing env validation, signup/login/token refresh/logout/status, fragment parsing/completion, keychain credential storage, and exported types (e.g., SupabaseTokenResponse, StoredCredential, AccessTokenResult, AuthStatus, SignupRedirect, etc.).
Tests
src/services/auth-service.test.ts
Adds tests for ensureSupabaseConfig behaviors and parseSignupFragment parsing including legacy anon key fallback and token-parsing simulations.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I thump my paw, deploy with glee,
A burrow-born CLI — hello, Listee!
Loopback doors and tokens hop,
Keychain keeps each secret stop.
Docs updated, tests in tow — 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly summarizes the addition of a loopback-based signup flow for the Supabase CLI authentication feature, focusing on the main change introduced in this PR.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/auth-mvp

Comment @coderabbitai help to get the list of available commands and usage tips.

@gentamura gentamura changed the title feat/auth mvp feat: bootstrap Supabase CLI auth with loopback signup Oct 7, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 password field stores a refresh token (as suggested by the PR's keychain storage context), consider renaming it to refreshToken or secret for 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

📥 Commits

Reviewing files that changed from the base of the PR and between f3301b9 and b70a3cb.

⛔ Files ignored due to path filters (1)
  • bun.lock is 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.ts
  • src/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.ts to auth-service.ts aligns 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/commands/auth.ts (3)

86-96: Direct innerHTML assignment 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 via successPage()), 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., textContent for messages) to establish a more defensible pattern, or add a comment explaining why innerHTML is safe here to prevent cargo-culting.


170-176: Timeout doesn't await server close.

Line 175 calls server.close() with the void operator, 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 _token variable could be removed.

The _token result from login() is assigned but never used (underscore prefix indicates intentional). If the token is automatically stored in the keychain by the login service 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

📥 Commits

Reviewing files that changed from the base of the PR and between b70a3cb and c70db1e.

📒 Files selected for processing (1)
  • src/commands/auth.ts (1 hunks)
🔇 Additional comments (5)
src/commands/auth.ts (5)

21-27: LGTM!

The ensureNonEmpty helper 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 invocation
  • finally block 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

@gentamura gentamura self-assigned this Oct 7, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c70db1e and b72c369.

📒 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.ts
  • src/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.ts
  • src/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)

@gentamura gentamura merged commit 633f990 into main Oct 7, 2025
1 check passed
@gentamura gentamura deleted the feat/auth-mvp branch October 7, 2025 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant