TLRecordAuthorizer
Authorizes a single record write from a client: any per-record, per-session rule the host wants to enforce server-side — veto writes the session isn't allowed to make, or rewrite the record on create. The session's meta carries whatever the rule needs (identity, roles, …); for example, force a comment's authorId to the signed-in user so nobody can post in someone else's name.
Called on create, update, and delete of records whose typeName it's registered for (see TLRecordAuthorizers), and only for client pushes — never for server-initiated writes.
prev and next are always at the server's schema version: client writes are migrated before the authorizer runs, so guarding or stamping a field never requires knowing what older clients call it. On create, the record you return is what gets stored (after validation) — no migration runs afterwards, so stamped fields can't be clobbered.
Return null to reject the write — it's skipped and the client self-corrects, exactly like the objectAccess gate. Otherwise the write is allowed, and:
- on create, the record you return is what gets stored, so stamp identity fields here (e.g. set
authorIdfromsession.meta); - on update and delete, only allow-vs-reject is used (the returned record's contents are ignored), so use them to veto changes to immutable fields or unauthorized deletes — returnnext/prevto allow,nullto reject.
⚠︎ Runs synchronously inside the commit transaction, on the same path as every document edit — it must be fast and do no I/O. next/prev are client-controlled records, so treat their contents as untrusted; prefer returning null to reject over throwing, though a throw is caught, logged, and treated as a rejection (fail closed) rather than crashing the push. For expensive, async checks (e.g. resolving mentions against who can access a file), react after the fact via onCommittedChanges.
type TLRecordAuthorizer<Rec extends UnknownRecord, SessionMeta> = (
args: {
session: {
isReadonly: boolean;
meta: SessionMeta;
sessionId: string;
};
} & (
| {
next: null;
prev: Rec;
type: "delete";
}
| {
next: Rec;
prev: null;
type: "create";
}
| {
next: Rec;
prev: Rec;
type: "update";
}
),
) => null | Rec;