epix-sdk
v0.2.2
Published
TypeScript client for EpixDB — self-hosted Postgres management
Downloads
27
Maintainers
Readme
epix-sdk
TypeScript client for EpixDB — self-hosted Postgres management.
Install
npm install epix-sdkUsage
import { EpixDB } from 'epix-sdk'
const db = new EpixDB({
url: 'https://api.r6mm.xyz',
database: 'myproject',
})
// Select with filters
const { data, error } = await db
.from('users')
.select()
.gt('elo', 1500)
.order('elo', { ascending: false })
.limit(10)
// Select specific columns
const { data, error } = await db
.from('users')
.select('id', 'name', 'elo')
// Single row
const { data, error } = await db
.from('users')
.select()
.eq('id', 5)
.single()
// Insert
const { data, error } = await db
.from('users')
.insert({ name: 'Chris', elo: 1800 })
// Bulk insert
const { data, error } = await db
.from('users')
.insert([
{ name: 'Player1', elo: 1200 },
{ name: 'Player2', elo: 1400 },
])
// Update
const { data, error } = await db
.from('users')
.update({ elo: 1900 })
.eq('id', 5)
// Delete
const { data, error } = await db
.from('users')
.delete()
.eq('id', 5)
// Raw SQL
const { data, error } = await db.query('SELECT * FROM users')
// Database management
const { data } = await db.databases.list()
await db.databases.create('newdb')
await db.databases.drop('olddb')
// Switch database
const other = db.useDatabase('otherproject')Filters
.eq(column, value) // equals
.neq(column, value) // not equals
.gt(column, value) // greater than
.gte(column, value) // greater than or equal
.lt(column, value) // less than
.lte(column, value) // less than or equal
.like(column, pattern) // LIKE
.ilike(column, pattern) // case-insensitive LIKE
.in(column, values[]) // IN
.is(column, value) // IS (null/true/false)Negated Filters
Prefix any filter with .not to negate it:
// Where status is NOT 'banned'
const { data } = await db
.from('users')
.select()
.not.eq('status', 'banned')
// Where rank is NOT in the list
const { data } = await db
.from('users')
.select()
.not.in('rank', ['Bronze', 'Silver'])Filter Groups
Use .or() and .and() for grouped conditions:
// Where rank is Diamond OR Champion
const { data } = await db
.from('users')
.select()
.or((q) => q.eq('rank', 'Diamond').eq('rank', 'Champion'))
// Combine with top-level filters
const { data } = await db
.from('users')
.select()
.eq('status', 'active')
.or((q) => q.eq('rank', 'Diamond').eq('rank', 'Champion'))Modifiers
.order(column, { ascending: false }) // supports multiple calls
.limit(count)
.offset(count)
.range(from, to) // e.g. .range(0, 9) for first 10 rows
.paginate(page, pageSize) // e.g. .paginate(2, 25) for page 2
.single() // expect exactly one row
.maybeSingle() // expect zero or one rowMultiple Order Columns
const { data } = await db
.from('users')
.select()
.order('rank')
.order('elo', { ascending: false })Mutations
Upsert
Insert or update on conflict:
const { data } = await db
.from('users')
.upsert(
{ id: 1, name: 'Chris', elo: 2000 },
{ onConflict: ['id'] }
)Returning
Get affected rows back from insert, update, or delete:
const { data } = await db
.from('users')
.insert({ name: 'Chris', elo: 1800 })
.returning('id', 'name')
// Return all columns
const { data } = await db
.from('users')
.update({ elo: 2000 })
.eq('id', 1)
.returning()Safety Guard
Update and delete without filters are blocked by default to prevent accidental table-wide operations. Use .unfiltered() to explicitly allow it:
// This returns a validation error
const { error } = await db.from('users').delete()
// This works
const { data } = await db.from('users').delete().unfiltered()Count
const { data: count } = await db
.from('users')
.count()
.eq('rank', 'Diamond')Error Handling
Every method returns { data, error } by default:
const { data, error } = await db.from('users').select()
if (error) {
console.error(error.message)
} else {
console.log(data)
}Throw on Error
Use .throwOnError() to throw instead of returning errors:
import { EpixRequestError } from 'epix-sdk'
try {
const { data } = await db
.from('users')
.select()
.eq('id', 999)
.single()
.throwOnError()
} catch (e) {
if (e instanceof EpixRequestError) {
console.error(e.message, e.status, e.code)
}
}Health Check
const { ok, latency } = await db.ping()
console.log(`Server ${ok ? 'up' : 'down'}, ${latency}ms`)Retry
Configure automatic retries for transient failures (5xx, 408, 429, network errors):
const db = new EpixDB({
url: 'https://api.r6mm.xyz',
database: 'myproject',
retry: {
maxRetries: 3, // default: 0 (no retries)
baseDelay: 300, // default: 300ms
maxDelay: 5000, // default: 5000ms
},
})Uses exponential backoff. Non-retryable errors (400, 401, 403, 404, etc.) fail immediately.
TypeScript
Use generics for typed column names and autocomplete:
interface User {
id: number
name: string
email: string
elo: number
}
const { data } = await db
.from<User>('users')
.select('id', 'name') // autocompletes column names
.eq('elo', 1500) // type-checked column
.order('name')
const { data } = await db
.from<User>('users')
.insert({ name: 'Chris', elo: 1800 }) // type-checked fieldsUUID Handling
UUID columns returned as byte arrays are automatically converted to standard UUID strings (0a7865d6-13d7-46ec-a738-e59790245292). No configuration needed.
