Skip to content

Commit e395e78

Browse files
committed
Moved raw fetch to use the client
1 parent 66be4d4 commit e395e78

File tree

4 files changed

+253
-21
lines changed

4 files changed

+253
-21
lines changed

lexicons.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
{
22
"version": 1,
3-
"lexicons": ["site.standard.document"],
3+
"lexicons": ["app.bsky.actor.profile", "site.standard.document"],
44
"resolutions": {
5+
"app.bsky.actor.profile": {
6+
"uri": "at://did:plc:4v4y5r3lwsbtmsxhile2ljac/com.atproto.lexicon.schema/app.bsky.actor.profile",
7+
"cid": "bafyreia6umzg3a6d7mjbow4p57tviey45muohklhgsvjoamcctoiusr4pe"
8+
},
9+
"com.atproto.label.defs": {
10+
"uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.label.defs",
11+
"cid": "bafyreig4hmnb2xkecyg4aaqfhr2rrcxxb3gsr4xks4rqb7rscrycalbrji"
12+
},
513
"com.atproto.repo.strongRef": {
614
"uri": "at://did:plc:6msi3pj7krzih5qxqtryxlzw/com.atproto.lexicon.schema/com.atproto.repo.strongRef",
715
"cid": "bafyreifrkdbnkvfjujntdaeigolnrjj3srrs53tfixjhmacclps72qlov4"
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"id": "app.bsky.actor.profile",
3+
"defs": {
4+
"main": {
5+
"key": "literal:self",
6+
"type": "record",
7+
"record": {
8+
"type": "object",
9+
"properties": {
10+
"avatar": {
11+
"type": "blob",
12+
"accept": ["image/png", "image/jpeg"],
13+
"maxSize": 1000000,
14+
"description": "Small image to be displayed next to posts from account. AKA, 'profile picture'"
15+
},
16+
"banner": {
17+
"type": "blob",
18+
"accept": ["image/png", "image/jpeg"],
19+
"maxSize": 1000000,
20+
"description": "Larger horizontal image to display behind profile view."
21+
},
22+
"labels": {
23+
"refs": ["com.atproto.label.defs#selfLabels"],
24+
"type": "union",
25+
"description": "Self-label values, specific to the Bluesky application, on the overall account."
26+
},
27+
"website": {
28+
"type": "string",
29+
"format": "uri"
30+
},
31+
"pronouns": {
32+
"type": "string",
33+
"maxLength": 200,
34+
"description": "Free-form pronouns text.",
35+
"maxGraphemes": 20
36+
},
37+
"createdAt": {
38+
"type": "string",
39+
"format": "datetime"
40+
},
41+
"pinnedPost": {
42+
"ref": "com.atproto.repo.strongRef",
43+
"type": "ref"
44+
},
45+
"description": {
46+
"type": "string",
47+
"maxLength": 2560,
48+
"description": "Free-form profile description text.",
49+
"maxGraphemes": 256
50+
},
51+
"displayName": {
52+
"type": "string",
53+
"maxLength": 640,
54+
"maxGraphemes": 64
55+
},
56+
"joinedViaStarterPack": {
57+
"ref": "com.atproto.repo.strongRef",
58+
"type": "ref"
59+
}
60+
}
61+
},
62+
"description": "A declaration of a Bluesky account profile."
63+
}
64+
},
65+
"$type": "com.atproto.lexicon.schema",
66+
"lexicon": 1
67+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
{
2+
"id": "com.atproto.label.defs",
3+
"defs": {
4+
"label": {
5+
"type": "object",
6+
"required": ["src", "uri", "val", "cts"],
7+
"properties": {
8+
"cid": {
9+
"type": "string",
10+
"format": "cid",
11+
"description": "Optionally, CID specifying the specific version of 'uri' resource this label applies to."
12+
},
13+
"cts": {
14+
"type": "string",
15+
"format": "datetime",
16+
"description": "Timestamp when this label was created."
17+
},
18+
"exp": {
19+
"type": "string",
20+
"format": "datetime",
21+
"description": "Timestamp at which this label expires (no longer applies)."
22+
},
23+
"neg": {
24+
"type": "boolean",
25+
"description": "If true, this is a negation label, overwriting a previous label."
26+
},
27+
"sig": {
28+
"type": "bytes",
29+
"description": "Signature of dag-cbor encoded label."
30+
},
31+
"src": {
32+
"type": "string",
33+
"format": "did",
34+
"description": "DID of the actor who created this label."
35+
},
36+
"uri": {
37+
"type": "string",
38+
"format": "uri",
39+
"description": "AT URI of the record, repository (account), or other resource that this label applies to."
40+
},
41+
"val": {
42+
"type": "string",
43+
"maxLength": 128,
44+
"description": "The short string name of the value or type of this label."
45+
},
46+
"ver": {
47+
"type": "integer",
48+
"description": "The AT Protocol version of the label object."
49+
}
50+
},
51+
"description": "Metadata tag on an atproto resource (eg, repo or record)."
52+
},
53+
"selfLabel": {
54+
"type": "object",
55+
"required": ["val"],
56+
"properties": {
57+
"val": {
58+
"type": "string",
59+
"maxLength": 128,
60+
"description": "The short string name of the value or type of this label."
61+
}
62+
},
63+
"description": "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel."
64+
},
65+
"labelValue": {
66+
"type": "string",
67+
"knownValues": [
68+
"!hide",
69+
"!no-promote",
70+
"!warn",
71+
"!no-unauthenticated",
72+
"dmca-violation",
73+
"doxxing",
74+
"porn",
75+
"sexual",
76+
"nudity",
77+
"nsfl",
78+
"gore"
79+
]
80+
},
81+
"selfLabels": {
82+
"type": "object",
83+
"required": ["values"],
84+
"properties": {
85+
"values": {
86+
"type": "array",
87+
"items": {
88+
"ref": "#selfLabel",
89+
"type": "ref"
90+
},
91+
"maxLength": 10
92+
}
93+
},
94+
"description": "Metadata tags on an atproto record, published by the author within the record."
95+
},
96+
"labelValueDefinition": {
97+
"type": "object",
98+
"required": ["identifier", "severity", "blurs", "locales"],
99+
"properties": {
100+
"blurs": {
101+
"type": "string",
102+
"description": "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.",
103+
"knownValues": ["content", "media", "none"]
104+
},
105+
"locales": {
106+
"type": "array",
107+
"items": {
108+
"ref": "#labelValueDefinitionStrings",
109+
"type": "ref"
110+
}
111+
},
112+
"severity": {
113+
"type": "string",
114+
"description": "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.",
115+
"knownValues": ["inform", "alert", "none"]
116+
},
117+
"adultOnly": {
118+
"type": "boolean",
119+
"description": "Does the user need to have adult content enabled in order to configure this label?"
120+
},
121+
"identifier": {
122+
"type": "string",
123+
"maxLength": 100,
124+
"description": "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).",
125+
"maxGraphemes": 100
126+
},
127+
"defaultSetting": {
128+
"type": "string",
129+
"default": "warn",
130+
"description": "The default setting for this label.",
131+
"knownValues": ["ignore", "warn", "hide"]
132+
}
133+
},
134+
"description": "Declares a label value and its expected interpretations and behaviors."
135+
},
136+
"labelValueDefinitionStrings": {
137+
"type": "object",
138+
"required": ["lang", "name", "description"],
139+
"properties": {
140+
"lang": {
141+
"type": "string",
142+
"format": "language",
143+
"description": "The code of the language these strings are written in."
144+
},
145+
"name": {
146+
"type": "string",
147+
"maxLength": 640,
148+
"description": "A short human-readable name for the label.",
149+
"maxGraphemes": 64
150+
},
151+
"description": {
152+
"type": "string",
153+
"maxLength": 100000,
154+
"description": "A longer description of what the label means and why it might be applied.",
155+
"maxGraphemes": 10000
156+
}
157+
},
158+
"description": "Strings which describe the label in the UI, localized into a specific language."
159+
}
160+
},
161+
"$type": "com.atproto.lexicon.schema",
162+
"lexicon": 1
163+
}

server/api/auth/atproto.get.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,8 @@ import { SLINGSHOT_HOST } from '#shared/utils/constants'
77
import { useServerSession } from '#server/utils/server-session'
88
import type { PublicUserSession } from '#shared/schemas/publicUserSession'
99
import { handleResolver } from '#server/utils/atproto/oauth'
10-
11-
interface ProfileRecord {
12-
avatar?: {
13-
$type: 'blob'
14-
ref: { $link: string }
15-
mimeType: string
16-
size: number
17-
}
18-
}
10+
import { type AtIdentifierString, Client } from '@atproto/lex'
11+
import * as app from '#shared/types/lexicons/app'
1912

2013
export default defineEventHandler(async event => {
2114
const config = useRuntimeConfig(event)
@@ -86,17 +79,18 @@ export default defineEventHandler(async event => {
8679
const pdsUrl = new URL(miniDoc.pds)
8780
// Only fetch from HTTPS PDS endpoints to prevent SSRF
8881
if (did && pdsUrl.protocol === 'https:') {
89-
const profileResponse = await fetch(
90-
`${pdsUrl.origin}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=app.bsky.actor.profile&rkey=self`,
91-
{ headers: { 'User-Agent': 'npmx' } },
92-
)
93-
if (profileResponse.ok) {
94-
const record = (await profileResponse.json()) as { value: ProfileRecord }
95-
const avatarBlob = record.value.avatar
96-
if (avatarBlob?.ref?.$link) {
97-
// Use Bluesky CDN for faster image loading
98-
avatar = `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${avatarBlob.ref.$link}@jpeg`
99-
}
82+
const client = new Client(pdsUrl)
83+
const profileResponse = await client.get(app.bsky.actor.profile, {
84+
// Hack for now need to find an example on how to use it properly
85+
repo: did as AtIdentifierString,
86+
rkey: 'self',
87+
})
88+
89+
const validatedResponse = app.bsky.actor.profile.main.validate(profileResponse.value)
90+
91+
if (validatedResponse.avatar?.ref) {
92+
// Use Bluesky CDN for faster image loading
93+
avatar = `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${validatedResponse.avatar?.ref}@jpeg`
10094
}
10195
}
10296
} catch {

0 commit comments

Comments
 (0)