👁️
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor lists to strongref decks

+51 -38
+5 -5
lexicons/com/deckbelcher/collection/list.json
··· 72 72 "deckItem": { 73 73 "type": "object", 74 74 "properties": { 75 - "deckUri": { 76 - "type": "string", 77 - "format": "at-uri", 78 - "description": "AT-URI of the deck record." 75 + "ref": { 76 + "type": "ref", 77 + "ref": "com.atproto.repo.strongRef", 78 + "description": "Reference to the deck record." 79 79 }, 80 80 "addedAt": { 81 81 "type": "string", ··· 85 85 }, 86 86 "description": "A deck saved to the list.", 87 87 "required": [ 88 - "deckUri", 88 + "ref", 89 89 "addedAt" 90 90 ] 91 91 }
+2 -2
src/components/list/SaveToListDialog.tsx
··· 72 72 const itemUri = 73 73 item.type === "card" 74 74 ? toOracleUri(item.oracleId) 75 - : (item.deckUri as `at://${string}`); 75 + : (item.uri as `at://${string}`); 76 76 const queryKeys = getConstellationQueryKeys(itemUri, userDid); 77 77 78 78 const previousSaved = queryClient.getQueryData<boolean>( ··· 225 225 const isSaved = 226 226 item.type === "card" 227 227 ? hasCard(list, item.scryfallId) 228 - : hasDeck(list, item.deckUri); 228 + : hasDeck(list, item.uri); 229 229 230 230 const handleClick = () => { 231 231 const isAdding = !isSaved;
+1 -1
src/components/social/SocialStats.tsx
··· 16 16 } 17 17 18 18 function getItemUri(item: SaveItem): SocialItemUri { 19 - return item.type === "card" ? toOracleUri(item.oracleId) : item.deckUri; 19 + return item.type === "card" ? toOracleUri(item.oracleId) : item.uri; 20 20 } 21 21 22 22 export function SocialStats({
+11 -8
src/lib/collection-list-queries.ts
··· 175 175 items.push({ 176 176 $type: "com.deckbelcher.collection.list#deckItem", 177 177 addedAt, 178 - deckUri: initialItem.deckUri as ResourceUri, 178 + ref: { 179 + uri: initialItem.uri as ResourceUri, 180 + cid: initialItem.cid, 181 + }, 179 182 }); 180 183 } 181 184 } ··· 389 392 const isSaved = 390 393 item.type === "card" 391 394 ? hasCard(list, item.scryfallId) 392 - : hasDeck(list, item.deckUri); 395 + : hasDeck(list, item.uri); 393 396 394 397 const updatedList = isSaved 395 398 ? item.type === "card" 396 399 ? removeCardFromList(list, item.scryfallId) 397 - : removeDeckFromList(list, item.deckUri) 400 + : removeDeckFromList(list, item.uri) 398 401 : item.type === "card" 399 402 ? addCardToList(list, item.scryfallId, item.oracleId) 400 - : addDeckToList(list, item.deckUri); 403 + : addDeckToList(list, item.uri, item.cid); 401 404 402 405 const result = await updateCollectionListRecord(agent, rkey, { 403 406 $type: "com.deckbelcher.collection.list", ··· 438 441 const isSaved = 439 442 item.type === "card" 440 443 ? hasCard(list, item.scryfallId) 441 - : hasDeck(list, item.deckUri); 444 + : hasDeck(list, item.uri); 442 445 443 446 // Compute updated list optimistically 444 447 const updatedList = isSaved 445 448 ? item.type === "card" 446 449 ? removeCardFromList(list, item.scryfallId) 447 - : removeDeckFromList(list, item.deckUri) 450 + : removeDeckFromList(list, item.uri) 448 451 : item.type === "card" 449 452 ? addCardToList(list, item.scryfallId, item.oracleId) 450 - : addDeckToList(list, item.deckUri); 453 + : addDeckToList(list, item.uri, item.cid); 451 454 452 455 // Cancel in-flight queries 453 456 await queryClient.cancelQueries({ ··· 497 500 const itemUri = 498 501 item.type === "card" 499 502 ? toOracleUri(item.oracleId) 500 - : (item.deckUri as `at://${string}`); 503 + : (item.uri as `at://${string}`); 501 504 const constellationKeys = getConstellationQueryKeys(itemUri, did); 502 505 503 506 await queryClient.cancelQueries({
+13 -10
src/lib/collection-list-types.ts
··· 11 11 /** 12 12 * Item to save to a list (card or deck) 13 13 * Shared by SaveToListDialog and SocialStats 14 + * Deck items use strongRef (uri + cid) matching the lexicon 14 15 */ 15 16 export type SaveItem = 16 17 | { type: "card"; scryfallId: ScryfallId; oracleId: OracleId } 17 - | { type: "deck"; deckUri: DeckItemUri; cid: string }; 18 + | { type: "deck"; uri: DeckItemUri; cid: string }; 18 19 19 20 /** 20 21 * App-side card item with flat typed IDs. ··· 54 55 ); 55 56 } 56 57 57 - export function hasDeck(list: CollectionList, deckUri: string): boolean { 58 - return list.items.some( 59 - (item) => isDeckItem(item) && item.deckUri === deckUri, 60 - ); 58 + export function hasDeck(list: CollectionList, uri: string): boolean { 59 + return list.items.some((item) => isDeckItem(item) && item.ref.uri === uri); 61 60 } 62 61 63 62 export function addCardToList( ··· 85 84 86 85 export function addDeckToList( 87 86 list: CollectionList, 88 - deckUri: string, 87 + uri: string, 88 + cid: string, 89 89 ): CollectionList { 90 - if (hasDeck(list, deckUri)) { 90 + if (hasDeck(list, uri)) { 91 91 return list; 92 92 } 93 93 94 94 const newItem: ListDeckItem = { 95 95 $type: "com.deckbelcher.collection.list#deckItem", 96 - deckUri: deckUri as ResourceUri, 96 + ref: { 97 + uri: uri as ResourceUri, 98 + cid, 99 + }, 97 100 addedAt: new Date().toISOString(), 98 101 }; 99 102 ··· 119 122 120 123 export function removeDeckFromList( 121 124 list: CollectionList, 122 - deckUri: string, 125 + uri: string, 123 126 ): CollectionList { 124 127 return { 125 128 ...list, 126 129 items: list.items.filter( 127 - (item) => !(isDeckItem(item) && item.deckUri === deckUri), 130 + (item) => !(isDeckItem(item) && item.ref.uri === uri), 128 131 ), 129 132 updatedAt: new Date().toISOString(), 130 133 };
+1 -1
src/lib/constellation-client.ts
··· 14 14 export const COLLECTION_LIST_CARD_PATH = 15 15 ".items[com.deckbelcher.collection.list#cardItem].ref.oracleUri"; 16 16 export const COLLECTION_LIST_DECK_PATH = 17 - ".items[com.deckbelcher.collection.list#deckItem].deckUri"; 17 + ".items[com.deckbelcher.collection.list#deckItem].ref.uri"; 18 18 // Future: cards in decks (also uses oracleUri for aggregation) 19 19 export const DECK_LIST_CARD_PATH = ".cards[].ref.oracleUri"; 20 20
+5 -2
src/lib/lexicons/types/com/deckbelcher/collection/list.ts
··· 1 1 import type {} from "@atcute/lexicons"; 2 2 import * as v from "@atcute/lexicons/validations"; 3 3 import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../atproto/repo/strongRef.js"; 4 5 import * as ComDeckbelcherDefs from "../defs.js"; 5 6 import * as ComDeckbelcherRichtext from "../richtext.js"; 6 7 ··· 28 29 */ 29 30 addedAt: /*#__PURE__*/ v.datetimeString(), 30 31 /** 31 - * AT-URI of the deck record. 32 + * Reference to the deck record. 32 33 */ 33 - deckUri: /*#__PURE__*/ v.resourceUriString(), 34 + get ref() { 35 + return ComAtprotoRepoStrongRef.mainSchema; 36 + }, 34 37 }); 35 38 const _mainSchema = /*#__PURE__*/ v.record( 36 39 /*#__PURE__*/ v.tidString(),
+2 -2
src/lib/like-queries.ts
··· 68 68 69 69 let subject: LikeSubject; 70 70 if (params.item.type === "deck") { 71 - subject = buildRecordSubject(params.item.deckUri, params.item.cid); 71 + subject = buildRecordSubject(params.item.uri, params.item.cid); 72 72 } else { 73 73 subject = buildCardSubject( 74 74 params.item.scryfallId, ··· 94 94 const userDid = session?.info.sub; 95 95 const itemUri = 96 96 params.item.type === "deck" 97 - ? (params.item.deckUri as `at://${string}`) 97 + ? (params.item.uri as `at://${string}`) 98 98 : toOracleUri(params.item.oracleId); 99 99 100 100 const keys = getConstellationQueryKeys(itemUri, userDid);
+5 -2
src/routes/profile/$did/deck/$rkey/index.tsx
··· 417 417 did={did} 418 418 rkey={rkey} 419 419 deck={deck} 420 + deckCid={deckRecord.cid} 420 421 groupBy={groupBy} 421 422 sortBy={sortBy} 422 423 previewCard={previewCard} ··· 458 459 did: string; 459 460 rkey: string; 460 461 deck: Deck; 462 + deckCid: string; 461 463 groupBy: GroupBy; 462 464 sortBy: SortBy; 463 465 previewCard: ScryfallId; ··· 496 498 did, 497 499 rkey, 498 500 deck, 501 + deckCid, 499 502 groupBy, 500 503 sortBy, 501 504 previewCard, ··· 586 589 <SocialStats 587 590 item={{ 588 591 type: "deck", 589 - deckUri: `at://${did}/com.deckbelcher.deck.list/${rkey}`, 590 - cid: deckRecord.cid, 592 + uri: `at://${did}/com.deckbelcher.deck.list/${rkey}`, 593 + cid: deckCid, 591 594 }} 592 595 itemName={deck.name} 593 596 />
+4 -3
src/routes/profile/$did/list/$rkey/index.tsx
··· 127 127 const handleRemoveDeck = (item: ListDeckItem) => { 128 128 const saveItem: SaveItem = { 129 129 type: "deck", 130 - deckUri: item.deckUri, 130 + uri: item.ref.uri, 131 + cid: item.ref.cid, 131 132 }; 132 133 toggleMutation.mutate({ list, item: saveItem }); 133 134 }; ··· 244 245 /> 245 246 ) : isDeckItem(item) ? ( 246 247 <DeckListItem 247 - key={item.deckUri} 248 + key={item.ref.uri} 248 249 item={item} 249 250 onRemove={isOwner ? handleRemoveDeck : undefined} 250 251 /> ··· 322 323 } 323 324 324 325 function DeckListItem({ item, onRemove }: DeckListItemProps) { 325 - const parts = item.deckUri.split("/"); 326 + const parts = item.ref.uri.split("/"); 326 327 const deckDid = parts[2] as Did; 327 328 const deckRkey = parts[4] as Rkey; 328 329
+2 -2
typelex/collection-list.tsp
··· 41 41 42 42 /** A deck saved to the list. */ 43 43 model DeckItem { 44 - /** AT-URI of the deck record. */ 44 + /** Reference to the deck record. */ 45 45 @required 46 - deckUri: atUri; 46 + ref: com.atproto.repo.strongRef.Main; 47 47 48 48 /** Timestamp when this item was added to the list. */ 49 49 @required