Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/supabase

src/update-user.ts

106 lines · 3.5 KB · TypeScript
import { projectAuth } from './setup.ts'
import { assertMutationAllowed, readMutationFlags } from './safety.ts'
import { asLive, projectRequest } from './client.ts'
import { summarizeAuthUser } from './list-users.ts'
import {
	isRecord,
	optionalBoolean,
	optionalString,
	requireString,
	type DryRunResult,
	type JsonRecord,
	type SupabaseAuthInput,
} from './types.ts'

export type UpdateUserInput = SupabaseAuthInput & {
	userId: string
	email?: string
	phone?: string
	password?: string
	emailConfirm?: boolean
	phoneConfirm?: boolean
	banDuration?: string
	userMetadata?: JsonRecord
	appMetadata?: JsonRecord
	dryRun?: boolean
	confirm?: boolean
}

/**
 * Update an Auth user. Requires `confirm: true`, or use `dryRun: true`.
 * @example
 * import updateUser from 'kody:@kody/supabase/update-user'
 * const preview = await updateUser({
 *   projectRef: 'abcdefghijklmnop',
 *   userId: '00000000-0000-0000-0000-000000000000',
 *   banDuration: '24h',
 *   dryRun: true,
 * })
 */
export async function updateUser(input: UpdateUserInput) {
	const userId = requireString(input.userId, 'userId')
	const flags = readMutationFlags(input)
	const body: JsonRecord = {
		email: optionalString(input.email, 'email'),
		phone: optionalString(input.phone, 'phone'),
		password: optionalString(input.password, 'password'),
		email_confirm: optionalBoolean(input.emailConfirm, 'emailConfirm'),
		phone_confirm: optionalBoolean(input.phoneConfirm, 'phoneConfirm'),
		ban_duration: optionalString(input.banDuration, 'banDuration'),
		user_metadata: input.userMetadata,
		app_metadata: input.appMetadata,
	}
	const previewBody = { ...body, password: body.password ? '[redacted]' : undefined }
	const allowed = assertMutationAllowed(flags, 'update-user')
	const path = `/auth/v1/admin/users/${encodeURIComponent(userId)}`
	if (allowed.dryRun) {
		const preview: DryRunResult = {
			dryRun: true,
			method: 'PUT',
			path,
			body: previewBody,
		}
		return preview
	}
	const live = asLive<{ data: unknown }>(
		await projectRequest({
			auth: projectAuth(input),
			method: 'PUT',
			path,
			body,
		}),
	)
	return summarizeAuthUser(live.data, true)
}

/**
 * Update an Auth user. Requires `confirm: true`, or use `dryRun: true`.
 * @example
 * import updateUser from 'kody:@kody/supabase/update-user'
 * const preview = await updateUser({ projectRef: 'abcdefghijklmnop', userId: '00000000-0000-0000-0000-000000000000', dryRun: true })
 */
export default async function updateUserEntrypoint(
	params: Partial<UpdateUserInput> & Record<string, unknown> = {},
) {
	return await updateUser({
		account: optionalString(params.account, 'account'),
		secretName: optionalString(params.secretName, 'secretName'),
		serviceRoleSecretName: optionalString(
			params.serviceRoleSecretName,
			'serviceRoleSecretName',
		),
		projectRef: optionalString(params.projectRef, 'projectRef'),
		projectUrl: optionalString(params.projectUrl, 'projectUrl'),
		userId: requireString(params.userId ?? params.id, 'userId'),
		email: optionalString(params.email, 'email'),
		phone: optionalString(params.phone, 'phone'),
		password: optionalString(params.password, 'password'),
		emailConfirm: optionalBoolean(params.emailConfirm, 'emailConfirm'),
		phoneConfirm: optionalBoolean(params.phoneConfirm, 'phoneConfirm'),
		banDuration: optionalString(params.banDuration, 'banDuration'),
		userMetadata: isRecord(params.userMetadata) ? params.userMetadata : undefined,
		appMetadata: isRecord(params.appMetadata) ? params.appMetadata : undefined,
		dryRun: optionalBoolean(params.dryRun, 'dryRun'),
		confirm: optionalBoolean(params.confirm, 'confirm'),
	})
}