community.gifthood.feed.defs

gifthood.community

{
  "id": "community.gifthood.feed.defs",
  "defs": {
    "imageView": {
      "type": "object",
      "required": [
        "cid"
      ],
      "properties": {
        "alt": {
          "type": "string",
          "description": "Alt text for the image. Absent when no alt text was provided."
        },
        "cid": {
          "type": "string",
          "format": "cid",
          "description": "CID of the image blob in the poster's repo."
        }
      },
      "description": "A single image blob associated with a listing."
    },
    "replyView": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "author",
        "text",
        "createdAt"
      ],
      "properties": {
        "cid": {
          "type": "string",
          "format": "cid",
          "description": "CID of the reply record."
        },
        "uri": {
          "type": "string",
          "format": "at-uri",
          "description": "AT-URI of the reply record."
        },
        "text": {
          "type": "string",
          "description": "The note text."
        },
        "author": {
          "ref": "#replyAuthorView",
          "type": "ref",
          "description": "The reply author's resolved identity."
        },
        "facets": {
          "type": "array",
          "items": {
            "ref": "app.bsky.richtext.facet",
            "type": "ref"
          },
          "description": "Rich-text annotations (links, mentions) over the text. Absent when none."
        },
        "hidden": {
          "type": "boolean",
          "description": "True when the listing owner's replygate hides this note from default views. Present only in owner (includeHidden) reads — otherwise hidden rows are omitted, not flagged."
        },
        "createdAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the reply was created (client-set)."
        }
      },
      "description": "A public note on a listing, flattened with the author's resolved identity. Mirrors the ListingReplyRow db row (getRepliesForListing)."
    },
    "listingView": {
      "type": "object",
      "required": [
        "did",
        "rkey",
        "title",
        "intent",
        "createdAt",
        "category",
        "adult",
        "geohash"
      ],
      "properties": {
        "did": {
          "type": "string",
          "format": "did",
          "description": "DID of the account that created the listing."
        },
        "out": {
          "type": "boolean",
          "description": "Derived: a lend listing whose item is currently out on loan (an exchange completed but not yet returned). Absent means not out."
        },
        "mode": {
          "type": "string",
          "description": "How the item changes hands: 'gift' or 'lend'. Open set (knownValues); absent means gift.",
          "knownValues": [
            "gift",
            "lend"
          ]
        },
        "rkey": {
          "type": "string",
          "description": "Record key (TID) of the listing record in the poster's repo."
        },
        "adult": {
          "type": "boolean",
          "description": "True if the listing is flagged as adult/mature content (self-label or moderator label)."
        },
        "title": {
          "type": "string",
          "description": "Short title of the item being offered or requested."
        },
        "intent": {
          "enum": [
            "offer",
            "request"
          ],
          "type": "string",
          "description": "Whether the poster is giving away an item or looking for one."
        },
        "paused": {
          "type": "boolean",
          "description": "Owner paused lending — hidden from feeds, interest disabled. Absent means active."
        },
        "status": {
          "enum": [
            "available",
            "pending",
            "gone"
          ],
          "type": "string",
          "description": "Current availability of the item. Absent means 'available'."
        },
        "geohash": {
          "type": "string",
          "description": "Approximate location as a geohash. Always at precision-6 (the ~1.2 km privacy floor). Used for map marker placement."
        },
        "category": {
          "type": "string",
          "description": "Single-level category for feed filtering. Unknown or missing values are indexed as 'other'. Not enum-restricted here to remain forward-compatible with new category values."
        },
        "imageAlt": {
          "type": "string",
          "description": "Alt text for the first image, parallel to imageCid. Absent when there is no first image or no alt text was provided."
        },
        "imageCid": {
          "type": "string",
          "description": "CID of the first image blob in the poster's repo. Used to construct the image proxy URL. Absent when the listing has no images."
        },
        "standing": {
          "type": "boolean",
          "description": "Standing (renewing) offer — exchanges never drive status; clients may label availability as ongoing."
        },
        "createdAt": {
          "type": "string",
          "format": "datetime",
          "description": "ISO 8601 datetime when the listing was created. Clients derive relative-time display from this value."
        },
        "distanceKm": {
          "type": "integer",
          "description": "Coarse cell-center-to-cell-center distance in kilometres from the query geohash, rounded to the nearest km. Absent when no search centre is available."
        },
        "moderation": {
          "ref": "#moderationView",
          "type": "ref",
          "description": "Active soft moderation signal for the listing, if any. Absent when the listing has no active moderation."
        },
        "replyCount": {
          "type": "integer",
          "description": "Visible notes on this listing. Derived by the AppView; absent on cards that don't compute it."
        },
        "locationName": {
          "type": "string",
          "description": "Human-readable area name derived from reverse geocoding the geohash. Display only; must not be used for proximity matching."
        }
      },
      "description": "A flattened, display-ready view of a single listing as returned by the AppView feed."
    },
    "viewerState": {
      "type": "object",
      "properties": {
        "interest": {
          "type": "string",
          "format": "at-uri",
          "description": "AT-URI of the viewer's own interest record on this listing, present when they have raised their hand. Absent otherwise. Follows the app.bsky viewerState.like as-string pattern."
        }
      },
      "description": "Metadata about the requesting account's relationship to this listing. Empty for logged-out viewers and viewers with no interaction."
    },
    "activityView": {
      "type": "object",
      "required": [
        "kind",
        "createdAt"
      ],
      "properties": {
        "kind": {
          "type": "string",
          "description": "Row kind — 'interest' = the viewer raised their hand on someone's listing (outgoing); 'hand' = a neighbor raised their hand on the viewer's listing (incoming). Open set (knownValues, not a closed enum): future kinds extend without a breaking change. 'follow' = a neighbor followed the viewer (incoming social signal; carries 'followers' instead of 'listing'). Exchange kinds (all carry 'listing' + 'neighbor' = the other party): 'exchangeChosen'/'exchangeCompleted' for the counterparty, 'exchangeConfirmed'/'exchangeDeclined' for the listing owner. 'exchangeReturned' = the owner marked the item the viewer borrowed as returned (incoming). 'reply' = a neighbor left a note on the viewer's listing (incoming; carries 'listing' + 'neighbor' + 'note'; hidden notes and the note author's own listing never produce a row).",
          "knownValues": [
            "interest",
            "hand",
            "follow",
            "exchangeChosen",
            "exchangeCompleted",
            "exchangeConfirmed",
            "exchangeDeclined",
            "exchangeReturned",
            "reply"
          ]
        },
        "note": {
          "type": "string",
          "description": "The interest's note/message — the viewer's own on an 'interest' row, the neighbor's on a 'hand' row (the same underlying interests.message field), or the note's text on a 'reply' row (replies.text). Absent when none left."
        },
        "listing": {
          "ref": "#listingView",
          "type": "ref",
          "description": "The listing this activity is about (full listingView; carries the moderation signal the outgoing-row gate reads). Absent on 'follow' rows."
        },
        "neighbor": {
          "ref": "community.gifthood.actor.defs#profileViewBasic",
          "type": "ref",
          "description": "The other member this row is about. Present on 'hand' rows (the neighbor who raised their hand), 'reply' rows (the note's author), and on exchange rows (the other party of the exchange); absent on 'interest' rows."
        },
        "createdAt": {
          "type": "string",
          "format": "datetime",
          "description": "When this activity event was created — the newest-first merge/sort key across all activity kinds (interest, hand, follow)."
        },
        "followers": {
          "type": "array",
          "items": {
            "ref": "community.gifthood.actor.defs#profileView",
            "type": "ref"
          },
          "description": "The neighbor(s) who followed the viewer. Present only on 'follow' rows; followers[0] is the primary actor, length > 1 is a grouped card. Each row carries its own viewer state (the inline follow-back button reads viewer.following)."
        },
        "isFollowBack": {
          "type": "boolean",
          "description": "Order-sensitive reciprocity: true when the viewer followed this actor first and they reciprocated. Server-computed; meaningful only on single (ungrouped) 'follow' rows."
        }
      },
      "description": "One row of the viewer's activity feed: an outgoing interest the viewer raised on someone's listing, an incoming raised hand on the viewer's own listing, or a neighbor who followed the viewer (carries 'followers' instead of 'listing')."
    },
    "exchangeView": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "listingUri",
        "giverDid",
        "receiverDid",
        "counterparty",
        "state",
        "createdAt"
      ],
      "properties": {
        "cid": {
          "type": "string",
          "format": "cid",
          "description": "CID of the exchange record."
        },
        "uri": {
          "type": "string",
          "format": "at-uri",
          "description": "AT-URI of the exchange record."
        },
        "state": {
          "type": "string",
          "description": "Derived exchange state. Open set (knownValues, not a closed enum).",
          "knownValues": [
            "pending",
            "completed",
            "confirmed",
            "declined"
          ]
        },
        "giverDid": {
          "type": "string",
          "format": "did",
          "description": "DID of the party giving the item."
        },
        "createdAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the exchange record was created."
        },
        "listingUri": {
          "type": "string",
          "format": "at-uri",
          "description": "AT-URI of the listing this exchange is for."
        },
        "returnedAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the owner marked the lent item returned. Absent until then; only present on lend-listing exchanges."
        },
        "completedAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the giver marked the gift complete — the item handed over or the service rendered. Absent until then."
        },
        "receiverDid": {
          "type": "string",
          "format": "did",
          "description": "DID of the party receiving the item."
        },
        "respondedAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the counterparty confirmed or declined. Absent until they respond."
        },
        "counterparty": {
          "ref": "#exchangeCounterpartyView",
          "type": "ref",
          "description": "The non-listing-owner party's resolved identity."
        }
      },
      "description": "The active exchange on a listing, flattened with the counterparty's resolved identity."
    },
    "interestView": {
      "type": "object",
      "required": [
        "did",
        "uri",
        "cid",
        "createdAt"
      ],
      "properties": {
        "cid": {
          "type": "string",
          "format": "cid",
          "description": "CID of the interest record (used for messaging/report)."
        },
        "did": {
          "type": "string",
          "format": "did",
          "description": "DID of the interested person."
        },
        "uri": {
          "type": "string",
          "format": "at-uri",
          "description": "AT-URI of the interest record."
        },
        "note": {
          "type": "string",
          "description": "The interest's note/message. Absent when none left."
        },
        "avatar": {
          "type": "string",
          "description": "Avatar image URL (proxied). Absent when none."
        },
        "handle": {
          "type": "string",
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
        },
        "createdAt": {
          "type": "string",
          "format": "datetime",
          "description": "When the interest was created (client-set; the row order key)."
        },
        "noteFacets": {
          "type": "array",
          "items": {
            "ref": "app.bsky.richtext.facet",
            "type": "ref"
          },
          "description": "Rich-text facets (links + mentions) over the note. Absent when none."
        },
        "displayName": {
          "type": "string",
          "description": "Real display name (nullable — the row shows name + @handle separately). Absent when none set."
        }
      },
      "description": "An interest ('raised hand') on a listing, flattened with the interested person's resolved identity (real displayName + handle + avatar). Mirrors the InterestedPerson row."
    },
    "moderationView": {
      "type": "object",
      "required": [
        "tier",
        "reason"
      ],
      "properties": {
        "tier": {
          "enum": [
            "warn",
            "hide"
          ],
          "type": "string",
          "description": "Severity tier. 'warn' shows a content warning over the card; 'hide' collapses the card to a quiet strip behind an expand affordance. Both tiers keep the listing in the feed response — only hard takedowns and blocked authors are omitted."
        },
        "reason": {
          "type": "string",
          "description": "Human-readable reason for the moderation action."
        }
      },
      "description": "Active soft moderation signal applied to a listing (warn or hide tier)."
    },
    "replyAuthorView": {
      "type": "object",
      "required": [
        "did"
      ],
      "properties": {
        "did": {
          "type": "string",
          "format": "did",
          "description": "DID of the reply's author."
        },
        "avatar": {
          "type": "string",
          "description": "Avatar image URL (proxied). Absent when none."
        },
        "handle": {
          "type": "string",
          "format": "handle",
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
        },
        "displayName": {
          "type": "string",
          "maxLength": 640,
          "description": "Real display name. Absent when none set.",
          "maxGraphemes": 64
        }
      },
      "description": "A reply author's resolved identity — sibling def to exchangeCounterpartyView (inline object property types are illegal in this lexicon toolchain)."
    },
    "listingDetailView": {
      "type": "object",
      "required": [
        "listing",
        "cid",
        "images"
      ],
      "properties": {
        "cid": {
          "type": "string",
          "format": "cid",
          "description": "CID of the listing record in the poster's repo."
        },
        "langs": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "language"
          },
          "description": "BCP-47 language tags for the listing's text content. Absent when unspecified."
        },
        "facets": {
          "type": "array",
          "items": {
            "ref": "app.bsky.richtext.facet",
            "type": "ref"
          },
          "description": "Rich-text annotations (links, mentions, tags) over the description. Absent when no facets are present."
        },
        "images": {
          "type": "array",
          "items": {
            "ref": "#imageView",
            "type": "ref"
          },
          "description": "All images associated with the listing. May be empty."
        },
        "viewer": {
          "ref": "#viewerState",
          "type": "ref",
          "description": "The requesting account's viewer-specific state for this listing (e.g. their own interest). Absent for logged-out viewers."
        },
        "listing": {
          "ref": "#listingView",
          "type": "ref",
          "description": "The summary listing view."
        },
        "description": {
          "type": "string",
          "description": "Full description of the item, in plain text. Absent when the poster provided no description."
        }
      },
      "description": "Full detail view of a single listing, including all images, rich-text facets, and viewer state."
    },
    "exchangeCounterpartyView": {
      "type": "object",
      "required": [
        "did"
      ],
      "properties": {
        "did": {
          "type": "string",
          "format": "did",
          "description": "DID of the counterparty."
        },
        "handle": {
          "type": "string",
          "format": "handle",
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
        },
        "displayName": {
          "type": "string",
          "maxLength": 640,
          "description": "Real display name. Absent when none set.",
          "maxGraphemes": 64
        }
      },
      "description": "The non-listing-owner exchange party's resolved identity."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}

Validate Record

Validate a record against community.gifthood.feed.defs

Validation Options
Automatically resolve and include external schemas for full validation
Treat any remaining unresolved references as valid

Metadata

DID
did:plc:7prvtl4j6wsfmkrfrnwknuxj
CID
bafyreignbrioiaibt333hrc2l7532j2mmoaaxh6bvbwqekwrl2rxzh26wa
Indexed At
2026-07-20 06:01 UTC
AT-URI
at://did:plc:7prvtl4j6wsfmkrfrnwknuxj/com.atproto.lexicon.schema/community.gifthood.feed.defs

Referenced Schemas (3)

Lexicon Garden

@