Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nickruigrok/baseflare/llms.txt

Use this file to discover all available pages before exploring further.

defineRules is a thin identity function that types a Rules object — it returns its argument unchanged. The real enforcement happens in the runtime, where evaluateRules is called before every database operation: before every get and query result is returned, before every insert, before every patch or replace, and before every delete. The model is deny by default: unless an explicit rule function returns true, the operation is blocked.

Signature

function defineRules<TRules extends Rules>(rules: TRules): TRules

Rules Type Structure

Rules is a two-level nested object:
type Rules = Record<string, TableRules>
The top-level key is a table name (matching a table in your schema). Each value is a TableRules object with optional read, insert, update, and delete keys. Missing operation keys default to false — the operation is denied.
interface TableRules {
  read?:   (input: ReadRuleInput)   => boolean | Promise<boolean>
  insert?: (input: InsertRuleInput) => boolean | Promise<boolean>
  update?: (input: UpdateRuleInput) => boolean | Promise<boolean>
  delete?: (input: DeleteRuleInput) => boolean | Promise<boolean>
}

Rule Operation Signatures

The input types use generics (TContext, TDocument, TValue) so that you can narrow them to your application’s specific types. In the Baseflare runtime, the ctx value is the live context object created for the surrounding function: a QueryCtx for read, and a MutationCtx for insert, update, and delete.

read

Called once per document when returning results from ctx.db.get() or ctx.db.query(). Documents for which the rule returns false are silently filtered out — they are invisible to the handler.
read: (input: ReadRuleInput) => boolean | Promise<boolean>

interface ReadRuleInput<TContext = unknown, TDocument = Record<string, unknown>> {
  ctx: TContext   // QueryCtx at runtime
  doc: TDocument  // the candidate document
}
input.ctx
unknown (QueryCtx at runtime)
The context from the surrounding function call. At runtime this is always a QueryCtx object, providing ctx.auth and ctx.db.
input.doc
Record<string, unknown>
The candidate document being evaluated. Includes all stored fields plus _id and _createdAt.

insert

Called before a document is written by ctx.db.insert(). Receives the validated field values that would be stored.
insert: (input: InsertRuleInput) => boolean | Promise<boolean>

interface InsertRuleInput<TContext = unknown, TValue = Record<string, unknown>> {
  ctx: TContext    // MutationCtx at runtime
  value: TValue   // validated data about to be inserted
}
input.ctx
unknown (MutationCtx at runtime)
The context from the surrounding mutation. At runtime this is a MutationCtx.
input.value
Record<string, unknown>
The validated document data about to be inserted (no _id yet).

update

Called before a document is modified by ctx.db.patch() or ctx.db.replace(). Receives both the existing document and the merged/replacement data.
update: (input: UpdateRuleInput) => boolean | Promise<boolean>

interface UpdateRuleInput<
  TContext = unknown,
  TDocument = Record<string, unknown>,
  TValue = Record<string, unknown>,
> {
  ctx: TContext           // MutationCtx at runtime
  existingDoc: TDocument // current stored document
  value: TValue          // proposed new document data
}
input.ctx
unknown (MutationCtx at runtime)
The context from the surrounding mutation.
input.existingDoc
Record<string, unknown>
The current document as stored in the database.
input.value
Record<string, unknown>
The proposed new document data after the patch or replace is applied.

delete

Called before a document is removed by ctx.db.delete().
delete: (input: DeleteRuleInput) => boolean | Promise<boolean>

interface DeleteRuleInput<TContext = unknown, TDocument = Record<string, unknown>> {
  ctx: TContext           // MutationCtx at runtime
  existingDoc: TDocument // document about to be deleted
}
input.ctx
unknown (MutationCtx at runtime)
The context from the surrounding mutation.
input.existingDoc
Record<string, unknown>
The document about to be deleted.

Full Example

import { defineRules } from 'baseflare/server'

export const rules = defineRules({
  todos: {
    read: async ({ ctx, doc }) =>
      doc.ownerId === (await ctx.auth.getUserIdentity()),

    insert: async ({ ctx, value }) =>
      value.ownerId === (await ctx.auth.getUserIdentity()),

    update: async ({ ctx, existingDoc }) =>
      existingDoc.ownerId === (await ctx.auth.getUserIdentity()),

    delete: async ({ ctx, existingDoc }) =>
      existingDoc.ownerId === (await ctx.auth.getUserIdentity()),
  },

  users: {
    // Anyone can read users (e.g. for profile lookups)
    read: async () => true,

    // Only the user themselves can update their own record
    update: async ({ ctx, existingDoc }) =>
      existingDoc._id === (await ctx.auth.getUserIdentity()),

    // Inserts and deletes are managed server-side only
  },
})
A table missing from defineRules() denies ALL operations for that table — even if no rules object is passed to createWorker. Always define rules for every table you intend to access from client-callable functions.

evaluateRules(rules, input)

evaluateRules is an internal function also exported from baseflare/server that the runtime calls before every database operation. Developers generally do not call it directly — it is documented here for completeness and for custom runtime integrations.
function evaluateRules(rules: Rules, input: EvaluationInput): Promise<boolean>
EvaluationInput is a discriminated union over tableName and operation:
type EvaluationInput =
  | ({ tableName: string; operation: 'read' }   & ReadRuleInput)
  | ({ tableName: string; operation: 'insert' } & InsertRuleInput)
  | ({ tableName: string; operation: 'update' } & UpdateRuleInput)
  | ({ tableName: string; operation: 'delete' } & DeleteRuleInput)
The function looks up rules[tableName] and dispatches to the correct operation handler. If no table entry or no operation handler is found, it returns false.

Build docs developers (and LLMs) love