Refactor post calls from lib/common/fetch in auth pages to data/fetchers (#36506)

* Deprecate use of getWithTimeout, refactor BuildingState and RestoringState to use RQ

* Refactor profile-create-mutation to use data/fetchers, and edge-function-status-query to use fetch

* Shift post from lib/common/fetch, refactor bucket-object-download-mutation

* Address feedback

* Minor fix

* Refactor post calls from lib/common/fetch in auth pages to data/fetchers

* Add missing POST users endpoint + small fix when deleting user via context menu

* simplify handleFetchError

* allow handleFetchError to accept unknown

* non-breaking change

---------

Co-authored-by: Alaister Young <a@alaisteryoung.com>
This commit is contained in:
Joshen LimandAlaister Young authored and GitHub committed 2025-07-21 12:45:53 +08:00
1 parent 88dca021d6
commit b9a0908331
13 files changed
+121 -393

No files matched your search

@@ -587,7 +587,10 @@ export const UsersV2 = () => {
visible={!!selectedUserToDelete}
selectedUser={selectedUserToDelete}
onClose={() => setSelectedUserToDelete(undefined)}
onDeleteSuccess={() => setSelectedUserToDelete(undefined)}
onDeleteSuccess={() => {
if (selectedUserToDelete?.id === selectedUser) setSelectedUser(undefined)
setSelectedUserToDelete(undefined)
}}
/>
</>
)
+2 -1
View File
@@ -1,6 +1,7 @@
import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query'
import type { components } from 'data/api'
import { get, handleError } from 'data/fetchers'
import { IS_PLATFORM } from 'lib/constants'
import { useCallback } from 'react'
import type { ResponseError } from 'types'
import { authKeys } from './keys'
@@ -40,7 +41,7 @@ export const useAuthConfigQuery = <TData = ProjectAuthConfigData>(
authKeys.authConfig(projectRef),
({ signal }) => getProjectAuthConfig({ projectRef }, signal),
{
enabled: enabled && typeof projectRef !== 'undefined',
enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined',
...options,
}
)
+35 -2
View File
@@ -193,6 +193,39 @@ async function handleFetchResponse<T>(response: Response): Promise<T | ResponseE
}
}
async function handleFetchError(response: unknown): Promise<ResponseError> {
let resJson: any = {}
if (response instanceof Error) {
resJson = response
}
if (response instanceof Response) {
resJson = await response.json()
}
const status = response instanceof Response ? response.status : undefined
const message =
resJson.message ??
resJson.msg ??
resJson.error ??
`An error has occurred: ${status ?? 'Unknown error'}`
const retryAfter =
response instanceof Response && response.headers.get('Retry-After')
? parseInt(response.headers.get('Retry-After')!)
: undefined
let error = new ResponseError(message, status, undefined, retryAfter)
// @ts-expect-error - [Alaister] many of our local api routes check `if (response.error)`.
// This is a fix to keep those checks working without breaking changes.
// In future we should check for `if (response instanceof ResponseError)` instead.
error.error = error
return error
}
/**
* To be used only for dashboard API endpoints. Use `fetch` directly if calling a non dashboard API endpoint
*
@@ -218,9 +251,9 @@ export async function fetchPost<T = any>(
...otherOptions,
signal: abortSignal,
})
if (!response.ok) return handleError(response)
if (!response.ok) return handleFetchError(response)
return handleFetchResponse(response)
} catch (error) {
return handleError(error)
return handleFetchError(error)
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { post } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import type { ResponseError } from 'types'
export async function queryPgMetaSelfHosted(sql: string, headersInit?: { [prop: string]: any }) {
const headers = constructHeaders(headersInit ?? {})
const response = await post(`${PG_META_URL}/query`, { query: sql }, { headers })
const response = await fetchPost(`${PG_META_URL}/query`, { query: sql }, { headers })
if (response.error) {
return { error: response.error as ResponseError }
@@ -1,179 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { get } from 'lib/common/fetch'
import { constructHeaders } from 'lib/api/apiHelpers'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
default:
res.setHeader('Allow', ['GET', 'POST'])
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders({})
const url = `${process.env.SUPABASE_URL}/auth/v1/settings`
const { external, disable_signup, mailer_autoconfirm, phone_autoconfirm } = await get(url, {
headers,
})
// Platform only API
return res.status(200).json({
app_version: '',
config_override_id: '',
project_id: '',
jwt_secret_encrypted: '',
isFreeTier: true,
SITE_URL: '',
OPERATOR_TOKEN: null,
DISABLE_SIGNUP: disable_signup ?? false,
RATE_LIMIT_HEADER: null,
JWT_EXP: 3600,
JWT_AUD: '',
JWT_DEFAULT_GROUP_NAME: '',
URI_ALLOW_LIST: '',
MAILER_AUTOCONFIRM: mailer_autoconfirm ?? false,
MAILER_OTP_EXP: 3600,
MAILER_OTP_LENGTH: 6,
MAILER_URLPATHS_INVITE: '',
MAILER_URLPATHS_CONFIRMATION: '',
MAILER_URLPATHS_RECOVERY: '',
MAILER_URLPATHS_EMAIL_CHANGE: '',
SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION: false,
SMTP_ADMIN_EMAIL: '',
SMTP_HOST: null,
SMTP_PORT: null,
SMTP_USER: null,
SMTP_PASS: null,
SMTP_MAX_FREQUENCY: 0,
EXTERNAL_ANONYMOUS_USERS_ENABLED: external?.anonymous_users ?? true,
EXTERNAL_EMAIL_ENABLED: external?.email ?? true,
EXTERNAL_PHONE_ENABLED: external?.phone ?? true,
EXTERNAL_APPLE_ENABLED: external?.apple ?? false,
EXTERNAL_APPLE_CLIENT_ID: null,
EXTERNAL_APPLE_SECRET: null,
EXTERNAL_AZURE_ENABLED: external?.azure ?? false,
EXTERNAL_AZURE_CLIENT_ID: null,
EXTERNAL_AZURE_SECRET: null,
EXTERNAL_AZURE_URL: null,
EXTERNAL_BITBUCKET_ENABLED: external?.bitbucket ?? false,
EXTERNAL_BITBUCKET_CLIENT_ID: null,
EXTERNAL_BITBUCKET_SECRET: null,
EXTERNAL_DISCORD_ENABLED: external?.discord ?? false,
EXTERNAL_DISCORD_CLIENT_ID: null,
EXTERNAL_DISCORD_SECRET: null,
EXTERNAL_FACEBOOK_ENABLED: external?.facebook ?? false,
EXTERNAL_FACEBOOK_CLIENT_ID: null,
EXTERNAL_FACEBOOK_SECRET: null,
EXTERNAL_FIGMA_ENABLED: external?.figma ?? false,
EXTERNAL_FIGMA_CLIENT_ID: null,
EXTERNAL_FIGMA_SECRET: null,
EXTERNAL_GITHUB_ENABLED: external?.github ?? false,
EXTERNAL_GITHUB_CLIENT_ID: null,
EXTERNAL_GITHUB_SECRET: null,
EXTERNAL_GITLAB_ENABLED: external?.gitlab ?? false,
EXTERNAL_GITLAB_CLIENT_ID: null,
EXTERNAL_GITLAB_SECRET: null,
EXTERNAL_GITLAB_REDIRECT_URI: null,
EXTERNAL_GOOGLE_ENABLED: external?.google ?? false,
EXTERNAL_GOOGLE_CLIENT_ID: null,
EXTERNAL_GOOGLE_SECRET: null,
EXTERNAL_KAKAO_ENABLED: external?.kakao ?? false,
EXTERNAL_KAKAO_CLIENT_ID: null,
EXTERNAL_KAKAO_SECRET: null,
EXTERNAL_KEYCLOAK_ENABLED: external?.keycloak ?? false,
EXTERNAL_KEYCLOAK_CLIENT_ID: null,
EXTERNAL_KEYCLOAK_SECRET: null,
EXTERNAL_KEYCLOAK_URL: null,
EXTERNAL_NOTION_ENABLED: external?.notion ?? false,
EXTERNAL_NOTION_CLIENT_ID: null,
EXTERNAL_NOTION_SECRET: null,
EXTERNAL_SPOTIFY_ENABLED: external?.spotify ?? false,
EXTERNAL_SPOTIFY_CLIENT_ID: null,
EXTERNAL_SPOTIFY_SECRET: null,
EXTERNAL_SLACK_OIDC_ENABLED: external?.slack ?? false,
EXTERNAL_SLACK_OIDC_CLIENT_ID: null,
EXTERNAL_SLACK_OIDC_SECRET: null,
EXTERNAL_TWITTER_ENABLED: external?.twitter ?? false,
EXTERNAL_TWITTER_CLIENT_ID: null,
EXTERNAL_TWITTER_SECRET: null,
EXTERNAL_TWITCH_ENABLED: external?.twitch ?? false,
EXTERNAL_TWITCH_CLIENT_ID: null,
EXTERNAL_TWITCH_SECRET: null,
EXTERNAL_WORKOS_ENABLED: external?.workos ?? false,
EXTERNAL_WORKOS_CLIENT_ID: null,
EXTERNAL_WORKOS_SECRET: null,
EXTERNAL_WORKOS_URL: null,
EXTERNAL_ZOOM_ENABLED: external?.zoom ?? false,
EXTERNAL_ZOOM_CLIENT_ID: null,
EXTERNAL_ZOOM_SECRET: null,
MAILER_SUBJECTS_INVITE: 'You have been invited',
MAILER_SUBJECTS_CONFIRMATION: 'Confirm Your Signup',
MAILER_SUBJECTS_RECOVERY: 'Reset Your Password',
MAILER_SUBJECTS_EMAIL_CHANGE: 'Confirm Email Change',
MAILER_SUBJECTS_MAGIC_LINK: 'Your Magic Link',
MAILER_SUBJECTS_REAUTHENTICATION: 'Confirm Reauthentication',
MAILER_TEMPLATES_INVITE: null,
MAILER_TEMPLATES_INVITE_CONTENT:
'<h2>You have been invited</h2>\n\n<p>You have been invited to create a user on {{ .SiteURL }}. Follow this link to accept the invite:</p>\n<p><a href="{{ .ConfirmationURL }}">Accept the invite</a></p>',
MAILER_TEMPLATES_CONFIRMATION: null,
MAILER_TEMPLATES_CONFIRMATION_CONTENT:
'<h2>Confirm your email</h2>\n\n<p>Follow this link to confirm your email:</p>\n\n<p><a href="{{ .ConfirmationURL }}">Confirm your email address</a></p>',
MAILER_TEMPLATES_RECOVERY: null,
MAILER_TEMPLATES_RECOVERY_CONTENT:
'<h2>Reset Password</h2>\n\n<p>Follow this link to reset the password for your user:</p>\n<p><a href="{{ .ConfirmationURL }}">Reset Password</a></p>',
MAILER_TEMPLATES_EMAIL_CHANGE: null,
MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT:
'<h2>Confirm Change of Email</h2>\n\n<p>Follow this link to confirm the update of your email from {{ .Email }} to {{ .NewEmail }}:</p>\n<p><a href="{{ .ConfirmationURL }}">Change Email</a></p>',
MAILER_TEMPLATES_MAGIC_LINK: null,
MAILER_TEMPLATES_MAGIC_LINK_CONTENT:
'<h2>Magic Link</h2>\n\n<p>Follow this link to login:</p>\n<p><a href="{{ .ConfirmationURL }}">Log In</a></p>',
PASSWORD_MIN_LENGTH: 6,
SMTP_SENDER_NAME: null,
SMS_AUTOCONFIRM: phone_autoconfirm ?? false,
SMS_MAX_FREQUENCY: 0,
SMS_OTP_EXP: 60,
SMS_OTP_LENGTH: 6,
SMS_PROVIDER: 'twilio',
SMS_TWILIO_ACCOUNT_SID: null,
SMS_TWILIO_AUTH_TOKEN: null,
SMS_TWILIO_CONTENT_SID: null,
SMS_TWILIO_MESSAGE_SERVICE_SID: null,
SMS_TWILIO_VERIFY_ACCOUNT_SID: null,
SMS_TWILIO_VERIFY_AUTH_TOKEN: null,
SMS_TWILIO_VERIFY_MESSAGE_SERVICE_SID: null,
SMS_TEMPLATE: 'Your code is {{ .Code }}',
SECURITY_CAPTCHA_ENABLED: false,
SECURITY_CAPTCHA_PROVIDER: 'hcaptcha',
SECURITY_CAPTCHA_SECRET: null,
SECURITY_MANUAL_LINKING_ENABLED: false,
SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: '10',
RATE_LIMIT_EMAIL_SENT: 0,
RATE_LIMIT_SMS_SENT: 0,
RATE_LIMIT_ANONYMOUS_USERS: 0,
MAILER_SECURE_EMAIL_CHANGE_ENABLED: true,
SMS_MESSAGEBIRD_ACCESS_KEY: null,
SMS_MESSAGEBIRD_ORIGINATOR: null,
SMS_VONAGE_API_KEY: null,
SMS_VONAGE_API_SECRET: null,
SMS_VONAGE_FROM: null,
SMS_TEXTLOCAL_API_KEY: null,
SMS_TEXTLOCAL_SENDER: null,
MAILER_TEMPLATES_REAUTHENTICATION: null,
MAILER_TEMPLATES_REAUTHENTICATION_CONTENT:
'<h2>Confirm reauthentication</h2> <p>Enter the code: {{ .Token }}</p>',
})
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
// Platform only API
return res.status(200).json({})
}
@@ -1,7 +1,11 @@
import { createClient } from '@supabase/supabase-js'
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { post } from 'lib/common/fetch'
import apiWrapper from 'lib/api/apiWrapper'
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
@@ -25,6 +29,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
})
const url = `${process.env.SUPABASE_URL}/auth/v1/invite`
const payload = { email: req.body.email }
const response = await post(url, payload, { headers })
return res.status(200).json(response)
const response = await fetchPost(url, payload, { headers })
if (response.error) {
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
}
@@ -1,10 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import SqlString from 'sqlstring'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { post } from 'lib/common/fetch'
import { tryParseInt } from 'lib/helpers'
import apiWrapper from 'lib/api/apiWrapper'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
})
const url = `${process.env.SUPABASE_URL}/auth/v1/magiclink`
const payload = { email: req.body.email }
const response = await post(url, payload, { headers })
return res.status(200).json(response)
const response = await fetchPost(url, payload, { headers })
if (response.error) {
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
}
@@ -1,10 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import SqlString from 'sqlstring'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { post } from 'lib/common/fetch'
import { tryParseInt } from 'lib/helpers'
import apiWrapper from 'lib/api/apiWrapper'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
})
const url = `${process.env.SUPABASE_URL}/auth/v1/otp`
const payload = { phone: req.body.phone }
const response = await post(url, payload, { headers })
return res.status(200).json(response)
const response = await fetchPost(url, payload, { headers })
if (response.error) {
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
}
@@ -1,10 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import SqlString from 'sqlstring'
import apiWrapper from 'lib/api/apiWrapper'
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import { post } from 'lib/common/fetch'
import { tryParseInt } from 'lib/helpers'
import apiWrapper from 'lib/api/apiWrapper'
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
@@ -28,6 +26,12 @@ const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
})
const url = `${process.env.SUPABASE_URL}/auth/v1/recover`
const payload = { email: req.body.email }
const response = await post(url, payload, { headers })
return res.status(200).json(response)
const response = await fetchPost(url, payload, { headers })
if (response.error) {
const { code, message } = response.error
return res.status(code).json({ message })
} else {
return res.status(200).json(response)
}
}
@@ -1,132 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import SqlString from 'sqlstring'
import { createClient } from '@supabase/supabase-js'
import { post } from 'lib/common/fetch'
import { tryParseInt } from 'lib/helpers'
import { PG_META_URL } from 'lib/constants'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders } from 'lib/api/apiHelpers'
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'DELETE'])
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
}
}
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const { keywords, limit, offset, verified } = req.query
const limitInt = tryParseInt(limit as string) || 10
const offsetInt = tryParseInt(offset as string) || 0
const hasValidKeywords = keywords && keywords != ''
const hasVerifiedValue = verified && verified != ''
let queryCount = ''
let queryUsers = ''
if (hasValidKeywords && !hasVerifiedValue) {
queryCount = SqlString.format(
'SELECT count(*) from auth.users WHERE (email ilike ? OR id::text ilike ?);',
[`%${keywords}%`, `%${keywords}%`]
)
queryUsers = SqlString.format(
'SELECT * from auth.users WHERE (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
)
}
if (!hasValidKeywords && hasVerifiedValue) {
if (verified === 'verified') {
queryCount = SqlString.format(
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL);'
)
queryUsers = SqlString.format(
'SELECT * from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[limitInt, offsetInt]
)
}
if (verified === 'unverified') {
queryCount = SqlString.format(
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL);'
)
queryUsers = SqlString.format(
'SELECT * from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[limitInt, offsetInt]
)
}
}
if (hasValidKeywords && hasVerifiedValue) {
if (verified === 'verified') {
queryCount = SqlString.format(
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) AND (email ilike ? OR id::text ilike ?);',
[`%${keywords}%`, `%${keywords}%`]
)
queryUsers = SqlString.format(
'SELECT * from auth.users WHERE (email_confirmed_at IS NOT NULL or phone_confirmed_at IS NOT NULL) AND (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
)
}
if (verified === 'unverified') {
queryCount = SqlString.format(
'SELECT count(*) from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) AND (email ilike ? OR id::text ilike ?);',
[`%${keywords}%`, `%${keywords}%`]
)
queryUsers = SqlString.format(
'SELECT * from auth.users WHERE (email_confirmed_at IS NULL AND phone_confirmed_at IS NULL) AND (email ilike ? OR id::text ilike ?) ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[`%${keywords}%`, `%${keywords}%`, limitInt, offsetInt]
)
}
}
if (!hasValidKeywords && !hasVerifiedValue) {
queryCount = 'SELECT count(*) from auth.users;'
queryUsers = SqlString.format(
'SELECT * from auth.users ORDER BY created_at DESC LIMIT ? OFFSET ?;',
[limitInt, offsetInt]
)
}
const [getTotal, getUsers] = await Promise.all([
post(`${PG_META_URL}/query`, { query: queryCount }, { headers }),
post(`${PG_META_URL}/query`, { query: queryUsers }, { headers }),
])
let total = 0
if (getTotal && (getTotal as any[]).length > 0) {
total = (getTotal[0] as any).count
}
return res.status(200).json({ total, users: getUsers })
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const { email, password, email_confirm } = req.body
const { data, error } = await supabase.auth.admin.createUser({ email, password, email_confirm })
if (error) return res.status(400).json({ error: { message: error.message } })
return res.status(200).json(data.user)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const { id } = req.body
const { data, error } = await supabase.auth.admin.deleteUser(id)
if (error) return res.status(400).json({ error: { message: error.message } })
return res.status(200).json(data.user)
}
@@ -0,0 +1,27 @@
import { createClient } from '@supabase/supabase-js'
import { NextApiRequest, NextApiResponse } from 'next'
import apiWrapper from 'lib/api/apiWrapper'
const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_KEY!)
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { method } = req
switch (method) {
case 'POST':
return handlePost(req, res)
default:
res.setHeader('Allow', ['POST'])
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
}
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const { data, error } = await supabase.auth.admin.createUser(req.body)
if (error) return res.status(400).json({ error: { message: error.message } })
return res.status(200).json(data.user)
}
@@ -1,8 +1,8 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { constructHeaders, toSnakeCase } from 'lib/api/apiHelpers'
import { get } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import { delete_, get, patch, post } from 'lib/common/fetch'
import { NextApiRequest, NextApiResponse } from 'next'
export default (req: NextApiRequest, res: NextApiResponse) =>
apiWrapper(req, res, handler, { withAuth: true })
@@ -13,12 +13,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
switch (method) {
case 'GET':
return handleGetAll(req, res)
case 'POST':
return handlePost(req, res)
case 'PATCH':
return handlePatch(req, res)
case 'DELETE':
return handleDelete(req, res)
default:
res.setHeader('Allow', ['GET', 'POST', 'PATCH', 'DELETE'])
res.status(405).json({ error: { message: `Method ${method} Not Allowed` } })
@@ -35,45 +29,3 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
}
return res.status(200).json(response)
}
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await post(`${PG_META_URL}/policies`, payload, {
headers,
})
if (response.error) {
console.error('Policies POST:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handlePatch = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const payload = toSnakeCase(req.body)
const response = await patch(`${PG_META_URL}/policies/${req.query.id}`, payload, {
headers,
})
if (response.error) {
console.error('Policies PATCH:', response)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
const headers = constructHeaders(req.headers)
const response = await delete_(`${PG_META_URL}/policies/${req.query.id}`, {}, { headers })
if (response.error) {
console.error('Policies DELETE:', response.error)
return res.status(400).json({ error: response.error })
}
return res.status(200).json(response)
}
@@ -1,6 +1,6 @@
import { fetchPost } from 'data/fetchers'
import { constructHeaders } from 'lib/api/apiHelpers'
import apiWrapper from 'lib/api/apiWrapper'
import { post } from 'lib/common/fetch'
import { PG_META_URL } from 'lib/constants'
import { NextApiRequest, NextApiResponse } from 'next'
@@ -22,10 +22,11 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
const handlePost = async (req: NextApiRequest, res: NextApiResponse) => {
const { query } = req.body
const headers = constructHeaders(req.headers)
const response = await post(`${PG_META_URL}/query`, { query }, { headers })
const response = await fetchPost(`${PG_META_URL}/query`, { query }, { headers })
if (response.error) {
return res.status(400).json(response.error)
const { code, message } = response.error
return res.status(code).json({ message, formattedError: message })
} else {
return res.status(200).json(response)
}