Repository navigation
chore: update all dependencies, move the schema editor to Prisma 8 #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
a082b5a
fix(create-db): plain progress when piped, JSON for argument errors
AmanVarshney01 7797934
chore(create-db-worker): move tests to @cloudflare/vitest-plugin
AmanVarshney01 1216dbe
feat(schema-api-routes): push and pull schemas with Prisma 8
AmanVarshney01 471a906
feat(claim-db-worker): schema editor on Prisma 8, Next.js 16, Studio …
AmanVarshney01 f32c54f
chore: update root tooling to the latest versions
AmanVarshney01 999fa05
fix(schema-api-routes): drop the unused vercel CLI dependency
AmanVarshney01 a974b4a
ci: run tests on the current Node.js LTS
AmanVarshney01 d7bf016
fix(create-db): leave usage text out of JSON errors and declare Node.…
AmanVarshney01 59a6ffb
fix(claim-db-worker): only connect Studio to Prisma Postgres hosts
AmanVarshney01 e84a5be
fix(schema-api-routes): delete only the subjects the user confirmed
AmanVarshney01 e4b7cda
fix(claim-db-worker): reject multi-host Studio connection strings
AmanVarshney01 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,67 +1,98 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { createPrismaPostgresHttpClient } from "@prisma/studio-core/data/ppg"; | ||
| import { serializeError } from "@prisma/studio-core/data/bff"; | ||
| import postgres from "postgres"; | ||
| import { serializeError, type StudioBFFRequest } from "@prisma/studio-core/data/bff"; | ||
| import { | ||
| createPostgresJSConnectionConfig, | ||
| createPostgresJSExecutor, | ||
| } from "@prisma/studio-core/data/postgresjs"; | ||
|
|
||
| export async function POST(request: NextRequest) { | ||
| /** | ||
| * The Prisma Postgres host the connection string points at, the only databases | ||
| * create-db makes, or undefined for anything else. | ||
| */ | ||
| function prismaPostgresHost(connectionString: string) { | ||
| try { | ||
| // 1. Check if request has content | ||
| const contentType = request.headers.get("content-type"); | ||
| if (!contentType || !contentType.includes("application/json")) { | ||
| return NextResponse.json([ | ||
| serializeError(new Error("Content-Type must be application/json")), | ||
| ]); | ||
| } | ||
|
|
||
| // 2. Extract the query and custom data from the request | ||
| let body; | ||
| try { | ||
| const text = await request.text(); | ||
| if (!text || text.trim() === "") { | ||
| return NextResponse.json([ | ||
| serializeError(new Error("Request body is empty")), | ||
| ]); | ||
| } | ||
| body = JSON.parse(text) as { query: any }; | ||
| } catch (parseError) { | ||
| return NextResponse.json([ | ||
| serializeError( | ||
| new Error( | ||
| `Invalid JSON: ${parseError instanceof Error ? parseError.message : "Unknown error"}` | ||
| ) | ||
| ), | ||
| ]); | ||
| } | ||
| const url = new URL(connectionString); | ||
| const isPrismaPostgres = | ||
| (url.protocol === "postgres:" || url.protocol === "postgresql:") && | ||
| /^(?:[a-z0-9-]+\.)*db\.prisma\.io$/.test(url.hostname) && | ||
| (url.port === "" || url.port === "5432"); | ||
| return isPrismaPostgres ? url.hostname : undefined; | ||
| } catch { | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| const { query } = body; | ||
| /** Studio's backend: runs the queries Studio sends against the user's database. */ | ||
| export async function POST(request: NextRequest) { | ||
| const connectionString = request.headers.get("X-Connection-String"); | ||
| if (!connectionString) { | ||
| return NextResponse.json([serializeError(new Error("Connection string not provided"))]); | ||
| } | ||
| // This route is public, so it must not open connections to arbitrary hosts. | ||
| const host = prismaPostgresHost(connectionString); | ||
| if (!host) { | ||
| return NextResponse.json([ | ||
| serializeError(new Error("Only Prisma Postgres connection strings are supported")), | ||
| ]); | ||
| } | ||
|
|
||
| if (!query) { | ||
| return NextResponse.json([ | ||
| serializeError(new Error("Query is required in request body")), | ||
| ]); | ||
| } | ||
| let payload: StudioBFFRequest; | ||
| try { | ||
| payload = (await request.json()) as StudioBFFRequest; | ||
| } catch (parseError) { | ||
| return NextResponse.json([ | ||
| serializeError( | ||
| new Error( | ||
| `Invalid JSON: ${parseError instanceof Error ? parseError.message : "Unknown error"}` | ||
| ) | ||
| ), | ||
| ]); | ||
| } | ||
|
|
||
| // 3. Get connection string from custom header | ||
| const connectionString = request.headers.get("X-Connection-String"); | ||
| // One client per request: a worker can't keep connections between requests. | ||
| const config = createPostgresJSConnectionConfig(connectionString); | ||
| const sql = postgres(config.connectionString, { | ||
| ...config.options, | ||
| // postgres.js parses the host itself (a comma means several hosts), so | ||
| // pin the one checked above. | ||
| host, | ||
| port: 5432, | ||
| max: 1, | ||
| connect_timeout: 10, | ||
| }); | ||
| const executor = createPostgresJSExecutor(sql); | ||
|
|
||
| if (!connectionString) { | ||
| return NextResponse.json([ | ||
| serializeError(new Error("Connection string not provided")), | ||
| ]); | ||
| try { | ||
| if (payload.procedure === "query") { | ||
| const [error, result] = await executor.execute(payload.query, { | ||
| schema: payload.schema, | ||
| }); | ||
| return NextResponse.json([error ? serializeError(error) : null, result]); | ||
| } | ||
|
|
||
| // 4. Execute the query against Prisma Postgres | ||
| const [error, results] = await createPrismaPostgresHttpClient({ | ||
| url: connectionString, | ||
| }).execute(query); | ||
| if (payload.procedure === "transaction" && executor.executeTransaction) { | ||
| const [error, result] = await executor.executeTransaction(payload.queries); | ||
| return NextResponse.json([error ? serializeError(error) : null, result]); | ||
| } | ||
|
|
||
| // 5. Return results or errors | ||
| if (error) { | ||
| return NextResponse.json([serializeError(error)]); | ||
| if (payload.procedure === "sql-lint" && executor.lintSql) { | ||
| const [error, result] = await executor.lintSql({ | ||
| schema: payload.schema, | ||
| schemaVersion: payload.schemaVersion, | ||
| sql: payload.sql, | ||
| }); | ||
| return NextResponse.json([error ? serializeError(error) : null, result]); | ||
| } | ||
|
|
||
| return NextResponse.json([null, results]); | ||
| return new NextResponse(`${payload.procedure} is not supported`, { status: 501 }); | ||
| } catch (error) { | ||
| console.error("Studio API error:", error); | ||
| return NextResponse.json([serializeError(error as Error)]); | ||
| } finally { | ||
| // A failed close must not replace the response. | ||
| await sql.end().catch((error: unknown) => { | ||
| console.error("Failed to close the Studio connection:", error); | ||
| }); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.