diff --git a/apps/studio/components/interfaces/Auth/Hooks/AddHookDropdown.tsx b/apps/studio/components/interfaces/Auth/Hooks/AddHookDropdown.tsx index f2802eafb60..12e55e0c8b2 100644 --- a/apps/studio/components/interfaces/Auth/Hooks/AddHookDropdown.tsx +++ b/apps/studio/components/interfaces/Auth/Hooks/AddHookDropdown.tsx @@ -16,7 +16,6 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, - SheetSection, } from 'ui' import { HOOKS_DEFINITIONS, HOOK_DEFINITION_TITLE, Hook } from './hooks.constants' import { extractMethod, isValidHook } from './hooks.utils' @@ -38,7 +37,7 @@ export const AddHookDropdown = ({ { enabled: IS_PLATFORM } ) const { data: authConfig } = useAuthConfigQuery({ projectRef }) - const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue') + const canUpdateAuthHook = useCheckPermissions(PermissionAction.AUTH_EXECUTE, '*') const hooks: Hook[] = HOOKS_DEFINITIONS.map((definition) => { return { @@ -57,7 +56,7 @@ export const AddHookDropdown = ({ const isTeamsOrEnterprisePlan = subscription?.plan.id === 'team' || subscription?.plan.id === 'enterprise' - if (!canUpdateConfig) { + if (!canUpdateAuthHook) { return ( - +
{nonEnterpriseHookOptions.map((h) => ( onSelectHook(h.title)}> @@ -87,7 +86,7 @@ export const AddHookDropdown = ({ ))}
- + {!isTeamsOrEnterprisePlan && ( diff --git a/apps/studio/components/interfaces/Auth/Hooks/CreateHookSheet.tsx b/apps/studio/components/interfaces/Auth/Hooks/CreateHookSheet.tsx index 5a25cd7643f..ca32ae51599 100644 --- a/apps/studio/components/interfaces/Auth/Hooks/CreateHookSheet.tsx +++ b/apps/studio/components/interfaces/Auth/Hooks/CreateHookSheet.tsx @@ -14,7 +14,7 @@ import CodeEditor from 'components/ui/CodeEditor/CodeEditor' import FunctionSelector from 'components/ui/FunctionSelector' import SchemaSelector from 'components/ui/SchemaSelector' import { AuthConfigResponse } from 'data/auth/auth-config-query' -import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation' +import { useAuthHooksUpdateMutation } from 'data/auth/auth-hooks-update-mutation' import { executeSql } from 'data/sql/execute-sql-query' import { useFlag } from 'hooks/ui/useFlag' import { @@ -42,10 +42,10 @@ import { extractMethod, getRevokePermissionStatements, isValidHook } from './hoo interface CreateHookSheetProps { visible: boolean - onClose: () => void - onDelete: () => void title: HOOK_DEFINITION_TITLE | null authConfig: AuthConfigResponse + onClose: () => void + onDelete: () => void } export function generateAuthHookSecret() { @@ -109,14 +109,13 @@ const FormSchema = z export const CreateHookSheet = ({ visible, - onClose, - onDelete, title, authConfig, + onClose, + onDelete, }: CreateHookSheetProps) => { const { ref: projectRef } = useParams() const { project } = useProjectContext() - const { mutate: updateAuthConfig, isLoading: isUpdatingConfig } = useAuthConfigUpdateMutation() const httpsAuthHooksEnabled = useFlag('httpsAuthHooksEnabled') const definition = useMemo( @@ -155,6 +154,79 @@ export const CreateHookSheet = ({ }, }) + const values = form.watch() + + const statements = useMemo(() => { + let permissionChanges: string[] = [] + if (hook.method.type === 'postgres') { + if ( + hook.method.schema !== '' && + hook.method.functionName !== '' && + hook.method.functionName !== values.postgresValues.functionName + ) { + permissionChanges = getRevokePermissionStatements( + hook.method.schema, + hook.method.functionName + ) + } + } + + if (values.postgresValues.functionName !== '') { + permissionChanges = [ + ...permissionChanges, + `-- Grant access to function to supabase_auth_admin\ngrant execute on function ${values.postgresValues.schema}.${values.postgresValues.functionName} to supabase_auth_admin;`, + `-- Grant access to schema to supabase_auth_admin\ngrant usage on schema ${values.postgresValues.schema} to supabase_auth_admin;`, + `-- Revoke function permissions from authenticated, anon and public\nrevoke execute on function ${values.postgresValues.schema}.${values.postgresValues.functionName} from authenticated, anon, public;`, + ] + } + return permissionChanges + }, [hook, values.postgresValues.schema, values.postgresValues.functionName]) + + const { mutate: updateAuthHooks, isLoading: isUpdatingAuthHooks } = useAuthHooksUpdateMutation({ + onSuccess: () => { + toast.success(`Successfully created ${values.hookType}.`) + if (statements.length > 0) { + executeSql({ + projectRef, + connectionString: project!.connectionString, + sql: statements.join('\n'), + }) + } + onClose() + }, + onError: (error) => { + toast.error(`Failed to create hook: ${error.message}`) + }, + }) + + const onSubmit: SubmitHandler> = async (values) => { + if (!project) return console.error('Project is required') + const definition = HOOKS_DEFINITIONS.find((d) => values.hookType === d.title) + + if (!definition) { + return + } + + const enabledLabel = definition.enabledKey + const uriLabel = definition.uriKey + const secretsLabel = definition.secretsKey + + let url = '' + if (values.selectedType === 'postgres') { + url = `pg-functions://postgres/${values.postgresValues.schema}/${values.postgresValues.functionName}` + } else { + url = values.httpsValues.url + } + + const payload = { + [enabledLabel]: values.enabled, + [uriLabel]: url, + [secretsLabel]: values.selectedType === 'https' ? values.httpsValues.secret : null, + } + + updateAuthHooks({ projectRef: projectRef!, config: payload }) + } + useEffect(() => { if (visible) { if (definition) { @@ -194,81 +266,6 @@ export const CreateHookSheet = ({ } }, [authConfig, title, visible, definition]) - const values = form.watch() - - const statements = useMemo(() => { - let permissionChanges: string[] = [] - if (hook.method.type === 'postgres') { - if ( - hook.method.schema !== '' && - hook.method.functionName !== '' && - hook.method.functionName !== values.postgresValues.functionName - ) { - permissionChanges = getRevokePermissionStatements( - hook.method.schema, - hook.method.functionName - ) - } - } - - if (values.postgresValues.functionName !== '') { - permissionChanges = [ - ...permissionChanges, - `-- Grant access to function to supabase_auth_admin\ngrant execute on function ${values.postgresValues.schema}.${values.postgresValues.functionName} to supabase_auth_admin;`, - `-- Grant access to schema to supabase_auth_admin\ngrant usage on schema ${values.postgresValues.schema} to supabase_auth_admin;`, - `-- Revoke function permissions from authenticated, anon and public\nrevoke execute on function ${values.postgresValues.schema}.${values.postgresValues.functionName} from authenticated, anon, public;`, - ] - } - return permissionChanges - }, [hook, values.postgresValues.schema, values.postgresValues.functionName]) - - const onSubmit: SubmitHandler> = async (values) => { - if (!project) return console.error('Project is required') - const definition = HOOKS_DEFINITIONS.find((d) => values.hookType === d.title) - - if (!definition) { - return - } - - const enabledLabel = definition.enabledKey - const uriLabel = definition.uriKey - const secretsLabel = definition.secretsKey - - let url = '' - if (values.selectedType === 'postgres') { - url = `pg-functions://postgres/${values.postgresValues.schema}/${values.postgresValues.functionName}` - } else { - url = values.httpsValues.url - } - - const payload = { - [enabledLabel]: values.enabled, - [uriLabel]: url, - [secretsLabel]: values.selectedType === 'https' ? values.httpsValues.secret : null, - } - - updateAuthConfig( - { projectRef: projectRef!, config: payload }, - { - onSuccess: () => { - toast.success(`Successfully created ${values.hookType}.`) - if (statements.length > 0) { - executeSql({ - projectRef, - connectionString: project.connectionString, - sql: statements.join('\n'), - }) - } - onClose() - }, - onError: (error) => { - toast.error(`Failed to create hook: ${error.message}`) - onClose() - }, - } - ) - } - return ( onClose()}> @@ -492,16 +489,16 @@ export const CreateHookSheet = ({ )} - diff --git a/apps/studio/components/interfaces/Auth/Hooks/HookCard.tsx b/apps/studio/components/interfaces/Auth/Hooks/HookCard.tsx index 38e78f349cc..9850a9a51da 100644 --- a/apps/studio/components/interfaces/Auth/Hooks/HookCard.tsx +++ b/apps/studio/components/interfaces/Auth/Hooks/HookCard.tsx @@ -1,18 +1,20 @@ +import { PermissionAction } from '@supabase/shared-types/out/constants' import { Check, Webhook } from 'lucide-react' import { Badge, Input } from 'ui' import { ButtonTooltip } from 'components/ui/ButtonTooltip' +import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { copyToClipboard } from 'lib/helpers' import { Hook } from './hooks.constants' interface HookCardProps { hook: Hook - canUpdateConfig: boolean - onToggle: (enabled: boolean) => void onSelect: () => void } -export const HookCard = ({ hook, canUpdateConfig, onToggle, onSelect }: HookCardProps) => { +export const HookCard = ({ hook, onSelect }: HookCardProps) => { + const canUpdateAuthHook = useCheckPermissions(PermissionAction.AUTH_EXECUTE, '*') + return (
@@ -93,7 +95,7 @@ export const HookCard = ({ hook, canUpdateConfig, onToggle, onSelect }: HookCard
onSelect()} tooltip={{ content: { diff --git a/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx b/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx index 86e4149705d..37c469af4ac 100644 --- a/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx +++ b/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx @@ -1,23 +1,21 @@ -import { PermissionAction } from '@supabase/shared-types/out/constants' import { useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import AlertError from 'components/ui/AlertError' +import CodeEditor from 'components/ui/CodeEditor/CodeEditor' import { FormHeader } from 'components/ui/Forms/FormHeader' import { useAuthConfigQuery } from 'data/auth/auth-config-query' -import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation' -import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import { useAuthHooksUpdateMutation } from 'data/auth/auth-hooks-update-mutation' +import { executeSql } from 'data/sql/execute-sql-query' +import { cn } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { AddHookDropdown } from './AddHookDropdown' import { CreateHookSheet } from './CreateHookSheet' import { HookCard } from './HookCard' import { HOOKS_DEFINITIONS, HOOK_DEFINITION_TITLE, Hook } from './hooks.constants' import { extractMethod, getRevokePermissionStatements, isValidHook } from './hooks.utils' -import { executeSql } from 'data/sql/execute-sql-query' -import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import CodeEditor from 'components/ui/CodeEditor/CodeEditor' -import { cn } from 'ui' export const HooksListing = () => { const { ref: projectRef } = useParams() @@ -27,8 +25,27 @@ export const HooksListing = () => { const [selectedHook, setSelectedHook] = useState(null) const [selectedHookForDeletion, setSelectedHookForDeletion] = useState(null) - const { mutateAsync: updateAuthConfig } = useAuthConfigUpdateMutation() - const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue') + const { mutate: updateAuthHooks, isLoading: isDeletingAuthHook } = useAuthHooksUpdateMutation({ + onSuccess: async () => { + if (!selectedHookForDeletion) return + + const { method } = selectedHookForDeletion + if (method.type === 'postgres') { + const revokeStatements = getRevokePermissionStatements(method.schema, method.functionName) + await executeSql({ + projectRef, + connectionString: project!.connectionString, + sql: revokeStatements.join('\n'), + }) + } + toast.success(`${selectedHookForDeletion.title} has been deleted.`) + setSelectedHookForDeletion(null) + setSelectedHook(null) + }, + onError: (error) => { + toast.error(`Failed to delete hook: ${error.message}`) + }, + }) const hooks: Hook[] = HOOKS_DEFINITIONS.map((definition) => { return { @@ -78,16 +95,7 @@ export const HooksListing = () => { - updateAuthConfig({ - projectRef: projectRef!, - config: { [hook.enabledKey]: enabled }, - }) - } - onSelect={() => { - setSelectedHook(hook.title) - }} + onSelect={() => setSelectedHook(hook.title)} /> ) })} @@ -98,9 +106,7 @@ export const HooksListing = () => { visible={!!selectedHook} onDelete={() => { const hook = hooks.find((h) => h.title === selectedHook) - if (hook) { - setSelectedHookForDeletion(hook) - } + if (hook) setSelectedHookForDeletion(hook) }} onClose={() => setSelectedHook(null)} authConfig={authConfig!} @@ -110,16 +116,14 @@ export const HooksListing = () => { visible={!!selectedHookForDeletion} size="large" variant="destructive" - title="Confirm to delete" + loading={isDeletingAuthHook} + title={`Confirm to delete ${selectedHookForDeletion?.title}`} confirmLabel="Delete" confirmLabelLoading="Deleting" onCancel={() => setSelectedHookForDeletion(null)} - onConfirm={async () => { - if (!selectedHookForDeletion) { - return - } - - await updateAuthConfig({ + onConfirm={() => { + if (!selectedHookForDeletion) return + updateAuthHooks({ projectRef: projectRef!, config: { [selectedHookForDeletion.enabledKey]: false, @@ -127,35 +131,20 @@ export const HooksListing = () => { [selectedHookForDeletion.secretsKey]: null, }, }) - - const { method } = selectedHookForDeletion - - if (method.type === 'postgres') { - const revokeStatements = getRevokePermissionStatements( - method.schema, - method.functionName - ) - await executeSql({ - projectRef, - connectionString: project!.connectionString, - sql: revokeStatements.join('\n'), - }) - } - toast.success(`${selectedHookForDeletion.title} has been deleted.`) - setSelectedHookForDeletion(null) - setSelectedHook(null) }} >
-

- {`Are you sure you want to delete the ${selectedHookForDeletion?.title}?`} +

+ Are you sure you want to delete the {selectedHookForDeletion?.title}?

{selectedHookForDeletion?.method.type === 'postgres' && ( <> -

- {`The following statements will be executed on the ${selectedHookForDeletion?.method.schema}.${selectedHookForDeletion?.method.functionName} function:`} +

+ The following statements will be executed on the{' '} + {selectedHookForDeletion?.method.schema}. + {selectedHookForDeletion?.method.functionName} function:

-
+
{ const [showCreateSecret, setShowCreateSecret] = useState(false) const [selectedSecret, setSelectedSecret] = useState() - const canReadSecrets = useCheckPermissions(PermissionAction.FUNCTIONS_READ, '*') - const canUpdateSecrets = useCheckPermissions(PermissionAction.FUNCTIONS_WRITE, '*') + const canReadSecrets = useCheckPermissions(PermissionAction.SECRETS_READ, '*') + const canUpdateSecrets = useCheckPermissions(PermissionAction.SECRETS_WRITE, '*') const { data, error, isLoading, isSuccess, isError } = useSecretsQuery({ projectRef: projectRef, diff --git a/apps/studio/data/auth/auth-hooks-update-mutation.ts b/apps/studio/data/auth/auth-hooks-update-mutation.ts new file mode 100644 index 00000000000..8b8ebecffe6 --- /dev/null +++ b/apps/studio/data/auth/auth-hooks-update-mutation.ts @@ -0,0 +1,54 @@ +import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { toast } from 'sonner' + +import type { components } from 'data/api' +import { handleError, patch } from 'data/fetchers' +import type { ResponseError } from 'types' +import { authKeys } from './keys' + +export type AuthHooksUpdateVariables = { + projectRef: string + config: components['schemas']['UpdateGoTrueConfigHooksBody'] +} + +export async function updateAuthHooks({ projectRef, config }: AuthHooksUpdateVariables) { + const { data, error } = await patch('/platform/auth/{ref}/config/hooks', { + params: { path: { ref: projectRef } }, + body: config, + }) + + if (error) handleError(error) + return data +} + +type AuthHooksUpdateData = Awaited> + +export const useAuthHooksUpdateMutation = ({ + onSuccess, + onError, + ...options +}: Omit< + UseMutationOptions, + 'mutationFn' +> = {}) => { + const queryClient = useQueryClient() + + return useMutation( + (vars) => updateAuthHooks(vars), + { + async onSuccess(data, variables, context) { + const { projectRef } = variables + await queryClient.invalidateQueries(authKeys.authConfig(projectRef)) + await onSuccess?.(data, variables, context) + }, + async onError(data, variables, context) { + if (onError === undefined) { + toast.error(`Failed to update auth hooks: ${data.message}`) + } else { + onError(data, variables, context) + } + }, + ...options, + } + ) +} diff --git a/apps/studio/package.json b/apps/studio/package.json index 55ad9b69b3d..6131743e9b8 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -40,7 +40,7 @@ "@supabase/auth-js": "2.64.2", "@supabase/pg-meta": "*", "@supabase/realtime-js": "2.10.2", - "@supabase/shared-types": "0.1.70", + "@supabase/shared-types": "0.1.73", "@supabase/supabase-js": "^2.44.3", "@tanstack/react-query": "4.35.7", "@tanstack/react-query-devtools": "4.35.7", diff --git a/package-lock.json b/package-lock.json index 884657ab1ac..82c222e368b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1826,7 +1826,7 @@ "@supabase/auth-js": "2.64.2", "@supabase/pg-meta": "*", "@supabase/realtime-js": "2.10.2", - "@supabase/shared-types": "0.1.70", + "@supabase/shared-types": "0.1.73", "@supabase/supabase-js": "^2.44.3", "@tanstack/react-query": "4.35.7", "@tanstack/react-query-devtools": "4.35.7", @@ -14739,9 +14739,9 @@ } }, "node_modules/@supabase/shared-types": { - "version": "0.1.70", - "resolved": "https://registry.npmjs.org/@supabase/shared-types/-/shared-types-0.1.70.tgz", - "integrity": "sha512-Z/JBbISlxMcOjFcomZdB5AGKrQdTy/dy3HQ8EpHx3xKz1yktbUDrzVcEFUKidRPrQu1GAt9JSW6qBsBlXHcyLA==" + "version": "0.1.73", + "resolved": "https://registry.npmjs.org/@supabase/shared-types/-/shared-types-0.1.73.tgz", + "integrity": "sha512-5BhGYrJ/ICBlIWdAZL3lRD2w6ZUAYvjpulvIkHfVKNcXpF3LpZ+2ONRDkm0B8dlWp+ZE1bm7DbFgJvoW+AT3XA==" }, "node_modules/@supabase/sql-to-rest": { "version": "0.1.6", diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index 15d57c796ef..3a85142fd88 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -101,6 +101,10 @@ export interface paths { /** Updates GoTrue config */ patch: operations['GoTrueConfigController_updateGoTrueConfig'] } + '/platform/auth/{ref}/config/hooks': { + /** Updates GoTrue config hooks */ + patch: operations['GoTrueConfigController_updateGoTrueConfigHooks'] + } '/platform/auth/{ref}/invite': { /** Sends an invite to the given email */ post: operations['AuthInviteController_sendInvite'] @@ -122,11 +126,25 @@ export interface paths { get: operations['TemplateController_getTemplate'] } '/platform/auth/{ref}/users': { - /** Gets users */ + /** + * Gets users + * @deprecated + */ get: operations['UsersController_getUsers'] - /** Delete user with given ID */ + /** Creates user */ + post: operations['UsersController_createUser'] + /** + * Delete user with given ID + * @deprecated + */ delete: operations['UsersController_deleteUser'] } + '/platform/auth/{ref}/users/{id}': { + /** Delete user with given ID */ + delete: operations['UsersController_deleteUserById'] + /** Updates user with given ID */ + patch: operations['UsersController_updateUserById'] + } '/platform/auth/{ref}/users/{id}/factors': { /** Delete all factors associated to a user */ delete: operations['FactorsController_deleteFactors'] @@ -1290,6 +1308,10 @@ export interface paths { /** Updates GoTrue config */ patch: operations['GoTrueConfigController_updateGoTrueConfig'] } + '/v0/auth/{ref}/config/hooks': { + /** Updates GoTrue config hooks */ + patch: operations['GoTrueConfigController_updateGoTrueConfigHooks'] + } '/v0/auth/{ref}/invite': { /** Sends an invite to the given email */ post: operations['AuthInviteController_sendInvite'] @@ -1311,11 +1333,25 @@ export interface paths { get: operations['TemplateController_getTemplate'] } '/v0/auth/{ref}/users': { - /** Gets users */ + /** + * Gets users + * @deprecated + */ get: operations['UsersController_getUsers'] - /** Delete user with given ID */ + /** Creates user */ + post: operations['UsersController_createUser'] + /** + * Delete user with given ID + * @deprecated + */ delete: operations['UsersController_deleteUser'] } + '/v0/auth/{ref}/users/{id}': { + /** Delete user with given ID */ + delete: operations['UsersController_deleteUserById'] + /** Updates user with given ID */ + patch: operations['UsersController_updateUserById'] + } '/v0/auth/{ref}/users/{id}/factors': { /** Delete all factors associated to a user */ delete: operations['FactorsController_deleteFactors'] @@ -3026,6 +3062,11 @@ export interface components { table: string table_id?: number } + CreateUserBody: { + email: string + email_confirm: boolean + password: string + } CreateUserContentFolderResponse: { id: string name: string @@ -3033,6 +3074,43 @@ export interface components { parent_id?: string | null project_id: number } + CreateUserReponse: { + aud?: string + banned_until?: string + confirmation_sent_at?: string + confirmation_token?: string + confirmed_at?: string + created_at?: string + deleted_at?: string + email?: string + email_change?: string + email_change_confirm_status?: number + email_change_sent_at?: string + email_change_token_current?: string + email_change_token_new?: string + email_confirmed_at?: string + encrypted_password?: string + id?: string + instance_id?: string + invited_at?: string + is_anonymous?: boolean + is_sso_user?: boolean + is_super_admin?: boolean + last_sign_in_at?: string + phone?: string + phone_change?: string + phone_change_sent_at?: string + phone_change_token?: string + phone_confirmed_at?: string + raw_app_meta_data?: Record + raw_user_meta_data?: Record + reauthentication_sent_at?: string + reauthentication_token?: string + recovery_sent_at?: string + recovery_token?: string + role?: string + updated_at?: string + } CreateVercelConnectionResponse: { env_sync_error?: components['schemas']['SyncVercelEnvError'] id: string @@ -6202,6 +6280,23 @@ export interface components { SMTP_USER?: string URI_ALLOW_LIST?: string } + UpdateGoTrueConfigHooksBody: { + HOOK_CUSTOM_ACCESS_TOKEN_ENABLED?: boolean + HOOK_CUSTOM_ACCESS_TOKEN_SECRETS?: string + HOOK_CUSTOM_ACCESS_TOKEN_URI?: string + HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED?: boolean + HOOK_MFA_VERIFICATION_ATTEMPT_SECRETS?: string + HOOK_MFA_VERIFICATION_ATTEMPT_URI?: string + HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED?: boolean + HOOK_PASSWORD_VERIFICATION_ATTEMPT_SECRETS?: string + HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI?: string + HOOK_SEND_EMAIL_ENABLED?: boolean + HOOK_SEND_EMAIL_SECRETS?: string + HOOK_SEND_EMAIL_URI?: string + HOOK_SEND_SMS_ENABLED?: boolean + HOOK_SEND_SMS_SECRETS?: string + HOOK_SEND_SMS_URI?: string + } UpdateMemberBody: { role_id: number } @@ -6420,6 +6515,46 @@ export interface components { table?: string table_id?: number } + UpdateUserBody: { + ban_duration?: string + } + UpdateUserReponse: { + aud?: string + banned_until?: string + confirmation_sent_at?: string + confirmation_token?: string + confirmed_at?: string + created_at?: string + deleted_at?: string + email?: string + email_change?: string + email_change_confirm_status?: number + email_change_sent_at?: string + email_change_token_current?: string + email_change_token_new?: string + email_confirmed_at?: string + encrypted_password?: string + id?: string + instance_id?: string + invited_at?: string + is_anonymous?: boolean + is_sso_user?: boolean + is_super_admin?: boolean + last_sign_in_at?: string + phone?: string + phone_change?: string + phone_change_sent_at?: string + phone_change_token?: string + phone_confirmed_at?: string + raw_app_meta_data?: Record + raw_user_meta_data?: Record + reauthentication_sent_at?: string + reauthentication_token?: string + recovery_sent_at?: string + recovery_token?: string + role?: string + updated_at?: string + } UpdateVercelConnectionsBody: { env_sync_targets?: ('production' | 'preview' | 'development')[] public_env_var_prefix?: string @@ -7140,6 +7275,34 @@ export interface operations { } } } + /** Updates GoTrue config hooks */ + GoTrueConfigController_updateGoTrueConfigHooks: { + parameters: { + path: { + /** @description Project ref */ + ref: string + } + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateGoTrueConfigHooksBody'] + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['GoTrueConfigResponse'] + } + } + 403: { + content: never + } + /** @description Failed to update GoTrue config hooks */ + 500: { + content: never + } + } + } /** Sends an invite to the given email */ AuthInviteController_sendInvite: { parameters: { @@ -7278,7 +7441,10 @@ export interface operations { } } } - /** Gets users */ + /** + * Gets users + * @deprecated + */ UsersController_getUsers: { parameters: { query: { @@ -7307,7 +7473,38 @@ export interface operations { } } } - /** Delete user with given ID */ + /** Creates user */ + UsersController_createUser: { + parameters: { + path: { + /** @description Project ref */ + ref: string + } + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateUserBody'] + } + } + responses: { + 201: { + content: { + 'application/json': components['schemas']['CreateUserReponse'] + } + } + 403: { + content: never + } + /** @description Failed to create user */ + 500: { + content: never + } + } + } + /** + * Delete user with given ID + * @deprecated + */ UsersController_deleteUser: { parameters: { path: { @@ -7335,6 +7532,57 @@ export interface operations { } } } + /** Delete user with given ID */ + UsersController_deleteUserById: { + parameters: { + path: { + /** @description Project ref */ + ref: string + id: string + } + } + responses: { + 200: { + content: never + } + 403: { + content: never + } + /** @description Failed to delete user */ + 500: { + content: never + } + } + } + /** Updates user with given ID */ + UsersController_updateUserById: { + parameters: { + path: { + /** @description Project ref */ + ref: string + id: string + } + } + requestBody: { + content: { + 'application/json': components['schemas']['UpdateUserBody'] + } + } + responses: { + 200: { + content: { + 'application/json': components['schemas']['UpdateUserReponse'] + } + } + 403: { + content: never + } + /** @description Failed to update user with given ID */ + 500: { + content: never + } + } + } /** Delete all factors associated to a user */ FactorsController_deleteFactors: { parameters: { @@ -12175,6 +12423,9 @@ export interface operations { 'application/json': components['schemas']['UpdateSecretsResponse'] } } + 403: { + content: never + } /** @description Failed to update project's secrets config */ 500: { content: never