Skip to content

Core Types ​

Branded types and AT Protocol identifiers used throughout the server.

Branded Types ​

Branded types provide type safety for AT Protocol identifiers, preventing accidental misuse of strings.

DID (Decentralized Identifier) ​

typescript
type DID = string & { readonly __brand: 'DID' };

Description: Permanent, unique identifier for users and repositories.

Format: did:plc: followed by base32-encoded identifier

Examples:

typescript
const userDid: DID = 'did:plc:abc123xyz789' as DID;
const repoDid: DID = 'did:plc:def456uvw012' as DID;

Characteristics:

  • Permanent (never changes)
  • Globally unique
  • Cryptographically verifiable
  • Use for internal references

ATURI (AT Protocol URI) ​

typescript
type ATURI = string & { readonly __brand: 'ATURI' };

Description: URI for AT Protocol resources (posts, likes, follows, etc.).

Format: at://[DID]/[collection]/[rkey]

Examples:

typescript
const postUri: ATURI = 'at://did:plc:abc123/app.bsky.feed.post/xyz789' as ATURI;
const likeUri: ATURI =
  'at://did:plc:abc123/app.bsky.feed.like/like123' as ATURI;
const followUri: ATURI =
  'at://did:plc:abc123/app.bsky.graph.follow/follow456' as ATURI;

Components:

  • DID: Repository identifier
  • Collection: Record type (e.g., app.bsky.feed.post)
  • Record Key (rkey): Unique record identifier

NSID (Namespaced Identifier) ​

typescript
type NSID = string & { readonly __brand: 'NSID' };

Description: Namespaced identifier for Lexicon schemas and collections.

Format: Reverse domain notation with segments

Examples:

typescript
const postType: NSID = 'app.bsky.feed.post' as NSID;
const likeType: NSID = 'app.bsky.feed.like' as NSID;
const profileType: NSID = 'app.bsky.actor.profile' as NSID;

Common NSIDs:

  • app.bsky.feed.post - Posts
  • app.bsky.feed.like - Likes
  • app.bsky.feed.repost - Reposts
  • app.bsky.graph.follow - Follows
  • app.bsky.graph.block - Blocks
  • app.bsky.actor.profile - Profiles

CID (Content Identifier) ​

typescript
type CID = string & { readonly __brand: 'CID' };

Description: Content-addressed identifier using IPFS CID format.

Format: Base32-encoded multihash

Examples:

typescript
const postCid: CID = 'bafyreiabc123xyz789...' as CID;
const imageCid: CID = 'bafkreidef456uvw012...' as CID;

Characteristics:

  • Content-addressed (hash of content)
  • Immutable
  • Verifiable
  • Used for data integrity

AT Protocol Types ​

IAtpSession ​

typescript
interface IAtpSession {
  did: DID;
  handle: string;
  accessJwt: string;
  refreshJwt: string;
  active: boolean;
}

Description: Authenticated session information.

Fields:

  • did - User's DID
  • handle - User's handle
  • accessJwt - Access token (2 hour lifetime)
  • refreshJwt - Refresh token (90 day lifetime)
  • active - Whether session is active

IAtpProfile ​

typescript
interface IAtpProfile {
  did: DID;
  handle: string;
  displayName?: string;
  description?: string;
  avatar?: string;
  banner?: string;
  followersCount?: number;
  followsCount?: number;
  postsCount?: number;
}

Description: User profile information.

Fields:

  • did - User's DID (required)
  • handle - User's handle (required)
  • displayName - Display name
  • description - Bio text
  • avatar - Avatar image URL
  • banner - Banner image URL
  • followersCount - Number of followers
  • followsCount - Number of follows
  • postsCount - Number of posts

IAtpPost ​

typescript
interface IAtpPost {
  uri: ATURI;
  cid: CID;
  author: IAtpProfile;
  record: {
    text: string;
    createdAt: string;
    reply?: {
      root: { uri: ATURI; cid: CID };
      parent: { uri: ATURI; cid: CID };
    };
    embed?: unknown;
    langs?: string[];
    labels?: unknown;
    tags?: string[];
  };
  replyCount?: number;
  repostCount?: number;
  likeCount?: number;
  indexedAt: string;
  viewer?: {
    repost?: ATURI;
    like?: ATURI;
  };
}

Description: Post data structure.

Fields:

  • uri - Post URI
  • cid - Post CID
  • author - Post author profile
  • record - Post record data
    • text - Post text content
    • createdAt - Creation timestamp
    • reply - Reply information (if reply)
    • embed - Embedded content
    • langs - Language codes
    • tags - Hashtags
  • replyCount - Number of replies
  • repostCount - Number of reposts
  • likeCount - Number of likes
  • indexedAt - Index timestamp
  • viewer - Viewer-specific data (when authenticated)

Validators and Type Guards ​

The server exports a validator and a type guard for each branded type.

The validate* functions throw on invalid input and return the value narrowed to the branded type. The is* functions are non-throwing type guards that return a boolean.

typescript
// Throwing validators (cast + runtime validation)
validateDID(value: string): DID;     // requires 'did:method:identifier'
validateATURI(value: string): ATURI; // requires 'at://authority/collection/rkey'
validateCID(value: string): CID;     // alphanumeric, length >= 10
validateNSID(value: string): NSID;   // reverse-DNS, >= 3 segments

// Non-throwing type guards
isDID(value: unknown): value is DID;
isATURI(value: unknown): value is ATURI;
isCID(value: unknown): value is CID;
isNSID(value: unknown): value is NSID;

Example:

typescript
// Throws if invalid
const did = validateDID('did:plc:abc123xyz789');

// Narrows without throwing
if (isATURI(input)) {
  // input is ATURI here
}

Usage Examples ​

Tools are snake_case MCP tools

The MCP tools exposed by this server use snake_case names (get_user_connections, like_post, reply_to_post, ...). The camelCase calls below are illustrative TypeScript using the branded types; they are not the MCP tool names.

Working with DIDs ​

typescript
// A DID is a permanent reference; store it rather than the handle
const userDid: DID = profile.did;

Working with AT URIs ​

typescript
// A post is referenced by its AT URI plus CID
const postUri: ATURI = post.uri;
const postCid: CID = post.cid;

Working with CIDs ​

typescript
// CIDs are content-addressed and immutable — useful for integrity checks
const cid: CID = post.cid;

Best Practices ​

Type Safety ​

  • Use branded types for all AT Protocol identifiers
  • Don't cast strings to branded types without validation
  • Implement type guards for runtime validation
  • Use TypeScript strict mode

Identifier Storage ​

  • Store DIDs for permanent references
  • Store AT URIs for resource references
  • Store CIDs for content verification
  • Don't rely on handles (they can change)

Validation ​

  • Validate format before casting to branded types
  • Check for null/undefined values
  • Handle invalid identifiers gracefully
  • Log validation errors

See Also ​