# actor

> Record who created, changed and deleted each row.

Source: https://bettersupabase.com/docs/plugins/actor

```ts
import { actor } from "better-supabase/plugins/actor";

const db = defineSupabase(schema)
  .use(actor())
  .connect(supabase, { actor: { id: user.id, kind: "user" } });
```

* Inserts get `createdBy` and `updatedBy`.
* Updates get `updatedBy`. With `softDelete()`, the delete is an update, so
  `updatedBy` records who deleted the row.
* Upserts that may update only get `updatedBy`.
* Tables with an `impersonated_by` column (`plugins.actor.impersonatedBy` in
  the config renames it) get `impersonatedBy` on each insert and update made
  during [impersonation](/docs/auth/impersonation): the admin from
  `actor.impersonator`. The user's own writes leave it alone, so the row
  keeps the last impersonating admin. That is what the SQL modules'
  `track_actor(table, impersonated_by => 'impersonated_by')` writes, and it
  also keeps `created_by` on updates.
* Anonymous requests set nothing.
* `createdBy`, `updatedBy` and `impersonatedBy` values you pass yourself are refused with
  `invalid_request`, so a caller cannot sign a row as someone else. Pass
  `{ override: true }` for imports and backfills.

Server adapters fill `actor` from the verified JWT. Jobs run as the user who
enqueued them with `bs.forContext(job.context)` (see
[jobs](/docs/blocks/jobs#actor-and-tenant)), webhooks and scripts with
`bs.actingAs(userId)`, and work no user owns with `bs.admin()`, whose actor
is `service`. Pass `resolve(context)` to read the id from somewhere else.

For a tamper-proof trail, add the `actor` and `audit` SQL module triggers, which
read `auth.uid()` inside the database.