@atproto/api 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/README.md +81 -0
  2. package/definitions/labels.json +212 -0
  3. package/definitions/locale/en/label-groups.json +38 -0
  4. package/definitions/locale/en/labels.json +366 -0
  5. package/definitions/locale/en/proposed-label-groups.json +38 -0
  6. package/definitions/locale/en/proposed-labels.json +632 -0
  7. package/definitions/moderation-behaviors.d.ts +48 -0
  8. package/definitions/post-moderation-behaviors.json +879 -0
  9. package/definitions/profile-moderation-behaviors.json +447 -0
  10. package/definitions/proposed-labels.json +326 -0
  11. package/dist/client/index.d.ts +3 -0
  12. package/dist/client/lexicons.d.ts +27 -1
  13. package/dist/client/types/app/bsky/actor/updateProfile.d.ts +3 -10
  14. package/dist/client/types/app/bsky/{feed/getBookmarkedFeeds.d.ts → graph/getListBlocks.d.ts} +2 -2
  15. package/dist/client/types/app/bsky/graph/listblock.d.ts +8 -0
  16. package/dist/client/types/app/bsky/{feed/unbookmarkFeed.d.ts → graph/subscribeMuteList.d.ts} +1 -1
  17. package/dist/client/types/app/bsky/{feed/bookmarkFeed.d.ts → graph/unsubscribeMuteList.d.ts} +1 -1
  18. package/dist/{src/client/types/app/bsky/notification/updateSeen.d.ts → client/types/app/bsky/unspecced/applyLabels.d.ts} +2 -1
  19. package/dist/helpers/bsky.d.ts +20 -0
  20. package/dist/index.d.ts +4 -0
  21. package/dist/index.js +1401 -12
  22. package/dist/index.js.map +4 -4
  23. package/dist/mixins/bsky.d.ts +23 -0
  24. package/dist/moderation/accumulator.d.ts +14 -0
  25. package/dist/moderation/const/label-groups.d.ts +2 -0
  26. package/dist/moderation/const/labels.d.ts +2 -0
  27. package/dist/moderation/index.d.ts +44 -0
  28. package/dist/moderation/subjects/account.d.ts +3 -0
  29. package/dist/moderation/subjects/feed-generator.d.ts +2 -0
  30. package/dist/moderation/subjects/post.d.ts +2 -0
  31. package/dist/moderation/subjects/profile.d.ts +3 -0
  32. package/dist/moderation/subjects/quoted-post.d.ts +6 -0
  33. package/dist/moderation/subjects/user-list.d.ts +2 -0
  34. package/dist/moderation/types.d.ts +97 -0
  35. package/dist/moderation/util.d.ts +12 -0
  36. package/dist/rich-text/sanitize.d.ts +4 -0
  37. package/docs/labels.md +522 -0
  38. package/docs/moderation-behaviors/posts.md +1919 -0
  39. package/docs/moderation-behaviors/profiles.md +907 -0
  40. package/docs/moderation.md +144 -0
  41. package/package.json +6 -4
  42. package/scripts/code/label-groups.mjs +68 -0
  43. package/scripts/code/labels.mjs +68 -0
  44. package/scripts/docs/labels.mjs +164 -0
  45. package/scripts/docs/post-moderation-behaviors.mjs +122 -0
  46. package/scripts/docs/profile-moderation-behaviors.mjs +122 -0
  47. package/scripts/generate-code.mjs +4 -0
  48. package/scripts/generate-docs.mjs +5 -0
  49. package/src/client/index.ts +13 -0
  50. package/src/client/lexicons.ts +29 -3
  51. package/src/client/types/app/bsky/unspecced/applyLabels.ts +33 -0
  52. package/src/client/types/com/atproto/admin/enableAccountInvites.ts +1 -1
  53. package/src/client/types/com/atproto/moderation/defs.ts +1 -1
  54. package/src/index.ts +4 -0
  55. package/src/moderation/accumulator.ts +181 -0
  56. package/src/moderation/const/label-groups.ts +143 -0
  57. package/src/moderation/const/labels.ts +798 -0
  58. package/src/moderation/index.ts +343 -0
  59. package/src/moderation/subjects/account.ts +40 -0
  60. package/src/moderation/subjects/feed-generator.ts +13 -0
  61. package/src/moderation/subjects/post.ts +23 -0
  62. package/src/moderation/subjects/profile.ts +31 -0
  63. package/src/moderation/subjects/quoted-post.ts +62 -0
  64. package/src/moderation/subjects/user-list.ts +13 -0
  65. package/src/moderation/types.ts +141 -0
  66. package/src/moderation/util.ts +98 -0
  67. package/tests/post-moderation.test.ts +46 -0
  68. package/tests/profile-moderation.test.ts +46 -0
  69. package/tests/util/index.ts +176 -0
  70. package/tests/util/moderation-behavior.ts +180 -0
  71. package/dist/client/types/app/bsky/actor/searchActor.d.ts +0 -22
  72. package/dist/client/types/app/bsky/actor/searchActorTypeahead.d.ts +0 -20
  73. package/dist/client/types/com/atproto/admin/getInviteCodeUsage.d.ts +0 -29
  74. package/dist/client/types/com/atproto/repo/importRepo.d.ts +0 -19
  75. package/dist/client/types/com/atproto/repo/uploadRepo.d.ts +0 -19
  76. package/dist/client/types/com/atproto/server/getUserInviteCodes.d.ts +0 -31
  77. package/dist/src/client/index.d.ts +0 -462
  78. package/dist/src/client/lexicons.d.ts +0 -2910
  79. package/dist/src/client/schemas.d.ts +0 -17
  80. package/dist/src/client/types/app/bsky/actor/createScene.d.ts +0 -32
  81. package/dist/src/client/types/app/bsky/actor/getProfile.d.ts +0 -36
  82. package/dist/src/client/types/app/bsky/actor/getSuggestions.d.ts +0 -36
  83. package/dist/src/client/types/app/bsky/actor/profile.d.ts +0 -15
  84. package/dist/src/client/types/app/bsky/actor/ref.d.ts +0 -14
  85. package/dist/src/client/types/app/bsky/actor/search.d.ts +0 -32
  86. package/dist/src/client/types/app/bsky/actor/searchTypeahead.d.ts +0 -28
  87. package/dist/src/client/types/app/bsky/actor/updateProfile.d.ts +0 -48
  88. package/dist/src/client/types/app/bsky/badge.d.ts +0 -22
  89. package/dist/src/client/types/app/bsky/badgeAccept.d.ts +0 -11
  90. package/dist/src/client/types/app/bsky/badgeOffer.d.ts +0 -11
  91. package/dist/src/client/types/app/bsky/declaration.d.ts +0 -6
  92. package/dist/src/client/types/app/bsky/embed/external.d.ts +0 -26
  93. package/dist/src/client/types/app/bsky/embed/images.d.ts +0 -23
  94. package/dist/src/client/types/app/bsky/feed/embed.d.ts +0 -36
  95. package/dist/src/client/types/app/bsky/feed/feedViewPost.d.ts +0 -26
  96. package/dist/src/client/types/app/bsky/feed/getAuthorFeed.d.ts +0 -22
  97. package/dist/src/client/types/app/bsky/feed/getPostThread.d.ts +0 -43
  98. package/dist/src/client/types/app/bsky/feed/getRepostedBy.d.ts +0 -35
  99. package/dist/src/client/types/app/bsky/feed/getTimeline.d.ts +0 -22
  100. package/dist/src/client/types/app/bsky/feed/getVotes.d.ts +0 -33
  101. package/dist/src/client/types/app/bsky/feed/mediaEmbed.d.ts +0 -18
  102. package/dist/src/client/types/app/bsky/feed/post.d.ts +0 -54
  103. package/dist/src/client/types/app/bsky/feed/repost.d.ts +0 -6
  104. package/dist/src/client/types/app/bsky/feed/setVote.d.ts +0 -25
  105. package/dist/src/client/types/app/bsky/feed/trend.d.ts +0 -6
  106. package/dist/src/client/types/app/bsky/feed/vote.d.ts +0 -7
  107. package/dist/src/client/types/app/bsky/follow.d.ts +0 -9
  108. package/dist/src/client/types/app/bsky/getAuthorFeed.d.ts +0 -56
  109. package/dist/src/client/types/app/bsky/getBadgeMembers.d.ts +0 -29
  110. package/dist/src/client/types/app/bsky/getHomeFeed.d.ts +0 -56
  111. package/dist/src/client/types/app/bsky/getLikedBy.d.ts +0 -29
  112. package/dist/src/client/types/app/bsky/getNotificationCount.d.ts +0 -16
  113. package/dist/src/client/types/app/bsky/getNotifications.d.ts +0 -33
  114. package/dist/src/client/types/app/bsky/getPostThread.d.ts +0 -55
  115. package/dist/src/client/types/app/bsky/getProfile.d.ts +0 -26
  116. package/dist/src/client/types/app/bsky/getRepostedBy.d.ts +0 -29
  117. package/dist/src/client/types/app/bsky/getTimeline.d.ts +0 -56
  118. package/dist/src/client/types/app/bsky/getUserFollowers.d.ts +0 -31
  119. package/dist/src/client/types/app/bsky/getUserFollows.d.ts +0 -31
  120. package/dist/src/client/types/app/bsky/getUsersSearch.d.ts +0 -26
  121. package/dist/src/client/types/app/bsky/getUsersTypeahead.d.ts +0 -22
  122. package/dist/src/client/types/app/bsky/graph/assertCreator.d.ts +0 -1
  123. package/dist/src/client/types/app/bsky/graph/assertMember.d.ts +0 -1
  124. package/dist/src/client/types/app/bsky/graph/assertion.d.ts +0 -7
  125. package/dist/src/client/types/app/bsky/graph/confirmation.d.ts +0 -8
  126. package/dist/src/client/types/app/bsky/graph/follow.d.ts +0 -6
  127. package/dist/src/client/types/app/bsky/graph/getAssertions.d.ts +0 -43
  128. package/dist/src/client/types/app/bsky/graph/getFollowers.d.ts +0 -34
  129. package/dist/src/client/types/app/bsky/graph/getFollows.d.ts +0 -33
  130. package/dist/src/client/types/app/bsky/graph/getMembers.d.ts +0 -33
  131. package/dist/src/client/types/app/bsky/graph/getMemberships.d.ts +0 -33
  132. package/dist/src/client/types/app/bsky/invite.d.ts +0 -10
  133. package/dist/src/client/types/app/bsky/inviteAccept.d.ts +0 -14
  134. package/dist/src/client/types/app/bsky/like.d.ts +0 -10
  135. package/dist/src/client/types/app/bsky/mediaEmbed.d.ts +0 -15
  136. package/dist/src/client/types/app/bsky/notification/getCount.d.ts +0 -17
  137. package/dist/src/client/types/app/bsky/notification/list.d.ts +0 -32
  138. package/dist/src/client/types/app/bsky/post.d.ts +0 -23
  139. package/dist/src/client/types/app/bsky/postNotificationsSeen.d.ts +0 -20
  140. package/dist/src/client/types/app/bsky/profile.d.ts +0 -5
  141. package/dist/src/client/types/app/bsky/repost.d.ts +0 -10
  142. package/dist/src/client/types/app/bsky/system/actorScene.d.ts +0 -1
  143. package/dist/src/client/types/app/bsky/system/actorUser.d.ts +0 -1
  144. package/dist/src/client/types/app/bsky/system/declRef.d.ts +0 -5
  145. package/dist/src/client/types/app/bsky/system/declaration.d.ts +0 -4
  146. package/dist/src/client/types/app/bsky/updateProfile.d.ts +0 -23
  147. package/dist/src/client/types/com/atproto/account/create.d.ts +0 -41
  148. package/dist/src/client/types/com/atproto/account/createInviteCode.d.ts +0 -22
  149. package/dist/src/client/types/com/atproto/account/delete.d.ts +0 -13
  150. package/dist/src/client/types/com/atproto/account/get.d.ts +0 -12
  151. package/dist/src/client/types/com/atproto/account/requestPasswordReset.d.ts +0 -17
  152. package/dist/src/client/types/com/atproto/account/resetPassword.d.ts +0 -24
  153. package/dist/src/client/types/com/atproto/blob/upload.d.ts +0 -19
  154. package/dist/src/client/types/com/atproto/createAccount.d.ts +0 -40
  155. package/dist/src/client/types/com/atproto/createInviteCode.d.ts +0 -20
  156. package/dist/src/client/types/com/atproto/createSession.d.ts +0 -24
  157. package/dist/src/client/types/com/atproto/data/uploadFile.d.ts +0 -19
  158. package/dist/src/client/types/com/atproto/deleteAccount.d.ts +0 -20
  159. package/dist/src/client/types/com/atproto/deleteSession.d.ts +0 -17
  160. package/dist/src/client/types/com/atproto/getAccount.d.ts +0 -16
  161. package/dist/src/client/types/com/atproto/getAccountsConfig.d.ts +0 -17
  162. package/dist/src/client/types/com/atproto/getSession.d.ts +0 -17
  163. package/dist/src/client/types/com/atproto/handle/resolve.d.ts +0 -18
  164. package/dist/src/client/types/com/atproto/refreshSession.d.ts +0 -20
  165. package/dist/src/client/types/com/atproto/repo/batchWrite.d.ts +0 -39
  166. package/dist/src/client/types/com/atproto/repo/createRecord.d.ts +0 -26
  167. package/dist/src/client/types/com/atproto/repo/deleteRecord.d.ts +0 -19
  168. package/dist/src/client/types/com/atproto/repo/describe.d.ts +0 -22
  169. package/dist/src/client/types/com/atproto/repo/getRecord.d.ts +0 -23
  170. package/dist/src/client/types/com/atproto/repo/listRecords.d.ts +0 -30
  171. package/dist/src/client/types/com/atproto/repo/putRecord.d.ts +0 -27
  172. package/dist/src/client/types/com/atproto/repo/strongRef.d.ts +0 -5
  173. package/dist/src/client/types/com/atproto/repoBatchWrite.d.ts +0 -36
  174. package/dist/src/client/types/com/atproto/repoCreateRecord.d.ts +0 -24
  175. package/dist/src/client/types/com/atproto/repoDeleteRecord.d.ts +0 -18
  176. package/dist/src/client/types/com/atproto/repoDescribe.d.ts +0 -21
  177. package/dist/src/client/types/com/atproto/repoGetRecord.d.ts +0 -22
  178. package/dist/src/client/types/com/atproto/repoListRecords.d.ts +0 -27
  179. package/dist/src/client/types/com/atproto/repoPutRecord.d.ts +0 -25
  180. package/dist/src/client/types/com/atproto/requestAccountPasswordReset.d.ts +0 -19
  181. package/dist/src/client/types/com/atproto/resetAccountPassword.d.ts +0 -26
  182. package/dist/src/client/types/com/atproto/resolveHandle.d.ts +0 -17
  183. package/dist/src/client/types/com/atproto/resolveName.d.ts +0 -17
  184. package/dist/src/client/types/com/atproto/server/getAccountsConfig.d.ts +0 -24
  185. package/dist/src/client/types/com/atproto/session/create.d.ts +0 -26
  186. package/dist/src/client/types/com/atproto/session/delete.d.ts +0 -13
  187. package/dist/src/client/types/com/atproto/session/get.d.ts +0 -18
  188. package/dist/src/client/types/com/atproto/session/refresh.d.ts +0 -21
  189. package/dist/src/client/types/com/atproto/sync/getRepo.d.ts +0 -15
  190. package/dist/src/client/types/com/atproto/sync/getRoot.d.ts +0 -18
  191. package/dist/src/client/types/com/atproto/sync/updateRepo.d.ts +0 -15
  192. package/dist/src/client/types/com/atproto/syncGetRepo.d.ts +0 -15
  193. package/dist/src/client/types/com/atproto/syncGetRoot.d.ts +0 -17
  194. package/dist/src/client/types/com/atproto/syncUpdateRepo.d.ts +0 -15
  195. package/dist/src/index.d.ts +0 -4
  196. package/dist/src/schemas.d.ts +0 -19
  197. package/dist/src/session.d.ts +0 -42
  198. package/dist/src/types/app/bsky/acceptedBadge.d.ts +0 -10
  199. package/dist/src/types/app/bsky/badge.d.ts +0 -22
  200. package/dist/src/types/app/bsky/badgeAccept.d.ts +0 -11
  201. package/dist/src/types/app/bsky/badgeOffer.d.ts +0 -11
  202. package/dist/src/types/app/bsky/declaration.d.ts +0 -6
  203. package/dist/src/types/app/bsky/follow.d.ts +0 -9
  204. package/dist/src/types/app/bsky/getAuthorFeed.d.ts +0 -56
  205. package/dist/src/types/app/bsky/getBadgeMembers.d.ts +0 -29
  206. package/dist/src/types/app/bsky/getHomeFeed.d.ts +0 -56
  207. package/dist/src/types/app/bsky/getLikedBy.d.ts +0 -29
  208. package/dist/src/types/app/bsky/getNotificationCount.d.ts +0 -16
  209. package/dist/src/types/app/bsky/getNotifications.d.ts +0 -33
  210. package/dist/src/types/app/bsky/getPostThread.d.ts +0 -55
  211. package/dist/src/types/app/bsky/getProfile.d.ts +0 -42
  212. package/dist/src/types/app/bsky/getRepostedBy.d.ts +0 -29
  213. package/dist/src/types/app/bsky/getUserFollowers.d.ts +0 -31
  214. package/dist/src/types/app/bsky/getUserFollows.d.ts +0 -31
  215. package/dist/src/types/app/bsky/getUsersSearch.d.ts +0 -26
  216. package/dist/src/types/app/bsky/getUsersTypeahead.d.ts +0 -22
  217. package/dist/src/types/app/bsky/invite.d.ts +0 -10
  218. package/dist/src/types/app/bsky/inviteAccept.d.ts +0 -14
  219. package/dist/src/types/app/bsky/like.d.ts +0 -10
  220. package/dist/src/types/app/bsky/mediaEmbed.d.ts +0 -15
  221. package/dist/src/types/app/bsky/post.d.ts +0 -23
  222. package/dist/src/types/app/bsky/postNotificationsSeen.d.ts +0 -19
  223. package/dist/src/types/app/bsky/profile.d.ts +0 -11
  224. package/dist/src/types/app/bsky/repost.d.ts +0 -10
  225. package/dist/src/types/app/bsky/updateProfile.d.ts +0 -27
  226. package/dist/src/types/com/atproto/createAccount.d.ts +0 -39
  227. package/dist/src/types/com/atproto/createInviteCode.d.ts +0 -19
  228. package/dist/src/types/com/atproto/createSession.d.ts +0 -23
  229. package/dist/src/types/com/atproto/deleteAccount.d.ts +0 -19
  230. package/dist/src/types/com/atproto/deleteSession.d.ts +0 -16
  231. package/dist/src/types/com/atproto/getAccount.d.ts +0 -19
  232. package/dist/src/types/com/atproto/getAccountsConfig.d.ts +0 -17
  233. package/dist/src/types/com/atproto/getSession.d.ts +0 -17
  234. package/dist/src/types/com/atproto/refreshSession.d.ts +0 -19
  235. package/dist/src/types/com/atproto/repoBatchWrite.d.ts +0 -35
  236. package/dist/src/types/com/atproto/repoCreateRecord.d.ts +0 -23
  237. package/dist/src/types/com/atproto/repoDeleteRecord.d.ts +0 -15
  238. package/dist/src/types/com/atproto/repoDescribe.d.ts +0 -21
  239. package/dist/src/types/com/atproto/repoGetRecord.d.ts +0 -22
  240. package/dist/src/types/com/atproto/repoListRecords.d.ts +0 -27
  241. package/dist/src/types/com/atproto/repoPutRecord.d.ts +0 -24
  242. package/dist/src/types/com/atproto/requestAccountPasswordReset.d.ts +0 -18
  243. package/dist/src/types/com/atproto/resetAccountPassword.d.ts +0 -25
  244. package/dist/src/types/com/atproto/resolveName.d.ts +0 -17
  245. package/dist/src/types/com/atproto/syncGetRepo.d.ts +0 -15
  246. package/dist/src/types/com/atproto/syncGetRoot.d.ts +0 -17
  247. package/dist/src/types/com/atproto/syncUpdateRepo.d.ts +0 -14
  248. package/dist/src/types/todo/adx/createAccount.d.ts +0 -36
  249. package/dist/src/types/todo/adx/createInviteCode.d.ts +0 -19
  250. package/dist/src/types/todo/adx/createSession.d.ts +0 -22
  251. package/dist/src/types/todo/adx/deleteAccount.d.ts +0 -19
  252. package/dist/src/types/todo/adx/deleteSession.d.ts +0 -19
  253. package/dist/src/types/todo/adx/getAccount.d.ts +0 -19
  254. package/dist/src/types/todo/adx/getAccountsConfig.d.ts +0 -17
  255. package/dist/src/types/todo/adx/getSession.d.ts +0 -17
  256. package/dist/src/types/todo/adx/repoBatchWrite.d.ts +0 -34
  257. package/dist/src/types/todo/adx/repoCreateRecord.d.ts +0 -22
  258. package/dist/src/types/todo/adx/repoDeleteRecord.d.ts +0 -15
  259. package/dist/src/types/todo/adx/repoDescribe.d.ts +0 -21
  260. package/dist/src/types/todo/adx/repoGetRecord.d.ts +0 -20
  261. package/dist/src/types/todo/adx/repoListRecords.d.ts +0 -25
  262. package/dist/src/types/todo/adx/repoPutRecord.d.ts +0 -23
  263. package/dist/src/types/todo/adx/requestAccountPasswordReset.d.ts +0 -18
  264. package/dist/src/types/todo/adx/resetAccountPassword.d.ts +0 -25
  265. package/dist/src/types/todo/adx/resolveName.d.ts +0 -17
  266. package/dist/src/types/todo/adx/syncGetRepo.d.ts +0 -15
  267. package/dist/src/types/todo/adx/syncGetRoot.d.ts +0 -17
  268. package/dist/src/types/todo/adx/syncUpdateRepo.d.ts +0 -14
  269. package/dist/src/types/todo/social/badge.d.ts +0 -23
  270. package/dist/src/types/todo/social/follow.d.ts +0 -5
  271. package/dist/src/types/todo/social/getAuthorFeed.d.ts +0 -55
  272. package/dist/src/types/todo/social/getFeed.d.ts +0 -55
  273. package/dist/src/types/todo/social/getHomeFeed.d.ts +0 -55
  274. package/dist/src/types/todo/social/getLikedBy.d.ts +0 -26
  275. package/dist/src/types/todo/social/getNotificationCount.d.ts +0 -16
  276. package/dist/src/types/todo/social/getNotifications.d.ts +0 -31
  277. package/dist/src/types/todo/social/getPostThread.d.ts +0 -54
  278. package/dist/src/types/todo/social/getProfile.d.ts +0 -40
  279. package/dist/src/types/todo/social/getRepostedBy.d.ts +0 -26
  280. package/dist/src/types/todo/social/getUserFollowers.d.ts +0 -30
  281. package/dist/src/types/todo/social/getUserFollows.d.ts +0 -30
  282. package/dist/src/types/todo/social/like.d.ts +0 -5
  283. package/dist/src/types/todo/social/mediaEmbed.d.ts +0 -15
  284. package/dist/src/types/todo/social/post.d.ts +0 -18
  285. package/dist/src/types/todo/social/postNotificationsSeen.d.ts +0 -19
  286. package/dist/src/types/todo/social/profile.d.ts +0 -10
  287. package/dist/src/types/todo/social/repost.d.ts +0 -5
  288. package/dist/tsconfig.build.tsbuildinfo +0 -1
  289. package/tests/_util.ts +0 -26
  290. package/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,343 @@
1
+ import { AppBskyActorDefs } from '../client/index'
2
+ import {
3
+ ModerationSubjectProfile,
4
+ ModerationSubjectPost,
5
+ ModerationSubjectFeedGenerator,
6
+ ModerationSubjectUserList,
7
+ ModerationOpts,
8
+ ModerationDecision,
9
+ ModerationUI,
10
+ } from './types'
11
+ import { decideAccount } from './subjects/account'
12
+ import { decideProfile } from './subjects/profile'
13
+ import { decidePost } from './subjects/post'
14
+ import {
15
+ decideQuotedPost,
16
+ decideQuotedPostAccount,
17
+ decideQuotedPostWithMedia,
18
+ decideQuotedPostWithMediaAccount,
19
+ } from './subjects/quoted-post'
20
+ import { decideFeedGenerator } from './subjects/feed-generator'
21
+ import { decideUserList } from './subjects/user-list'
22
+ import {
23
+ takeHighestPriorityDecision,
24
+ downgradeDecision,
25
+ isModerationDecisionNoop,
26
+ isQuotedPost,
27
+ isQuotedPostWithMedia,
28
+ toModerationUI,
29
+ } from './util'
30
+
31
+ // profiles
32
+ // =
33
+
34
+ export interface ProfileModeration {
35
+ decisions: {
36
+ account: ModerationDecision
37
+ profile: ModerationDecision
38
+ }
39
+ account: ModerationUI
40
+ profile: ModerationUI
41
+ avatar: ModerationUI
42
+ }
43
+
44
+ export function moderateProfile(
45
+ subject: ModerationSubjectProfile,
46
+ opts: ModerationOpts,
47
+ ): ProfileModeration {
48
+ // decide the moderation the account and the profile
49
+ const account = decideAccount(subject, opts)
50
+ const profile = decideProfile(subject, opts)
51
+
52
+ // if the decision is supposed to blur media,
53
+ // - have it apply to the view if it's on the account
54
+ // - otherwise ignore it
55
+ if (account.blurMedia) {
56
+ account.blur = true
57
+ }
58
+
59
+ // dont give profile.filter because that is meaningless
60
+ profile.filter = false
61
+
62
+ // downgrade based on authorship
63
+ if (!isModerationDecisionNoop(account) && account.did === opts.userDid) {
64
+ downgradeDecision(account, { alert: true })
65
+ }
66
+ if (!isModerationDecisionNoop(profile) && profile.did === opts.userDid) {
67
+ downgradeDecision(profile, { alert: true })
68
+ }
69
+
70
+ // derive avatar blurring from account & profile, but override for mutes because that shouldnt blur
71
+ let avatarBlur = false
72
+ let avatarNoOverride = false
73
+ if ((account.blur || account.blurMedia) && account.cause?.type !== 'muted') {
74
+ avatarBlur = true
75
+ avatarNoOverride = account.noOverride || profile.noOverride
76
+ } else if (profile.blur || profile.blurMedia) {
77
+ avatarBlur = true
78
+ avatarNoOverride = account.noOverride || profile.noOverride
79
+ }
80
+
81
+ // dont blur the account for blocking & muting
82
+ if (
83
+ account.cause?.type === 'blocking' ||
84
+ account.cause?.type === 'blocked-by' ||
85
+ account.cause?.type === 'muted'
86
+ ) {
87
+ account.blur = false
88
+ account.noOverride = false
89
+ }
90
+
91
+ return {
92
+ decisions: { account, profile },
93
+
94
+ // moderate all content based on account
95
+ account:
96
+ account.filter || account.blur || account.alert
97
+ ? toModerationUI(account)
98
+ : {},
99
+
100
+ // moderate the profile details based on the profile
101
+ profile:
102
+ profile.filter || profile.blur || profile.alert
103
+ ? toModerationUI(profile)
104
+ : {},
105
+
106
+ // blur or alert the avatar based on the account and profile decisions
107
+ avatar: {
108
+ blur: avatarBlur,
109
+ alert: account.alert || profile.alert,
110
+ noOverride: avatarNoOverride,
111
+ },
112
+ }
113
+ }
114
+
115
+ // posts
116
+ // =
117
+
118
+ export interface PostModeration {
119
+ decisions: {
120
+ post: ModerationDecision
121
+ account: ModerationDecision
122
+ profile: ModerationDecision
123
+ quote?: ModerationDecision
124
+ quotedAccount?: ModerationDecision
125
+ }
126
+ content: ModerationUI
127
+ avatar: ModerationUI
128
+ embed: ModerationUI
129
+ }
130
+
131
+ export function moderatePost(
132
+ subject: ModerationSubjectPost,
133
+ opts: ModerationOpts,
134
+ ): PostModeration {
135
+ // decide the moderation for the post, the post author's account,
136
+ // and the post author's profile
137
+ const post = decidePost(subject, opts)
138
+ const account = decideAccount(subject.author, opts)
139
+ const profile = decideProfile(subject.author, opts)
140
+
141
+ // decide the moderation for any quoted posts
142
+ let quote: ModerationDecision | undefined
143
+ let quotedAccount: ModerationDecision | undefined
144
+ if (isQuotedPost(subject.embed)) {
145
+ quote = decideQuotedPost(subject.embed, opts)
146
+ quotedAccount = decideQuotedPostAccount(subject.embed, opts)
147
+ } else if (isQuotedPostWithMedia(subject.embed)) {
148
+ quote = decideQuotedPostWithMedia(subject.embed, opts)
149
+ quotedAccount = decideQuotedPostWithMediaAccount(subject.embed, opts)
150
+ }
151
+
152
+ // downgrade based on authorship
153
+ if (!isModerationDecisionNoop(post) && post.did === opts.userDid) {
154
+ downgradeDecision(post, { alert: true })
155
+ }
156
+ if (!isModerationDecisionNoop(account) && account.did === opts.userDid) {
157
+ downgradeDecision(account, { alert: false })
158
+ }
159
+ if (!isModerationDecisionNoop(profile) && profile.did === opts.userDid) {
160
+ downgradeDecision(profile, { alert: false })
161
+ }
162
+ if (quote && !isModerationDecisionNoop(quote) && quote.did === opts.userDid) {
163
+ downgradeDecision(quote, { alert: true })
164
+ }
165
+ if (
166
+ quotedAccount &&
167
+ !isModerationDecisionNoop(quotedAccount) &&
168
+ quotedAccount.did === opts.userDid
169
+ ) {
170
+ downgradeDecision(quotedAccount, { alert: false })
171
+ }
172
+
173
+ // derive filtering from feeds from the post, post author's account,
174
+ // quoted post, and quoted post author's account
175
+ const mergedForFeed = takeHighestPriorityDecision(
176
+ post,
177
+ account,
178
+ quote,
179
+ quotedAccount,
180
+ )
181
+
182
+ // derive view blurring from the post and the post author's account
183
+ const mergedForView = takeHighestPriorityDecision(post, account)
184
+
185
+ // derive embed blurring from the quoted post and the quoted post author's account
186
+ const mergedQuote = takeHighestPriorityDecision(quote, quotedAccount)
187
+
188
+ // derive avatar blurring from account & profile, but override for mutes because that shouldnt blur
189
+ let blurAvatar = false
190
+ if ((account.blur || account.blurMedia) && account.cause?.type !== 'muted') {
191
+ blurAvatar = true
192
+ } else if (
193
+ (profile.blur || profile.blurMedia) &&
194
+ profile.cause?.type !== 'muted'
195
+ ) {
196
+ blurAvatar = true
197
+ }
198
+
199
+ return {
200
+ decisions: { post, account, profile, quote, quotedAccount },
201
+
202
+ // content behaviors are pulled from feed and view derivations above
203
+ content: {
204
+ cause: !isModerationDecisionNoop(mergedForView)
205
+ ? mergedForView.cause
206
+ : mergedForFeed.filter
207
+ ? mergedForFeed.cause
208
+ : undefined,
209
+ filter: mergedForFeed.filter,
210
+ blur: mergedForView.blur,
211
+ alert: mergedForView.alert,
212
+ noOverride: mergedForView.noOverride,
213
+ },
214
+
215
+ // blur or alert the avatar based on the account and profile decisions
216
+ avatar: {
217
+ blur: blurAvatar,
218
+ alert: account.alert || profile.alert,
219
+ noOverride: account.noOverride || profile.noOverride,
220
+ },
221
+
222
+ // blur the embed if the quoted post required it,
223
+ // or else if the account or post decision was to blur media
224
+ embed: !isModerationDecisionNoop(mergedQuote, { ignoreFilter: true })
225
+ ? {
226
+ cause: mergedQuote.cause,
227
+ blur: mergedQuote.blur,
228
+ alert: mergedQuote.alert,
229
+ noOverride: mergedQuote.noOverride,
230
+ }
231
+ : account.blurMedia
232
+ ? {
233
+ cause: account.cause,
234
+ blur: true,
235
+ noOverride: account.noOverride,
236
+ }
237
+ : post.blurMedia
238
+ ? {
239
+ cause: post.cause,
240
+ blur: true,
241
+ noOverride: post.noOverride,
242
+ }
243
+ : {},
244
+ }
245
+ }
246
+
247
+ // feed generators
248
+ // =
249
+
250
+ export interface FeedGeneratorModeration {
251
+ decisions: {
252
+ feedGenerator: ModerationDecision
253
+ account: ModerationDecision
254
+ profile: ModerationDecision
255
+ }
256
+ content: ModerationUI
257
+ avatar: ModerationUI
258
+ }
259
+
260
+ export function moderateFeedGenerator(
261
+ subject: ModerationSubjectFeedGenerator,
262
+ opts: ModerationOpts,
263
+ ): FeedGeneratorModeration {
264
+ // decide the moderation for the generator, the generator creator's account,
265
+ // and the generator creator's profile
266
+ const feedGenerator = decideFeedGenerator(subject, opts)
267
+ const account = decideAccount(subject.creator, opts)
268
+ const profile = decideProfile(subject.creator, opts)
269
+
270
+ // derive behaviors from feeds from the generator and the generator's account
271
+ const merged = takeHighestPriorityDecision(feedGenerator, account)
272
+
273
+ return {
274
+ decisions: { feedGenerator, account, profile },
275
+
276
+ // content behaviors are pulled from merged decisions
277
+ content: {
278
+ cause: isModerationDecisionNoop(merged) ? undefined : merged.cause,
279
+ filter: merged.filter,
280
+ blur: merged.blur,
281
+ alert: merged.alert,
282
+ noOverride: merged.noOverride,
283
+ },
284
+
285
+ // blur or alert the avatar based on the account and profile decisions
286
+ avatar: {
287
+ blur: account.blurMedia || profile.blurMedia,
288
+ alert: account.alert,
289
+ noOverride: account.noOverride || profile.noOverride,
290
+ },
291
+ }
292
+ }
293
+
294
+ // user lists
295
+ // =
296
+
297
+ export interface UserListModeration {
298
+ decisions: {
299
+ userList: ModerationDecision
300
+ account: ModerationDecision
301
+ profile: ModerationDecision
302
+ }
303
+ content: ModerationUI
304
+ avatar: ModerationUI
305
+ }
306
+
307
+ export function moderateUserList(
308
+ subject: ModerationSubjectUserList,
309
+ opts: ModerationOpts,
310
+ ): UserListModeration {
311
+ // decide the moderation for the list, the list creator's account,
312
+ // and the list creator's profile
313
+ const userList = decideUserList(subject, opts)
314
+ const account = AppBskyActorDefs.isProfileViewBasic(subject.creator)
315
+ ? decideAccount(subject.creator, opts)
316
+ : ModerationDecision.noop()
317
+ const profile = AppBskyActorDefs.isProfileViewBasic(subject.creator)
318
+ ? decideProfile(subject.creator, opts)
319
+ : ModerationDecision.noop()
320
+
321
+ // derive behaviors from feeds from the list and the list's account
322
+ const merged = takeHighestPriorityDecision(userList, account)
323
+
324
+ return {
325
+ decisions: { userList, account, profile },
326
+
327
+ // content behaviors are pulled from merged decisions
328
+ content: {
329
+ cause: isModerationDecisionNoop(merged) ? undefined : merged.cause,
330
+ filter: merged.filter,
331
+ blur: merged.blur,
332
+ alert: merged.alert,
333
+ noOverride: merged.noOverride,
334
+ },
335
+
336
+ // blur or alert the avatar based on the account and profile decisions
337
+ avatar: {
338
+ blur: account.blurMedia || profile.blurMedia,
339
+ alert: account.alert,
340
+ noOverride: account.noOverride || profile.noOverride,
341
+ },
342
+ }
343
+ }
@@ -0,0 +1,40 @@
1
+ import { ModerationCauseAccumulator } from '../accumulator'
2
+ import {
3
+ Label,
4
+ ModerationSubjectProfile,
5
+ ModerationOpts,
6
+ ModerationDecision,
7
+ } from '../types'
8
+
9
+ export function decideAccount(
10
+ subject: ModerationSubjectProfile,
11
+ opts: ModerationOpts,
12
+ ): ModerationDecision {
13
+ const acc = new ModerationCauseAccumulator()
14
+
15
+ acc.setDid(subject.did)
16
+ if (subject.viewer?.muted) {
17
+ if (subject.viewer?.mutedByList) {
18
+ acc.addMutedByList(subject.viewer?.mutedByList)
19
+ } else {
20
+ acc.addMuted(subject.viewer?.muted)
21
+ }
22
+ }
23
+ acc.addBlocking(subject.viewer?.blocking)
24
+ acc.addBlockedBy(subject.viewer?.blockedBy)
25
+
26
+ for (const label of filterAccountLabels(subject.labels)) {
27
+ acc.addLabel(label, opts)
28
+ }
29
+
30
+ return acc.finalizeDecision(opts)
31
+ }
32
+
33
+ export function filterAccountLabels(labels?: Label[]): Label[] {
34
+ if (!labels) {
35
+ return []
36
+ }
37
+ return labels.filter(
38
+ (label) => !label.uri.endsWith('/app.bsky.actor.profile/self'),
39
+ )
40
+ }
@@ -0,0 +1,13 @@
1
+ import {
2
+ ModerationSubjectFeedGenerator,
3
+ ModerationDecision,
4
+ ModerationOpts,
5
+ } from '../types'
6
+
7
+ export function decideFeedGenerator(
8
+ subject: ModerationSubjectFeedGenerator,
9
+ opts: ModerationOpts,
10
+ ): ModerationDecision {
11
+ // TODO handle labels applied on the feed generator itself
12
+ return ModerationDecision.noop()
13
+ }
@@ -0,0 +1,23 @@
1
+ import { ModerationCauseAccumulator } from '../accumulator'
2
+ import {
3
+ ModerationSubjectPost,
4
+ ModerationOpts,
5
+ ModerationDecision,
6
+ } from '../types'
7
+
8
+ export function decidePost(
9
+ subject: ModerationSubjectPost,
10
+ opts: ModerationOpts,
11
+ ): ModerationDecision {
12
+ const acc = new ModerationCauseAccumulator()
13
+
14
+ acc.setDid(subject.author.did)
15
+
16
+ if (subject.labels?.length) {
17
+ for (const label of subject.labels) {
18
+ acc.addLabel(label, opts)
19
+ }
20
+ }
21
+
22
+ return acc.finalizeDecision(opts)
23
+ }
@@ -0,0 +1,31 @@
1
+ import { ModerationCauseAccumulator } from '../accumulator'
2
+ import {
3
+ Label,
4
+ ModerationSubjectProfile,
5
+ ModerationOpts,
6
+ ModerationDecision,
7
+ } from '../types'
8
+
9
+ export function decideProfile(
10
+ subject: ModerationSubjectProfile,
11
+ opts: ModerationOpts,
12
+ ): ModerationDecision {
13
+ const acc = new ModerationCauseAccumulator()
14
+
15
+ acc.setDid(subject.did)
16
+
17
+ for (const label of filterProfileLabels(subject.labels)) {
18
+ acc.addLabel(label, opts)
19
+ }
20
+
21
+ return acc.finalizeDecision(opts)
22
+ }
23
+
24
+ export function filterProfileLabels(labels?: Label[]): Label[] {
25
+ if (!labels) {
26
+ return []
27
+ }
28
+ return labels.filter((label) =>
29
+ label.uri.endsWith('/app.bsky.actor.profile/self'),
30
+ )
31
+ }
@@ -0,0 +1,62 @@
1
+ import { AppBskyEmbedRecord, AppBskyEmbedRecordWithMedia } from '../../client'
2
+ import { ModerationCauseAccumulator } from '../accumulator'
3
+ import { ModerationOpts, ModerationDecision } from '../types'
4
+ import { decideAccount } from './account'
5
+
6
+ export function decideQuotedPost(
7
+ subject: AppBskyEmbedRecord.View,
8
+ opts: ModerationOpts,
9
+ ): ModerationDecision {
10
+ const acc = new ModerationCauseAccumulator()
11
+
12
+ if (AppBskyEmbedRecord.isViewRecord(subject.record)) {
13
+ acc.setDid(subject.record.author.did)
14
+
15
+ if (subject.record.labels?.length) {
16
+ for (const label of subject.record.labels) {
17
+ acc.addLabel(label, opts)
18
+ }
19
+ }
20
+ }
21
+
22
+ return acc.finalizeDecision(opts)
23
+ }
24
+
25
+ export function decideQuotedPostAccount(
26
+ subject: AppBskyEmbedRecord.View,
27
+ opts: ModerationOpts,
28
+ ): ModerationDecision {
29
+ if (AppBskyEmbedRecord.isViewRecord(subject.record)) {
30
+ return decideAccount(subject.record.author, opts)
31
+ }
32
+ return ModerationDecision.noop()
33
+ }
34
+
35
+ export function decideQuotedPostWithMedia(
36
+ subject: AppBskyEmbedRecordWithMedia.View,
37
+ opts: ModerationOpts,
38
+ ): ModerationDecision {
39
+ const acc = new ModerationCauseAccumulator()
40
+
41
+ if (AppBskyEmbedRecord.isViewRecord(subject.record.record)) {
42
+ acc.setDid(subject.record.record.author.did)
43
+
44
+ if (subject.record.record.labels?.length) {
45
+ for (const label of subject.record.record.labels) {
46
+ acc.addLabel(label, opts)
47
+ }
48
+ }
49
+ }
50
+
51
+ return acc.finalizeDecision(opts)
52
+ }
53
+
54
+ export function decideQuotedPostWithMediaAccount(
55
+ subject: AppBskyEmbedRecordWithMedia.View,
56
+ opts: ModerationOpts,
57
+ ): ModerationDecision {
58
+ if (AppBskyEmbedRecord.isViewRecord(subject.record.record)) {
59
+ return decideAccount(subject.record.record.author, opts)
60
+ }
61
+ return ModerationDecision.noop()
62
+ }
@@ -0,0 +1,13 @@
1
+ import {
2
+ ModerationSubjectUserList,
3
+ ModerationOpts,
4
+ ModerationDecision,
5
+ } from '../types'
6
+
7
+ export function decideUserList(
8
+ subject: ModerationSubjectUserList,
9
+ opts: ModerationOpts,
10
+ ): ModerationDecision {
11
+ // TODO handle labels applied on the list itself
12
+ return ModerationDecision.noop()
13
+ }
@@ -0,0 +1,141 @@
1
+ import {
2
+ AppBskyActorDefs,
3
+ AppBskyFeedDefs,
4
+ AppBskyGraphDefs,
5
+ ComAtprotoLabelDefs,
6
+ } from '../client/index'
7
+
8
+ // labels
9
+ // =
10
+
11
+ export type Label = ComAtprotoLabelDefs.Label
12
+
13
+ export type LabelPreference = 'ignore' | 'warn' | 'hide'
14
+ export type LabelDefinitionFlag = 'no-override' | 'adult'
15
+ export type LabelDefinitionOnWarnBehavior =
16
+ | 'blur'
17
+ | 'blur-media'
18
+ | 'alert'
19
+ | null
20
+
21
+ export interface LabelDefinitionLocalizedStrings {
22
+ name: string
23
+ description: string
24
+ }
25
+
26
+ export type LabelDefinitionLocalizedStringsMap = Record<
27
+ string,
28
+ LabelDefinitionLocalizedStrings
29
+ >
30
+
31
+ export interface LabelDefinition {
32
+ id: string
33
+ groupId: string
34
+ configurable: boolean
35
+ preferences: LabelPreference[]
36
+ flags: LabelDefinitionFlag[]
37
+ onwarn: LabelDefinitionOnWarnBehavior
38
+ strings: {
39
+ settings: LabelDefinitionLocalizedStringsMap
40
+ account: LabelDefinitionLocalizedStringsMap
41
+ content: LabelDefinitionLocalizedStringsMap
42
+ }
43
+ }
44
+
45
+ export interface LabelGroupDefinition {
46
+ id: string
47
+ configurable: boolean
48
+ labels: LabelDefinition[]
49
+ strings: {
50
+ settings: LabelDefinitionLocalizedStringsMap
51
+ }
52
+ }
53
+
54
+ export type LabelDefinitionMap = Record<string, LabelDefinition>
55
+ export type LabelGroupDefinitionMap = Record<string, LabelGroupDefinition>
56
+
57
+ // labelers
58
+ // =
59
+
60
+ interface Labeler {
61
+ did: string
62
+ displayName: string
63
+ }
64
+
65
+ export interface LabelerSettings {
66
+ labeler: Labeler
67
+ settings: Record<string, LabelPreference>
68
+ }
69
+
70
+ // subjects
71
+ // =
72
+
73
+ export type ModerationSubjectProfile =
74
+ | AppBskyActorDefs.ProfileViewBasic
75
+ | AppBskyActorDefs.ProfileView
76
+ | AppBskyActorDefs.ProfileViewDetailed
77
+
78
+ export type ModerationSubjectPost = AppBskyFeedDefs.PostView
79
+
80
+ export type ModerationSubjectFeedGenerator = AppBskyFeedDefs.GeneratorView
81
+
82
+ export type ModerationSubjectUserList =
83
+ | AppBskyGraphDefs.ListViewBasic
84
+ | AppBskyGraphDefs.ListView
85
+
86
+ export type ModerationSubject =
87
+ | ModerationSubjectProfile
88
+ | ModerationSubjectPost
89
+ | ModerationSubjectFeedGenerator
90
+ | ModerationSubjectUserList
91
+
92
+ // behaviors
93
+ // =
94
+
95
+ export type ModerationCauseSource =
96
+ | { type: 'user' }
97
+ | { type: 'list'; list: AppBskyGraphDefs.ListViewBasic }
98
+
99
+ export type ModerationCause =
100
+ | { type: 'blocking'; source: ModerationCauseSource; priority: 3 }
101
+ | { type: 'blocked-by'; source: ModerationCauseSource; priority: 4 }
102
+ | {
103
+ type: 'label'
104
+ labeler: Labeler
105
+ label: Label
106
+ labelDef: LabelDefinition
107
+ setting: LabelPreference
108
+ priority: 1 | 2 | 5 | 7 | 8
109
+ }
110
+ | { type: 'muted'; source: ModerationCauseSource; priority: 6 }
111
+
112
+ export interface ModerationOpts {
113
+ userDid: string
114
+ adultContentEnabled: boolean
115
+ labelerSettings: LabelerSettings[]
116
+ }
117
+
118
+ export class ModerationDecision {
119
+ static noop() {
120
+ return new ModerationDecision()
121
+ }
122
+
123
+ constructor(
124
+ public cause: ModerationCause | undefined = undefined,
125
+ public alert: boolean = false,
126
+ public blur: boolean = false,
127
+ public blurMedia: boolean = false,
128
+ public filter: boolean = false,
129
+ public noOverride: boolean = false,
130
+ public additionalCauses: ModerationCause[] = [],
131
+ public did: string = '',
132
+ ) {}
133
+ }
134
+
135
+ export interface ModerationUI {
136
+ filter?: boolean
137
+ blur?: boolean
138
+ alert?: boolean
139
+ cause?: ModerationCause
140
+ noOverride?: boolean
141
+ }