@atproto/api 0.5.4 → 0.6.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.
- package/README.md +11 -3
- package/dist/client/lexicons.d.ts +48 -0
- package/dist/client/types/app/bsky/actor/profile.d.ts +5 -0
- package/dist/client/types/app/bsky/feed/generator.d.ts +5 -0
- package/dist/client/types/app/bsky/feed/getAuthorFeed.d.ts +1 -0
- package/dist/client/types/app/bsky/feed/post.d.ts +5 -0
- package/dist/client/types/app/bsky/graph/list.d.ts +5 -0
- package/dist/client/types/com/atproto/label/defs.d.ts +12 -0
- package/dist/index.js +76 -8
- package/dist/index.js.map +2 -2
- package/dist/moderation/types.d.ts +7 -3
- package/docs/moderation.md +14 -5
- package/package.json +1 -1
- package/src/client/lexicons.ts +55 -0
- package/src/client/types/app/bsky/actor/profile.ts +4 -0
- package/src/client/types/app/bsky/feed/generator.ts +4 -0
- package/src/client/types/app/bsky/feed/getAuthorFeed.ts +5 -0
- package/src/client/types/app/bsky/feed/post.ts +4 -0
- package/src/client/types/app/bsky/graph/list.ts +4 -0
- package/src/client/types/com/atproto/label/defs.ts +37 -0
- package/src/moderation/accumulator.ts +17 -12
- package/src/moderation/types.ts +5 -3
- package/tests/moderation.test.ts +334 -0
- package/tests/util/moderation-behavior.ts +3 -2
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -37,7 +37,7 @@ interface Labeler {
|
|
|
37
37
|
}
|
|
38
38
|
export interface LabelerSettings {
|
|
39
39
|
labeler: Labeler;
|
|
40
|
-
|
|
40
|
+
labels: Record<string, LabelPreference>;
|
|
41
41
|
}
|
|
42
42
|
export declare type ModerationSubjectProfile = AppBskyActorDefs.ProfileViewBasic | AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewDetailed;
|
|
43
43
|
export declare type ModerationSubjectPost = AppBskyFeedDefs.PostView;
|
|
@@ -49,6 +49,9 @@ export declare type ModerationCauseSource = {
|
|
|
49
49
|
} | {
|
|
50
50
|
type: 'list';
|
|
51
51
|
list: AppBskyGraphDefs.ListViewBasic;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'labeler';
|
|
54
|
+
labeler: Labeler;
|
|
52
55
|
};
|
|
53
56
|
export declare type ModerationCause = {
|
|
54
57
|
type: 'blocking';
|
|
@@ -60,7 +63,7 @@ export declare type ModerationCause = {
|
|
|
60
63
|
priority: 4;
|
|
61
64
|
} | {
|
|
62
65
|
type: 'label';
|
|
63
|
-
|
|
66
|
+
source: ModerationCauseSource;
|
|
64
67
|
label: Label;
|
|
65
68
|
labelDef: LabelDefinition;
|
|
66
69
|
setting: LabelPreference;
|
|
@@ -73,7 +76,8 @@ export declare type ModerationCause = {
|
|
|
73
76
|
export interface ModerationOpts {
|
|
74
77
|
userDid: string;
|
|
75
78
|
adultContentEnabled: boolean;
|
|
76
|
-
|
|
79
|
+
labels: Record<string, LabelPreference>;
|
|
80
|
+
labelers: LabelerSettings[];
|
|
77
81
|
}
|
|
78
82
|
export declare class ModerationDecision {
|
|
79
83
|
cause: ModerationCause | undefined;
|
package/docs/moderation.md
CHANGED
|
@@ -26,14 +26,22 @@ Every moderation function takes a set of options which look like this:
|
|
|
26
26
|
// is adult content allowed?
|
|
27
27
|
adultContentEnabled: true,
|
|
28
28
|
|
|
29
|
-
// the
|
|
30
|
-
|
|
29
|
+
// the global label settings (used on self-labels)
|
|
30
|
+
labels: {
|
|
31
|
+
porn: 'hide',
|
|
32
|
+
sexual: 'warn',
|
|
33
|
+
nudity: 'ignore',
|
|
34
|
+
// ...
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// the per-labeler settings
|
|
38
|
+
labelers: [
|
|
31
39
|
{
|
|
32
40
|
labeler: {
|
|
33
41
|
did: '...',
|
|
34
42
|
displayName: 'My mod service'
|
|
35
43
|
},
|
|
36
|
-
|
|
44
|
+
labels: {
|
|
37
45
|
porn: 'hide',
|
|
38
46
|
sexual: 'warn',
|
|
39
47
|
nudity: 'ignore',
|
|
@@ -50,7 +58,8 @@ This should match the following interfaces:
|
|
|
50
58
|
interface ModerationOpts {
|
|
51
59
|
userDid: string
|
|
52
60
|
adultContentEnabled: boolean
|
|
53
|
-
|
|
61
|
+
labels: Record<string, LabelPreference>
|
|
62
|
+
labelers: LabelerSettings[]
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
interface Labeler {
|
|
@@ -62,7 +71,7 @@ type LabelPreference = 'ignore' | 'warn' | 'hide'
|
|
|
62
71
|
|
|
63
72
|
interface LabelerSettings {
|
|
64
73
|
labeler: Labeler
|
|
65
|
-
|
|
74
|
+
labels: Record<string, LabelPreference>
|
|
66
75
|
}
|
|
67
76
|
```
|
|
68
77
|
|
package/package.json
CHANGED
package/src/client/lexicons.ts
CHANGED
|
@@ -1441,6 +1441,36 @@ export const schemaDict = {
|
|
|
1441
1441
|
},
|
|
1442
1442
|
},
|
|
1443
1443
|
},
|
|
1444
|
+
selfLabels: {
|
|
1445
|
+
type: 'object',
|
|
1446
|
+
description:
|
|
1447
|
+
'Metadata tags on an atproto record, published by the author within the record.',
|
|
1448
|
+
required: ['values'],
|
|
1449
|
+
properties: {
|
|
1450
|
+
values: {
|
|
1451
|
+
type: 'array',
|
|
1452
|
+
items: {
|
|
1453
|
+
type: 'ref',
|
|
1454
|
+
ref: 'lex:com.atproto.label.defs#selfLabel',
|
|
1455
|
+
},
|
|
1456
|
+
maxLength: 10,
|
|
1457
|
+
},
|
|
1458
|
+
},
|
|
1459
|
+
},
|
|
1460
|
+
selfLabel: {
|
|
1461
|
+
type: 'object',
|
|
1462
|
+
description:
|
|
1463
|
+
'Metadata tag on an atproto record, published by the author within the record. Note -- schemas should use #selfLabels, not #selfLabel.',
|
|
1464
|
+
required: ['val'],
|
|
1465
|
+
properties: {
|
|
1466
|
+
val: {
|
|
1467
|
+
type: 'string',
|
|
1468
|
+
maxLength: 128,
|
|
1469
|
+
description:
|
|
1470
|
+
'the short string name of the value or type of this label',
|
|
1471
|
+
},
|
|
1472
|
+
},
|
|
1473
|
+
},
|
|
1444
1474
|
},
|
|
1445
1475
|
},
|
|
1446
1476
|
ComAtprotoLabelQueryLabels: {
|
|
@@ -3925,6 +3955,10 @@ export const schemaDict = {
|
|
|
3925
3955
|
accept: ['image/png', 'image/jpeg'],
|
|
3926
3956
|
maxSize: 1000000,
|
|
3927
3957
|
},
|
|
3958
|
+
labels: {
|
|
3959
|
+
type: 'union',
|
|
3960
|
+
refs: ['lex:com.atproto.label.defs#selfLabels'],
|
|
3961
|
+
},
|
|
3928
3962
|
},
|
|
3929
3963
|
},
|
|
3930
3964
|
},
|
|
@@ -4671,6 +4705,10 @@ export const schemaDict = {
|
|
|
4671
4705
|
accept: ['image/png', 'image/jpeg'],
|
|
4672
4706
|
maxSize: 1000000,
|
|
4673
4707
|
},
|
|
4708
|
+
labels: {
|
|
4709
|
+
type: 'union',
|
|
4710
|
+
refs: ['lex:com.atproto.label.defs#selfLabels'],
|
|
4711
|
+
},
|
|
4674
4712
|
createdAt: {
|
|
4675
4713
|
type: 'string',
|
|
4676
4714
|
format: 'datetime',
|
|
@@ -4752,6 +4790,15 @@ export const schemaDict = {
|
|
|
4752
4790
|
cursor: {
|
|
4753
4791
|
type: 'string',
|
|
4754
4792
|
},
|
|
4793
|
+
filter: {
|
|
4794
|
+
type: 'string',
|
|
4795
|
+
knownValues: [
|
|
4796
|
+
'posts_with_replies',
|
|
4797
|
+
'posts_no_replies',
|
|
4798
|
+
'posts_with_media',
|
|
4799
|
+
],
|
|
4800
|
+
default: 'posts_with_replies',
|
|
4801
|
+
},
|
|
4755
4802
|
},
|
|
4756
4803
|
},
|
|
4757
4804
|
output: {
|
|
@@ -5321,6 +5368,10 @@ export const schemaDict = {
|
|
|
5321
5368
|
format: 'language',
|
|
5322
5369
|
},
|
|
5323
5370
|
},
|
|
5371
|
+
labels: {
|
|
5372
|
+
type: 'union',
|
|
5373
|
+
refs: ['lex:com.atproto.label.defs#selfLabels'],
|
|
5374
|
+
},
|
|
5324
5375
|
createdAt: {
|
|
5325
5376
|
type: 'string',
|
|
5326
5377
|
format: 'datetime',
|
|
@@ -5940,6 +5991,10 @@ export const schemaDict = {
|
|
|
5940
5991
|
accept: ['image/png', 'image/jpeg'],
|
|
5941
5992
|
maxSize: 1000000,
|
|
5942
5993
|
},
|
|
5994
|
+
labels: {
|
|
5995
|
+
type: 'union',
|
|
5996
|
+
refs: ['lex:com.atproto.label.defs#selfLabels'],
|
|
5997
|
+
},
|
|
5943
5998
|
createdAt: {
|
|
5944
5999
|
type: 'string',
|
|
5945
6000
|
format: 'datetime',
|
|
@@ -5,12 +5,16 @@ import { ValidationResult, BlobRef } from '@atproto/lexicon'
|
|
|
5
5
|
import { isObj, hasProp } from '../../../../util'
|
|
6
6
|
import { lexicons } from '../../../../lexicons'
|
|
7
7
|
import { CID } from 'multiformats/cid'
|
|
8
|
+
import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs'
|
|
8
9
|
|
|
9
10
|
export interface Record {
|
|
10
11
|
displayName?: string
|
|
11
12
|
description?: string
|
|
12
13
|
avatar?: BlobRef
|
|
13
14
|
banner?: BlobRef
|
|
15
|
+
labels?:
|
|
16
|
+
| ComAtprotoLabelDefs.SelfLabels
|
|
17
|
+
| { $type: string; [k: string]: unknown }
|
|
14
18
|
[k: string]: unknown
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -6,6 +6,7 @@ import { isObj, hasProp } from '../../../../util'
|
|
|
6
6
|
import { lexicons } from '../../../../lexicons'
|
|
7
7
|
import { CID } from 'multiformats/cid'
|
|
8
8
|
import * as AppBskyRichtextFacet from '../richtext/facet'
|
|
9
|
+
import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs'
|
|
9
10
|
|
|
10
11
|
export interface Record {
|
|
11
12
|
did: string
|
|
@@ -13,6 +14,9 @@ export interface Record {
|
|
|
13
14
|
description?: string
|
|
14
15
|
descriptionFacets?: AppBskyRichtextFacet.Main[]
|
|
15
16
|
avatar?: BlobRef
|
|
17
|
+
labels?:
|
|
18
|
+
| ComAtprotoLabelDefs.SelfLabels
|
|
19
|
+
| { $type: string; [k: string]: unknown }
|
|
16
20
|
createdAt: string
|
|
17
21
|
[k: string]: unknown
|
|
18
22
|
}
|
|
@@ -10,6 +10,7 @@ import * as AppBskyEmbedImages from '../embed/images'
|
|
|
10
10
|
import * as AppBskyEmbedExternal from '../embed/external'
|
|
11
11
|
import * as AppBskyEmbedRecord from '../embed/record'
|
|
12
12
|
import * as AppBskyEmbedRecordWithMedia from '../embed/recordWithMedia'
|
|
13
|
+
import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs'
|
|
13
14
|
import * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef'
|
|
14
15
|
|
|
15
16
|
export interface Record {
|
|
@@ -25,6 +26,9 @@ export interface Record {
|
|
|
25
26
|
| AppBskyEmbedRecordWithMedia.Main
|
|
26
27
|
| { $type: string; [k: string]: unknown }
|
|
27
28
|
langs?: string[]
|
|
29
|
+
labels?:
|
|
30
|
+
| ComAtprotoLabelDefs.SelfLabels
|
|
31
|
+
| { $type: string; [k: string]: unknown }
|
|
28
32
|
createdAt: string
|
|
29
33
|
[k: string]: unknown
|
|
30
34
|
}
|
|
@@ -7,6 +7,7 @@ import { lexicons } from '../../../../lexicons'
|
|
|
7
7
|
import { CID } from 'multiformats/cid'
|
|
8
8
|
import * as AppBskyGraphDefs from './defs'
|
|
9
9
|
import * as AppBskyRichtextFacet from '../richtext/facet'
|
|
10
|
+
import * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs'
|
|
10
11
|
|
|
11
12
|
export interface Record {
|
|
12
13
|
purpose: AppBskyGraphDefs.ListPurpose
|
|
@@ -14,6 +15,9 @@ export interface Record {
|
|
|
14
15
|
description?: string
|
|
15
16
|
descriptionFacets?: AppBskyRichtextFacet.Main[]
|
|
16
17
|
avatar?: BlobRef
|
|
18
|
+
labels?:
|
|
19
|
+
| ComAtprotoLabelDefs.SelfLabels
|
|
20
|
+
| { $type: string; [k: string]: unknown }
|
|
17
21
|
createdAt: string
|
|
18
22
|
[k: string]: unknown
|
|
19
23
|
}
|
|
@@ -34,3 +34,40 @@ export function isLabel(v: unknown): v is Label {
|
|
|
34
34
|
export function validateLabel(v: unknown): ValidationResult {
|
|
35
35
|
return lexicons.validate('com.atproto.label.defs#label', v)
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
/** Metadata tags on an atproto record, published by the author within the record. */
|
|
39
|
+
export interface SelfLabels {
|
|
40
|
+
values: SelfLabel[]
|
|
41
|
+
[k: string]: unknown
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isSelfLabels(v: unknown): v is SelfLabels {
|
|
45
|
+
return (
|
|
46
|
+
isObj(v) &&
|
|
47
|
+
hasProp(v, '$type') &&
|
|
48
|
+
v.$type === 'com.atproto.label.defs#selfLabels'
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function validateSelfLabels(v: unknown): ValidationResult {
|
|
53
|
+
return lexicons.validate('com.atproto.label.defs#selfLabels', v)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Metadata tag on an atproto record, published by the author within the record. Note -- schemas should use #selfLabels, not #selfLabel. */
|
|
57
|
+
export interface SelfLabel {
|
|
58
|
+
/** the short string name of the value or type of this label */
|
|
59
|
+
val: string
|
|
60
|
+
[k: string]: unknown
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function isSelfLabel(v: unknown): v is SelfLabel {
|
|
64
|
+
return (
|
|
65
|
+
isObj(v) &&
|
|
66
|
+
hasProp(v, '$type') &&
|
|
67
|
+
v.$type === 'com.atproto.label.defs#selfLabel'
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function validateSelfLabel(v: unknown): ValidationResult {
|
|
72
|
+
return lexicons.validate('com.atproto.label.defs#selfLabel', v)
|
|
73
|
+
}
|
|
@@ -47,15 +47,15 @@ export class ModerationCauseAccumulator {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// look up the label preference
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return
|
|
58
|
-
}
|
|
50
|
+
const isSelf = label.src === this.did
|
|
51
|
+
const labeler = isSelf
|
|
52
|
+
? undefined
|
|
53
|
+
: opts.labelers.find((s) => s.labeler.did === label.src)
|
|
54
|
+
|
|
55
|
+
/* TODO when 3P labelers are supported
|
|
56
|
+
if (!isSelf && !labeler) {
|
|
57
|
+
return // skip labelers not configured by the user
|
|
58
|
+
}*/
|
|
59
59
|
|
|
60
60
|
// establish the label preference for interpretation
|
|
61
61
|
let labelPref: LabelPreference = 'ignore'
|
|
@@ -63,8 +63,10 @@ export class ModerationCauseAccumulator {
|
|
|
63
63
|
labelPref = labelDef.preferences[0]
|
|
64
64
|
} else if (labelDef.flags.includes('adult') && !opts.adultContentEnabled) {
|
|
65
65
|
labelPref = 'hide'
|
|
66
|
-
} else if (
|
|
67
|
-
labelPref =
|
|
66
|
+
} else if (labeler?.labels[label.val]) {
|
|
67
|
+
labelPref = labeler.labels[label.val]
|
|
68
|
+
} else if (opts.labels[label.val]) {
|
|
69
|
+
labelPref = opts.labels[label.val]
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
// ignore labels the user has asked to ignore
|
|
@@ -88,9 +90,12 @@ export class ModerationCauseAccumulator {
|
|
|
88
90
|
|
|
89
91
|
this.causes.push({
|
|
90
92
|
type: 'label',
|
|
93
|
+
source:
|
|
94
|
+
isSelf || !labeler
|
|
95
|
+
? { type: 'user' }
|
|
96
|
+
: { type: 'labeler', labeler: labeler.labeler },
|
|
91
97
|
label,
|
|
92
98
|
labelDef,
|
|
93
|
-
labeler: labelerSettings.labeler,
|
|
94
99
|
setting: labelPref,
|
|
95
100
|
priority,
|
|
96
101
|
})
|
package/src/moderation/types.ts
CHANGED
|
@@ -64,7 +64,7 @@ interface Labeler {
|
|
|
64
64
|
|
|
65
65
|
export interface LabelerSettings {
|
|
66
66
|
labeler: Labeler
|
|
67
|
-
|
|
67
|
+
labels: Record<string, LabelPreference>
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// subjects
|
|
@@ -95,13 +95,14 @@ export type ModerationSubject =
|
|
|
95
95
|
export type ModerationCauseSource =
|
|
96
96
|
| { type: 'user' }
|
|
97
97
|
| { type: 'list'; list: AppBskyGraphDefs.ListViewBasic }
|
|
98
|
+
| { type: 'labeler'; labeler: Labeler }
|
|
98
99
|
|
|
99
100
|
export type ModerationCause =
|
|
100
101
|
| { type: 'blocking'; source: ModerationCauseSource; priority: 3 }
|
|
101
102
|
| { type: 'blocked-by'; source: ModerationCauseSource; priority: 4 }
|
|
102
103
|
| {
|
|
103
104
|
type: 'label'
|
|
104
|
-
|
|
105
|
+
source: ModerationCauseSource
|
|
105
106
|
label: Label
|
|
106
107
|
labelDef: LabelDefinition
|
|
107
108
|
setting: LabelPreference
|
|
@@ -112,7 +113,8 @@ export type ModerationCause =
|
|
|
112
113
|
export interface ModerationOpts {
|
|
113
114
|
userDid: string
|
|
114
115
|
adultContentEnabled: boolean
|
|
115
|
-
|
|
116
|
+
labels: Record<string, LabelPreference>
|
|
117
|
+
labelers: LabelerSettings[]
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
export class ModerationDecision {
|