at.meme-museum.meme
Schema Diff
+85 -21
Compatibility Analysis
Breaking Changes Detected
13 breaking changes, 31 non-breaking changes.
Breaking Changes (13)
- RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.alt", kind: "prop", name: Some("alt") }
- RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.name", kind: "prop", name: Some("name") }
- RemovedVertex RemovedVertex { vertex_id: "app.bsky.richtext.facet" }
- RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.avatar" }
- RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.description" }
- RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets" }
- RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets:items" }
- RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.name" }
- RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.avatar", kind: "prop", name: Some("avatar") }
- RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.description", kind: "prop", name: Some("description") }
- RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.descriptionFacets", kind: "prop", name: Some("descriptionFacets") }
- RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets", tgt: "at.meme-museum.meme:body.descriptionFacets:items", kind: "items", name: None }
- RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }
Non-Breaking Changes (31)
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.importedFrom" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.note" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.url" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.alt" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.height" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.image" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.isAnimated" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.source" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.tags" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.tags:items" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.title" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.visibility" }
- AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.width" }
- AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.importedFrom", kind: "prop", name: Some("importedFrom") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.note", kind: "prop", name: Some("note") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.url", kind: "prop", name: Some("url") }
- 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.height", kind: "prop", name: Some("height") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.image", kind: "prop", name: Some("image") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.isAnimated", kind: "prop", name: Some("isAnimated") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.source", kind: "prop", name: Some("source") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.tags", kind: "prop", name: Some("tags") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.title", kind: "prop", name: Some("title") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.visibility", kind: "prop", name: Some("visibility") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.width", kind: "prop", name: Some("width") }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body.source", tgt: "at.meme-museum.meme#source", kind: "ref", name: None }
- AddedEdge AddedEdge { src: "at.meme-museum.meme:body.tags", tgt: "at.meme-museum.meme:body.tags:items", kind: "items", name: None }
Migration Guidance
Removed Elements
RemovedVertex { vertex_id: "app.bsky.richtext.facet" }RemovedVertex { vertex_id: "at.meme-museum.meme:body.avatar" }RemovedVertex { vertex_id: "at.meme-museum.meme:body.description" }RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets" }RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets:items" }RemovedVertex { vertex_id: "at.meme-museum.meme:body.name" }
Added Elements
AddedVertex { vertex_id: "at.meme-museum.meme#source" }AddedVertex { vertex_id: "at.meme-museum.meme#source.importedFrom" }AddedVertex { vertex_id: "at.meme-museum.meme#source.note" }AddedVertex { vertex_id: "at.meme-museum.meme#source.url" }AddedVertex { vertex_id: "at.meme-museum.meme:body.alt" }AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }AddedVertex { vertex_id: "at.meme-museum.meme:body.height" }AddedVertex { vertex_id: "at.meme-museum.meme:body.image" }AddedVertex { vertex_id: "at.meme-museum.meme:body.isAnimated" }AddedVertex { vertex_id: "at.meme-museum.meme:body.source" }AddedVertex { vertex_id: "at.meme-museum.meme:body.tags" }AddedVertex { vertex_id: "at.meme-museum.meme:body.tags:items" }AddedVertex { vertex_id: "at.meme-museum.meme:body.title" }AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }AddedVertex { vertex_id: "at.meme-museum.meme:body.visibility" }AddedVertex { vertex_id: "at.meme-museum.meme:body.width" }
Additional Notes
- Breaking: RequiredEdgeAdded { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.alt", kind: "prop", name: Some("alt") }
- Breaking: RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.name", kind: "prop", name: Some("name") }
- Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.avatar", kind: "prop", name: Some("avatar") }
- Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.description", kind: "prop", name: Some("description") }
- Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.descriptionFacets", kind: "prop", name: Some("descriptionFacets") }
- Breaking: RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets", tgt: "at.meme-museum.meme:body.descriptionFacets:items", kind: "items", name: None }
- Breaking: RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.importedFrom", kind: "prop", name: Some("importedFrom") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.note", kind: "prop", name: Some("note") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.url", kind: "prop", name: Some("url") }
- 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.height", kind: "prop", name: Some("height") }
- Non-breaking: AddedEdge { 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.isAnimated", kind: "prop", name: Some("isAnimated") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.source", kind: "prop", name: Some("source") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.tags", kind: "prop", name: Some("tags") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.title", kind: "prop", name: Some("title") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.visibility", kind: "prop", name: Some("visibility") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.width", kind: "prop", name: Some("width") }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body.source", tgt: "at.meme-museum.meme#source", kind: "ref", name: None }
- Non-breaking: AddedEdge { src: "at.meme-museum.meme:body.tags", tgt: "at.meme-museum.meme:body.tags:items", kind: "items", name: None }
1
1
{
2
2
"id": "at.meme-museum.meme",
3
3
"defs": {
4
4
"main": {
5
-
"key": "any",
5
+
"key": "tid",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
-
"name",
10
+
"alt",
11
11
"createdAt"
12
12
],
13
13
"properties": {
14
-
"name": {
14
+
"alt": {
15
15
"type": "string",
16
-
"maxLength": 640,
17
-
"minLength": 1,
18
-
"description": "TODO: title name of record; can not be empty",
19
-
"maxGraphemes": 64
16
+
"maxLength": 2000,
17
+
"description": "Accessibility alt text. Required, same convention as app.bsky.embed.images.",
18
+
"maxGraphemes": 1000
20
19
},
21
-
"avatar": {
20
+
"tags": {
21
+
"type": "array",
22
+
"items": {
23
+
"type": "string",
24
+
"maxLength": 64
25
+
},
26
+
"maxLength": 25
27
+
},
28
+
"image": {
22
29
"type": "blob",
23
30
"accept": [
24
31
"image/png",
25
-
"image/jpeg"
32
+
"image/jpeg",
33
+
"image/webp",
34
+
"image/gif"
26
35
],
27
-
"maxSize": 2000000
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
+
},
39
+
"title": {
40
+
"type": "string",
41
+
"maxLength": 300,
42
+
"description": "Short human label for the meme, distinct from alt text (e.g. \"distracted boyfriend\").",
43
+
"maxGraphemes": 100
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
+
},
53
+
"width": {
54
+
"type": "integer",
55
+
"minimum": 1
56
+
},
57
+
"height": {
58
+
"type": "integer",
59
+
"minimum": 1
60
+
},
61
+
"source": {
62
+
"ref": "#source",
63
+
"type": "ref"
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."
28
69
},
29
70
"createdAt": {
30
71
"type": "string",
31
72
"format": "datetime"
32
73
},
33
-
"description": {
34
-
"type": "string",
35
-
"maxLength": 3000,
36
-
"maxGraphemes": 300
74
+
"isAnimated": {
75
+
"type": "boolean",
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."
37
77
},
38
-
"descriptionFacets": {
39
-
"type": "array",
40
-
"items": {
41
-
"ref": "app.bsky.richtext.facet",
42
-
"type": "ref"
43
-
}
78
+
"visibility": {
79
+
"type": "string",
80
+
"default": "public",
81
+
"maxLength": 64,
82
+
"description": "Soft signal only, not access control -- see docs/data-model.md.",
83
+
"knownValues": [
84
+
"public",
85
+
"unlisted"
86
+
]
44
87
}
45
88
}
46
89
},
47
-
"description": "TODO: describe purpose of this schema"
90
+
"description": "A single meme asset (still image, animated image, or short video clip) in a user's library."
91
+
},
92
+
"source": {
93
+
"type": "object",
94
+
"properties": {
95
+
"url": {
96
+
"type": "string",
97
+
"format": "uri",
98
+
"description": "A webpage the image came from, if relevant."
99
+
},
100
+
"note": {
101
+
"type": "string",
102
+
"maxLength": 500,
103
+
"description": "Free-text credit, e.g. \"via @someone.bsky.social\"."
104
+
},
105
+
"importedFrom": {
106
+
"type": "string",
107
+
"format": "at-uri",
108
+
"description": "If copied in from another ATProto app's or user's collection, the original record's at-uri."
109
+
}
110
+
},
111
+
"description": "Provenance/attribution for a meme, if known."
48
112
}
49
113
},
50
114
"$type": "com.atproto.lexicon.schema",
51
115
"lexicon": 1
52
116
}