at.meme-museum.meme
Schema Diff
+17 -4
Compatibility Analysis
Breaking Changes Detected
1 breaking change, 4 non-breaking changes.
Breaking Changes (1)
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.image", kind: "prop", name: Some("image") }
Non-Breaking Changes (4)
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.duration", kind: "prop", name: Some("duration") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }
Additional Notes
- Breaking: RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.image", kind: "prop", name: Some("image") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.duration", kind: "prop", name: Some("duration") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
1
1
{
2
2
"id": "at.meme-museum.meme",
3
3
"defs": {
4
4
"main": {
5
5
"key": "tid",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
-
"image",
11
10
"alt",
12
11
"createdAt"
13
12
],
14
13
"properties": {
15
14
"alt": {
16
15
"type": "string",
17
16
"maxLength": 2000,
18
17
"description": "Accessibility alt text. Required, same convention as app.bsky.embed.images.",
19
18
"maxGraphemes": 1000
20
19
},
21
20
"tags": {
22
21
"type": "array",
23
22
"items": {
24
23
"type": "string",
25
24
"maxLength": 64
26
25
},
27
26
"maxLength": 25
28
27
},
29
28
"image": {
30
29
"type": "blob",
31
30
"accept": [
32
31
"image/png",
33
32
"image/jpeg",
34
33
"image/webp",
35
34
"image/gif"
36
35
],
37
-
"maxSize": 8000000
36
+
"maxSize": 8000000,
37
+
"description": "The asset, when this meme is an image. Exactly one of image/video is set -- a constraint Lexicon can't express, so it's enforced client-side. Neither is required here so that adding video didn't have to break records written before it existed."
38
38
},
39
39
"title": {
40
40
"type": "string",
41
41
"maxLength": 300,
42
42
"description": "Short human label for the meme, distinct from alt text (e.g. \"distracted boyfriend\").",
43
43
"maxGraphemes": 100
44
44
},
45
+
"video": {
46
+
"type": "blob",
47
+
"accept": [
48
+
"video/mp4"
49
+
],
50
+
"maxSize": 100000000,
51
+
"description": "The asset, when this meme is a video clip. Always mp4 regardless of what the user picked: the blob is the one Bluesky's video service transcodes and writes back to the PDS, and app.bsky.embed.video accepts nothing else."
52
+
},
45
53
"width": {
46
54
"type": "integer",
47
55
"minimum": 1
48
56
},
49
57
"height": {
50
58
"type": "integer",
51
59
"minimum": 1
52
60
},
53
61
"source": {
54
62
"ref": "#source",
55
63
"type": "ref"
56
64
},
65
+
"duration": {
66
+
"type": "integer",
67
+
"minimum": 1,
68
+
"description": "Video memes only: clip length in milliseconds, read client-side at upload time. Omitted when the browser couldn't decode metadata for the picked file."
69
+
},
57
70
"createdAt": {
58
71
"type": "string",
59
72
"format": "datetime"
60
73
},
61
74
"isAnimated": {
62
75
"type": "boolean",
63
-
"description": "Set client-side from frame-count inspection at upload time; not reliably inferable from mimetype alone."
76
+
"description": "Image memes only: set client-side from frame-count inspection at upload time, since it isn't reliably inferable from mimetype alone. Not written for video, where it would be trivially true."
64
77
},
65
78
"visibility": {
66
79
"type": "string",
67
80
"default": "public",
68
81
"maxLength": 64,
69
82
"description": "Soft signal only, not access control -- see docs/data-model.md.",
70
83
"knownValues": [
71
84
"public",
72
85
"unlisted"
73
86
]
74
87
}
75
88
}
76
89
},
77
-
"description": "A single meme asset (still or animated image) in a user's library."
90
+
"description": "A single meme asset (still image, animated image, or short video clip) in a user's library."
78
91
},
79
92
"source": {
80
93
"type": "object",
81
94
"properties": {
82
95
"url": {
83
96
"type": "string",
84
97
"format": "uri",
85
98
"description": "A webpage the image came from, if relevant."
86
99
},
87
100
"note": {
88
101
"type": "string",
89
102
"maxLength": 500,
90
103
"description": "Free-text credit, e.g. \"via @someone.bsky.social\"."
91
104
},
92
105
"importedFrom": {
93
106
"type": "string",
94
107
"format": "at-uri",
95
108
"description": "If copied in from another ATProto app's or user's collection, the original record's at-uri."
96
109
}
97
110
},
98
111
"description": "Provenance/attribution for a meme, if known."
99
112
}
100
113
},
101
114
"$type": "com.atproto.lexicon.schema",
102
115
"lexicon": 1
103
116
}