@atproto/api 0.20.22 → 0.20.25

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 (64) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/client/lexicons.d.ts +28 -12
  3. package/dist/client/lexicons.d.ts.map +1 -1
  4. package/dist/client/lexicons.js +14 -6
  5. package/dist/client/lexicons.js.map +1 -1
  6. package/dist/client/types/app/bsky/ageassurance/defs.d.ts +2 -0
  7. package/dist/client/types/app/bsky/ageassurance/defs.d.ts.map +1 -1
  8. package/dist/client/types/app/bsky/ageassurance/defs.js.map +1 -1
  9. package/package.json +22 -16
  10. package/definitions/labels.json +0 -170
  11. package/docs/moderation.md +0 -260
  12. package/jest.config.cjs +0 -23
  13. package/jest.d.ts +0 -20
  14. package/jest.setup.ts +0 -97
  15. package/scripts/code/labels.mjs +0 -77
  16. package/scripts/generate-code.mjs +0 -4
  17. package/src/age-assurance.test.ts +0 -218
  18. package/src/age-assurance.ts +0 -137
  19. package/src/agent.ts +0 -1645
  20. package/src/atp-agent.ts +0 -570
  21. package/src/bsky-agent.ts +0 -14
  22. package/src/const.ts +0 -1
  23. package/src/index.ts +0 -44
  24. package/src/mocker.ts +0 -220
  25. package/src/moderation/decision.ts +0 -389
  26. package/src/moderation/index.ts +0 -69
  27. package/src/moderation/mutewords.ts +0 -170
  28. package/src/moderation/subjects/account.ts +0 -44
  29. package/src/moderation/subjects/feed-generator.ts +0 -24
  30. package/src/moderation/subjects/notification.ts +0 -25
  31. package/src/moderation/subjects/post.ts +0 -433
  32. package/src/moderation/subjects/profile.ts +0 -26
  33. package/src/moderation/subjects/status.ts +0 -27
  34. package/src/moderation/subjects/user-list.ts +0 -48
  35. package/src/moderation/types.ts +0 -191
  36. package/src/moderation/ui.ts +0 -21
  37. package/src/moderation/util.ts +0 -111
  38. package/src/predicate.ts +0 -52
  39. package/src/rich-text/detection.ts +0 -146
  40. package/src/rich-text/rich-text.ts +0 -418
  41. package/src/rich-text/sanitization.ts +0 -42
  42. package/src/rich-text/unicode.ts +0 -47
  43. package/src/rich-text/util.ts +0 -15
  44. package/src/session-manager.ts +0 -5
  45. package/src/types.ts +0 -165
  46. package/src/util.ts +0 -96
  47. package/tests/atp-agent.test.ts +0 -3863
  48. package/tests/dispatcher.test.ts +0 -527
  49. package/tests/errors.test.ts +0 -29
  50. package/tests/moderation-behaviors.test.ts +0 -951
  51. package/tests/moderation-custom-labels.test.ts +0 -334
  52. package/tests/moderation-mutewords.test.ts +0 -1299
  53. package/tests/moderation-prefs.test.ts +0 -402
  54. package/tests/moderation-quoteposts.test.ts +0 -277
  55. package/tests/moderation.test.ts +0 -739
  56. package/tests/rich-text-detection.test.ts +0 -456
  57. package/tests/rich-text-sanitization.test.ts +0 -216
  58. package/tests/rich-text.test.ts +0 -705
  59. package/tests/util/echo-server.ts +0 -37
  60. package/tests/util/moderation-behavior.ts +0 -268
  61. package/tsconfig.build.json +0 -9
  62. package/tsconfig.build.tsbuildinfo +0 -1
  63. package/tsconfig.json +0 -7
  64. package/tsconfig.tests.json +0 -10
package/src/mocker.ts DELETED
@@ -1,220 +0,0 @@
1
- import {
2
- AppBskyActorDefs,
3
- AppBskyEmbedRecord,
4
- AppBskyFeedDefs,
5
- AppBskyFeedPost,
6
- AppBskyGraphDefs,
7
- AppBskyNotificationListNotifications,
8
- ComAtprotoLabelDefs,
9
- } from './client/index.js'
10
- import { $Typed, Un$Typed } from './client/util.js'
11
-
12
- const FAKE_CID = 'bafyreiclp443lavogvhj3d2ob2cxbfuscni2k5jk7bebjzg7khl3esabwq'
13
-
14
- export const mock = {
15
- post({
16
- text,
17
- facets,
18
- reply,
19
- embed,
20
- }: {
21
- text: string
22
- facets?: AppBskyFeedPost.Record['facets']
23
- reply?: AppBskyFeedPost.ReplyRef
24
- embed?: AppBskyFeedPost.Record['embed']
25
- }): $Typed<AppBskyFeedPost.Record> {
26
- return {
27
- $type: 'app.bsky.feed.post',
28
- text,
29
- facets,
30
- reply,
31
- embed,
32
- langs: ['en'],
33
- createdAt: new Date().toISOString(),
34
- }
35
- },
36
-
37
- postView({
38
- record,
39
- author,
40
- embed,
41
- replyCount,
42
- repostCount,
43
- likeCount,
44
- viewer,
45
- labels,
46
- }: {
47
- record: AppBskyFeedPost.Record
48
- author: AppBskyActorDefs.ProfileViewBasic
49
- embed?: AppBskyFeedDefs.PostView['embed']
50
- replyCount?: number
51
- repostCount?: number
52
- likeCount?: number
53
- viewer?: AppBskyFeedDefs.ViewerState
54
- labels?: ComAtprotoLabelDefs.Label[]
55
- }): $Typed<AppBskyFeedDefs.PostView> {
56
- return {
57
- $type: 'app.bsky.feed.defs#postView',
58
- uri: `at://${author.did}/app.bsky.feed.post/fake`,
59
- cid: FAKE_CID,
60
- author,
61
- record,
62
- embed,
63
- replyCount,
64
- repostCount,
65
- likeCount,
66
- indexedAt: new Date().toISOString(),
67
- viewer,
68
- labels,
69
- }
70
- },
71
-
72
- embedRecordView({
73
- record,
74
- author,
75
- labels,
76
- }: {
77
- record: AppBskyFeedPost.Record
78
- author: AppBskyActorDefs.ProfileViewBasic
79
- labels?: ComAtprotoLabelDefs.Label[]
80
- }): $Typed<AppBskyEmbedRecord.View> {
81
- return {
82
- $type: 'app.bsky.embed.record#view',
83
- record: {
84
- $type: 'app.bsky.embed.record#viewRecord',
85
- uri: `at://${author.did}/app.bsky.feed.post/fake`,
86
- cid: FAKE_CID,
87
- author,
88
- value: record,
89
- labels,
90
- indexedAt: new Date().toISOString(),
91
- },
92
- }
93
- },
94
-
95
- profileViewBasic({
96
- handle,
97
- displayName,
98
- description,
99
- viewer,
100
- labels,
101
- }: {
102
- handle: string
103
- displayName?: string
104
- description?: string
105
- viewer?: AppBskyActorDefs.ViewerState
106
- labels?: ComAtprotoLabelDefs.Label[]
107
- }): AppBskyActorDefs.ProfileViewBasic {
108
- return {
109
- did: `did:web:${handle}`,
110
- handle,
111
- displayName,
112
- // @ts-expect-error technically not in ProfileViewBasic but useful in some cases
113
- description,
114
- viewer,
115
- labels,
116
- }
117
- },
118
-
119
- actorViewerState({
120
- muted,
121
- mutedByList,
122
- blockedBy,
123
- blocking,
124
- blockingByList,
125
- following,
126
- followedBy,
127
- }: {
128
- muted?: boolean
129
- mutedByList?: AppBskyGraphDefs.ListViewBasic
130
- blockedBy?: boolean
131
- blocking?: string
132
- blockingByList?: AppBskyGraphDefs.ListViewBasic
133
- following?: string
134
- followedBy?: string
135
- }): AppBskyActorDefs.ViewerState {
136
- return {
137
- muted,
138
- mutedByList,
139
- blockedBy,
140
- blocking,
141
- blockingByList,
142
- following,
143
- followedBy,
144
- }
145
- },
146
-
147
- listViewBasic({ name }: { name: string }): AppBskyGraphDefs.ListViewBasic {
148
- return {
149
- uri: 'at://did:plc:fake/app.bsky.graph.list/fake',
150
- cid: FAKE_CID,
151
- name,
152
- purpose: 'app.bsky.graph.defs#modlist',
153
- indexedAt: new Date().toISOString(),
154
- }
155
- },
156
-
157
- replyNotification({
158
- author,
159
- record,
160
- labels,
161
- }: {
162
- record: AppBskyFeedPost.Record
163
- author: Un$Typed<AppBskyActorDefs.ProfileViewBasic>
164
- labels?: ComAtprotoLabelDefs.Label[]
165
- }): AppBskyNotificationListNotifications.Notification {
166
- return {
167
- uri: `at://${author.did}/app.bsky.feed.post/fake`,
168
- cid: FAKE_CID,
169
- author,
170
- reason: 'reply',
171
- reasonSubject: `at://${author.did}/app.bsky.feed.post/fake-parent`,
172
- record,
173
- isRead: false,
174
- indexedAt: new Date().toISOString(),
175
- labels,
176
- }
177
- },
178
-
179
- followNotification({
180
- author,
181
- subjectDid,
182
- labels,
183
- }: {
184
- author: Un$Typed<AppBskyActorDefs.ProfileViewBasic>
185
- subjectDid: string
186
- labels?: ComAtprotoLabelDefs.Label[]
187
- }): AppBskyNotificationListNotifications.Notification {
188
- return {
189
- uri: `at://${author.did}/app.bsky.graph.follow/fake`,
190
- cid: FAKE_CID,
191
- author,
192
- reason: 'follow',
193
- record: {
194
- $type: 'app.bsky.graph.follow',
195
- createdAt: new Date().toISOString(),
196
- subject: subjectDid,
197
- },
198
- isRead: false,
199
- indexedAt: new Date().toISOString(),
200
- labels,
201
- }
202
- },
203
-
204
- label({
205
- val,
206
- uri,
207
- src,
208
- }: {
209
- val: string
210
- uri: string
211
- src?: string
212
- }): ComAtprotoLabelDefs.Label {
213
- return {
214
- src: src || 'did:plc:fake-labeler',
215
- uri,
216
- val,
217
- cts: new Date().toISOString(),
218
- }
219
- },
220
- }
@@ -1,389 +0,0 @@
1
- import { AppBskyGraphDefs } from '../client/index.js'
2
- import { LABELS } from './const/labels.js'
3
- import { MuteWordMatch } from './mutewords.js'
4
- import {
5
- BLOCK_BEHAVIOR,
6
- CUSTOM_LABEL_VALUE_RE,
7
- HIDE_BEHAVIOR,
8
- Label,
9
- LabelPreference,
10
- LabelTarget,
11
- MUTEWORD_BEHAVIOR,
12
- MUTE_BEHAVIOR,
13
- ModerationBehavior,
14
- ModerationCause,
15
- ModerationOpts,
16
- NOOP_BEHAVIOR,
17
- } from './types.js'
18
- import { ModerationUI } from './ui.js'
19
-
20
- enum ModerationBehaviorSeverity {
21
- High,
22
- Medium,
23
- Low,
24
- }
25
-
26
- export class ModerationDecision {
27
- did = ''
28
- isMe = false
29
- causes: ModerationCause[] = []
30
-
31
- constructor() {}
32
-
33
- static merge(
34
- ...decisions: (ModerationDecision | undefined)[]
35
- ): ModerationDecision {
36
- const decisionsFiltered = decisions.filter((v) => v != null)
37
- const decision = new ModerationDecision()
38
- if (decisionsFiltered[0]) {
39
- decision.did = decisionsFiltered[0].did
40
- decision.isMe = decisionsFiltered[0].isMe
41
- }
42
- decision.causes = decisionsFiltered.flatMap((d) => d.causes)
43
- return decision
44
- }
45
-
46
- downgrade() {
47
- for (const cause of this.causes) {
48
- cause.downgraded = true
49
- }
50
- return this
51
- }
52
-
53
- get blocked() {
54
- return !!this.blockCause
55
- }
56
-
57
- get muted() {
58
- return !!this.muteCause
59
- }
60
-
61
- get blockCause() {
62
- return this.causes.find(
63
- (cause) =>
64
- cause.type === 'blocking' ||
65
- cause.type === 'blocked-by' ||
66
- cause.type === 'block-other',
67
- )
68
- }
69
-
70
- get muteCause() {
71
- return this.causes.find((cause) => cause.type === 'muted')
72
- }
73
-
74
- get labelCauses() {
75
- return this.causes.filter((cause) => cause.type === 'label')
76
- }
77
-
78
- ui(context: keyof ModerationBehavior): ModerationUI {
79
- const ui = new ModerationUI()
80
- for (const cause of this.causes) {
81
- if (
82
- cause.type === 'blocking' ||
83
- cause.type === 'blocked-by' ||
84
- cause.type === 'block-other'
85
- ) {
86
- if (this.isMe) {
87
- continue
88
- }
89
- if (context === 'profileList' || context === 'contentList') {
90
- ui.filters.push(cause)
91
- }
92
- if (!cause.downgraded) {
93
- if (BLOCK_BEHAVIOR[context] === 'blur') {
94
- ui.noOverride = true
95
- ui.blurs.push(cause)
96
- } else if (BLOCK_BEHAVIOR[context] === 'alert') {
97
- ui.alerts.push(cause)
98
- } else if (BLOCK_BEHAVIOR[context] === 'inform') {
99
- ui.informs.push(cause)
100
- }
101
- }
102
- } else if (cause.type === 'muted') {
103
- if (this.isMe) {
104
- continue
105
- }
106
- if (context === 'profileList' || context === 'contentList') {
107
- ui.filters.push(cause)
108
- }
109
- if (!cause.downgraded) {
110
- if (MUTE_BEHAVIOR[context] === 'blur') {
111
- ui.blurs.push(cause)
112
- } else if (MUTE_BEHAVIOR[context] === 'alert') {
113
- ui.alerts.push(cause)
114
- } else if (MUTE_BEHAVIOR[context] === 'inform') {
115
- ui.informs.push(cause)
116
- }
117
- }
118
- } else if (cause.type === 'mute-word') {
119
- if (this.isMe) {
120
- continue
121
- }
122
- if (context === 'contentList') {
123
- ui.filters.push(cause)
124
- }
125
- if (!cause.downgraded) {
126
- if (MUTEWORD_BEHAVIOR[context] === 'blur') {
127
- ui.blurs.push(cause)
128
- } else if (MUTEWORD_BEHAVIOR[context] === 'alert') {
129
- ui.alerts.push(cause)
130
- } else if (MUTEWORD_BEHAVIOR[context] === 'inform') {
131
- ui.informs.push(cause)
132
- }
133
- }
134
- } else if (cause.type === 'hidden') {
135
- if (context === 'profileList' || context === 'contentList') {
136
- ui.filters.push(cause)
137
- }
138
- if (!cause.downgraded) {
139
- if (HIDE_BEHAVIOR[context] === 'blur') {
140
- ui.blurs.push(cause)
141
- } else if (HIDE_BEHAVIOR[context] === 'alert') {
142
- ui.alerts.push(cause)
143
- } else if (HIDE_BEHAVIOR[context] === 'inform') {
144
- ui.informs.push(cause)
145
- }
146
- }
147
- } else if (cause.type === 'label') {
148
- if (context === 'profileList' && cause.target === 'account') {
149
- if (cause.setting === 'hide' && !this.isMe) {
150
- ui.filters.push(cause)
151
- }
152
- } else if (
153
- context === 'contentList' &&
154
- (cause.target === 'account' || cause.target === 'content')
155
- ) {
156
- if (cause.setting === 'hide' && !this.isMe) {
157
- ui.filters.push(cause)
158
- }
159
- }
160
- if (!cause.downgraded) {
161
- if (cause.behavior[context] === 'blur') {
162
- ui.blurs.push(cause)
163
- if (cause.noOverride && !this.isMe) {
164
- ui.noOverride = true
165
- }
166
- } else if (cause.behavior[context] === 'alert') {
167
- ui.alerts.push(cause)
168
- } else if (cause.behavior[context] === 'inform') {
169
- ui.informs.push(cause)
170
- }
171
- }
172
- }
173
- }
174
-
175
- ui.filters.sort(sortByPriority)
176
- ui.blurs.sort(sortByPriority)
177
-
178
- return ui
179
- }
180
-
181
- setDid(did: string) {
182
- this.did = did
183
- }
184
-
185
- setIsMe(isMe: boolean) {
186
- this.isMe = isMe
187
- }
188
-
189
- addHidden(hidden: boolean) {
190
- if (hidden) {
191
- this.causes.push({
192
- type: 'hidden',
193
- source: { type: 'user' },
194
- priority: 6,
195
- })
196
- }
197
- }
198
-
199
- addMutedWord(matches: MuteWordMatch[] | undefined) {
200
- if (matches?.length) {
201
- this.causes.push({
202
- type: 'mute-word',
203
- source: { type: 'user' },
204
- priority: 6,
205
- matches,
206
- })
207
- }
208
- }
209
-
210
- addBlocking(blocking: string | undefined) {
211
- if (blocking) {
212
- this.causes.push({
213
- type: 'blocking',
214
- source: { type: 'user' },
215
- priority: 3,
216
- })
217
- }
218
- }
219
-
220
- addBlockingByList(
221
- blockingByList: AppBskyGraphDefs.ListViewBasic | undefined,
222
- ) {
223
- if (blockingByList) {
224
- this.causes.push({
225
- type: 'blocking',
226
- source: { type: 'list', list: blockingByList },
227
- priority: 3,
228
- })
229
- }
230
- }
231
-
232
- addBlockedBy(blockedBy: boolean | undefined) {
233
- if (blockedBy) {
234
- this.causes.push({
235
- type: 'blocked-by',
236
- source: { type: 'user' },
237
- priority: 4,
238
- })
239
- }
240
- }
241
-
242
- addBlockOther(blockOther: boolean | undefined) {
243
- if (blockOther) {
244
- this.causes.push({
245
- type: 'block-other',
246
- source: { type: 'user' },
247
- priority: 4,
248
- })
249
- }
250
- }
251
-
252
- addLabel(target: LabelTarget, label: Label, opts: ModerationOpts) {
253
- // look up the label definition
254
- const labelDef = CUSTOM_LABEL_VALUE_RE.test(label.val)
255
- ? opts.labelDefs?.[label.src]?.find(
256
- (def) => def.identifier === label.val,
257
- ) || LABELS[label.val]
258
- : LABELS[label.val]
259
- if (!labelDef) {
260
- // ignore labels we don't understand
261
- return
262
- }
263
-
264
- // look up the label preference
265
- const isSelf = label.src === this.did
266
- const labeler = isSelf
267
- ? undefined
268
- : opts.prefs.labelers.find((s) => s.did === label.src)
269
-
270
- if (!isSelf && !labeler) {
271
- return // skip labelers not configured by the user
272
- }
273
- if (isSelf && labelDef.flags.includes('no-self')) {
274
- return // skip self-labels that aren't supported
275
- }
276
-
277
- // establish the label preference for interpretation
278
- let labelPref: LabelPreference = labelDef.defaultSetting || 'ignore'
279
- if (!labelDef.configurable) {
280
- labelPref = labelDef.defaultSetting || 'hide'
281
- } else if (
282
- labelDef.flags.includes('adult') &&
283
- !opts.prefs.adultContentEnabled
284
- ) {
285
- labelPref = 'hide'
286
- } else if (labeler?.labels[labelDef.identifier]) {
287
- labelPref = labeler?.labels[labelDef.identifier]
288
- } else if (opts.prefs.labels[labelDef.identifier]) {
289
- labelPref = opts.prefs.labels[labelDef.identifier]
290
- }
291
-
292
- // ignore labels the user has asked to ignore
293
- if (labelPref === 'ignore') {
294
- return
295
- }
296
-
297
- // ignore 'unauthed' labels when the user is authed
298
- if (labelDef.flags.includes('unauthed') && !!opts.userDid) {
299
- return
300
- }
301
-
302
- // establish the priority of the label
303
- let priority: 1 | 2 | 5 | 7 | 8
304
- const severity = measureModerationBehaviorSeverity(
305
- labelDef.behaviors[target],
306
- )
307
- if (
308
- labelDef.flags.includes('no-override') ||
309
- (labelDef.flags.includes('adult') && !opts.prefs.adultContentEnabled)
310
- ) {
311
- priority = 1
312
- } else if (labelPref === 'hide') {
313
- priority = 2
314
- } else if (severity === ModerationBehaviorSeverity.High) {
315
- // blurring profile view or content view
316
- priority = 5
317
- } else if (severity === ModerationBehaviorSeverity.Medium) {
318
- // blurring content list or content media
319
- priority = 7
320
- } else {
321
- // blurring avatar, adding alerts
322
- priority = 8
323
- }
324
-
325
- let noOverride = false
326
- if (labelDef.flags.includes('no-override')) {
327
- noOverride = true
328
- } else if (
329
- labelDef.flags.includes('adult') &&
330
- !opts.prefs.adultContentEnabled
331
- ) {
332
- noOverride = true
333
- }
334
-
335
- this.causes.push({
336
- type: 'label',
337
- source:
338
- isSelf || !labeler
339
- ? { type: 'user' }
340
- : { type: 'labeler', did: labeler.did },
341
- label,
342
- labelDef,
343
- target,
344
- setting: labelPref,
345
- behavior: labelDef.behaviors[target] || NOOP_BEHAVIOR,
346
- noOverride,
347
- priority,
348
- })
349
- }
350
-
351
- addMuted(muted: boolean | undefined) {
352
- if (muted) {
353
- this.causes.push({
354
- type: 'muted',
355
- source: { type: 'user' },
356
- priority: 6,
357
- })
358
- }
359
- }
360
-
361
- addMutedByList(mutedByList: AppBskyGraphDefs.ListViewBasic | undefined) {
362
- if (mutedByList) {
363
- this.causes.push({
364
- type: 'muted',
365
- source: { type: 'list', list: mutedByList },
366
- priority: 6,
367
- })
368
- }
369
- }
370
- }
371
-
372
- function measureModerationBehaviorSeverity(
373
- beh: ModerationBehavior | undefined,
374
- ): ModerationBehaviorSeverity {
375
- if (!beh) {
376
- return ModerationBehaviorSeverity.Low
377
- }
378
- if (beh.profileView === 'blur' || beh.contentView === 'blur') {
379
- return ModerationBehaviorSeverity.High
380
- }
381
- if (beh.contentList === 'blur' || beh.contentMedia === 'blur') {
382
- return ModerationBehaviorSeverity.Medium
383
- }
384
- return ModerationBehaviorSeverity.Low
385
- }
386
-
387
- function sortByPriority(a: ModerationCause, b: ModerationCause) {
388
- return a.priority - b.priority
389
- }
@@ -1,69 +0,0 @@
1
- import { ModerationDecision } from './decision.js'
2
- import { decideAccount } from './subjects/account.js'
3
- import { decideFeedGenerator } from './subjects/feed-generator.js'
4
- import { decideNotification } from './subjects/notification.js'
5
- import { decidePost } from './subjects/post.js'
6
- import { decideProfile } from './subjects/profile.js'
7
- import { decideStatus } from './subjects/status.js'
8
- import { decideUserList } from './subjects/user-list.js'
9
- import {
10
- ModerationOpts,
11
- ModerationSubjectFeedGenerator,
12
- ModerationSubjectNotification,
13
- ModerationSubjectPost,
14
- ModerationSubjectProfile,
15
- ModerationSubjectUserList,
16
- } from './types.js'
17
-
18
- export { ModerationUI } from './ui.js'
19
- export { ModerationDecision } from './decision.js'
20
- export { hasMutedWord, matchMuteWords } from './mutewords.js'
21
- export {
22
- interpretLabelValueDefinition,
23
- interpretLabelValueDefinitions,
24
- } from './util.js'
25
-
26
- export function moderateProfile(
27
- subject: ModerationSubjectProfile,
28
- opts: ModerationOpts,
29
- ): ModerationDecision {
30
- return ModerationDecision.merge(
31
- decideAccount(subject, opts),
32
- decideProfile(subject, opts),
33
- )
34
- }
35
-
36
- export function moderatePost(
37
- subject: ModerationSubjectPost,
38
- opts: ModerationOpts,
39
- ): ModerationDecision {
40
- return decidePost(subject, opts)
41
- }
42
-
43
- export function moderateNotification(
44
- subject: ModerationSubjectNotification,
45
- opts: ModerationOpts,
46
- ): ModerationDecision {
47
- return decideNotification(subject, opts)
48
- }
49
-
50
- export function moderateFeedGenerator(
51
- subject: ModerationSubjectFeedGenerator,
52
- opts: ModerationOpts,
53
- ): ModerationDecision {
54
- return decideFeedGenerator(subject, opts)
55
- }
56
-
57
- export function moderateUserList(
58
- subject: ModerationSubjectUserList,
59
- opts: ModerationOpts,
60
- ): ModerationDecision {
61
- return decideUserList(subject, opts)
62
- }
63
-
64
- export function moderateStatus(
65
- subject: ModerationSubjectProfile,
66
- opts: ModerationOpts,
67
- ): ModerationDecision {
68
- return decideStatus(subject, opts)
69
- }