Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[pull] master from supabase:master #79

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 4 commits into from
Jun 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 64 additions & 14 deletions apps/docs/app/api/graphql/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ export const preferredRegion = [

const MAX_DEPTH = 5

function isAllowedCorsOrigin(origin: string): boolean {
const exactMatches = IS_DEV
? ['http://localhost:8082', 'https://supabase.com']
: ['https://supabase.com']
if (exactMatches.includes(origin)) {
return true
}

return /^https:\/\/[\w-]+\w-supabase.vercel.app$/.test(origin)
}

function getCorsHeaders(request: Request): Record<string, string> {
const origin = request.headers.get('Origin')

if (origin && isAllowedCorsOrigin(origin)) {
return {
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
}
}

return {}
}

const validationRules = [
...specifiedRules,
createQueryDepthLimiter(MAX_DEPTH),
Expand Down Expand Up @@ -78,13 +103,18 @@ async function handleGraphQLRequest(request: Request): Promise<NextResponse> {
const { query, variables, operationName } = parsedBody.data
const validationErrors = validateGraphQLRequest(query, isDevGraphiQL(request))
if (validationErrors.length > 0) {
return NextResponse.json({
errors: validationErrors.map((error) => ({
message: error.message,
locations: error.locations,
path: error.path,
})),
})
return NextResponse.json(
{
errors: validationErrors.map((error) => ({
message: error.message,
locations: error.locations,
path: error.path,
})),
},
{
headers: getCorsHeaders(request),
}
)
}

const result = await graphql({
Expand All @@ -94,7 +124,9 @@ async function handleGraphQLRequest(request: Request): Promise<NextResponse> {
variableValues: variables,
operationName,
})
return NextResponse.json(result)
return NextResponse.json(result, {
headers: getCorsHeaders(request),
})
}

function validateGraphQLRequest(query: string, isDevGraphiQL = false): ReadonlyArray<GraphQLError> {
Expand All @@ -112,6 +144,14 @@ function validateGraphQLRequest(query: string, isDevGraphiQL = false): ReadonlyA
return validate(rootGraphQLSchema, documentAST, rules)
}

export async function OPTIONS(request: Request): Promise<NextResponse> {
const corsHeaders = getCorsHeaders(request)
return new NextResponse(null, {
status: 204,
headers: corsHeaders,
})
}

export async function POST(request: Request): Promise<NextResponse> {
try {
const result = await handleGraphQLRequest(request)
Expand All @@ -130,18 +170,28 @@ export async function POST(request: Request): Promise<NextResponse> {
// https://github.com/getsentry/sentry-javascript/issues/9626
await Sentry.flush(2000)

return NextResponse.json({
errors: [{ message: error.isPrivate() ? 'Internal Server Error' : error.message }],
})
return NextResponse.json(
{
errors: [{ message: error.isPrivate() ? 'Internal Server Error' : error.message }],
},
{
headers: getCorsHeaders(request),
}
)
} else {
Sentry.captureException(error)
// Do not let Vercel close the process until Sentry has flushed
// https://github.com/getsentry/sentry-javascript/issues/9626
await Sentry.flush(2000)

return NextResponse.json({
errors: [{ message: 'Internal Server Error' }],
})
return NextResponse.json(
{
errors: [{ message: 'Internal Server Error' }],
},
{
headers: getCorsHeaders(request),
}
)
}
}
}
2 changes: 1 addition & 1 deletion apps/docs/content/guides/getting-started/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Each Supabase project consists of several tools:

### Postgres (database)

Postgres is the core of Supabase. We do not abstract the Postgres databaseβ€”you can access it and use it with full privileges. We provide tools which makes Postgres as easy to use as Firebase.
Postgres is the core of Supabase. We do not abstract the Postgres databaseβ€”you can access it and use it with full privileges. We provide tools which make Postgres as easy to use as Firebase.

- Official Docs: [postgresql.org/docs](https://www.postgresql.org/docs/current/index.html)
- Source code: [github.com/postgres/postgres](https://github.com/postgres/postgres) (mirror)
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/guides/getting-started/features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Deploy read-only databases across multiple regions, for lower latency and better

### Log drains

Export Supabase logs at to 3rd party providers and external tooling. [Docs](/docs/guides/platform/log-drains).
Export Supabase logs to 3rd party providers and external tooling. [Docs](/docs/guides/platform/log-drains).

## Studio

Expand Down
111 changes: 111 additions & 0 deletions apps/studio/components/interfaces/Settings/Logs/ErrorCodeDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
Alert_Shadcn_,
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Badge,
Button_Shadcn_,
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from 'ui'
import { useErrorCodesQuery } from 'data/content-api/docs-error-codes-query'
import { type ErrorCodeQueryQuery, Service } from 'data/graphql/graphql'
import { AlertTriangle } from 'lucide-react'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'

interface ErrorCodeDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
errorCode: string
service?: Service
}

export const ErrorCodeDialog = ({
open,
onOpenChange,
errorCode,
service,
}: ErrorCodeDialogProps) => {
const { data, isLoading, isSuccess, refetch } = useErrorCodesQuery(
{ code: errorCode, service },
{ enabled: open }
)

return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle className="mb-4">
Help for error code <code>{errorCode}</code>
</DialogTitle>
<DialogDescription>
{isLoading && <LoadingState />}
{isSuccess && <SuccessState data={data} />}
{!isLoading && !isSuccess && <ErrorState refetch={refetch} />}
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
)
}

const LoadingState = () => (
<>
<ShimmeringLoader className="w-3/4 mb-2" />
<ShimmeringLoader className="w-1/2" />
</>
)

const SuccessState = ({ data }: { data: ErrorCodeQueryQuery | undefined }) => {
const errors = data?.errors?.nodes?.filter((error) => !!error.message)
if (!errors || errors.length === 0) {
return <>No information found for this error code.</>
}

return (
<>
<p className="mb-4">Possible explanations for this error:</p>
<div className="grid gap-2 grid-cols-[max-content_1fr]">
{errors.map((error) => (
<ErrorExplanation key={`${error.service}-${error.code}`} {...error} />
))}
</div>
</>
)
}

const ErrorExplanation = ({
code,
service,
message,
}: {
code: string
service: Service
message?: string | null
}) => {
if (!message) return null

return (
<>
<Badge className="h-fit">{service}</Badge>
<p>{message}</p>
</>
)
}

const ErrorState = ({ refetch }: { refetch?: () => void }) => (
<Alert_Shadcn_ variant="warning">
<AlertTriangle />
<AlertTitle_Shadcn_>Lookup failed</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
<p>Failed to look up error code help info</p>
{refetch && (
<Button_Shadcn_ variant="outline" size="sm" className="mt-2" onClick={refetch}>
Try again
</Button_Shadcn_>
)}
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
)
Loading
Loading