auth/actor_lookup_queries.ts

Batched actor-by-id resolver.

Joins actor ⨝ account so callers see (username, display_name) for each actor row. The byline / owner-column / grantor surfaces stamp an actor id, so resolving "who is this actor?" lands the human label in one round trip.

Accounts may host multiple actors (multi-actor shipped in v0.55.0). The inner join still resolves one row per actor β€” actor.account_id is NOT NULL so every actor has exactly one account.

Info-leak posture (see actor_lookup_action_specs.ts Β§audit):

- Row shape omits account_id β€” the join is control-plane, not wire-visible. - Hard-deleted actors (or account-cascade-orphaned rows) drop out silently β€” indistinguishable from never-existed (no tombstone oracle). - No created_at / updated_at projected (timing-oracle avoidance). - Response order is unspecified β€” WHERE id = ANY(...) returns index-scan order in practice but callers must not depend on it.

Caller is responsible for capping ids.length β€” the SQL itself does not enforce a bound; the action-spec layer surfaces invalid_params via ACTOR_LOOKUP_IDS_MAX.

Declarations
#

2 declarations

view source

ActorLookupRow
#

auth/actor_lookup_queries.ts view source

ActorLookupRow

Row shape returned to handlers β€” wire mapping happens at the action layer.

id

type Uuid

username

type string

display_name

type string | null

query_actors_by_ids
#

auth/actor_lookup_queries.ts view source

(deps: QueryDeps, ids: readonly (string & $brand<"Uuid">)[]): Promise<ActorLookupRow[]>

Resolve a batch of actor ids to (id, username, display_name). Empty input fast-paths to []. Hard-deleted actors (or account-cascade- orphaned rows) drop out of the result silently.

deps

ids

type readonly (string & $brand<"Uuid">)[]

returns

Promise<ActorLookupRow[]>

Imported by
#