{
"id": "community.gifthood.actor.defs",
"defs": {
"areaView": {
"type": "object",
"required": [
"geohash",
"precision"
],
"properties": {
"geohash": {
"type": "string",
"description": "The viewer's home area as a geohash, precision 6 (~1.2 km privacy-floor cell)."
},
"precision": {
"type": "integer",
"description": "Search radius as geohash precision (gh-6 ~1.2 km / gh-5 ~5 km); lower = wider."
},
"displayName": {
"type": "string",
"description": "Human-readable area name from reverse-geocoding the cell. Display only; absent when the cell has no name."
}
},
"description": "The viewer's home browse area and search radius."
},
"profileView": {
"type": "object",
"required": [
"did"
],
"properties": {
"did": {
"type": "string",
"format": "did",
"description": "DID of the account."
},
"avatar": {
"type": "string",
"description": "Avatar image URL (proxied). Absent when none."
},
"handle": {
"type": "string",
"description": "Live-resolved handle (without leading @). Absent when unresolvable."
},
"viewer": {
"ref": "#viewerState",
"type": "ref",
"description": "Viewer-relative relationship state (following/followedBy/blocking/blockedBy/muted); absent for logged-out viewers."
},
"description": {
"type": "string",
"description": "Bio/description. Absent when none."
},
"displayName": {
"type": "string",
"description": "Real display name. Absent when none set."
},
"hiddenByOptOut": {
"type": "boolean",
"description": "True when this account self-labeled !no-unauthenticated and the request is anonymous: all other optional fields are withheld. Never present for signed-in viewers."
}
},
"description": "Medium profile view: identity + viewer relationship, as returned per row by the graph lists (followers/follows). Sits between profileViewBasic (cheap, handle-less batch tier) and profileViewDetailed (full counts + known-followers + moderation)."
},
"viewerState": {
"type": "object",
"properties": {
"muted": {
"type": "boolean",
"description": "True when the viewer has muted this account."
},
"blocking": {
"type": "boolean",
"description": "True when the viewer has blocked this account."
},
"blockedBy": {
"type": "boolean",
"description": "True when this account has blocked the viewer."
},
"following": {
"type": "string",
"format": "at-uri",
"description": "AT-URI of the viewer's follow record for this account; present when the viewer follows them."
},
"followedBy": {
"type": "boolean",
"description": "True when this account follows the viewer back."
}
},
"description": "The requesting account's relationship to this profile, resolved server-side from the session. Absent for logged-out viewers."
},
"knownFollowers": {
"type": "object",
"required": [
"count",
"profiles"
],
"properties": {
"count": {
"type": "integer",
"description": "Total number of the viewer's follows who follow this account."
},
"profiles": {
"type": "array",
"items": {
"ref": "#profileViewBasic",
"type": "ref"
},
"description": "A small sample of those known followers (hydrated via profileViewBasic)."
}
}
},
"preferencesView": {
"type": "object",
"required": [
"showAdult",
"feedSort",
"mutedCategories",
"requireAltText",
"hideClaimed",
"area"
],
"properties": {
"area": {
"ref": "#areaView",
"type": "ref",
"description": "The viewer's home area + search radius. Always present for the authenticated viewer (populated server-side from memberArea + geocode; falls back to DEFAULT_AREA when no row exists)."
},
"feedSort": {
"type": "string",
"description": "The viewer's nearby-feed sort order.",
"knownValues": [
"newest",
"oldest",
"nearest"
]
},
"showAdult": {
"type": "boolean",
"description": "Whether the viewer sees adult-flagged listings (opt-out; defaults true)."
},
"hideClaimed": {
"type": "boolean",
"description": "Whether the viewer hides claimed (gone/found) listings from the feed (opt-in; defaults false)."
},
"requireAltText": {
"type": "boolean",
"description": "Whether the viewer requires a description on every photo they post (opt-in; defaults false)."
},
"mutedCategories": {
"type": "array",
"items": {
"type": "string"
},
"description": "Listing categories the viewer has muted from the feed."
}
},
"description": "The viewer's personalization settings as one flat bundle. All fields are required — each underlying read applies its own default so the bundle is always complete."
},
"profileViewBasic": {
"type": "object",
"required": [
"did"
],
"properties": {
"did": {
"type": "string",
"format": "did",
"description": "DID of the account."
},
"avatar": {
"type": "string",
"description": "Resolved avatar image URL (gifthood, or the Bluesky fallback). Absent when no avatar is known."
},
"displayName": {
"type": "string",
"description": "Resolved display name (the gifthood profile name, or the Bluesky fallback). Absent when no name is known."
},
"hiddenByOptOut": {
"type": "boolean",
"description": "True when this account self-labeled !no-unauthenticated and the request is anonymous: all other optional fields are withheld. Never present for signed-in viewers."
}
},
"description": "Minimal display identity for a poster/card: the resolved display name + avatar. Server resolves these via the gifthood-over-Bluesky merge."
},
"profileViewDetailed": {
"type": "object",
"required": [
"did",
"followersCount",
"followingCount"
],
"properties": {
"did": {
"type": "string",
"format": "did",
"description": "DID of the account."
},
"avatar": {
"type": "string",
"description": "Avatar image URL (proxied). Absent when none."
},
"banner": {
"type": "string",
"description": "Banner image URL (proxied). Absent when none."
},
"handle": {
"type": "string",
"description": "Live-resolved handle (without leading @). Absent when unresolvable."
},
"sprite": {
"type": "string",
"description": "rpg.actor sprite-sheet URL. Absent when none."
},
"viewer": {
"ref": "#viewerState",
"type": "ref",
"description": "Viewer-relative relationship state; absent for logged-out viewers."
},
"website": {
"type": "string"
},
"joinedAt": {
"type": "string",
"format": "datetime",
"description": "Gifthood join date ('neighbor since')."
},
"pronouns": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "Bluesky account creation time (account age)."
},
"moderation": {
"ref": "community.gifthood.feed.defs#moderationView",
"type": "ref",
"description": "Active soft moderation signal on this account, if any. Reuses feed.defs#moderationView (cross-ref, NOT re-declared)."
},
"description": {
"type": "string",
"description": "Bio."
},
"displayName": {
"type": "string",
"description": "Real display name (nullable — the client does the @handle fallback). Absent when none set."
},
"verification": {
"type": "unknown",
"description": "Bluesky verification status, passed through opaquely (not rendered yet; backlog #8)."
},
"listingsCount": {
"type": "integer",
"description": "Number of the account's publicly-visible listings (includes claimed/'gone'; excludes taken-down and, for a non-consenting viewer, adult). Viewer-relative; the handler always emits it."
},
"spriteColumns": {
"type": "integer",
"description": "Walk-cycle column count when a sprite exists."
},
"followersCount": {
"type": "integer",
"description": "Number of accounts following this account."
},
"followingCount": {
"type": "integer",
"description": "Number of accounts this account follows."
},
"hiddenByOptOut": {
"type": "boolean",
"description": "True when this account self-labeled !no-unauthenticated and the request is anonymous: all other optional fields are withheld. Never present for signed-in viewers."
},
"knownFollowers": {
"ref": "#knownFollowers",
"type": "ref",
"description": "Followed-by-people-you-follow sample; absent logged-out / own-profile / none."
}
},
"description": "Rich single-account profile: identity + counts + viewer relationship + known-followers + moderation."
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1
}