API reference
Reference. Every public export of @atjam/lexicons, with exact signatures. For the wire-level field reference (max lengths, formats), see the JSON schemas — this page documents the TypeScript surface.Everything below is exported from the package root:
import {
Jam, Round, Signup, Invitation, Submission,
Queries, Validate, Eligibility,
NSIDS, type StrongRef,
} from "@atjam/lexicons";Jam, Round, Signup, Invitation, Submission, Queries, Validate, and Eligibility are namespaces (export * as …). StrongRef and NSIDS are re-exported directly.
The blocks below show each export's shape as accessed through its namespace — e.g. theJam.Jamtype, theRound.deriveStatefunction. They are reference notation, not literal declarations you can paste (you can't declareinterface Jam.Jam). For copy-ready imports, see Getting started.
NSIDS
A frozen map of the five collection NSIDs.
const NSIDS: {
jam: "at.atjam.jam";
round: "at.atjam.round";
signup: "at.atjam.signup";
invitation: "at.atjam.invitation";
submission: "at.atjam.submission";
}StrongRef
interface StrongRef {
uri: string;
cid: string;
}A content-addressed reference to a record. Used wherever one record points at another (round.jam, signup.round, signup.invitation, invitation.round, submission.round, submission.payload).
Jam
Jam.NSID; // "at.atjam.jam"
interface Jam.JamLink {
label?: string;
url: string;
}
interface Jam.Jam {
$type?: "at.atjam.jam";
name: string;
description?: string;
kind?: string;
links?: Jam.JamLink[];
createdAt: string;
}
// Type guard: true if v has string `name` and `createdAt`.
function Jam.isJam(v: unknown): v is Jam.Jam;Round
Round.NSID; // "at.atjam.round"
interface Round.Milestone {
label: string;
date: string;
}
type Round.JoinMode = "open" | "hosted" | "network";
type Round.NetworkGate = "signup" | "contributed";
type Round.RoundState = "open" | "in-progress" | "closed";
interface Round.Round {
$type?: "at.atjam.round";
jam: StrongRef;
name?: string;
assignment: string;
subject?: unknown;
acceptedSubmissionTypes: string[];
milestones: Round.Milestone[];
closingEvent?: unknown;
joinMode?: Round.JoinMode | string;
networkGate?: Round.NetworkGate | string;
createdAt: string;
}
// Resolve joinMode for consumer logic; unknown/absent → "open".
function Round.getJoinMode(round: Round.Round): Round.JoinMode;
// Resolve networkGate (only meaningful for "network"); unknown/absent → "signup".
function Round.getNetworkGate(round: Round.Round): Round.NetworkGate;
// True for "hosted" and "network"; false for "open" and unknown values.
function Round.requiresInvitation(round: Round.Round): boolean;
// Type guard: checks `assignment`, `acceptedSubmissionTypes`, `milestones`, `createdAt`.
function Round.isRound(v: unknown): v is Round.Round;
// Derive state from milestones. "closed" if past submission-deadline; else
// "in-progress" if past signup-deadline; else "open". Missing deadlines bias
// toward "open". Boundary comparisons use >= (the deadline moment counts as past).
function Round.deriveState(round: Round.Round, now?: Date): Round.RoundState;
interface Round.RoundPhase {
index: number; // 0 before the first milestone; milestones.length after the last
since?: Round.Milestone; // milestone that opened the current phase
until?: Round.Milestone; // next upcoming milestone
}
// Where now falls among the (date-sorted) milestones — a fine-grained companion
// to deriveState for rounds using custom milestone labels as phases.
function Round.deriveCurrentPhase(round: Round.Round, now?: Date): Round.RoundPhase;Signup
Signup.NSID; // "at.atjam.signup"
interface Signup.Signup {
$type?: "at.atjam.signup";
round: StrongRef;
invitation?: StrongRef; // required by readers for hosted/network rounds
note?: string;
createdAt: string;
}Invitation
Invitation.NSID; // "at.atjam.invitation"
interface Invitation.Invitation {
$type?: "at.atjam.invitation";
round: StrongRef;
invitee: string; // a DID
note?: string;
createdAt: string;
}
// Type guard: checks `round` (object), `invitee` (string), `createdAt` (string).
function Invitation.isInvitation(v: unknown): v is Invitation.Invitation;Submission
Submission.NSID; // "at.atjam.submission"
interface Submission.Submission {
$type?: "at.atjam.submission";
round: StrongRef;
payload?: StrongRef; // preferred deliverable: a record on its native app
url?: string; // fallback deliverable: a plain link (prefer payload)
note?: string;
createdAt: string;
}
// The deliverable normalized to one form — the single gate for "exactly one of".
type Submission.Deliverable =
| { kind: "record"; ref: StrongRef }
| { kind: "url"; url: string };
// Returns the record (preferred), else the url, else null (malformed).
function Submission.getDeliverable(s: Submission.Submission): Submission.Deliverable | null;
// Whether a submission carries any deliverable (the "at least one" rule).
function Submission.hasDeliverable(s: Submission.Submission): boolean;Queries
The read layer. Re-exports the contents of at-uri, did, pds, constellation, and fetchers.
AT URI utilities (no network)
interface Queries.ParsedAtUri {
did: string;
collection: string;
rkey: string;
}
// Parse "at://<did>/<collection>/<rkey>". Throws on a non-at:// or malformed URI.
function Queries.parseAtUri(uri: string): Queries.ParsedAtUri;
// Reassemble an AT URI from its parts.
function Queries.buildAtUri(parts: Queries.ParsedAtUri): string;DID resolution
interface Queries.ResolvedDid {
pds: string;
handle?: string; // best-effort, from alsoKnownAs[0]
}
type Queries.HandleMap = Record<string, string>;
// Configure the PLC directory URL (default "https://plc.directory"). No-op on empty.
function Queries.setPlcDirectoryUrl(url: string): void;
function Queries.getPlcDirectoryUrl(): string;
// Resolve a DID to its PDS endpoint (and best-effort handle). Supports
// did:plc and did:web. Per-process cached.
function Queries.resolveDid(did: string): Promise<Queries.ResolvedDid>;
// Resolve many DIDs to a HandleMap in parallel; per-DID failures are dropped.
function Queries.resolveHandles(dids: Iterable<string>): Promise<Queries.HandleMap>;Raw PDS reads (unauthenticated)
interface Queries.PdsRecord<T = unknown> {
uri: string;
cid: string;
value: T;
}
interface Queries.ListRecordsResponse<T = unknown> {
records: Queries.PdsRecord<T>[];
cursor?: string;
}
// com.atproto.repo.listRecords against the DID's PDS.
function Queries.listRecords<T = unknown>(args: {
did: string;
collection: string;
limit?: number;
cursor?: string;
reverse?: boolean;
}): Promise<Queries.ListRecordsResponse<T>>;
// com.atproto.repo.getRecord against the DID's PDS.
function Queries.getRecord<T = unknown>(args: {
did: string;
collection: string;
rkey: string;
}): Promise<Queries.PdsRecord<T>>;Constellation backlinks
interface Queries.BacklinkRef {
uri: string;
cid?: string;
}
interface Queries.BacklinksResponse {
links: Queries.BacklinkRef[];
cursor?: string;
total?: number;
}
// Configure the Constellation URL (default "https://constellation.microcosm.blue"). No-op on empty.
function Queries.setConstellationUrl(url: string): void;
function Queries.getConstellationUrl(): string;
// Given a target record, return records that link to it at the given JSON path.
function Queries.getBacklinks(args: {
target: string;
collection: string;
path: string;
limit?: number;
cursor?: string;
}): Promise<Queries.BacklinksResponse>;Composed atjam fetchers
// Direct reads.
function Queries.fetchRound(did: string, rkey: string): Promise<Queries.PdsRecord<Round.Round>>;
function Queries.fetchJam(did: string, rkey: string): Promise<Queries.PdsRecord<Jam.Jam>>;
function Queries.fetchJamByUri(jamUri: string): Promise<Queries.PdsRecord<Jam.Jam>>;
// Rounds under a jam (backlinks + fetch each body; unreadable rounds dropped).
function Queries.fetchRoundsForJam(jamUri: string): Promise<Queries.PdsRecord<Round.Round>[]>;
// A round's signups — raw backlinks (bodies not fetched).
function Queries.fetchSignupsForRound(roundUri: string): Promise<Queries.BacklinksResponse>;
// A round's submissions / invitations — bodies fetched (unreadable dropped).
function Queries.fetchSubmissionsForRound(roundUri: string): Promise<Queries.PdsRecord<Submission.Submission>[]>;
function Queries.fetchInvitationsForRound(roundUri: string): Promise<Queries.PdsRecord<Invitation.Invitation>[]>;
// Cross-organizer feed: list each DID's rounds, dedupe, sort by createdAt desc.
function Queries.fetchHomeFeed(dids: string[]): Promise<Queries.PdsRecord<Round.Round>[]>;
// A DID's own jams (newest first).
function Queries.fetchMyJams(did: string): Promise<Queries.PdsRecord<Jam.Jam>[]>;Validate
Read-only signup validation. See the validation contract.
interface Validate.ValidationResult {
valid: boolean;
reason?: string;
}
// Fetchers the validator needs; defaults wrap Queries. Tests inject stubs.
interface Validate.ValidateFetchers {
getInvitation(uri: string): Promise<Invitation.Invitation | null>;
getSignupForRound(args: { did: string; roundUri: string }): Promise<{ uri: string; value: Signup.Signup } | null>;
hasSubmissionForRound(args: { did: string; roundUri: string }): Promise<boolean>;
}
interface Validate.ValidateSignupArgs {
signup: { uri: string; value: Signup.Signup };
round: { uri: string; value: Round.Round };
fetchers?: Partial<Validate.ValidateFetchers>;
}
function Validate.validateSignup(args: Validate.ValidateSignupArgs): Promise<Validate.ValidationResult>;Eligibility
Pure predicates (no I/O) for prospective "may this DID invite?" questions.
interface Eligibility.InviterContext {
round: Round.Round;
organizerDid: string;
validSignerDids: readonly string[];
submitterDids: readonly string[];
}
// Is inviterDid a valid inviter for the round?
// organizer → always; hosted → only organizer; network → valid signer
// (and, under "contributed", must also be a submitter).
function Eligibility.isValidInviter(ctx: Eligibility.InviterContext, inviterDid: string): boolean;
// May viewerDid issue invitations? Open rounds → always false; else isValidInviter.
function Eligibility.canInvite(ctx: Eligibility.InviterContext, viewerDid: string): boolean;
// The invitation that would make viewerDid's signup valid: names the viewer
// as invitee AND comes from a valid inviter. Generic over the record shape.
function Eligibility.findUsableInvitation<
I extends { uri: string; value: { invitee: string } },
>(
ctx: Eligibility.InviterContext,
viewerDid: string,
invitations: readonly I[],
): I | undefined;Not exported: writes
@atjam/lexicons provides no write helpers. Writing records is the application's job, via com.atproto.repo.createRecord with your own ATProto client. See Reading, writing, validating.