Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
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)