👁️
5
fork

Configure Feed

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

start on replies

+665
+132
lexicons/com/deckbelcher/social/comment.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.deckbelcher.social.comment", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "properties": { 11 + "subject": { 12 + "type": "union", 13 + "refs": [ 14 + "#cardSubject", 15 + "#recordSubject" 16 + ], 17 + "description": "What this comment is on." 18 + }, 19 + "target": { 20 + "type": "union", 21 + "refs": [ 22 + "#cardTarget", 23 + "#deckTarget", 24 + "#sectionTarget", 25 + "#tagTarget" 26 + ], 27 + "description": "Optional refinement within subject (card/section/tag in a deck)." 28 + }, 29 + "content": { 30 + "type": "ref", 31 + "ref": "com.deckbelcher.richtext#document", 32 + "description": "Rich text content." 33 + }, 34 + "createdAt": { 35 + "type": "string", 36 + "format": "datetime" 37 + }, 38 + "updatedAt": { 39 + "type": "string", 40 + "format": "datetime" 41 + } 42 + }, 43 + "required": [ 44 + "subject", 45 + "content", 46 + "createdAt" 47 + ] 48 + }, 49 + "description": "Top-level comment on a card, deck, or collection." 50 + }, 51 + "cardSubject": { 52 + "type": "object", 53 + "properties": { 54 + "ref": { 55 + "type": "ref", 56 + "ref": "com.deckbelcher.defs#cardRef" 57 + } 58 + }, 59 + "description": "Subject: a card (global comment on the card itself).", 60 + "required": [ 61 + "ref" 62 + ] 63 + }, 64 + "recordSubject": { 65 + "type": "object", 66 + "properties": { 67 + "ref": { 68 + "type": "ref", 69 + "ref": "com.atproto.repo.strongRef" 70 + } 71 + }, 72 + "description": "Subject: an ATProto record (deck, collection).", 73 + "required": [ 74 + "ref" 75 + ] 76 + }, 77 + "cardTarget": { 78 + "type": "object", 79 + "properties": { 80 + "ref": { 81 + "type": "ref", 82 + "ref": "com.deckbelcher.defs#cardRef" 83 + } 84 + }, 85 + "description": "Target: a card (in a deck or collection).", 86 + "required": [ 87 + "ref" 88 + ] 89 + }, 90 + "deckTarget": { 91 + "type": "object", 92 + "properties": { 93 + "ref": { 94 + "type": "ref", 95 + "ref": "com.atproto.repo.strongRef" 96 + } 97 + }, 98 + "description": "Target: a deck (in a collection).", 99 + "required": [ 100 + "ref" 101 + ] 102 + }, 103 + "sectionTarget": { 104 + "type": "object", 105 + "properties": { 106 + "section": { 107 + "type": "string", 108 + "maxLength": 640, 109 + "maxGraphemes": 64 110 + } 111 + }, 112 + "description": "Target: a deck section (mainboard, sideboard, etc).", 113 + "required": [ 114 + "section" 115 + ] 116 + }, 117 + "tagTarget": { 118 + "type": "object", 119 + "properties": { 120 + "tag": { 121 + "type": "string", 122 + "maxLength": 640, 123 + "maxGraphemes": 64 124 + } 125 + }, 126 + "description": "Target: a tag package (ramp, removal, wincons, etc).", 127 + "required": [ 128 + "tag" 129 + ] 130 + } 131 + } 132 + }
+45
lexicons/com/deckbelcher/social/reply.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.deckbelcher.social.reply", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "key": "tid", 8 + "record": { 9 + "type": "object", 10 + "properties": { 11 + "parent": { 12 + "type": "ref", 13 + "ref": "com.atproto.repo.strongRef", 14 + "description": "The comment or reply being replied to." 15 + }, 16 + "root": { 17 + "type": "ref", 18 + "ref": "com.atproto.repo.strongRef", 19 + "description": "The root top-level comment (for efficient thread loading)." 20 + }, 21 + "content": { 22 + "type": "ref", 23 + "ref": "com.deckbelcher.richtext#document", 24 + "description": "Rich text content." 25 + }, 26 + "createdAt": { 27 + "type": "string", 28 + "format": "datetime" 29 + }, 30 + "updatedAt": { 31 + "type": "string", 32 + "format": "datetime" 33 + } 34 + }, 35 + "required": [ 36 + "parent", 37 + "root", 38 + "content", 39 + "createdAt" 40 + ] 41 + }, 42 + "description": "Reply to a comment or another reply." 43 + } 44 + } 45 + }
+72
src/lib/atproto-client.ts
··· 16 16 ComDeckbelcherActorProfile, 17 17 ComDeckbelcherCollectionList, 18 18 ComDeckbelcherDeckList, 19 + ComDeckbelcherSocialComment, 19 20 ComDeckbelcherSocialLike, 21 + ComDeckbelcherSocialReply, 20 22 } from "./lexicons/index"; 21 23 22 24 type AtUri = `at://${string}`; ··· 570 572 ComDeckbelcherActorProfile.mainSchema, 571 573 ); 572 574 } 575 + 576 + // ============================================================================ 577 + // Comment Records (top-level comments) 578 + // ============================================================================ 579 + 580 + export type CommentRecordResponse = 581 + RecordResponse<ComDeckbelcherSocialComment.Main>; 582 + 583 + export function getCommentRecord(did: Did, rkey: Rkey) { 584 + return getRecord(did, rkey, ComDeckbelcherSocialComment.mainSchema); 585 + } 586 + 587 + export function createCommentRecord( 588 + agent: OAuthUserAgent, 589 + record: ComDeckbelcherSocialComment.Main, 590 + ) { 591 + return createRecord(agent, record, ComDeckbelcherSocialComment.mainSchema); 592 + } 593 + 594 + export function updateCommentRecord( 595 + agent: OAuthUserAgent, 596 + rkey: Rkey, 597 + record: ComDeckbelcherSocialComment.Main, 598 + ) { 599 + return updateRecord( 600 + agent, 601 + rkey, 602 + record, 603 + ComDeckbelcherSocialComment.mainSchema, 604 + ); 605 + } 606 + 607 + export function deleteCommentRecord(agent: OAuthUserAgent, rkey: Rkey) { 608 + return deleteRecord(agent, rkey, ComDeckbelcherSocialComment.mainSchema); 609 + } 610 + 611 + // ============================================================================ 612 + // Reply Records (threaded replies to comments) 613 + // ============================================================================ 614 + 615 + export type ReplyRecordResponse = 616 + RecordResponse<ComDeckbelcherSocialReply.Main>; 617 + 618 + export function getReplyRecord(did: Did, rkey: Rkey) { 619 + return getRecord(did, rkey, ComDeckbelcherSocialReply.mainSchema); 620 + } 621 + 622 + export function createReplyRecord( 623 + agent: OAuthUserAgent, 624 + record: ComDeckbelcherSocialReply.Main, 625 + ) { 626 + return createRecord(agent, record, ComDeckbelcherSocialReply.mainSchema); 627 + } 628 + 629 + export function updateReplyRecord( 630 + agent: OAuthUserAgent, 631 + rkey: Rkey, 632 + record: ComDeckbelcherSocialReply.Main, 633 + ) { 634 + return updateRecord( 635 + agent, 636 + rkey, 637 + record, 638 + ComDeckbelcherSocialReply.mainSchema, 639 + ); 640 + } 641 + 642 + export function deleteReplyRecord(agent: OAuthUserAgent, rkey: Rkey) { 643 + return deleteRecord(agent, rkey, ComDeckbelcherSocialReply.mainSchema); 644 + }
+20
src/lib/constellation-client.ts
··· 7 7 import { 8 8 ComDeckbelcherCollectionList, 9 9 ComDeckbelcherDeckList, 10 + ComDeckbelcherSocialComment, 10 11 ComDeckbelcherSocialLike, 12 + ComDeckbelcherSocialReply, 11 13 } from "./lexicons/index"; 12 14 13 15 const CONSTELLATION_BASE = "https://constellation.microcosm.blue"; ··· 23 25 export const LIKE_NSID = getCollectionFromSchema( 24 26 ComDeckbelcherSocialLike.mainSchema, 25 27 ); 28 + export const COMMENT_NSID = getCollectionFromSchema( 29 + ComDeckbelcherSocialComment.mainSchema, 30 + ); 31 + export const REPLY_NSID = getCollectionFromSchema( 32 + ComDeckbelcherSocialReply.mainSchema, 33 + ); 26 34 27 35 // Path constants for DeckBelcher collections 28 36 // Constellation includes $type in paths for union array elements ··· 35 43 // Like paths (subject is a union but NOT an array, so no [$type] notation) 36 44 export const LIKE_CARD_PATH = ".subject.ref.oracleUri"; 37 45 export const LIKE_RECORD_PATH = ".subject.ref.uri"; 46 + 47 + // Comment paths (top-level comments, subject is union) 48 + // Query comments on a card (global card discussion) 49 + export const COMMENT_CARD_PATH = ".subject.ref.oracleUri"; 50 + // Query comments on a record (deck, collection, etc) 51 + export const COMMENT_RECORD_PATH = ".subject.ref.uri"; 52 + 53 + // Reply paths (threaded replies) 54 + // Query by root to get all replies in a thread (for thread expansion) 55 + export const REPLY_ROOT_PATH = ".root.uri"; 56 + // Query by parent to get direct replies to a specific comment/reply 57 + export const REPLY_PARENT_PATH = ".parent.uri"; 38 58 39 59 export interface BacklinkRecord { 40 60 did: string;
+116
src/lib/constellation-queries.ts
··· 14 14 COLLECTION_LIST_CARD_PATH, 15 15 COLLECTION_LIST_DECK_PATH, 16 16 COLLECTION_LIST_NSID, 17 + COMMENT_CARD_PATH, 18 + COMMENT_NSID, 19 + COMMENT_RECORD_PATH, 17 20 DECK_LIST_CARD_PATH, 18 21 DECK_LIST_NSID, 19 22 getBacklinks, ··· 21 24 LIKE_CARD_PATH, 22 25 LIKE_NSID, 23 26 LIKE_RECORD_PATH, 27 + REPLY_NSID, 28 + REPLY_PARENT_PATH, 29 + REPLY_ROOT_PATH, 24 30 } from "./constellation-client"; 25 31 import type { OracleUri } from "./scryfall-types"; 26 32 import { useAuth } from "./useAuth"; ··· 394 400 : null, 395 401 ] as const); 396 402 } 403 + 404 + // ============================================================================ 405 + // Comment Queries 406 + // ============================================================================ 407 + 408 + function getCommentPathForItemType(itemType: SocialItemType): string { 409 + return itemType === "card" ? COMMENT_CARD_PATH : COMMENT_RECORD_PATH; 410 + } 411 + 412 + /** 413 + * Query options for getting top-level comment count for an item 414 + */ 415 + export function itemCommentCountQueryOptions<T extends SocialItemType>( 416 + itemUri: T extends "card" ? CardItemUri : DeckItemUri, 417 + itemType: T, 418 + ) { 419 + return queryOptions({ 420 + queryKey: ["constellation", "commentCount", itemUri] as const, 421 + queryFn: async (): Promise<number> => { 422 + const result = await getLinksCount({ 423 + target: itemUri, 424 + collection: COMMENT_NSID, 425 + path: getCommentPathForItemType(itemType), 426 + }); 427 + 428 + if (!result.success) { 429 + throw result.error; 430 + } 431 + 432 + return result.data.total; 433 + }, 434 + staleTime: 60 * 1000, 435 + }); 436 + } 437 + 438 + /** 439 + * Infinite query for top-level comments on an item (card or deck/collection) 440 + */ 441 + export function itemCommentsQueryOptions<T extends SocialItemType>( 442 + itemUri: T extends "card" ? CardItemUri : DeckItemUri, 443 + itemType: T, 444 + ) { 445 + return infiniteQueryOptions({ 446 + queryKey: ["constellation", "comments", itemUri] as const, 447 + queryFn: async ({ pageParam }) => { 448 + const result = await getBacklinks({ 449 + subject: itemUri, 450 + source: buildSource(COMMENT_NSID, getCommentPathForItemType(itemType)), 451 + limit: 25, 452 + cursor: pageParam, 453 + }); 454 + if (!result.success) throw result.error; 455 + return result.data; 456 + }, 457 + initialPageParam: undefined as string | undefined, 458 + getNextPageParam: (lastPage) => lastPage.cursor ?? undefined, 459 + staleTime: 60 * 1000, 460 + }); 461 + } 462 + 463 + // ============================================================================ 464 + // Reply Queries (for threading) 465 + // ============================================================================ 466 + 467 + /** 468 + * Infinite query for all replies in a thread (by root comment URI). 469 + * Use this to expand an entire thread - returns all replies regardless of depth. 470 + */ 471 + export function threadRepliesQueryOptions(rootCommentUri: string) { 472 + return infiniteQueryOptions({ 473 + queryKey: ["constellation", "threadReplies", rootCommentUri] as const, 474 + queryFn: async ({ pageParam }) => { 475 + const result = await getBacklinks({ 476 + subject: rootCommentUri, 477 + source: buildSource(REPLY_NSID, REPLY_ROOT_PATH), 478 + limit: 50, 479 + cursor: pageParam, 480 + }); 481 + if (!result.success) throw result.error; 482 + return result.data; 483 + }, 484 + initialPageParam: undefined as string | undefined, 485 + getNextPageParam: (lastPage) => lastPage.cursor ?? undefined, 486 + staleTime: 60 * 1000, 487 + }); 488 + } 489 + 490 + /** 491 + * Query options for getting direct reply count for any comment or reply. 492 + * Use this to show "X replies" on a specific comment. 493 + */ 494 + export function directReplyCountQueryOptions(commentOrReplyUri: string) { 495 + return queryOptions({ 496 + queryKey: ["constellation", "directReplyCount", commentOrReplyUri] as const, 497 + queryFn: async (): Promise<number> => { 498 + const result = await getLinksCount({ 499 + target: commentOrReplyUri, 500 + collection: REPLY_NSID, 501 + path: REPLY_PARENT_PATH, 502 + }); 503 + 504 + if (!result.success) { 505 + throw result.error; 506 + } 507 + 508 + return result.data.total; 509 + }, 510 + staleTime: 60 * 1000, 511 + }); 512 + }
+2
src/lib/lexicons/index.ts
··· 5 5 export * as ComDeckbelcherDefs from "./types/com/deckbelcher/defs.js"; 6 6 export * as ComDeckbelcherRichtext from "./types/com/deckbelcher/richtext.js"; 7 7 export * as ComDeckbelcherRichtextFacet from "./types/com/deckbelcher/richtext/facet.js"; 8 + export * as ComDeckbelcherSocialComment from "./types/com/deckbelcher/social/comment.js"; 8 9 export * as ComDeckbelcherSocialLike from "./types/com/deckbelcher/social/like.js"; 10 + export * as ComDeckbelcherSocialReply from "./types/com/deckbelcher/social/reply.js";
+138
src/lib/lexicons/types/com/deckbelcher/social/comment.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../atproto/repo/strongRef.js"; 5 + import * as ComDeckbelcherDefs from "../defs.js"; 6 + import * as ComDeckbelcherRichtext from "../richtext.js"; 7 + 8 + const _cardSubjectSchema = /*#__PURE__*/ v.object({ 9 + $type: /*#__PURE__*/ v.optional( 10 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#cardSubject"), 11 + ), 12 + get ref() { 13 + return ComDeckbelcherDefs.cardRefSchema; 14 + }, 15 + }); 16 + const _cardTargetSchema = /*#__PURE__*/ v.object({ 17 + $type: /*#__PURE__*/ v.optional( 18 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#cardTarget"), 19 + ), 20 + get ref() { 21 + return ComDeckbelcherDefs.cardRefSchema; 22 + }, 23 + }); 24 + const _deckTargetSchema = /*#__PURE__*/ v.object({ 25 + $type: /*#__PURE__*/ v.optional( 26 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#deckTarget"), 27 + ), 28 + get ref() { 29 + return ComAtprotoRepoStrongRef.mainSchema; 30 + }, 31 + }); 32 + const _mainSchema = /*#__PURE__*/ v.record( 33 + /*#__PURE__*/ v.tidString(), 34 + /*#__PURE__*/ v.object({ 35 + $type: /*#__PURE__*/ v.literal("com.deckbelcher.social.comment"), 36 + /** 37 + * Rich text content. 38 + */ 39 + get content() { 40 + return ComDeckbelcherRichtext.documentSchema; 41 + }, 42 + createdAt: /*#__PURE__*/ v.datetimeString(), 43 + /** 44 + * What this comment is on. 45 + */ 46 + get subject() { 47 + return /*#__PURE__*/ v.variant([cardSubjectSchema, recordSubjectSchema]); 48 + }, 49 + /** 50 + * Optional refinement within subject (card/section/tag in a deck). 51 + */ 52 + get target() { 53 + return /*#__PURE__*/ v.optional( 54 + /*#__PURE__*/ v.variant([ 55 + cardTargetSchema, 56 + deckTargetSchema, 57 + sectionTargetSchema, 58 + tagTargetSchema, 59 + ]), 60 + ); 61 + }, 62 + updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 63 + }), 64 + ); 65 + const _recordSubjectSchema = /*#__PURE__*/ v.object({ 66 + $type: /*#__PURE__*/ v.optional( 67 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#recordSubject"), 68 + ), 69 + get ref() { 70 + return ComAtprotoRepoStrongRef.mainSchema; 71 + }, 72 + }); 73 + const _sectionTargetSchema = /*#__PURE__*/ v.object({ 74 + $type: /*#__PURE__*/ v.optional( 75 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#sectionTarget"), 76 + ), 77 + /** 78 + * @maxLength 640 79 + * @maxGraphemes 64 80 + */ 81 + section: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 82 + /*#__PURE__*/ v.stringLength(0, 640), 83 + /*#__PURE__*/ v.stringGraphemes(0, 64), 84 + ]), 85 + }); 86 + const _tagTargetSchema = /*#__PURE__*/ v.object({ 87 + $type: /*#__PURE__*/ v.optional( 88 + /*#__PURE__*/ v.literal("com.deckbelcher.social.comment#tagTarget"), 89 + ), 90 + /** 91 + * @maxLength 640 92 + * @maxGraphemes 64 93 + */ 94 + tag: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 95 + /*#__PURE__*/ v.stringLength(0, 640), 96 + /*#__PURE__*/ v.stringGraphemes(0, 64), 97 + ]), 98 + }); 99 + 100 + type cardSubject$schematype = typeof _cardSubjectSchema; 101 + type cardTarget$schematype = typeof _cardTargetSchema; 102 + type deckTarget$schematype = typeof _deckTargetSchema; 103 + type main$schematype = typeof _mainSchema; 104 + type recordSubject$schematype = typeof _recordSubjectSchema; 105 + type sectionTarget$schematype = typeof _sectionTargetSchema; 106 + type tagTarget$schematype = typeof _tagTargetSchema; 107 + 108 + export interface cardSubjectSchema extends cardSubject$schematype {} 109 + export interface cardTargetSchema extends cardTarget$schematype {} 110 + export interface deckTargetSchema extends deckTarget$schematype {} 111 + export interface mainSchema extends main$schematype {} 112 + export interface recordSubjectSchema extends recordSubject$schematype {} 113 + export interface sectionTargetSchema extends sectionTarget$schematype {} 114 + export interface tagTargetSchema extends tagTarget$schematype {} 115 + 116 + export const cardSubjectSchema = _cardSubjectSchema as cardSubjectSchema; 117 + export const cardTargetSchema = _cardTargetSchema as cardTargetSchema; 118 + export const deckTargetSchema = _deckTargetSchema as deckTargetSchema; 119 + export const mainSchema = _mainSchema as mainSchema; 120 + export const recordSubjectSchema = _recordSubjectSchema as recordSubjectSchema; 121 + export const sectionTargetSchema = _sectionTargetSchema as sectionTargetSchema; 122 + export const tagTargetSchema = _tagTargetSchema as tagTargetSchema; 123 + 124 + export interface CardSubject extends v.InferInput<typeof cardSubjectSchema> {} 125 + export interface CardTarget extends v.InferInput<typeof cardTargetSchema> {} 126 + export interface DeckTarget extends v.InferInput<typeof deckTargetSchema> {} 127 + export interface Main extends v.InferInput<typeof mainSchema> {} 128 + export interface RecordSubject 129 + extends v.InferInput<typeof recordSubjectSchema> {} 130 + export interface SectionTarget 131 + extends v.InferInput<typeof sectionTargetSchema> {} 132 + export interface TagTarget extends v.InferInput<typeof tagTargetSchema> {} 133 + 134 + declare module "@atcute/lexicons/ambient" { 135 + interface Records { 136 + "com.deckbelcher.social.comment": mainSchema; 137 + } 138 + }
+46
src/lib/lexicons/types/com/deckbelcher/social/reply.ts
··· 1 + import type {} from "@atcute/lexicons"; 2 + import * as v from "@atcute/lexicons/validations"; 3 + import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../atproto/repo/strongRef.js"; 5 + import * as ComDeckbelcherRichtext from "../richtext.js"; 6 + 7 + const _mainSchema = /*#__PURE__*/ v.record( 8 + /*#__PURE__*/ v.tidString(), 9 + /*#__PURE__*/ v.object({ 10 + $type: /*#__PURE__*/ v.literal("com.deckbelcher.social.reply"), 11 + /** 12 + * Rich text content. 13 + */ 14 + get content() { 15 + return ComDeckbelcherRichtext.documentSchema; 16 + }, 17 + createdAt: /*#__PURE__*/ v.datetimeString(), 18 + /** 19 + * The comment or reply being replied to. 20 + */ 21 + get parent() { 22 + return ComAtprotoRepoStrongRef.mainSchema; 23 + }, 24 + /** 25 + * The root top-level comment (for efficient thread loading). 26 + */ 27 + get root() { 28 + return ComAtprotoRepoStrongRef.mainSchema; 29 + }, 30 + updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 31 + }), 32 + ); 33 + 34 + type main$schematype = typeof _mainSchema; 35 + 36 + export interface mainSchema extends main$schematype {} 37 + 38 + export const mainSchema = _mainSchema as mainSchema; 39 + 40 + export interface Main extends v.InferInput<typeof mainSchema> {} 41 + 42 + declare module "@atcute/lexicons/ambient" { 43 + interface Records { 44 + "com.deckbelcher.social.reply": mainSchema; 45 + } 46 + }
+2
typelex/main.tsp
··· 6 6 import "./deck-list.tsp"; 7 7 import "./collection-list.tsp"; 8 8 import "./social-like.tsp"; 9 + import "./social-comment.tsp"; 10 + import "./social-reply.tsp"; 9 11 10 12 namespace com.deckbelcher.actor.profile { 11 13 /** A DeckBelcher user profile. */
+66
typelex/social-comment.tsp
··· 1 + import "@typelex/emitter"; 2 + import "./externals.tsp"; 3 + import "./defs.tsp"; 4 + import "./richtext.tsp"; 5 + 6 + namespace com.deckbelcher.social.comment { 7 + /** Top-level comment on a card, deck, or collection. */ 8 + @rec("tid") 9 + model Main { 10 + /** What this comment is on. */ 11 + @required 12 + subject: CardSubject | RecordSubject | unknown; 13 + 14 + /** Optional refinement within subject (card/section/tag in a deck). */ 15 + target?: CardTarget | DeckTarget | SectionTarget | TagTarget | unknown; 16 + 17 + /** Rich text content. */ 18 + @required 19 + content: com.deckbelcher.richtext.Document; 20 + 21 + @required 22 + createdAt: datetime; 23 + 24 + updatedAt?: datetime; 25 + } 26 + 27 + /** Subject: a card (global comment on the card itself). */ 28 + model CardSubject { 29 + @required 30 + ref: com.deckbelcher.defs.CardRef; 31 + } 32 + 33 + /** Subject: an ATProto record (deck, collection). */ 34 + model RecordSubject { 35 + @required 36 + ref: com.atproto.repo.strongRef.Main; 37 + } 38 + 39 + /** Target: a card (in a deck or collection). */ 40 + model CardTarget { 41 + @required 42 + ref: com.deckbelcher.defs.CardRef; 43 + } 44 + 45 + /** Target: a deck (in a collection). */ 46 + model DeckTarget { 47 + @required 48 + ref: com.atproto.repo.strongRef.Main; 49 + } 50 + 51 + /** Target: a deck section (mainboard, sideboard, etc). */ 52 + model SectionTarget { 53 + @required 54 + @maxGraphemes(64) 55 + @maxLength(640) 56 + section: string; 57 + } 58 + 59 + /** Target: a tag package (ramp, removal, wincons, etc). */ 60 + model TagTarget { 61 + @required 62 + @maxGraphemes(64) 63 + @maxLength(640) 64 + tag: string; 65 + } 66 + }
+26
typelex/social-reply.tsp
··· 1 + import "@typelex/emitter"; 2 + import "./externals.tsp"; 3 + import "./richtext.tsp"; 4 + 5 + namespace com.deckbelcher.social.reply { 6 + /** Reply to a comment or another reply. */ 7 + @rec("tid") 8 + model Main { 9 + /** The comment or reply being replied to. */ 10 + @required 11 + parent: com.atproto.repo.strongRef.Main; 12 + 13 + /** The root top-level comment (for efficient thread loading). */ 14 + @required 15 + root: com.atproto.repo.strongRef.Main; 16 + 17 + /** Rich text content. */ 18 + @required 19 + content: com.deckbelcher.richtext.Document; 20 + 21 + @required 22 + createdAt: datetime; 23 + 24 + updatedAt?: datetime; 25 + } 26 + }