Types

Core

DatrixEntry

interface DatrixEntry {
  id:        number
  createdAt: Date
  updatedAt: Date
}

Base type every record extends. Fields are injected automatically and cannot be written manually.


IDatrix

interface IDatrix extends IRawCrud {
  // CRUD (with plugin hooks) — same as IRawCrud methods
  findOne(model, where, options?):          Promise<T | null>
  findById(model, id, options?):            Promise<T | null>
  findMany(model, options?):               Promise<T[]>
  count(model, where?):                    Promise<number>
  create(model, data, options?):           Promise<T>
  createMany(model, data[], options?):     Promise<T[]>
  update(model, id, data, options?):       Promise<T>
  updateMany(model, where, data, options?): Promise<T[]>
  delete(model, id, options?):             Promise<T>
  deleteMany(model, where, options?):      Promise<T[]>

  // Raw CRUD (bypasses plugin hooks)
  readonly raw: IRawCrud

  // Schema access
  getSchemas():              ISchemaRegistry
  getSchema(name):           SchemaDefinition | undefined
  hasSchema(name):           boolean
  getAllSchemas():            readonly SchemaDefinition[]

  // Plugin access
  getPlugins():              readonly DatrixPlugin[]
  getPlugin(name):           DatrixPlugin | null
  hasPlugin(name):           boolean

  // Lifecycle
  isInitialized():           boolean
  getConfig():               DatrixConfig
  getAdapter<T>():           T
  shutdown():                Promise<void>
}

Main Datrix instance interface. Returned by the function created with defineConfig(). All CRUD methods run through plugin hooks — use .raw for direct database access without hooks.


RawCrudOptions

interface RawCrudOptions<T> {
  select?:      SelectClause<T>
  populate?:    PopulateClause<T>
  noReturning?: boolean
}

Options for single-record operations (findOne, findById, create, update, delete).


RawFindManyOptions

interface RawFindManyOptions<T> extends RawCrudOptions<T> {
  where?:   WhereClause<T>
  orderBy?: OrderByClause<T>
  limit?:   number
  offset?:  number
}

Options for findMany. Extends RawCrudOptions with filtering and pagination.


Query

WhereClause

type WhereClause<T> =
  | { [K in keyof T]?: ComparisonOperators<T[K]> | T[K] }
  | { $and: WhereClause<T>[] }
  | { $or:  WhereClause<T>[] }
  | { $not: WhereClause<T> }

Filter expression. Supports direct values, comparison operators ($eq, $gt, $in…), logical operators ($and, $or, $not), and nested relation conditions.


SelectClause

type SelectClause<T> =
  | (keyof T)[]
  | keyof T
  | "*"

Fields to return. Use "*" for all fields. Relation fields cannot appear here — use populate instead.


PopulateClause

type PopulateClause<T> =
  | true
  | "*"
  | string[]
  | { [relation: string]: true | PopulateOptions }

Relations to load alongside the main record. Supports true, "*", array of names, or object with per-relation options.


PopulateOptions

type PopulateOptions<T> = {
  select?:   SelectClause<T>
  where?:    WhereClause<T>
  populate?: PopulateClause<T>
  limit?:    number
  offset?:   number
  orderBy?:  OrderByClause<T>
}

Per-relation populate options. Used as the value in an object-form PopulateClause.


OrderByClause

type OrderByClause<T> =
  | { field: keyof T; direction: "asc" | "desc"; nulls?: "first" | "last" }[]
  | { [K in keyof T]?: "asc" | "desc" }
  | string[]

Sort order. Three formats: full object array, shorthand object, or string array ("-field" for desc).


Schema

SchemaDefinition

interface SchemaDefinition {
  name:        string
  fields:      Record<string, FieldDefinition>
  indexes?:    IndexDefinition[]
  hooks?:      LifecycleHooks
  timestamps?: boolean
  softDelete?: boolean
  tableName?:  string
  permission?: SchemaPermission
}

Defines a database table's structure, constraints, and access rules. Pass the result of defineSchema() to schemas[] in defineConfig().


FieldDefinition

type FieldDefinition =
  | StringField
  | NumberField
  | BooleanField
  | DateField
  | JsonField
  | EnumField
  | ArrayField
  | RelationField
  | FileField

Discriminated union of all field type interfaces. The type property on each determines which options are available.


StringField

interface StringField {
  type:          "string"
  required?:     boolean
  default?:      string
  unique?:       boolean
  minLength?:    number
  maxLength?:    number
  pattern?:      RegExp
  validator?:    (value: string) => true | string
  errorMessage?: string
  description?:  string
  permission?:   FieldPermission
}

String field definition. Use minLength/maxLength for length constraints, pattern for regex validation, validator for custom logic.


NumberField

interface NumberField {
  type:           "number"
  required?:      boolean
  default?:       number
  unique?:        boolean
  min?:           number
  max?:           number
  integer?:       boolean
  autoIncrement?: boolean
  validator?:     (value: number) => true | string
  description?:   string
  permission?:    FieldPermission
}

Number field definition. Set integer: true to disallow decimals. autoIncrement is typically only used for the primary key.


BooleanField

interface BooleanField {
  type:         "boolean"
  required?:    boolean
  default?:     boolean
  description?: string
  permission?:  FieldPermission
}

Boolean field definition.


DateField

interface DateField {
  type:         "date"
  required?:    boolean
  default?:     Date
  min?:         Date
  max?:         Date
  description?: string
  permission?:  FieldPermission
}

Date field definition.


JsonField

interface JsonField {
  type:         "json"
  required?:    boolean
  default?:     Record<string, unknown>
  schema?:      Record<string, unknown>  // JSON schema validation
  description?: string
  permission?:  FieldPermission
}

JSON field definition. Stored as a JSON column. Optionally validated against a JSON schema.


EnumField

interface EnumField {
  type:         "enum"
  required?:    boolean
  default?:     string
  values:       readonly string[]  // allowed values
  description?: string
  permission?:  FieldPermission
}

Enum field definition. values defines the complete set of allowed string literals.


ArrayField

interface ArrayField {
  type:         "array"
  required?:    boolean
  items:        FieldDefinition  // type of each element
  minItems?:    number
  maxItems?:    number
  unique?:      boolean          // all items must be unique
  description?: string
  permission?:  FieldPermission
}

Array field definition. items defines the type of each element — can be any FieldDefinition including nested objects.


RelationField

interface RelationField {
  type:        "relation"
  required?:   boolean
  model:       string      // target schema name
  kind:        RelationKind
  foreignKey?: string      // defaults to fieldName + "Id"
  through?:    string      // join table for manyToMany
  onDelete?:   "cascade" | "setNull" | "restrict"
  onUpdate?:   "cascade" | "restrict"
  description?: string
  permission?:  FieldPermission
}

Relation field definition. kind determines the cardinality. For manyToMany, a junction table is auto-generated if through is omitted.


RelationKind

type RelationKind =
  | "hasOne"     // 1:1  — this model owns the FK on the other side
  | "hasMany"    // 1:N  — other model holds the FK
  | "belongsTo"  // N:1  — this model holds the FK
  | "manyToMany" // N:N  — junction table

Defines the cardinality of a relation field.


FileField

interface FileField {
  type:          "file"
  required?:     boolean
  allowedTypes?: string[]  // MIME types, e.g. ["image/png"]
  maxSize?:      number    // bytes
  multiple?:     boolean
  description?:  string
  permission?:   FieldPermission
}

File field definition. Requires the upload plugin to be configured.


IndexDefinition

interface IndexDefinition {
  name?:   string
  fields:  readonly string[]
  unique?: boolean
  type?:   "btree" | "hash" | "gist" | "gin"
}

Defines a database index on one or more fields. Pass to indexes[] in SchemaDefinition.


LifecycleHooks

interface LifecycleHooks<T extends DatrixEntry = DatrixEntry> {
  beforeCreate?: (
    query: QueryInsertObject<T>,
    ctx: QueryContext,
  ) => Promise<QueryInsertObject<T>> | QueryInsertObject<T>

  afterCreate?: (
    records: readonly T[],
    ctx: QueryContext,
  ) => Promise<readonly T[]> | readonly T[]

  beforeUpdate?: (
    query: QueryUpdateObject<T>,
    ctx: QueryContext,
  ) => Promise<QueryUpdateObject<T>> | QueryUpdateObject<T>

  afterUpdate?: (
    records: readonly T[],
    ctx: QueryContext,
  ) => Promise<readonly T[]> | readonly T[]

  beforeDelete?: (
    query: QueryDeleteObject<T>,
    ctx: QueryContext,
  ) => Promise<QueryDeleteObject<T>> | QueryDeleteObject<T>

  afterDelete?: (
    records: readonly T[],
    ctx: QueryContext,
  ) => Promise<void> | void

  beforeFind?: (
    query: QuerySelectObject<T>,
    ctx: QueryContext,
  ) => Promise<QuerySelectObject<T>> | QuerySelectObject<T>

  afterFind?: (
    records: readonly T[],
    ctx: QueryContext,
  ) => Promise<readonly T[]> | readonly T[]
}

Schema lifecycle hooks. Defined in the hooks field of SchemaDefinition. Before hooks receive the full query object and must return it. After hooks receive all affected records as an array. ctx.datrix gives access to the Datrix instance for additional queries.


Permissions

SchemaPermission

interface SchemaPermission {
  create?: PermissionValue
  read?:   PermissionValue
  update?: PermissionValue
  delete?: PermissionValue
}

Schema-level access control. Each action accepts true, false, a role array, a function, or a mixed array of roles and functions.

NOTE: Only enforced when using the @datrix/api package.


FieldPermission

interface FieldPermission {
  read?:  PermissionValue
  write?: PermissionValue
}

Field-level access control. read: if denied, field is stripped from the response. write: if denied, returns 403.

NOTE: Only enforced when using the @datrix/api package.


PermissionValue

type PermissionValue =
  | boolean
  | readonly string[]                    // role names
  | PermissionFn                         // (ctx) => boolean
  | readonly (string | PermissionFn)[]   // role OR function (OR logic)

Defines who can perform an action. true = everyone, false = nobody, string array = specific roles, function = custom logic.

NOTE: Only enforced when using the @datrix/api package.


PermissionFn

type PermissionFn = (ctx: PermissionContext) => boolean | Promise<boolean>

Custom permission function. Receives the full request context and returns true to allow, false to deny.

NOTE: Only enforced when using the @datrix/api package.


PermissionContext

interface PermissionContext {
  readonly user:    AuthUser | undefined
  readonly action:  PermissionAction
  readonly record?: DatrixEntry        // existing record (update/delete)
  readonly input?:  Partial<DatrixEntry> // incoming data (create/update)
  readonly id?:     number | null
}

Context passed to permission functions. user is undefined for unauthenticated requests.


Adapter

DatabaseAdapter

interface DatabaseAdapter<TConfig = object> {
  readonly name:   string
  readonly config: TConfig
  connect():                    Promise<void>
  disconnect():                 Promise<void>
  isConnected():                boolean
  beginTransaction():           Promise<Transaction>
  getTables():                  Promise<readonly string[]>
  tableExists(name: string):    Promise<boolean>
  executeQuery(query):          Promise<QueryResult>
  createTable(schema):          Promise<void>
  dropTable(name):              Promise<void>
  alterTable(name, ops):        Promise<void>
}

Interface all database adapters must implement. Passed as adapter in defineConfig().


Transaction

interface Transaction {
  readonly id: string
  commit():               Promise<void>
  rollback():             Promise<void>
  savepoint(name):        Promise<void>
  rollbackTo(name):       Promise<void>
  release(name):          Promise<void>
  executeQuery(query):    Promise<QueryResult>
  executeRawQuery(sql):   Promise<QueryResult>
  createTable(schema):    Promise<void>
  dropTable(name):        Promise<void>
  alterTable(name, ops):  Promise<void>
}

Wraps a database transaction. Supports query execution and schema operations atomically. Returned by DatabaseAdapter.beginTransaction().


Plugin

DatrixPlugin

interface DatrixPlugin<TOptions = Record<string, unknown>> {
  readonly name:    string
  readonly version: string
  readonly options: TOptions
  init(context: PluginContext):                          Promise<void>
  destroy():                                            Promise<void>
  getSchemas?():                                        Promise<SchemaDefinition[]>
  extendSchemas?(ctx: SchemaExtensionContext):           Promise<SchemaExtension[]>
  onBeforeQuery?<T>(query: QueryObject<T>, ctx: QueryContext): Promise<QueryObject<T>>
  onAfterQuery?<T>(result: T, ctx: QueryContext):        Promise<T>
}

Interface all Datrix plugins must implement.


PluginContext

interface PluginContext {
  readonly adapter: DatabaseAdapter
  readonly schemas: SchemaRegistry
  readonly config:  DatrixConfig
}

Context provided to a plugin's init() method. Gives access to the adapter, schema registry, and configuration.


QueryContext

interface QueryContext {
  readonly action:   QueryAction
  readonly datrix:    IDatrix
  readonly metadata: Record<string, unknown>
  user?:             AuthUser
}

Context passed to plugin hooks and schema lifecycle hooks. Gives access to the current action, the Datrix instance, shared metadata, and the authenticated user.


SchemaExtensionContext

interface SchemaExtensionContext {
  readonly schemas:  readonly SchemaDefinition[]
  extendAll(modifier):                         SchemaExtension[]
  extendWhere(predicate, modifier):            SchemaExtension[]
  extendByPattern(pattern, modifier):          SchemaExtension[]
}

Context passed to a plugin's extendSchemas() hook. Provides helpers to extend all or a subset of schemas.


SchemaExtension

interface SchemaExtension {
  readonly targetSchema:   string
  readonly fields?:        Record<string, FieldDefinition>
  readonly removeFields?:  string[]
  readonly modifyFields?:  Record<string, Partial<FieldDefinition>>
  readonly indexes?:       IndexDefinition[]
}

Describes fields and indexes to add, remove, or modify on an existing schema. Returned from extendSchemas().


Schema registry

SchemaRegistry

class SchemaRegistry {
  get(name: string):    SchemaDefinition | undefined
  has(name: string):    boolean
  getAll():             readonly SchemaDefinition[]
  getNames():           readonly string[]
  readonly size:        number
}

Registry that holds all registered schemas. Returned by getSchemas().


Migration

MigrationSession

class MigrationSession {
  tablesToCreate:  readonly SchemaDefinition[]
  ambiguous:       readonly AmbiguousChange[]
  hasAmbiguous:    boolean
  resolveAmbiguous(id: string, action: AmbiguousActionType): void
  getPlan():       MigrationPlan
  apply():         Promise<readonly MigrationExecutionResult[]>
}

Returned by beginMigrate(). Represents a diff session between current schemas and database state.


AmbiguousChange

interface AmbiguousChange {
  readonly id:          string   // e.g. "user.name->lastname"
  readonly description: string
  readonly options:     readonly AmbiguousActionType[]
}

A schema change that Datrix cannot resolve automatically — typically a field rename vs. drop+add. Must be resolved with MigrationSession.resolveAmbiguous() before applying.


AmbiguousActionType

type AmbiguousActionType =
  | "rename"  // treat as a rename operation
  | "drop"    // drop the old field and add the new one

Resolution for an ambiguous schema change. Passed to MigrationSession.resolveAmbiguous().


AlterOperation

type AlterOperation =
  | { type: "addColumn";     column: string; definition: FieldDefinition }
  | { type: "dropColumn";    column: string }
  | { type: "modifyColumn";  column: string; newDefinition: FieldDefinition }
  | { type: "renameColumn";  from: string; to: string }
  | { type: "addMetaField";  field: string; definition: FieldDefinition }
  | { type: "dropMetaField"; field: string }
  | { type: "modifyMetaField"; field: string; newDefinition: FieldDefinition }

Discriminated union of column-level DDL operations used in alterTable(). MetaField variants are for internal Datrix-managed columns.


Migration

interface Migration {
  readonly metadata:   MigrationMetadata
  readonly operations: readonly MigrationOperation[]
}

A single migration unit — metadata plus the list of DDL operations to execute.


MigrationMetadata

interface MigrationMetadata {
  readonly name:         string
  readonly version:      string
  readonly timestamp:    number
  readonly description?: string
  readonly author?:      string
}

Descriptive metadata attached to a migration. version is used to track which migrations have been applied.


MigrationOperation

type MigrationOperation =
  | { type: "createTable";  schema: SchemaDefinition }
  | { type: "dropTable";    tableName: string }
  | { type: "alterTable";   tableName: string; operations: AlterOperation[] }
  | { type: "createIndex";  tableName: string; index: IndexDefinition }
  | { type: "dropIndex";    tableName: string; indexName: string }
  | { type: "renameTable";  from: string; to: string }
  | { type: "raw";          sql: string; params?: unknown[] }
  | { type: "dataTransfer"; description: string }

Discriminated union of all DDL operations a migration can contain.


MigrationStatus

type MigrationStatus =
  | "pending"
  | "running"
  | "completed"
  | "failed"

Execution state of a migration.


MigrationPlan

interface MigrationPlan {
  readonly migrations: readonly Migration[]
  readonly target?:    string
}

The list of migrations to execute, as returned by MigrationSession.getPlan(). target is undefined when targeting the latest version.


MigrationExecutionResult

interface MigrationExecutionResult {
  readonly migration:     Migration
  readonly status:        MigrationStatus
  readonly executionTime: number
  readonly error?:        Error
  readonly warnings?:     string[]
}

Result of a single migration execution. status is one of 'pending' | 'running' | 'completed' | 'failed'.


Config

DatrixConfig

interface DatrixConfig {
  adapter:    DatabaseAdapter
  schemas:    SchemaDefinition[]
  plugins?:   DatrixPlugin[]
  migration?: MigrationConfig
  dev?:       DevConfig
}

Top-level configuration object passed to defineConfig().


MigrationConfig

interface MigrationConfig {
  auto?:      boolean  // run migrations on startup
  directory?: string   // default: "./migrations"
  modelName?: string   // tracking table name
}

Controls migration behavior. auto defaults to false in production.


DevConfig

interface DevConfig {
  logging?:         boolean  // detailed query logging
  validateQueries?: boolean  // validate queries before execution
  prettyErrors?:    boolean  // pretty-print errors with stack traces
}

Development mode options. All options default to false in production.


API

ApiConfig

interface ApiConfig<TRole extends string = string> {
  prefix?:           string       // route prefix — default: '/api'
  defaultPageSize?:  number       // default: 25
  maxPageSize?:      number       // default: 100
  maxPopulateDepth?: number       // default: 5
  autoRoutes?:       boolean      // auto-generate CRUD routes — default: true
  excludeSchemas?:   string[]     // schemas to exclude from auto-routes
  auth?:             AuthConfig<TRole>
  upload?:           IUpload
}

Configuration for ApiPlugin. Pass to new ApiPlugin({ ... }).


AuthConfig

interface AuthConfig<TRole extends string = string> {
  roles:              readonly TRole[]
  defaultRole:        TRole
  defaultPermission?: SchemaPermission
  jwt?:               JwtConfig
  session?:           SessionConfig
  password?:          PasswordConfig
  authSchemaName?:    string  // default: 'authentication'
  userSchema?: {
    name?:  string  // default: 'user'
    email?: string  // default: 'email'
  }
  endpoints?: {
    login?:           string   // default: '/auth/login'
    register?:        string   // default: '/auth/register'
    logout?:          string   // default: '/auth/logout'
    me?:              string   // default: '/auth/me'
    disableRegister?: boolean  // default: false
  }
}

Authentication configuration block inside ApiConfig. Enables JWT and/or session auth, RBAC roles, and password policy.


JwtConfig

interface JwtConfig {
  secret:     string                    // min 32 characters
  expiresIn?: string | number           // e.g. "7d", "1h" or seconds
  algorithm?: "HS256" | "HS512"        // default: "HS256"
  issuer?:    string                    // JWT iss claim
  audience?:  string                    // JWT aud claim
}

JWT signing options inside AuthConfig.


SessionConfig

interface SessionConfig {
  store?:       "memory" | SessionStore  // default: "memory"
  maxAge?:      number  // session lifetime in seconds — default: 86400
  checkPeriod?: number  // expired session cleanup interval — default: 3600
  prefix?:      string  // session key prefix for memory store — default: "sess:"
}

Session storage options inside AuthConfig. Pass a custom SessionStore instance for Redis, database, or any other backend.


PasswordConfig

interface PasswordConfig {
  iterations?: number  // PBKDF2 iterations — default: 100000
  keyLength?:  number  // derived key length in bytes — default: 64
  minLength?:  number  // minimum password length — default: 8
}

Password hashing policy inside AuthConfig.


SessionStore

interface SessionStore {
  get(sessionId: string):                    Promise<SessionData | undefined>
  set(sessionId: string, data: SessionData): Promise<void>
  delete(sessionId: string):                 Promise<void>
  cleanup():                                 Promise<number>
  clear():                                   Promise<void>
}

Interface for custom session backends. Implement this to use Redis, a database, or any other storage instead of the default in-memory store.


ParsedQuery

interface ParsedQuery<T extends DatrixEntry = DatrixRecord> {
  select?:   SelectClause<T>
  where?:    WhereClause<T>
  populate?: PopulateClause<T>
  orderBy?:  OrderByClause<T>
  page?:     number
  pageSize?: number
}

Typed query object accepted by queryToParams and parsed by the server. Client and server share the same shape.


Upload

UploadOptions

interface UploadOptions<TResolutions extends string = string> {
  provider:           StorageProvider
  modelName?:         string            // default: "media"
  maxSize?:           number            // max file size in bytes
  allowedMimeTypes?:  string[]          // supports wildcards, e.g. "image/*"
  format?:            ImageFormat       // convert all images to this format
  quality?:           number            // 1–100 — default: 80
  resolutions?:       Record<TResolutions, ResolutionConfig>
  permission?:        SchemaPermission
}

Options passed to new Upload({ ... }). Controls storage, validation, format conversion, and resolution variants.


ImageFormat

type ImageFormat = "webp" | "jpeg" | "png" | "avif"

Target format for image conversion. All uploaded images are converted to this format before storage.


ResolutionConfig

interface ResolutionConfig {
  width:   number
  height?: number   // omit to preserve aspect ratio
  fit?:    ResizeFit
}

Config for a single named resolution variant. height is optional — if omitted, aspect ratio is preserved.


ResizeFit

type ResizeFit =
  | "cover"    // crop to fill the box exactly
  | "contain"  // fit within the box, letterbox if needed
  | "fill"     // stretch to fill — ignores aspect ratio
  | "inside"   // resize so both dimensions fit inside the box
  | "outside"  // resize so one dimension fills the box

Sharp fit mode used when both width and height are set on a ResolutionConfig.


LocalProviderOptions

interface LocalProviderOptions {
  basePath:         string   // directory to write files into
  baseUrl:          string   // public URL prefix
  ensureDirectory?: boolean  // create basePath if missing — default: true
}

Options for LocalStorageProvider.


S3ProviderOptions

interface S3ProviderOptions {
  bucket:          string
  region:          string
  accessKeyId:     string
  secretAccessKey: string
  endpoint?:       string  // custom endpoint for R2 / MinIO
  pathPrefix?:     string  // optional key prefix
}

Options for S3StorageProvider. Compatible with AWS S3, Cloudflare R2, MinIO, and any S3-compatible storage.


StorageProvider

interface StorageProvider {
  readonly name: string
  upload(file: UploadFile):   Promise<UploadResult>
  delete(key: string):        Promise<void>
  getUrl(key: string):        string
  exists(key: string):        Promise<boolean>
}

Interface all storage backends must implement. Implement this to add a custom storage provider.


MediaEntry

interface MediaEntry<TResolutions extends string = string> extends DatrixEntry {
  filename:     string
  originalName: string
  mimeType:     string
  size:         number
  key:          string
  url:          string  // injected at response time, not stored in DB
  variants:     MediaVariants<TResolutions> | null
}

Shape of a media record. key is stored in the database — url is derived at response time via the configured provider.


MediaVariant

interface MediaVariant {
  key:      string
  url:      string  // injected at response time, not stored in DB
  width:    number
  height:   number
  size:     number
  mimeType: string
}

A single processed resolution variant. Available in MediaEntry.variants under the resolution name.