SDKaudit

junjo.audit

Read the audit log for a group. The audit log is the durable record of every mutation Junjo has performed; the live event stream (junjo.groups.subscribe) is for transient UX, and audit.list is for “what has happened to this group, ever.”

import { Junjo } from "@junjo/sdk";
 
const junjo = new Junjo({ apiKey: process.env.JUNJO_API_KEY! });
 
const page = await junjo.audit.list(groupId, {
  limit: 50,
  actions: ["member.invited", "member.joined", "member.left", "member.kicked"],
});
for (const entry of page.items) {
  console.log(entry.action, entry.targetId, entry.createdAt);
}

list(groupId, opts?)

Returns Promise<Page<AuditEntry>>. Entries are sorted newest first.

list(groupId: GroupId, opts?: ListAuditOptions): Promise<Page<AuditEntry>>;
 
interface ListAuditOptions {
  limit?: number;
  before?: Date;
  actions?: AuditAction[];
}

Options

FieldTypeDefaultNotes
limitnumber (1-100)50Max entries to return on this page.
beforeDate(no filter)Filter to entries with createdAt < before. Used for pagination by feeding the previous page’s nextCursor (an ISO timestamp) back through new Date(...).
actionsAuditAction[](no filter)Restrict the page to entries whose action is in the supplied list. Empty array is treated as “no filter” by the SDK and the server.

Pagination

Page<AuditEntry>.nextCursor is the ISO 8601 createdAt of the last item when the page is full, or null otherwise. Walk pages by feeding it back as before:

let cursor: string | null = null;
do {
  const opts: ListAuditOptions = { limit: 100 };
  if (cursor !== null) opts.before = new Date(cursor);
  const page = await junjo.audit.list(groupId, opts);
  for (const entry of page.items) handle(entry);
  cursor = page.nextCursor;
} while (cursor !== null);

If two entries share createdAt to millisecond precision, the page boundary may skip entries with that exact timestamp on the next call. Audit entries are written one per transaction, so collisions are rare; consumers that need strict ordering across page boundaries should treat the audit log as eventually consistent.

Entry shape

interface AuditEntry {
  id: AuditEntryId;
  groupId: GroupId;
  actorUserId: UserId | null;
  action: AuditAction;
  targetId: string | null;
  payload: Record<string, unknown>;
  createdAt: Date;
}

actorUserId is null for system-driven actions and for the V1 mutations that have no auth-adapter actor wired (most of them). targetId is a free-form pointer to whatever the action targeted: a user id, role id, permission key, or group id; type depends on action.

Errors

CodeStatusWhen
bad_request400Out-of-range limit, malformed before, or unknown action value.
not_found404Group missing, soft-deleted, or owned by a different game.
invalid_api_key401API key missing, malformed, or revoked.