Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol diffdown.com
at main 98 lines 3.4 kB view raw
1package model 2 3import ( 4 "strings" 5 "time" 6) 7 8type User struct { 9 ID string `json:"id"` 10 DID string `json:"did"` 11} 12 13type ATProtoSession struct { 14 UserID string `json:"user_id"` 15 DID string `json:"did"` 16 PDSURL string `json:"pds_url"` 17 AccessToken string `json:"access_token"` 18 RefreshToken string `json:"refresh_token"` 19 DPoPKeyJWK string `json:"dpop_key_jwk"` 20 DPoPNonce string `json:"dpop_nonce"` 21 TokenEndpoint string `json:"token_endpoint"` 22 ExpiresAt time.Time `json:"expires_at"` 23 UpdatedAt time.Time `json:"updated_at"` 24} 25 26// --- Document model (Diffdown lexicon) --- 27 28type Document struct { 29 // ATProto metadata 30 URI string `json:"uri,omitempty"` 31 CID string `json:"cid,omitempty"` 32 RKey string `json:"rkey,omitempty"` 33 // Document fields 34 Title string `json:"title"` 35 Content *MarkdownContent `json:"content,omitempty"` 36 TextContent string `json:"textContent,omitempty"` 37 Collaborators []string `json:"collaborators,omitempty"` 38 Comments []EmbeddedComment `json:"comments,omitempty"` 39 CreatedAt string `json:"createdAt"` 40 UpdatedAt string `json:"updatedAt,omitempty"` 41} 42 43type MarkdownContent struct { 44 Type string `json:"$type"` 45 Flavor string `json:"flavor"` 46 Text MarkdownText `json:"text"` 47} 48 49type MarkdownText struct { 50 RawMarkdown string `json:"rawMarkdown"` 51} 52 53type EmbeddedComment struct { 54 ID string `json:"id"` // random 8-char hex for dedup 55 ThreadID string `json:"threadId"` // links to ProseMirror comment mark 56 QuotedText string `json:"quotedText"` // text the comment was anchored to 57 Text string `json:"text"` 58 Author string `json:"author"` // DID 59 AuthorHandle string `json:"authorHandle"` // resolved handle, may be empty 60 CreatedAt string `json:"createdAt"` // RFC3339 61} 62 63type CommentRecord struct { 64 ID string `json:"id"` // record key (rkey) 65 ThreadID string `json:"threadId"` // groups replies into threads 66 DocRKey string `json:"docRKey"` // document rkey this comment belongs to 67 DocOwnerDID string `json:"docOwnerDid"` // owner DID for quick filtering 68 QuotedText string `json:"quotedText"` // text the comment was anchored to 69 Text string `json:"text"` // comment content 70 Author string `json:"author"` // DID 71 AuthorHandle string `json:"authorHandle"` // resolved handle 72 CreatedAt string `json:"createdAt"` // RFC3339 73 ReplyTo string `json:"replyTo,omitempty"` // parent comment URI (null for root) 74 Resolved bool `json:"resolved"` // thread resolution state 75} 76 77type Invite struct { 78 ID string `json:"id"` 79 DocumentRKey string `json:"document_rkey"` 80 Token string `json:"token"` 81 CreatedBy string `json:"created_by"` 82 CreatedAt time.Time `json:"created_at"` 83 ExpiresAt time.Time `json:"expires_at"` 84} 85 86// RKeyFromURI extracts the rkey (last path segment) from an at:// URI. 87func RKeyFromURI(uri string) string { 88 parts := strings.Split(uri, "/") 89 if len(parts) > 0 { 90 return parts[len(parts)-1] 91 } 92 return "" 93} 94 95const ( 96 CollectionDocument = "com.diffdown.document" 97 CollectionComment = "com.diffdown.comment" 98)