feat: add drizzle studio to admin area#62
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds an embedded Drizzle Studio database admin UI at /admin/database, protected server-side proxy and RPC endpoints, a Nitro startup plugin that applies local SQLite migrations, utilities to start/poll an embedded Studio process, a protected frontend page with i18n, a runtime config option for the Studio port, updates to storage init behavior, and corresponding docs and .env example changes. ChangesDrizzle Studio integration
Sequence DiagramsequenceDiagram
participant Browser
participant Server as Nuxt/Nitro Server
participant Studio as Embedded Drizzle Studio
participant DB as SQLite Database
Note over Server: Server startup
Server->>Server: server/plugins/migrations.ts\napplyLocalMigrations()
Server->>DB: Run migrations
Browser->>Server: GET /admin/database -> requests /api/admin/drizzle-studio/app
Server->>Server: verifyAdmin()
Server->>Server: ensureDrizzleStudioServer()
activate Server
Server->>Studio: Poll POST / with {type: 'init'}
Studio->>DB: Open DB, report dialect
Studio-->>Server: { dialect: 'sqlite' }
deactivate Server
Server->>Studio: Fetch https://local.drizzle.studio/
Studio-->>Server: App HTML
Server->>Server: sanitizeStudioHtml()
Server-->>Browser: Sanitized HTML (served)
Browser->>Server: GET /api/admin/drizzle-studio/app/<asset>
Server->>Server: verifyAdmin()
Server->>Studio: Fetch asset
Studio-->>Server: Asset bytes
Server-->>Browser: Asset
Browser->>Server: POST / (RPC)
Server->>Server: verifyAdmin()
Server->>Server: ensureDrizzleStudioServer()
Server->>Studio: Forward RPC POST to internal RPC URL
Studio->>DB: Query
DB-->>Studio: Result
Studio-->>Server: RPC response
Server-->>Browser: RPC response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Review rate limit: 4/5 reviews remaining, refill in 12 minutes. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@server/api/admin/drizzle-studio/app/`[...asset].get.ts:
- Around line 25-32: The upstream fetch for upstreamUrl is not protected by a
timeout and network-level failures (e.g., DNS, connection reset, or AbortError)
bypass the existing response.ok mapping; update the fetch call to use an
AbortController with a short timeout (setTimeout -> controller.abort) and pass
controller.signal to fetch, clear the timeout on success/response, and catch
errors from fetch: if error.name === 'AbortError' or timeout triggered throw
createError with statusCode 504 and a message including assetPath, otherwise
throw createError with statusCode 502 for other network errors including the
original error message; keep the existing response.ok branch intact to handle
non-2xx upstream responses.
In `@server/api/admin/drizzle-studio/app/index.get.ts`:
- Around line 7-13: The current analyticsScript RegExp in index.get.ts is too
strict and only matches one exact attribute order/format so small upstream
changes bypass it; update the removal to robustly target the third-party script
by either parsing the HTML and removing any <script> elements whose src contains
"assets.onedollarstats.com/stonks.js" and/or have data-site-id
"local.drizzle.studio", or replace analyticsScript with a more permissive,
case-insensitive/global RegExp that matches a <script> tag with those attributes
in any order (allowing optional whitespace, single/double quotes, and optional
defer) and use html.replace(...) to remove all matches.
- Around line 18-25: Wrap the unprotected fetch call that assigns response in a
try-catch and handle network errors/timeouts by throwing the existing
createError with statusCode 502 and a descriptive statusMessage including the
caught error message; specifically, in the code that calls
fetch(`${DRIZZLE_STUDIO_APP_ORIGIN}/`) (and likewise the fetch in
app/[...asset].get.ts), use an AbortController to enforce a timeout, await fetch
inside try, and in catch detect AbortError/timeouts and other errors then call
throw createError({ statusCode: 502, statusMessage: `Failed to load Drizzle
Studio: ${err.message}` }) so failures produce the intended proxy 502 instead of
an unhandled 500.
In `@server/routes/index.post.ts`:
- Around line 26-33: The fetch to the internal RPC URL (inside the call to
fetch(getDrizzleStudioInternalRpcUrl(event), {...}) that sends requestBody)
needs an AbortSignal timeout so the endpoint cannot hang indefinitely; update
the fetch options to include a signal:
AbortSignal.timeout(<reasonable-ms-or-configured-constant>) and ensure you clear
or handle the abort appropriately (e.g., catch the AbortError) so the call using
getDrizzleStudioInternalRpcUrl, requestBody and the surrounding logic in
index.post.ts fails fast on timeout; make the timeout value configurable (env or
constant) rather than hard-coding.
In `@server/utils/drizzle-studio.ts`:
- Around line 43-50: The fetch in waitForDrizzleStudio lacks a timeout and can
hang; wrap the POST fetch to url with an AbortController, pass controller.signal
into fetch, and start a setTimeout that calls controller.abort() after a short
timeout (e.g., a few seconds or the remaining time before the 15s deadline),
then clear that timeout after fetch completes; ensure you catch AbortError
specifically and treat it like a failed attempt so the loop continues and
resources are cleaned up (clearTimeout and not leaking controllers).
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 0c13b5ad-8092-484d-8bcf-2cea27a82508
📒 Files selected for processing (16)
README.mdapp/pages/admin/database.vueapp/pages/admin/index.vuedocs/api.mddocs/deployment-docker.mddocs/quick-start.mddocs/setup-production.mddocs/storage.mdnuxt.config.tsserver/api/admin/drizzle-studio/app/[...asset].get.tsserver/api/admin/drizzle-studio/app/index.get.tsserver/plugins/migrations.tsserver/routes/index.post.tsserver/routes/init.tsserver/utils/drizzle-studio.tsserver/utils/storage.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.env.example:
- Around line 15-17: Remove the hard-coded NUXT_JWT_SECRET value in .env.example
and replace it with a placeholder and a generation comment: delete the concrete
secret line containing NUXT_JWT_SECRET=tryUJ0z... and instead provide a
blank/placeholder like NUXT_JWT_SECRET=your_jwt_secret_here plus a one-line
instruction to generate a strong secret (for example using openssl rand -base64
48) so examples never ship reusable secrets.
In `@server/api/admin/drizzle-studio/app/`[...asset].get.ts:
- Around line 15-25: Validate the catch-all assetPath before constructing
upstreamUrl: split assetPath by '/' (or path.sep), reject any segment equal to
"." or ".." (throw createError with 400/Bad Request or 404/Drizzle Studio asset
not found to match existing handling), and only proceed to call
getRequestURL(event) and build upstreamUrl when all segments are safe; update
the code around assetPath, getRequestURL, and upstreamUrl to perform this check
(use the same createError helper and verifyAdmin flow already present).
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: dee083e2-f8e3-45fa-b135-00893209db6f
📒 Files selected for processing (5)
.env.exampleserver/api/admin/drizzle-studio/app/[...asset].get.tsserver/api/admin/drizzle-studio/app/index.get.tsserver/routes/index.post.tsserver/utils/drizzle-studio.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- server/api/admin/drizzle-studio/app/index.get.ts
- server/utils/drizzle-studio.ts
Summary by CodeRabbit
New Features
Documentation
Chores