Remove dashboard#25
Conversation
The @betterbase/dashboard workspace has been removed along with all its dependencies including @radix-ui components, @tanstack/react-query, recharts, and tailwindcss. Additionally, login command scaffolding has been added to the CLI (commented out, awaiting app.betterbase.com).
Removes all dashboard-related documentation from CODEBASE_MAP.md and README.md to reflect the dashboard package removal from the monorepo. Simplifies architecture diagrams and removes the apps/dashboard section entirely.
📝 WalkthroughWalkthroughThis PR reorganizes the public API across CLI, Client SDK, Core, Templates and Providers, renaming and relocating many exported modules and command entry points. It also adds backend auth (device-code/browser login), API-key middleware, request-logging, a meta API, and supporting DB schema and CLI credential persistence. Changes
Sequence Diagram(s)sequenceDiagram
participant User as CLI User
participant CLI as bb CLI
participant Auth as Auth Server
participant Browser as Browser
participant FS as Local Filesystem
User->>CLI: runLoginCommand()
CLI->>Auth: POST /auth/device-code (request device code)
Auth-->>CLI: { deviceCode, userCode, verificationUrl, interval }
CLI->>Browser: open(verificationUrl?user_code=...)
CLI->>CLI: pollToken(deviceCode, interval...)
Browser->>Auth: User authenticates & approves (via verification URL)
Auth-->>Auth: bind token to deviceCode
CLI->>Auth: POST /auth/token (poll with deviceCode)
Auth-->>CLI: { accessToken, refreshToken, user, expiresAt }
CLI->>FS: save ~/.betterbase/credentials.json
CLI-->>User: print success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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: 8
🧹 Nitpick comments (1)
packages/cli/src/index.ts (1)
12-12: Prefer feature-flagged wiring over commented command blocks.Line 12 and Lines 309-321 keep login/logout integration as comments. This path is not type-checked and tends to drift from the actual command implementation. Prefer either:
- wiring behind a runtime feature flag, or
- removing the commented block and tracking activation in a dedicated issue/doc.
Also applies to: 309-322
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/index.ts` at line 12, The commented-out login/logout imports and wiring (runLoginCommand, runLogoutCommand) should be replaced with feature-flagged registration instead of leaving commented code: add a runtime flag (e.g., ENABLE_LOGIN_COMMAND env/config) and conditionally import or call runLoginCommand and runLogoutCommand where commands are wired (the command registration section in packages/cli/src/index.ts), so TypeScript checks those symbols and keeps them in sync; alternatively, if you don't want runtime gating, delete the commented lines and create a tracking issue/doc referenced in the repo. Ensure the conditional path uses dynamic import or gated calls so type-checking and build step still validate the functions when the flag is enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@betterbase_backend_rebuild.md`:
- Around line 378-379: The doc is inconsistent: the key format is declared as
`bb_<type>_<projectId>` but the examples/generation use
`bb_<type>_<projectId>_<random>`; update the documentation so both match by
choosing one canonical format and applying it everywhere — either change the
format definition to `bb_<type>_<projectId>_<random>` (and explain the
purpose/length/character set of `<random>`) or remove the `<random>` suffix from
the generation examples (lines showing `bb_<type>_<projectId>_<random>`) so they
conform to `bb_<type>_<projectId>`, and ensure the same decision is applied to
the other occurrences mentioned (lines ~407-409).
- Around line 1-4: The document header conflicts with the PR objective: update
the top section (the title and first 4 lines) so the scope and intent match the
PR "Remove dashboard" rather than "Dashboard Readiness"; specifically replace or
rewrite the title, priority line, and purpose/Who-this-is-for lines to state
that this is for removing the dashboard, clarify that the listed backend changes
are for decommissioning or decoupling dashboard features, and remove any
ordering/instruction claims that imply rebuilding the dashboard to avoid
implementation ambiguity.
- Around line 801-809: The route handler metaRoute.delete("/users/:userId")
currently only deletes from authUser and does not remove related sessions;
update the handler to also delete session rows tied to the user (e.g., delete
from the sessions table where sessions.user_id or sessions.userId equals userId)
before/within the same transaction as the authUser deletion, or explicitly rely
on and document a DB cascade; ensure you reference the authUser deletion and the
sessions deletion together (or wrap both operations in a single transaction) so
the endpoint truly removes both the user and their sessions.
- Around line 818-829: The parsed filters method, statusMin, and statusMax are
parsed but never applied to the DB queries; update the query building for logs
(the
db.select().from(betterbaseLogs).orderBy(desc(betterbaseLogs.createdAt)).limit(limit).offset(offset)
call) to conditionally add .where(...) clauses: add a
where(betterbaseLogs.method, '=', method) if method is present, add
where(betterbaseLogs.status, '>=', statusMin) if statusMin is defined, and add
where(betterbaseLogs.status, '<=', statusMax) if statusMax is defined; apply the
same conditional filters to the total count query (db.select({ count: count()
}).from(betterbaseLogs).get()) so the total reflects the filtered set.
In `@CODEBASE_MAP.md`:
- Line 40: Two markdown lint rules are failing: the fenced code blocks
(currently ``` at the block starting around the first large code fence and the
one near the repeated section) need explicit language identifiers to satisfy
MD040, and the table near the bottom of the document needs proper blank-line
spacing to satisfy MD058; update the two fenced code blocks (the opening
backticks at the top-level code block and the similar fenced block around line
879) to include the appropriate language tag (e.g., ```json, ```bash, or
```text) and insert a single blank line before and after the Markdown table
around the region flagged for MD058 so the table is separated from surrounding
text, then re-run markdownlint to confirm MD040 and MD058 are resolved.
- Around line 220-223: The CLI map entries in CODEBASE_MAP.md are out of sync
with the actual registered commands; inspect the CLI registration in index.ts to
get the canonical command names and signatures (e.g., the registered handlers
for "bb rls", "bb storage", "bb webhook" and the staged login), then update the
CODEBASE_MAP.md entries (including the documented usage lines and the entry for
runLoginCommand) to match the real command wiring and exported function names;
remove or mark as staged any commands not currently registered and ensure
usages/signatures exactly match what index.ts registers so the map and CLI
remain consistent.
In `@packages/cli/src/commands/login.ts`:
- Around line 14-169: The file currently has the full auth implementation
commented out which removes exports for runLoginCommand, runLogoutCommand,
getCredentials, and requireCredentials; add minimal explicit stub
implementations for these functions (exported) so the module compiles and other
code paths can call them: create simple async stubs for runLoginCommand and
runLogoutCommand that log a clear "not yet available" or throw a specific
NotImplemented error, implement getCredentials to return null and
requireCredentials to call getCredentials then log the same message and exit or
throw; ensure the exported Credentials type/signature is preserved and the stub
functions use the same names (runLoginCommand, runLogoutCommand, getCredentials,
requireCredentials) so switching back to the real implementation is trivial.
In `@README.md`:
- Around line 193-196: The README CLI examples (LoginCmd, RLSCmd, StorageCmd,
WebhookCmd and the dev --generate example) do not match the actual command
registrations in packages/cli/src/index.ts, causing copy/paste failures; sync
them by either updating README examples to use the exact subcommand names and
flags implemented in packages/cli/src/index.ts or by re-introducing the missing
commands into the CLI; inspect the command registration code in
packages/cli/src/index.ts (look for where commands are registered/defined) and
ensure README entries for login, rls, storage, webhook and the dev --generate
usage reflect the exact command names, options, and invocation patterns present
in that file.
---
Nitpick comments:
In `@packages/cli/src/index.ts`:
- Line 12: The commented-out login/logout imports and wiring (runLoginCommand,
runLogoutCommand) should be replaced with feature-flagged registration instead
of leaving commented code: add a runtime flag (e.g., ENABLE_LOGIN_COMMAND
env/config) and conditionally import or call runLoginCommand and
runLogoutCommand where commands are wired (the command registration section in
packages/cli/src/index.ts), so TypeScript checks those symbols and keeps them in
sync; alternatively, if you don't want runtime gating, delete the commented
lines and create a tracking issue/doc referenced in the repo. Ensure the
conditional path uses dynamic import or gated calls so type-checking and build
step still validate the functions when the flag is enabled.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
CODEBASE_MAP.mdREADME.mdbetterbase_backend_rebuild.mdpackages/cli/src/commands/login.tspackages/cli/src/index.ts
| # BetterBase — Backend Rebuild for Dashboard Readiness | ||
| > **Priority:** CRITICAL. Complete this entire document before touching the BetterBaseDashboard repo. | ||
| > **Why:** The dashboard cannot display real data without these backend changes. Every section in this document is a prerequisite for a specific dashboard feature. | ||
| > **Who this is for:** An LLM agent (Cursor, Codex) that will implement these changes. Read the entire document before writing a single line of code. The order of implementation matters. |
There was a problem hiding this comment.
Document scope conflicts with the PR objective.
Lines 1-4 frame this work as “dashboard readiness,” but the PR objective is “Remove dashboard.” This creates implementation ambiguity and should be reconciled before further work proceeds.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase_backend_rebuild.md` around lines 1 - 4, The document header
conflicts with the PR objective: update the top section (the title and first 4
lines) so the scope and intent match the PR "Remove dashboard" rather than
"Dashboard Readiness"; specifically replace or rewrite the title, priority line,
and purpose/Who-this-is-for lines to state that this is for removing the
dashboard, clarify that the listed backend changes are for decommissioning or
decoupling dashboard features, and remove any ordering/instruction claims that
imply rebuilding the dashboard to avoid implementation ambiguity.
| Structure: `bb_<type>_<projectId>` | ||
|
|
There was a problem hiding this comment.
Key format definition conflicts with the generation example.
Line 378 defines bb_<type>_<projectId>, but Lines 407-408 generate bb_<type>_<projectId>_<random>. Implementers following the declared format will reject generated keys.
🛠️ Proposed doc fix
-Structure: `bb_<type>_<projectId>`
+Structure: `bb_<type>_<projectId>_<random>`Also applies to: 407-409
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase_backend_rebuild.md` around lines 378 - 379, The doc is
inconsistent: the key format is declared as `bb_<type>_<projectId>` but the
examples/generation use `bb_<type>_<projectId>_<random>`; update the
documentation so both match by choosing one canonical format and applying it
everywhere — either change the format definition to
`bb_<type>_<projectId>_<random>` (and explain the purpose/length/character set
of `<random>`) or remove the `<random>` suffix from the generation examples
(lines showing `bb_<type>_<projectId>_<random>`) so they conform to
`bb_<type>_<projectId>`, and ensure the same decision is applied to the other
occurrences mentioned (lines ~407-409).
| // ── DELETE /api/meta/users/:userId ─────────────────────────────────────────── | ||
| // Deletes a user and their sessions | ||
|
|
||
| metaRoute.delete("/users/:userId", async (c) => { | ||
| const userId = c.req.param("userId") | ||
|
|
||
| await db.delete(authUser).where(eq(authUser.id, userId)) | ||
|
|
||
| return c.json({ data: { deleted: true }, error: null }) |
There was a problem hiding this comment.
User deletion snippet does not match its stated behavior.
Line 802 says user and sessions are deleted, but Line 807 only deletes from authUser. This leaves session cleanup undefined unless cascade rules are guaranteed.
🛠️ Proposed snippet fix
metaRoute.delete("/users/:userId", async (c) => {
const userId = c.req.param("userId")
+ await db.delete(authSession).where(eq(authSession.userId, userId))
await db.delete(authUser).where(eq(authUser.id, userId))
return c.json({ data: { deleted: true }, error: null })
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // ── DELETE /api/meta/users/:userId ─────────────────────────────────────────── | |
| // Deletes a user and their sessions | |
| metaRoute.delete("/users/:userId", async (c) => { | |
| const userId = c.req.param("userId") | |
| await db.delete(authUser).where(eq(authUser.id, userId)) | |
| return c.json({ data: { deleted: true }, error: null }) | |
| // ── DELETE /api/meta/users/:userId ─────────────────────────────────────────── | |
| // Deletes a user and their sessions | |
| metaRoute.delete("/users/:userId", async (c) => { | |
| const userId = c.req.param("userId") | |
| await db.delete(authSession).where(eq(authSession.userId, userId)) | |
| await db.delete(authUser).where(eq(authUser.id, userId)) | |
| return c.json({ data: { deleted: true }, error: null }) | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase_backend_rebuild.md` around lines 801 - 809, The route handler
metaRoute.delete("/users/:userId") currently only deletes from authUser and does
not remove related sessions; update the handler to also delete session rows tied
to the user (e.g., delete from the sessions table where sessions.user_id or
sessions.userId equals userId) before/within the same transaction as the
authUser deletion, or explicitly rely on and document a DB cascade; ensure you
reference the authUser deletion and the sessions deletion together (or wrap both
operations in a single transaction) so the endpoint truly removes both the user
and their sessions.
| const method = c.req.query("method") | ||
| const statusMin = c.req.query("statusMin") ? parseInt(c.req.query("statusMin")!) : undefined | ||
| const statusMax = c.req.query("statusMax") ? parseInt(c.req.query("statusMax")!) : undefined | ||
|
|
||
| const logs = await db | ||
| .select() | ||
| .from(betterbaseLogs) | ||
| .orderBy(desc(betterbaseLogs.createdAt)) | ||
| .limit(limit) | ||
| .offset(offset) | ||
|
|
||
| const total = await db.select({ count: count() }).from(betterbaseLogs).get() |
There was a problem hiding this comment.
Parsed log filters are never applied in the query.
Lines 818-821 parse method, statusMin, and statusMax, but Lines 822-828 fetch all logs without filtering.
🛠️ Proposed snippet fix
+ const filters = []
+ if (method) filters.push(eq(betterbaseLogs.method, method))
+ if (statusMin !== undefined) filters.push(gte(betterbaseLogs.statusCode, statusMin))
+ if (statusMax !== undefined) filters.push(sql`${betterbaseLogs.statusCode} <= ${statusMax}`)
+
const logs = await db
.select()
.from(betterbaseLogs)
+ .where(filters.length ? and(...filters) : undefined)
.orderBy(desc(betterbaseLogs.createdAt))
.limit(limit)
.offset(offset)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const method = c.req.query("method") | |
| const statusMin = c.req.query("statusMin") ? parseInt(c.req.query("statusMin")!) : undefined | |
| const statusMax = c.req.query("statusMax") ? parseInt(c.req.query("statusMax")!) : undefined | |
| const logs = await db | |
| .select() | |
| .from(betterbaseLogs) | |
| .orderBy(desc(betterbaseLogs.createdAt)) | |
| .limit(limit) | |
| .offset(offset) | |
| const total = await db.select({ count: count() }).from(betterbaseLogs).get() | |
| const method = c.req.query("method") | |
| const statusMin = c.req.query("statusMin") ? parseInt(c.req.query("statusMin")!) : undefined | |
| const statusMax = c.req.query("statusMax") ? parseInt(c.req.query("statusMax")!) : undefined | |
| const filters = [] | |
| if (method) filters.push(eq(betterbaseLogs.method, method)) | |
| if (statusMin !== undefined) filters.push(gte(betterbaseLogs.statusCode, statusMin)) | |
| if (statusMax !== undefined) filters.push(sql`${betterbaseLogs.statusCode} <= ${statusMax}`) | |
| const logs = await db | |
| .select() | |
| .from(betterbaseLogs) | |
| .where(filters.length ? and(...filters) : undefined) | |
| .orderBy(desc(betterbaseLogs.createdAt)) | |
| .limit(limit) | |
| .offset(offset) | |
| const total = await db.select({ count: count() }).from(betterbaseLogs).get() |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@betterbase_backend_rebuild.md` around lines 818 - 829, The parsed filters
method, statusMin, and statusMax are parsed but never applied to the DB queries;
update the query building for logs (the
db.select().from(betterbaseLogs).orderBy(desc(betterbaseLogs.createdAt)).limit(limit).offset(offset)
call) to conditionally add .where(...) clauses: add a
where(betterbaseLogs.method, '=', method) if method is present, add
where(betterbaseLogs.status, '>=', statusMin) if statusMin is defined, and add
where(betterbaseLogs.status, '<=', statusMax) if statusMax is defined; apply the
same conditional filters to the total count query (db.select({ count: count()
}).from(betterbaseLogs).get()) so the total reflects the filtered set.
| Root --> Auth | ||
| ``` | ||
|
|
||
| ``` |
There was a problem hiding this comment.
Markdown lint warnings remain in changed sections.
Line 40 and Line 879 use fenced code blocks without language identifiers (MD040), and Line 899 violates blank-line spacing around tables (MD058).
Also applies to: 879-879, 899-899
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 40-40: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@CODEBASE_MAP.md` at line 40, Two markdown lint rules are failing: the fenced
code blocks (currently ``` at the block starting around the first large code
fence and the one near the repeated section) need explicit language identifiers
to satisfy MD040, and the table near the bottom of the document needs proper
blank-line spacing to satisfy MD058; update the two fenced code blocks (the
opening backticks at the top-level code block and the similar fenced block
around line 879) to include the appropriate language tag (e.g., ```json,
```bash, or ```text) and insert a single blank line before and after the
Markdown table around the region flagged for MD058 so the table is separated
from surrounding text, then re-run markdownlint to confirm MD040 and MD058 are
resolved.
| #### [`commands/login.ts`](packages/cli/src/commands/login.ts) | ||
| **Purpose:** `bb login` command - authenticate with BetterBase cloud. | ||
| - **Exports:** `runLoginCommand(options)` - main function | ||
| - **Internal Deps:** `../utils/logger` |
There was a problem hiding this comment.
CLI map is out of sync with the implemented CLI surface.
Line 222 and Lines 758-770 document command signatures/usages that don’t match current CLI wiring in packages/cli/src/index.ts (e.g., bb rls, bb storage, bb webhook, and staged bb login). Please align this map with actual registered commands to avoid command-not-found UX.
Also applies to: 758-770
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@CODEBASE_MAP.md` around lines 220 - 223, The CLI map entries in
CODEBASE_MAP.md are out of sync with the actual registered commands; inspect the
CLI registration in index.ts to get the canonical command names and signatures
(e.g., the registered handlers for "bb rls", "bb storage", "bb webhook" and the
staged login), then update the CODEBASE_MAP.md entries (including the documented
usage lines and the entry for runLoginCommand) to match the real command wiring
and exported function names; remove or mark as staged any commands not currently
registered and ensure usages/signatures exactly match what index.ts registers so
the map and CLI remain consistent.
| /* | ||
| // ── bb login — STAGED FOR ACTIVATION ──────────────────────────────────────── | ||
| // This code is complete and tested. Uncomment when app.betterbase.com is live. | ||
| // See: betterbase_backend_rebuild.md Part 3 | ||
| // ──────────────────────────────────────────────────────────────────────────── | ||
|
|
||
| const BETTERBASE_API = process.env.BETTERBASE_API_URL ?? "https://app.betterbase.com" | ||
| const CREDENTIALS_PATH = path.join(os.homedir(), ".betterbase", "credentials.json") | ||
| const POLL_INTERVAL_MS = 2000 | ||
| const POLL_TIMEOUT_MS = 300000 // 5 minutes | ||
|
|
||
| // runLoginCommand | ||
| // Authenticates the CLI with app.betterbase.com via browser OAuth flow. | ||
| export async function runLoginCommand(): Promise<void> { | ||
| // Check if already logged in | ||
| const existing = await getCredentials() | ||
| if (existing) { | ||
| info(`Already logged in as ${existing.email}`) | ||
| info("Run bb logout to sign out.") | ||
| return | ||
| } | ||
|
|
||
| // Generate a one-time device code | ||
| const code = generateDeviceCode() | ||
| const authUrl = `${BETTERBASE_API}/cli/auth?code=${code}` | ||
|
|
||
| info("Opening browser for authentication...") | ||
| info(`Auth URL: ${authUrl}`) | ||
| info("Waiting for authentication... (timeout: 5 minutes)") | ||
|
|
||
| // Try to open the browser | ||
| await openBrowser(authUrl) | ||
|
|
||
| // Poll for authentication | ||
| const credentials = await pollForAuth(code) | ||
|
|
||
| if (!credentials) { | ||
| logError("Authentication timed out. Run bb login to try again.") | ||
| process.exit(1) | ||
| } | ||
|
|
||
| // Store credentials | ||
| await saveCredentials(credentials) | ||
| success(`Logged in as ${credentials.email}`) | ||
| } | ||
|
|
||
| // runLogoutCommand | ||
| // Removes stored credentials. | ||
| export async function runLogoutCommand(): Promise<void> { | ||
| if (existsSync(CREDENTIALS_PATH)) { | ||
| await fs.unlink(CREDENTIALS_PATH) | ||
| success("Logged out successfully.") | ||
| } else { | ||
| warn("Not currently logged in.") | ||
| } | ||
| } | ||
|
|
||
| // getCredentials | ||
| // Reads stored credentials from ~/.betterbase/credentials.json | ||
| // Returns null if not logged in or credentials expired. | ||
| export async function getCredentials(): Promise<Credentials | null> { | ||
| if (!existsSync(CREDENTIALS_PATH)) return null | ||
| try { | ||
| const raw = await fs.readFile(CREDENTIALS_PATH, "utf-8") | ||
| const creds = JSON.parse(raw) as Credentials | ||
| if (new Date(creds.expiresAt) < new Date()) return null | ||
| return creds | ||
| } catch { | ||
| return null | ||
| } | ||
| } | ||
|
|
||
| // requireCredentials | ||
| // Used by commands that require authentication (like bb init in managed mode). | ||
| // Exits with a helpful message if not logged in. | ||
| export async function requireCredentials(): Promise<Credentials> { | ||
| const creds = await getCredentials() | ||
| if (!creds) { | ||
| logError( | ||
| "Not logged in. Run: bb login\n" + | ||
| "This connects your CLI with app.betterbase.com so your project\n" + | ||
| "can be registered and managed from the dashboard." | ||
| ) | ||
| process.exit(1) | ||
| } | ||
| return creds | ||
| } | ||
|
|
||
| // Internal helpers | ||
|
|
||
| function generateDeviceCode(): string { | ||
| const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" | ||
| const part1 = Array.from({ length: 4 }, () => chars[Math.floor(Math.random() * chars.length)]).join("") | ||
| const part2 = Array.from({ length: 4 }, () => chars[Math.floor(Math.random() * chars.length)]).join("") | ||
| return `${part1}-${part2}` | ||
| } | ||
|
|
||
| async function openBrowser(url: string): Promise<void> { | ||
| const { platform } = process | ||
| try { | ||
| if (platform === "darwin") { | ||
| const { execSync } = await import("child_process") | ||
| execSync(`open "${url}"`, { stdio: "ignore" }) | ||
| } else if (platform === "win32") { | ||
| const { execSync } = await import("child_process") | ||
| execSync(`start "" "${url}"`, { stdio: "ignore" }) | ||
| } else { | ||
| const { execSync } = await import("child_process") | ||
| execSync(`xdg-open "${url}"`, { stdio: "ignore" }) | ||
| } | ||
| } catch { | ||
| // Browser open failed — URL already printed, user can open manually | ||
| } | ||
| } | ||
|
|
||
| async function pollForAuth(code: string): Promise<Credentials | null> { | ||
| const startTime = Date.now() | ||
|
|
||
| while (Date.now() - startTime < POLL_TIMEOUT_MS) { | ||
| await sleep(POLL_INTERVAL_MS) | ||
|
|
||
| try { | ||
| const response = await fetch( | ||
| `${BETTERBASE_API}/api/cli/auth/poll?code=${code}` | ||
| ) | ||
|
|
||
| if (response.status === 200) { | ||
| const data = await response.json() as { | ||
| token: string | ||
| email: string | ||
| userId: string | ||
| expiresAt: string | ||
| } | ||
| return data | ||
| } | ||
| // 202 = still pending, continue polling | ||
| // Any other status = error, continue polling until timeout | ||
| } catch { | ||
| // Network error — continue polling | ||
| } | ||
| } | ||
|
|
||
| return null | ||
| } | ||
|
|
||
| async function saveCredentials(creds: Credentials): Promise<void> { | ||
| const dir = path.dirname(CREDENTIALS_PATH) | ||
| await fs.mkdir(dir, { recursive: true }) | ||
| await fs.writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8") | ||
| } | ||
|
|
||
| function sleep(ms: number): Promise<void> { | ||
| return new Promise(resolve => setTimeout(resolve, ms)) | ||
| } | ||
|
|
||
| */ |
There was a problem hiding this comment.
The login command API is effectively absent in this file.
Line 14 comments out the full implementation (runLoginCommand, runLogoutCommand, getCredentials, requireCredentials). The module currently exports only Credentials, which creates an availability gap and prevents compile-time coverage for the auth flow.
💡 Proposed stopgap (explicit stubs until activation)
+export async function runLoginCommand(): Promise<void> {
+ throw new Error("bb login is not enabled in this build.");
+}
+
+export async function runLogoutCommand(): Promise<void> {
+ throw new Error("bb logout is not enabled in this build.");
+}
+
+export async function getCredentials(): Promise<Credentials | null> {
+ return null;
+}
+
+export async function requireCredentials(): Promise<Credentials> {
+ throw new Error("Authentication is not enabled in this build.");
+}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/cli/src/commands/login.ts` around lines 14 - 169, The file currently
has the full auth implementation commented out which removes exports for
runLoginCommand, runLogoutCommand, getCredentials, and requireCredentials; add
minimal explicit stub implementations for these functions (exported) so the
module compiles and other code paths can call them: create simple async stubs
for runLoginCommand and runLogoutCommand that log a clear "not yet available" or
throw a specific NotImplemented error, implement getCredentials to return null
and requireCredentials to call getCredentials then log the same message and exit
or throw; ensure the exported Credentials type/signature is preserved and the
stub functions use the same names (runLoginCommand, runLogoutCommand,
getCredentials, requireCredentials) so switching back to the real implementation
is trivial.
| Init -->|login| LoginCmd[User Login] | ||
| Init -->|rls| RLSCmd[Manage RLS Policies] | ||
| Init -->|storage| StorageCmd[Storage Operations] | ||
| Init -->|webhook| WebhookCmd[Webhook Management] |
There was a problem hiding this comment.
README CLI examples currently contradict implemented commands.
Line 193 (login flow), Lines 629-672 (bb rls, bb storage, bb webhook usage), and Line 1006 (bb dev --generate) don’t match the current command surface in packages/cli/src/index.ts. This will cause immediate copy/paste failures for users.
Also applies to: 629-672, 1001-1007
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` around lines 193 - 196, The README CLI examples (LoginCmd, RLSCmd,
StorageCmd, WebhookCmd and the dev --generate example) do not match the actual
command registrations in packages/cli/src/index.ts, causing copy/paste failures;
sync them by either updating README examples to use the exact subcommand names
and flags implemented in packages/cli/src/index.ts or by re-introducing the
missing commands into the CLI; inspect the command registration code in
packages/cli/src/index.ts (look for where commands are registered/defined) and
ensure README entries for login, rls, storage, webhook and the dev --generate
usage reflect the exact command names, options, and invocation patterns present
in that file.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/src/index.ts`:
- Around line 298-307: The action callback currently treats projectRoot as part
of the options object but Commander passes positional args separately; update
the .action signature for the deploy command from (name, options) to (name,
projectRootArg, options) so the positional '[project-root]' is received, then
compute const projectRoot = projectRootArg ?? process.cwd() and pass that into
runFunctionCommand(['deploy', name, options.syncEnv ? '--sync-env' : ''],
projectRoot). Change references to the action callback on
fn.command('deploy')/.argument('[project-root]') so runFunctionCommand uses the
positional projectRoot parameter rather than options.projectRoot.
| fn | ||
| .command('deploy') | ||
| .description('Deploy function to cloud') | ||
| .argument('<name>', 'function name') | ||
| .option('--sync-env', 'Sync environment variables from .env') | ||
| .argument('[project-root]', 'project root directory', process.cwd()) | ||
| .action(async (name: string, options: { syncEnv?: boolean; projectRoot?: string }) => { | ||
| const projectRoot = options.projectRoot ?? process.cwd(); | ||
| await runFunctionCommand(['deploy', name, options.syncEnv ? '--sync-env' : ''], projectRoot); | ||
| }); |
There was a problem hiding this comment.
Bug: projectRoot argument won't be received in options object.
In Commander, positional arguments are passed as separate parameters to the action callback before the options object. With .argument('[project-root]'), the callback signature should be (name: string, projectRoot: string, options: {...}), not (name: string, options: { projectRoot?: string }).
Currently, options.projectRoot will always be undefined, causing the command to always use process.cwd() regardless of what the user provides.
🐛 Proposed fix
fn
.command('deploy')
.description('Deploy function to cloud')
.argument('<name>', 'function name')
- .option('--sync-env', 'Sync environment variables from .env')
.argument('[project-root]', 'project root directory', process.cwd())
- .action(async (name: string, options: { syncEnv?: boolean; projectRoot?: string }) => {
- const projectRoot = options.projectRoot ?? process.cwd();
- await runFunctionCommand(['deploy', name, options.syncEnv ? '--sync-env' : ''], projectRoot);
+ .option('--sync-env', 'Sync environment variables from .env')
+ .action(async (name: string, projectRoot: string, options: { syncEnv?: boolean }) => {
+ await runFunctionCommand(['deploy', name, options.syncEnv ? '--sync-env' : ''], projectRoot);
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/cli/src/index.ts` around lines 298 - 307, The action callback
currently treats projectRoot as part of the options object but Commander passes
positional args separately; update the .action signature for the deploy command
from (name, options) to (name, projectRootArg, options) so the positional
'[project-root]' is received, then compute const projectRoot = projectRootArg ??
process.cwd() and pass that into runFunctionCommand(['deploy', name,
options.syncEnv ? '--sync-env' : ''], projectRoot). Change references to the
action callback on fn.command('deploy')/.argument('[project-root]') so
runFunctionCommand uses the positional projectRoot parameter rather than
options.projectRoot.
Summary by CodeRabbit
New Features
Documentation
Refactor