import { projectAuth } from './setup.ts'
import { assertMutationAllowed, readMutationFlags } from './safety.ts'
import { projectRequest } from './client.ts'
import {
isReadMethod,
isRecord,
normalizeHttpMethod,
optionalBoolean,
optionalString,
requireString,
type HttpMethod,
type Json,
type SupabaseAuthInput,
} from './types.ts'
export type ProjectRequestInput = SupabaseAuthInput & {
path: string
method?: HttpMethod
query?: Record<string, string | number | boolean | undefined>
headers?: Record<string, string>
body?: Json
dryRun?: boolean
confirm?: boolean
}
/**
* Call a project API path (Auth, PostgREST, Storage, or another /.../v1 route).
* Prefer named helpers. Mutating methods require `dryRun: true` or `confirm: true`.
* @example
* import request from 'kody:@kody/supabase/request'
* const result = await request({
* projectRef: 'abcdefghijklmnop',
* path: '/rest/v1/items',
* query: { select: 'id,name', limit: 5 },
* })
*/
export async function request(input: ProjectRequestInput) {
const path = requireString(input.path, 'path')
if (!path.startsWith('/')) {
throw new Error('path must start with "/".')
}
const method = normalizeHttpMethod(input.method, 'GET')
if (!isReadMethod(method)) {
assertMutationAllowed(readMutationFlags(input), `request ${method}`)
}
return await projectRequest({
auth: projectAuth(input),
method,
path,
query: input.query,
headers: input.headers,
body: input.body,
dryRun: input.dryRun === true,
})
}
/**
* Call a project API path. Prefer named helpers.
* Mutating methods require `dryRun: true` or `confirm: true`.
* @example
* import request from 'kody:@kody/supabase/request'
* const result = await request({ projectRef: 'abcdefghijklmnop', path: '/rest/v1/items?select=id' })
*/
export default async function requestEntrypoint(
params: Partial<ProjectRequestInput> & Record<string, unknown> = {},
) {
return await request({
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'),
path: requireString(params.path, 'path'),
method: normalizeHttpMethod(params.method, 'GET'),
query: isRecord(params.query)
? (params.query as Record<string, string | number | boolean | undefined>)
: undefined,
headers: isRecord(params.headers)
? Object.fromEntries(
Object.entries(params.headers).filter(
(entry): entry is [string, string] => typeof entry[1] === 'string',
),
)
: undefined,
body: params.body as Json | undefined,
dryRun: optionalBoolean(params.dryRun, 'dryRun'),
confirm: optionalBoolean(params.confirm, 'confirm'),
})
}