community.gifthood.feed.defs

gifthood.community

Schema Diff

+5 -0

From

CID
bafyreignbrioiai...
Indexed At
2026-07-20 06:01 UTC
View this version

To

CID
bafyreife2ohta32...
Indexed At
2026-08-27 17:51 UTC
View this version

Compatibility Analysis

Backward Compatible

Backward compatible. 4 non-breaking changes.

Non-Breaking Changes (4)
  • AddedVertex AddedVertex { vertex_id: "community.gifthood.feed.defs#imageView.aspectRatio" }
  • AddedVertex AddedVertex { vertex_id: "community.gifthood.listing#aspectRatio" }
  • AddedEdge AddedEdge { src: "community.gifthood.feed.defs#imageView", tgt: "community.gifthood.feed.defs#imageView.aspectRatio", kind: "prop", name: Some("aspectRatio") }
  • AddedEdge AddedEdge { src: "community.gifthood.feed.defs#imageView.aspectRatio", tgt: "community.gifthood.listing#aspectRatio", kind: "ref", name: None }

Migration Guidance

Added Elements

  • AddedVertex { vertex_id: "community.gifthood.feed.defs#imageView.aspectRatio" }
  • AddedVertex { vertex_id: "community.gifthood.listing#aspectRatio" }

Additional Notes

  • Non-breaking: AddedEdge { src: "community.gifthood.feed.defs#imageView", tgt: "community.gifthood.feed.defs#imageView.aspectRatio", kind: "prop", name: Some("aspectRatio") }
  • Non-breaking: AddedEdge { src: "community.gifthood.feed.defs#imageView.aspectRatio", tgt: "community.gifthood.listing#aspectRatio", kind: "ref", name: None }
1 1
{
2 2
  "id": "community.gifthood.feed.defs",
3 3
  "defs": {
4 4
    "imageView": {
5 5
      "type": "object",
6 6
      "required": [
7 7
        "cid"
8 8
      ],
9 9
      "properties": {
10 10
        "alt": {
11 11
          "type": "string",
12 12
          "description": "Alt text for the image. Absent when no alt text was provided."
13 13
        },
14 14
        "cid": {
15 15
          "type": "string",
16 16
          "format": "cid",
17 17
          "description": "CID of the image blob in the poster's repo."
18 +
        },
19 +
        "aspectRatio": {
20 +
          "ref": "community.gifthood.listing#aspectRatio",
21 +
          "type": "ref",
22 +
          "description": "Aspect ratio from the listing record, passed through unchanged. Absent when the poster's client did not record one."
18 23
        }
19 24
      },
20 25
      "description": "A single image blob associated with a listing."
21 26
    },
22 27
    "replyView": {
23 28
      "type": "object",
24 29
      "required": [
25 30
        "uri",
26 31
        "cid",
27 32
        "author",
28 33
        "text",
29 34
        "createdAt"
30 35
      ],
31 36
      "properties": {
32 37
        "cid": {
33 38
          "type": "string",
34 39
          "format": "cid",
35 40
          "description": "CID of the reply record."
36 41
        },
37 42
        "uri": {
38 43
          "type": "string",
39 44
          "format": "at-uri",
40 45
          "description": "AT-URI of the reply record."
41 46
        },
42 47
        "text": {
43 48
          "type": "string",
44 49
          "description": "The note text."
45 50
        },
46 51
        "author": {
47 52
          "ref": "#replyAuthorView",
48 53
          "type": "ref",
49 54
          "description": "The reply author's resolved identity."
50 55
        },
51 56
        "facets": {
52 57
          "type": "array",
53 58
          "items": {
54 59
            "ref": "app.bsky.richtext.facet",
55 60
            "type": "ref"
56 61
          },
57 62
          "description": "Rich-text annotations (links, mentions) over the text. Absent when none."
58 63
        },
59 64
        "hidden": {
60 65
          "type": "boolean",
61 66
          "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."
62 67
        },
63 68
        "createdAt": {
64 69
          "type": "string",
65 70
          "format": "datetime",
66 71
          "description": "When the reply was created (client-set)."
67 72
        }
68 73
      },
69 74
      "description": "A public note on a listing, flattened with the author's resolved identity. Mirrors the ListingReplyRow db row (getRepliesForListing)."
70 75
    },
71 76
    "listingView": {
72 77
      "type": "object",
73 78
      "required": [
74 79
        "did",
75 80
        "rkey",
76 81
        "title",
77 82
        "intent",
78 83
        "createdAt",
79 84
        "category",
80 85
        "adult",
81 86
        "geohash"
82 87
      ],
83 88
      "properties": {
84 89
        "did": {
85 90
          "type": "string",
86 91
          "format": "did",
87 92
          "description": "DID of the account that created the listing."
88 93
        },
89 94
        "out": {
90 95
          "type": "boolean",
91 96
          "description": "Derived: a lend listing whose item is currently out on loan (an exchange completed but not yet returned). Absent means not out."
92 97
        },
93 98
        "mode": {
94 99
          "type": "string",
95 100
          "description": "How the item changes hands: 'gift' or 'lend'. Open set (knownValues); absent means gift.",
96 101
          "knownValues": [
97 102
            "gift",
98 103
            "lend"
99 104
          ]
100 105
        },
101 106
        "rkey": {
102 107
          "type": "string",
103 108
          "description": "Record key (TID) of the listing record in the poster's repo."
104 109
        },
105 110
        "adult": {
106 111
          "type": "boolean",
107 112
          "description": "True if the listing is flagged as adult/mature content (self-label or moderator label)."
108 113
        },
109 114
        "title": {
110 115
          "type": "string",
111 116
          "description": "Short title of the item being offered or requested."
112 117
        },
113 118
        "intent": {
114 119
          "enum": [
115 120
            "offer",
116 121
            "request"
117 122
          ],
118 123
          "type": "string",
119 124
          "description": "Whether the poster is giving away an item or looking for one."
120 125
        },
121 126
        "paused": {
122 127
          "type": "boolean",
123 128
          "description": "Owner paused lending — hidden from feeds, interest disabled. Absent means active."
124 129
        },
125 130
        "status": {
126 131
          "enum": [
127 132
            "available",
128 133
            "pending",
129 134
            "gone"
130 135
          ],
131 136
          "type": "string",
132 137
          "description": "Current availability of the item. Absent means 'available'."
133 138
        },
134 139
        "geohash": {
135 140
          "type": "string",
136 141
          "description": "Approximate location as a geohash. Always at precision-6 (the ~1.2 km privacy floor). Used for map marker placement."
137 142
        },
138 143
        "category": {
139 144
          "type": "string",
140 145
          "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."
141 146
        },
142 147
        "imageAlt": {
143 148
          "type": "string",
144 149
          "description": "Alt text for the first image, parallel to imageCid. Absent when there is no first image or no alt text was provided."
145 150
        },
146 151
        "imageCid": {
147 152
          "type": "string",
148 153
          "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."
149 154
        },
150 155
        "standing": {
151 156
          "type": "boolean",
152 157
          "description": "Standing (renewing) offer — exchanges never drive status; clients may label availability as ongoing."
153 158
        },
154 159
        "createdAt": {
155 160
          "type": "string",
156 161
          "format": "datetime",
157 162
          "description": "ISO 8601 datetime when the listing was created. Clients derive relative-time display from this value."
158 163
        },
159 164
        "distanceKm": {
160 165
          "type": "integer",
161 166
          "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."
162 167
        },
163 168
        "moderation": {
164 169
          "ref": "#moderationView",
165 170
          "type": "ref",
166 171
          "description": "Active soft moderation signal for the listing, if any. Absent when the listing has no active moderation."
167 172
        },
168 173
        "replyCount": {
169 174
          "type": "integer",
170 175
          "description": "Visible notes on this listing. Derived by the AppView; absent on cards that don't compute it."
171 176
        },
172 177
        "locationName": {
173 178
          "type": "string",
174 179
          "description": "Human-readable area name derived from reverse geocoding the geohash. Display only; must not be used for proximity matching."
175 180
        }
176 181
      },
177 182
      "description": "A flattened, display-ready view of a single listing as returned by the AppView feed."
178 183
    },
179 184
    "viewerState": {
180 185
      "type": "object",
181 186
      "properties": {
182 187
        "interest": {
183 188
          "type": "string",
184 189
          "format": "at-uri",
185 190
          "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."
186 191
        }
187 192
      },
188 193
      "description": "Metadata about the requesting account's relationship to this listing. Empty for logged-out viewers and viewers with no interaction."
189 194
    },
190 195
    "activityView": {
191 196
      "type": "object",
192 197
      "required": [
193 198
        "kind",
194 199
        "createdAt"
195 200
      ],
196 201
      "properties": {
197 202
        "kind": {
198 203
          "type": "string",
199 204
          "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).",
200 205
          "knownValues": [
201 206
            "interest",
202 207
            "hand",
203 208
            "follow",
204 209
            "exchangeChosen",
205 210
            "exchangeCompleted",
206 211
            "exchangeConfirmed",
207 212
            "exchangeDeclined",
208 213
            "exchangeReturned",
209 214
            "reply"
210 215
          ]
211 216
        },
212 217
        "note": {
213 218
          "type": "string",
214 219
          "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."
215 220
        },
216 221
        "listing": {
217 222
          "ref": "#listingView",
218 223
          "type": "ref",
219 224
          "description": "The listing this activity is about (full listingView; carries the moderation signal the outgoing-row gate reads). Absent on 'follow' rows."
220 225
        },
221 226
        "neighbor": {
222 227
          "ref": "community.gifthood.actor.defs#profileViewBasic",
223 228
          "type": "ref",
224 229
          "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."
225 230
        },
226 231
        "createdAt": {
227 232
          "type": "string",
228 233
          "format": "datetime",
229 234
          "description": "When this activity event was created — the newest-first merge/sort key across all activity kinds (interest, hand, follow)."
230 235
        },
231 236
        "followers": {
232 237
          "type": "array",
233 238
          "items": {
234 239
            "ref": "community.gifthood.actor.defs#profileView",
235 240
            "type": "ref"
236 241
          },
237 242
          "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)."
238 243
        },
239 244
        "isFollowBack": {
240 245
          "type": "boolean",
241 246
          "description": "Order-sensitive reciprocity: true when the viewer followed this actor first and they reciprocated. Server-computed; meaningful only on single (ungrouped) 'follow' rows."
242 247
        }
243 248
      },
244 249
      "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')."
245 250
    },
246 251
    "exchangeView": {
247 252
      "type": "object",
248 253
      "required": [
249 254
        "uri",
250 255
        "cid",
251 256
        "listingUri",
252 257
        "giverDid",
253 258
        "receiverDid",
254 259
        "counterparty",
255 260
        "state",
256 261
        "createdAt"
257 262
      ],
258 263
      "properties": {
259 264
        "cid": {
260 265
          "type": "string",
261 266
          "format": "cid",
262 267
          "description": "CID of the exchange record."
263 268
        },
264 269
        "uri": {
265 270
          "type": "string",
266 271
          "format": "at-uri",
267 272
          "description": "AT-URI of the exchange record."
268 273
        },
269 274
        "state": {
270 275
          "type": "string",
271 276
          "description": "Derived exchange state. Open set (knownValues, not a closed enum).",
272 277
          "knownValues": [
273 278
            "pending",
274 279
            "completed",
275 280
            "confirmed",
276 281
            "declined"
277 282
          ]
278 283
        },
279 284
        "giverDid": {
280 285
          "type": "string",
281 286
          "format": "did",
282 287
          "description": "DID of the party giving the item."
283 288
        },
284 289
        "createdAt": {
285 290
          "type": "string",
286 291
          "format": "datetime",
287 292
          "description": "When the exchange record was created."
288 293
        },
289 294
        "listingUri": {
290 295
          "type": "string",
291 296
          "format": "at-uri",
292 297
          "description": "AT-URI of the listing this exchange is for."
293 298
        },
294 299
        "returnedAt": {
295 300
          "type": "string",
296 301
          "format": "datetime",
297 302
          "description": "When the owner marked the lent item returned. Absent until then; only present on lend-listing exchanges."
298 303
        },
299 304
        "completedAt": {
300 305
          "type": "string",
301 306
          "format": "datetime",
302 307
          "description": "When the giver marked the gift complete — the item handed over or the service rendered. Absent until then."
303 308
        },
304 309
        "receiverDid": {
305 310
          "type": "string",
306 311
          "format": "did",
307 312
          "description": "DID of the party receiving the item."
308 313
        },
309 314
        "respondedAt": {
310 315
          "type": "string",
311 316
          "format": "datetime",
312 317
          "description": "When the counterparty confirmed or declined. Absent until they respond."
313 318
        },
314 319
        "counterparty": {
315 320
          "ref": "#exchangeCounterpartyView",
316 321
          "type": "ref",
317 322
          "description": "The non-listing-owner party's resolved identity."
318 323
        }
319 324
      },
320 325
      "description": "The active exchange on a listing, flattened with the counterparty's resolved identity."
321 326
    },
322 327
    "interestView": {
323 328
      "type": "object",
324 329
      "required": [
325 330
        "did",
326 331
        "uri",
327 332
        "cid",
328 333
        "createdAt"
329 334
      ],
330 335
      "properties": {
331 336
        "cid": {
332 337
          "type": "string",
333 338
          "format": "cid",
334 339
          "description": "CID of the interest record (used for messaging/report)."
335 340
        },
336 341
        "did": {
337 342
          "type": "string",
338 343
          "format": "did",
339 344
          "description": "DID of the interested person."
340 345
        },
341 346
        "uri": {
342 347
          "type": "string",
343 348
          "format": "at-uri",
344 349
          "description": "AT-URI of the interest record."
345 350
        },
346 351
        "note": {
347 352
          "type": "string",
348 353
          "description": "The interest's note/message. Absent when none left."
349 354
        },
350 355
        "avatar": {
351 356
          "type": "string",
352 357
          "description": "Avatar image URL (proxied). Absent when none."
353 358
        },
354 359
        "handle": {
355 360
          "type": "string",
356 361
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
357 362
        },
358 363
        "createdAt": {
359 364
          "type": "string",
360 365
          "format": "datetime",
361 366
          "description": "When the interest was created (client-set; the row order key)."
362 367
        },
363 368
        "noteFacets": {
364 369
          "type": "array",
365 370
          "items": {
366 371
            "ref": "app.bsky.richtext.facet",
367 372
            "type": "ref"
368 373
          },
369 374
          "description": "Rich-text facets (links + mentions) over the note. Absent when none."
370 375
        },
371 376
        "displayName": {
372 377
          "type": "string",
373 378
          "description": "Real display name (nullable — the row shows name + @handle separately). Absent when none set."
374 379
        }
375 380
      },
376 381
      "description": "An interest ('raised hand') on a listing, flattened with the interested person's resolved identity (real displayName + handle + avatar). Mirrors the InterestedPerson row."
377 382
    },
378 383
    "moderationView": {
379 384
      "type": "object",
380 385
      "required": [
381 386
        "tier",
382 387
        "reason"
383 388
      ],
384 389
      "properties": {
385 390
        "tier": {
386 391
          "enum": [
387 392
            "warn",
388 393
            "hide"
389 394
          ],
390 395
          "type": "string",
391 396
          "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."
392 397
        },
393 398
        "reason": {
394 399
          "type": "string",
395 400
          "description": "Human-readable reason for the moderation action."
396 401
        }
397 402
      },
398 403
      "description": "Active soft moderation signal applied to a listing (warn or hide tier)."
399 404
    },
400 405
    "replyAuthorView": {
401 406
      "type": "object",
402 407
      "required": [
403 408
        "did"
404 409
      ],
405 410
      "properties": {
406 411
        "did": {
407 412
          "type": "string",
408 413
          "format": "did",
409 414
          "description": "DID of the reply's author."
410 415
        },
411 416
        "avatar": {
412 417
          "type": "string",
413 418
          "description": "Avatar image URL (proxied). Absent when none."
414 419
        },
415 420
        "handle": {
416 421
          "type": "string",
417 422
          "format": "handle",
418 423
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
419 424
        },
420 425
        "displayName": {
421 426
          "type": "string",
422 427
          "maxLength": 640,
423 428
          "description": "Real display name. Absent when none set.",
424 429
          "maxGraphemes": 64
425 430
        }
426 431
      },
427 432
      "description": "A reply author's resolved identity — sibling def to exchangeCounterpartyView (inline object property types are illegal in this lexicon toolchain)."
428 433
    },
429 434
    "listingDetailView": {
430 435
      "type": "object",
431 436
      "required": [
432 437
        "listing",
433 438
        "cid",
434 439
        "images"
435 440
      ],
436 441
      "properties": {
437 442
        "cid": {
438 443
          "type": "string",
439 444
          "format": "cid",
440 445
          "description": "CID of the listing record in the poster's repo."
441 446
        },
442 447
        "langs": {
443 448
          "type": "array",
444 449
          "items": {
445 450
            "type": "string",
446 451
            "format": "language"
447 452
          },
448 453
          "description": "BCP-47 language tags for the listing's text content. Absent when unspecified."
449 454
        },
450 455
        "facets": {
451 456
          "type": "array",
452 457
          "items": {
453 458
            "ref": "app.bsky.richtext.facet",
454 459
            "type": "ref"
455 460
          },
456 461
          "description": "Rich-text annotations (links, mentions, tags) over the description. Absent when no facets are present."
457 462
        },
458 463
        "images": {
459 464
          "type": "array",
460 465
          "items": {
461 466
            "ref": "#imageView",
462 467
            "type": "ref"
463 468
          },
464 469
          "description": "All images associated with the listing. May be empty."
465 470
        },
466 471
        "viewer": {
467 472
          "ref": "#viewerState",
468 473
          "type": "ref",
469 474
          "description": "The requesting account's viewer-specific state for this listing (e.g. their own interest). Absent for logged-out viewers."
470 475
        },
471 476
        "listing": {
472 477
          "ref": "#listingView",
473 478
          "type": "ref",
474 479
          "description": "The summary listing view."
475 480
        },
476 481
        "description": {
477 482
          "type": "string",
478 483
          "description": "Full description of the item, in plain text. Absent when the poster provided no description."
479 484
        }
480 485
      },
481 486
      "description": "Full detail view of a single listing, including all images, rich-text facets, and viewer state."
482 487
    },
483 488
    "exchangeCounterpartyView": {
484 489
      "type": "object",
485 490
      "required": [
486 491
        "did"
487 492
      ],
488 493
      "properties": {
489 494
        "did": {
490 495
          "type": "string",
491 496
          "format": "did",
492 497
          "description": "DID of the counterparty."
493 498
        },
494 499
        "handle": {
495 500
          "type": "string",
496 501
          "format": "handle",
497 502
          "description": "Live-resolved handle (without leading @). Absent when unresolvable."
498 503
        },
499 504
        "displayName": {
500 505
          "type": "string",
501 506
          "maxLength": 640,
502 507
          "description": "Real display name. Absent when none set.",
503 508
          "maxGraphemes": 64
504 509
        }
505 510
      },
506 511
      "description": "The non-listing-owner exchange party's resolved identity."
507 512
    }
508 513
  },
509 514
  "$type": "com.atproto.lexicon.schema",
510 515
  "lexicon": 1
511 516
}

Compare Other Versions

Lexicon Garden

@