@atcute/bluesky-moderation 1.0.1
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/LICENSE +17 -0
- package/README.md +174 -0
- package/dist/behaviors.d.ts +41 -0
- package/dist/behaviors.js +56 -0
- package/dist/behaviors.js.map +1 -0
- package/dist/decision.d.ts +85 -0
- package/dist/decision.js +214 -0
- package/dist/decision.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/keyword-filter.d.ts +8 -0
- package/dist/internal/keyword-filter.js +27 -0
- package/dist/internal/keyword-filter.js.map +1 -0
- package/dist/keyword-filter.d.ts +26 -0
- package/dist/keyword-filter.js +61 -0
- package/dist/keyword-filter.js.map +1 -0
- package/dist/label.d.ts +73 -0
- package/dist/label.js +286 -0
- package/dist/label.js.map +1 -0
- package/dist/subjects/feed-generator.d.ts +3 -0
- package/dist/subjects/feed-generator.js +10 -0
- package/dist/subjects/feed-generator.js.map +1 -0
- package/dist/subjects/list.d.ts +3 -0
- package/dist/subjects/list.js +27 -0
- package/dist/subjects/list.js.map +1 -0
- package/dist/subjects/notification.d.ts +3 -0
- package/dist/subjects/notification.js +10 -0
- package/dist/subjects/notification.js.map +1 -0
- package/dist/subjects/post.d.ts +3 -0
- package/dist/subjects/post.js +215 -0
- package/dist/subjects/post.js.map +1 -0
- package/dist/subjects/profile.d.ts +3 -0
- package/dist/subjects/profile.js +27 -0
- package/dist/subjects/profile.js.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.js +145 -0
- package/dist/ui.js.map +1 -0
- package/lib/behaviors.ts +65 -0
- package/lib/decision.ts +363 -0
- package/lib/index.ts +63 -0
- package/lib/internal/keyword-filter.ts +45 -0
- package/lib/keyword-filter.ts +95 -0
- package/lib/label.ts +353 -0
- package/lib/subjects/feed-generator.ts +22 -0
- package/lib/subjects/list.ts +41 -0
- package/lib/subjects/notification.ts +22 -0
- package/lib/subjects/post.ts +316 -0
- package/lib/subjects/profile.ts +42 -0
- package/lib/types.ts +61 -0
- package/lib/ui.ts +183 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
2
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
3
|
+
in the Software without restriction, including without limitation the rights
|
|
4
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
5
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
6
|
+
furnished to do so, subject to the following conditions:
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be included in all
|
|
9
|
+
copies or substantial portions of the Software.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
14
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
15
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
17
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @atcute/bluesky-moderation
|
|
2
|
+
|
|
3
|
+
interprets Bluesky's content moderation labels.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import type { XRPC } from '@atcute/client';
|
|
7
|
+
import type {
|
|
8
|
+
AppBskyActorDefs,
|
|
9
|
+
AppBskyFeedDefs,
|
|
10
|
+
AppBskyLabelerDefs,
|
|
11
|
+
At,
|
|
12
|
+
} from '@atcute/client/lexicons';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
DisplayContext,
|
|
16
|
+
getDisplayRestrictions,
|
|
17
|
+
interpretLabelerDefinitions,
|
|
18
|
+
interpretMutedWordPreferences,
|
|
19
|
+
LabelPreference,
|
|
20
|
+
moderatePost,
|
|
21
|
+
type ModerationPreferences,
|
|
22
|
+
} from '@atcute/bluesky-moderation';
|
|
23
|
+
|
|
24
|
+
declare const rpc: XRPC;
|
|
25
|
+
|
|
26
|
+
// first, let's get the user's preferences
|
|
27
|
+
const labelerDids = new Set<At.Did>([
|
|
28
|
+
// Bluesky moderation service
|
|
29
|
+
'did:plc:ar7c4by46qjdydhdevvrndac',
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const modPrefs: ModerationPreferences = {
|
|
33
|
+
adultContentEnabled: false,
|
|
34
|
+
globalLabelPrefs: {},
|
|
35
|
+
prefsByLabelers: {
|
|
36
|
+
'did:plc:ar7c4by46qjdydhdevvrndac': {
|
|
37
|
+
labelPrefs: {},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
keywordFilters: [],
|
|
41
|
+
hiddenPosts: [],
|
|
42
|
+
temporaryMutes: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
const { data } = await rpc.get('app.bsky.actor.getPreferences', {});
|
|
47
|
+
|
|
48
|
+
const labelPrefs: AppBskyActorDefs.ContentLabelPref[] = [];
|
|
49
|
+
|
|
50
|
+
const globalLabelPrefs = (modPrefs.globalLabelPrefs ??= {});
|
|
51
|
+
const prefsByLabelers = (modPrefs.prefsByLabelers ??= {});
|
|
52
|
+
|
|
53
|
+
for (const pref of data.preferences) {
|
|
54
|
+
switch (pref.$type) {
|
|
55
|
+
case 'app.bsky.actor.defs#adultContentPref': {
|
|
56
|
+
modPrefs.adultContentEnabled = pref.enabled;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'app.bsky.actor.defs#labelersPref': {
|
|
60
|
+
for (const labeler of pref.labelers) {
|
|
61
|
+
prefsByLabelers[labeler.did] ??= { labelPrefs: {} };
|
|
62
|
+
labelerDids.add(labeler.did);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'app.bsky.actor.defs#contentLabelPref': {
|
|
68
|
+
labelPrefs.push(pref);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'app.bsky.actor.defs#mutedWordsPref': {
|
|
72
|
+
modPrefs.keywordFilters = interpretMutedWordPreferences(pref);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case 'app.bsky.actor.defs#hiddenPostsPref': {
|
|
76
|
+
modPrefs.hiddenPosts = pref.items as At.CanonicalResourceUri[];
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const { labelerDid, label, visibility } of labelPrefs) {
|
|
83
|
+
let pref: LabelPreference | undefined;
|
|
84
|
+
switch (visibility) {
|
|
85
|
+
case 'show':
|
|
86
|
+
case 'ignore': {
|
|
87
|
+
pref = LabelPreference.Ignore;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case 'warn': {
|
|
91
|
+
pref = LabelPreference.Warn;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'hide': {
|
|
95
|
+
pref = LabelPreference.Hide;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (labelerDid === undefined) {
|
|
101
|
+
globalLabelPrefs[label] = pref;
|
|
102
|
+
} else if (labelerDid in prefsByLabelers) {
|
|
103
|
+
const labelerPref = prefsByLabelers[labelerDid]!;
|
|
104
|
+
|
|
105
|
+
labelerPref.labelPrefs[label] = pref;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// grab labeler's definitions
|
|
111
|
+
let labelers: AppBskyLabelerDefs.LabelerViewDetailed[] = [];
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
const { data } = await rpc.get('app.bsky.labeler.getServices', {
|
|
115
|
+
params: {
|
|
116
|
+
dids: [...labelerDids],
|
|
117
|
+
detailed: true,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
labelers = data.views.filter(
|
|
122
|
+
(view) => view.$type === 'app.bsky.labeler.defs#labelerViewDetailed',
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// interpret the labeler's definitions into something the library can understand
|
|
127
|
+
const labelDefs = interpretLabelerDefinitions(labelers);
|
|
128
|
+
|
|
129
|
+
// then we call the appropriate moderation functions
|
|
130
|
+
{
|
|
131
|
+
declare const post: AppBskyFeedDefs.PostView;
|
|
132
|
+
|
|
133
|
+
const mod = moderatePost(post, {
|
|
134
|
+
viewerDid: 'did:plc:xyz',
|
|
135
|
+
labelDefs,
|
|
136
|
+
prefs: modPrefs,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// when displaying the post in feeds...
|
|
140
|
+
{
|
|
141
|
+
const ui = getDisplayRestrictions(mod, DisplayContext.ContentList);
|
|
142
|
+
|
|
143
|
+
if (ui.filters.length > 0) {
|
|
144
|
+
// don't include the post in the feed
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (ui.blurs.length > 0) {
|
|
148
|
+
// hide the post behind a cover
|
|
149
|
+
|
|
150
|
+
if (ui.noOverride) {
|
|
151
|
+
// don't allow the cover to be removed
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (ui.alerts.length > 0 || ui.informs.length > 0) {
|
|
156
|
+
// show warning/inform badges in the post
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// when displaying an expanded version of the post...
|
|
161
|
+
{
|
|
162
|
+
const ui = getDisplayRestrictions(mod, DisplayContext.ContentView);
|
|
163
|
+
|
|
164
|
+
// ...
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// when displaying images/videos of a post...
|
|
168
|
+
{
|
|
169
|
+
const ui = getDisplayRestrictions(mod, DisplayContext.ProfileMedia);
|
|
170
|
+
|
|
171
|
+
// ...
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const enum LabelTarget {
|
|
2
|
+
/** label is intended for account's content */
|
|
3
|
+
Content = "content",
|
|
4
|
+
/** label is intended for account's profile */
|
|
5
|
+
Profile = "profile",
|
|
6
|
+
/** label is intended for account's content and profile */
|
|
7
|
+
Account = "account"
|
|
8
|
+
}
|
|
9
|
+
export declare const enum DisplayContext {
|
|
10
|
+
/** content in expanded view */
|
|
11
|
+
ContentView = "contentView",
|
|
12
|
+
/** images or video contained in content */
|
|
13
|
+
ContentMedia = "contentMedia",
|
|
14
|
+
/** content in a list/feed */
|
|
15
|
+
ContentList = "contentList",
|
|
16
|
+
/** profile in expanded view */
|
|
17
|
+
ProfileView = "profileView",
|
|
18
|
+
/** profile's avatar or banner */
|
|
19
|
+
ProfileMedia = "profileMedia",
|
|
20
|
+
/** profile in a list */
|
|
21
|
+
ProfileList = "profileList"
|
|
22
|
+
}
|
|
23
|
+
export declare const enum ModerationAction {
|
|
24
|
+
/** should cause blurring */
|
|
25
|
+
Blur = "blur",
|
|
26
|
+
/** should cause an alert */
|
|
27
|
+
Alert = "alert",
|
|
28
|
+
/** should cause a notice */
|
|
29
|
+
Inform = "inform"
|
|
30
|
+
}
|
|
31
|
+
export type BehaviorMapping = {
|
|
32
|
+
[C in DisplayContext]?: ModerationAction;
|
|
33
|
+
};
|
|
34
|
+
export type LabelBehaviorMatrix = {
|
|
35
|
+
[T in LabelTarget]: BehaviorMapping;
|
|
36
|
+
};
|
|
37
|
+
export declare const BLOCK_BEHAVIOR: BehaviorMapping;
|
|
38
|
+
export declare const MUTE_BEHAVIOR: BehaviorMapping;
|
|
39
|
+
export declare const KEYWORD_MUTE_BEHAVIOR: BehaviorMapping;
|
|
40
|
+
export declare const HIDE_BEHAVIOR: BehaviorMapping;
|
|
41
|
+
export declare const NOOP_BEHAVIOR: BehaviorMapping;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export var LabelTarget;
|
|
2
|
+
(function (LabelTarget) {
|
|
3
|
+
/** label is intended for account's content */
|
|
4
|
+
LabelTarget["Content"] = "content";
|
|
5
|
+
/** label is intended for account's profile */
|
|
6
|
+
LabelTarget["Profile"] = "profile";
|
|
7
|
+
/** label is intended for account's content and profile */
|
|
8
|
+
LabelTarget["Account"] = "account";
|
|
9
|
+
})(LabelTarget || (LabelTarget = {}));
|
|
10
|
+
export var DisplayContext;
|
|
11
|
+
(function (DisplayContext) {
|
|
12
|
+
/** content in expanded view */
|
|
13
|
+
DisplayContext["ContentView"] = "contentView";
|
|
14
|
+
/** images or video contained in content */
|
|
15
|
+
DisplayContext["ContentMedia"] = "contentMedia";
|
|
16
|
+
/** content in a list/feed */
|
|
17
|
+
DisplayContext["ContentList"] = "contentList";
|
|
18
|
+
/** profile in expanded view */
|
|
19
|
+
DisplayContext["ProfileView"] = "profileView";
|
|
20
|
+
/** profile's avatar or banner */
|
|
21
|
+
DisplayContext["ProfileMedia"] = "profileMedia";
|
|
22
|
+
/** profile in a list */
|
|
23
|
+
DisplayContext["ProfileList"] = "profileList";
|
|
24
|
+
})(DisplayContext || (DisplayContext = {}));
|
|
25
|
+
export var ModerationAction;
|
|
26
|
+
(function (ModerationAction) {
|
|
27
|
+
/** should cause blurring */
|
|
28
|
+
ModerationAction["Blur"] = "blur";
|
|
29
|
+
/** should cause an alert */
|
|
30
|
+
ModerationAction["Alert"] = "alert";
|
|
31
|
+
/** should cause a notice */
|
|
32
|
+
ModerationAction["Inform"] = "inform";
|
|
33
|
+
})(ModerationAction || (ModerationAction = {}));
|
|
34
|
+
export const BLOCK_BEHAVIOR = {
|
|
35
|
+
[DisplayContext.ProfileList]: ModerationAction.Blur,
|
|
36
|
+
[DisplayContext.ProfileView]: ModerationAction.Alert,
|
|
37
|
+
[DisplayContext.ProfileMedia]: ModerationAction.Blur,
|
|
38
|
+
[DisplayContext.ContentList]: ModerationAction.Blur,
|
|
39
|
+
[DisplayContext.ContentView]: ModerationAction.Blur,
|
|
40
|
+
};
|
|
41
|
+
export const MUTE_BEHAVIOR = {
|
|
42
|
+
[DisplayContext.ProfileList]: ModerationAction.Inform,
|
|
43
|
+
[DisplayContext.ProfileView]: ModerationAction.Alert,
|
|
44
|
+
[DisplayContext.ContentList]: ModerationAction.Blur,
|
|
45
|
+
[DisplayContext.ContentView]: ModerationAction.Inform,
|
|
46
|
+
};
|
|
47
|
+
export const KEYWORD_MUTE_BEHAVIOR = {
|
|
48
|
+
[DisplayContext.ContentList]: ModerationAction.Blur,
|
|
49
|
+
[DisplayContext.ContentView]: ModerationAction.Blur,
|
|
50
|
+
};
|
|
51
|
+
export const HIDE_BEHAVIOR = {
|
|
52
|
+
[DisplayContext.ContentList]: ModerationAction.Blur,
|
|
53
|
+
[DisplayContext.ContentView]: ModerationAction.Blur,
|
|
54
|
+
};
|
|
55
|
+
export const NOOP_BEHAVIOR = {};
|
|
56
|
+
//# sourceMappingURL=behaviors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviors.js","sourceRoot":"","sources":["../lib/behaviors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAkB,WAOjB;AAPD,WAAkB,WAAW;IAC5B,8CAA8C;IAC9C,kCAAmB,CAAA;IACnB,8CAA8C;IAC9C,kCAAmB,CAAA;IACnB,0DAA0D;IAC1D,kCAAmB,CAAA;AACpB,CAAC,EAPiB,WAAW,KAAX,WAAW,QAO5B;AAED,MAAM,CAAN,IAAkB,cAcjB;AAdD,WAAkB,cAAc;IAC/B,+BAA+B;IAC/B,6CAA2B,CAAA;IAC3B,2CAA2C;IAC3C,+CAA6B,CAAA;IAC7B,6BAA6B;IAC7B,6CAA2B,CAAA;IAE3B,+BAA+B;IAC/B,6CAA2B,CAAA;IAC3B,iCAAiC;IACjC,+CAA6B,CAAA;IAC7B,wBAAwB;IACxB,6CAA2B,CAAA;AAC5B,CAAC,EAdiB,cAAc,KAAd,cAAc,QAc/B;AAED,MAAM,CAAN,IAAkB,gBAOjB;AAPD,WAAkB,gBAAgB;IACjC,4BAA4B;IAC5B,iCAAa,CAAA;IACb,4BAA4B;IAC5B,mCAAe,CAAA;IACf,4BAA4B;IAC5B,qCAAiB,CAAA;AAClB,CAAC,EAPiB,gBAAgB,KAAhB,gBAAgB,QAOjC;AAKD,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC9C,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;IACnD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,KAAK;IACpD,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC,IAAI;IAEpD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;IACnD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;CACnD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAoB;IAC7C,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,MAAM;IACrD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,KAAK;IAEpD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;IACnD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,MAAM;CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAoB;IACrD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;IACnD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;CACnD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAoB;IAC7C,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;IACnD,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,IAAI;CACnD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AppBskyGraphDefs, At } from '@atcute/client/lexicons';
|
|
2
|
+
import { type BehaviorMapping, type LabelTarget } from './behaviors.js';
|
|
3
|
+
import type { Label, ModerationOptions } from './types.js';
|
|
4
|
+
import type { KeywordFilter } from './keyword-filter.js';
|
|
5
|
+
import { LabelPreference, type InterpretedLabelDefinition } from './label.js';
|
|
6
|
+
export declare const enum ModerationCauseType {
|
|
7
|
+
/** caused by a label */
|
|
8
|
+
Label = 1,
|
|
9
|
+
/** caused by viewer blocking the subject */
|
|
10
|
+
Blocking = 2,
|
|
11
|
+
/** caused by subject blocking the viewer */
|
|
12
|
+
BlockedBy = 3,
|
|
13
|
+
/** caused by viewer having a (permanent) mute on subject */
|
|
14
|
+
MutedPermanent = 4,
|
|
15
|
+
/** caused by a temporary mute */
|
|
16
|
+
MutedTemporary = 5,
|
|
17
|
+
/** caused by a keyword mute */
|
|
18
|
+
MutedKeyword = 6,
|
|
19
|
+
/** caused by a hidden post */
|
|
20
|
+
Hidden = 7
|
|
21
|
+
}
|
|
22
|
+
export interface BlockingModerationCause {
|
|
23
|
+
type: ModerationCauseType.Blocking;
|
|
24
|
+
priority: 3;
|
|
25
|
+
source: AppBskyGraphDefs.ListViewBasic | null;
|
|
26
|
+
downgraded: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface BlockedByModerationCause {
|
|
29
|
+
type: ModerationCauseType.BlockedBy;
|
|
30
|
+
priority: 4;
|
|
31
|
+
downgraded: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface HiddenModerationCause {
|
|
34
|
+
type: ModerationCauseType.Hidden;
|
|
35
|
+
priority: 6;
|
|
36
|
+
downgraded: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface LabelModerationCause {
|
|
39
|
+
type: ModerationCauseType.Label;
|
|
40
|
+
priority: 1 | 2 | 5 | 7 | 8;
|
|
41
|
+
source: At.Did | null;
|
|
42
|
+
label: Label;
|
|
43
|
+
labelDef: InterpretedLabelDefinition;
|
|
44
|
+
target: LabelTarget;
|
|
45
|
+
pref: LabelPreference;
|
|
46
|
+
behavior: BehaviorMapping;
|
|
47
|
+
noOverride: boolean;
|
|
48
|
+
downgraded: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface MutedPermanentModerationCause {
|
|
51
|
+
type: ModerationCauseType.MutedPermanent;
|
|
52
|
+
priority: 6;
|
|
53
|
+
source: AppBskyGraphDefs.ListViewBasic | null;
|
|
54
|
+
downgraded: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface MutedTemporaryModerationCause {
|
|
57
|
+
type: ModerationCauseType.MutedTemporary;
|
|
58
|
+
priority: 6;
|
|
59
|
+
downgraded: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface MutedKeywordModerationCause {
|
|
62
|
+
type: ModerationCauseType.MutedKeyword;
|
|
63
|
+
priority: 6;
|
|
64
|
+
source: KeywordFilter;
|
|
65
|
+
downgraded: boolean;
|
|
66
|
+
}
|
|
67
|
+
export type ModerationCause = BlockedByModerationCause | BlockingModerationCause | HiddenModerationCause | LabelModerationCause | MutedKeywordModerationCause | MutedPermanentModerationCause | MutedTemporaryModerationCause;
|
|
68
|
+
export interface ModerationDecision {
|
|
69
|
+
authorDid: At.Did;
|
|
70
|
+
isMe: boolean;
|
|
71
|
+
causes: ModerationCause[];
|
|
72
|
+
}
|
|
73
|
+
export declare const createModerationDecision: (authorDid: At.Did, { viewerDid }: ModerationOptions) => ModerationDecision;
|
|
74
|
+
type FalsyValue = 0 | '' | false | null | undefined;
|
|
75
|
+
export declare const mergeModerationDecisions: (sources_0: ModerationDecision, sources_1: ModerationDecision | FalsyValue, ...sources: (ModerationDecision | FalsyValue)[]) => ModerationDecision;
|
|
76
|
+
export declare const considerHidden: (decision: ModerationDecision) => void;
|
|
77
|
+
export declare const considerBlocking: (decision: ModerationDecision, source: AppBskyGraphDefs.ListViewBasic | null) => void;
|
|
78
|
+
export declare const considerBlockedBy: (decision: ModerationDecision) => void;
|
|
79
|
+
export declare const considerPermanentMute: (decision: ModerationDecision, source: AppBskyGraphDefs.ListViewBasic | null) => void;
|
|
80
|
+
export declare const considerTemporaryMute: (decision: ModerationDecision, { prefs }: ModerationOptions) => void;
|
|
81
|
+
export declare const considerKeywordMute: (decision: ModerationDecision, source: KeywordFilter) => void;
|
|
82
|
+
export declare const considerLabels: (decision: ModerationDecision, target: LabelTarget, labels: Label[] | undefined, opts: ModerationOptions) => void;
|
|
83
|
+
export declare const considerLabel: (decision: ModerationDecision, target: LabelTarget, label: Label, { viewerDid, prefs, labelDefs }: ModerationOptions) => void;
|
|
84
|
+
export declare const downgradeDecision: <T extends ModerationDecision | undefined>(decision: T) => T;
|
|
85
|
+
export {};
|
package/dist/decision.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { DisplayContext, ModerationAction } from './behaviors.js';
|
|
2
|
+
import { BUILTIN_LABELS, isCustomLabelValue, LabelFlags, LabelPreference, } from './label.js';
|
|
3
|
+
var ModerationSeverity;
|
|
4
|
+
(function (ModerationSeverity) {
|
|
5
|
+
ModerationSeverity[ModerationSeverity["High"] = 1] = "High";
|
|
6
|
+
ModerationSeverity[ModerationSeverity["Medium"] = 2] = "Medium";
|
|
7
|
+
ModerationSeverity[ModerationSeverity["Low"] = 3] = "Low";
|
|
8
|
+
})(ModerationSeverity || (ModerationSeverity = {}));
|
|
9
|
+
export var ModerationCauseType;
|
|
10
|
+
(function (ModerationCauseType) {
|
|
11
|
+
/** caused by a label */
|
|
12
|
+
ModerationCauseType[ModerationCauseType["Label"] = 1] = "Label";
|
|
13
|
+
/** caused by viewer blocking the subject */
|
|
14
|
+
ModerationCauseType[ModerationCauseType["Blocking"] = 2] = "Blocking";
|
|
15
|
+
/** caused by subject blocking the viewer */
|
|
16
|
+
ModerationCauseType[ModerationCauseType["BlockedBy"] = 3] = "BlockedBy";
|
|
17
|
+
/** caused by viewer having a (permanent) mute on subject */
|
|
18
|
+
ModerationCauseType[ModerationCauseType["MutedPermanent"] = 4] = "MutedPermanent";
|
|
19
|
+
/** caused by a temporary mute */
|
|
20
|
+
ModerationCauseType[ModerationCauseType["MutedTemporary"] = 5] = "MutedTemporary";
|
|
21
|
+
/** caused by a keyword mute */
|
|
22
|
+
ModerationCauseType[ModerationCauseType["MutedKeyword"] = 6] = "MutedKeyword";
|
|
23
|
+
/** caused by a hidden post */
|
|
24
|
+
ModerationCauseType[ModerationCauseType["Hidden"] = 7] = "Hidden";
|
|
25
|
+
})(ModerationCauseType || (ModerationCauseType = {}));
|
|
26
|
+
export const createModerationDecision = (authorDid, { viewerDid }) => {
|
|
27
|
+
return {
|
|
28
|
+
authorDid: authorDid,
|
|
29
|
+
isMe: authorDid === viewerDid,
|
|
30
|
+
causes: [],
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export const mergeModerationDecisions = (...sources) => {
|
|
34
|
+
return {
|
|
35
|
+
authorDid: sources[0].authorDid,
|
|
36
|
+
isMe: sources[0].isMe,
|
|
37
|
+
causes: sources.filter((source) => !!source).flatMap((source) => source.causes),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export const considerHidden = (decision) => {
|
|
41
|
+
decision.causes.push({
|
|
42
|
+
type: ModerationCauseType.Hidden,
|
|
43
|
+
priority: 6,
|
|
44
|
+
downgraded: false,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export const considerBlocking = (decision, source) => {
|
|
48
|
+
if (decision.isMe) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
decision.causes.push({
|
|
52
|
+
type: ModerationCauseType.Blocking,
|
|
53
|
+
priority: 3,
|
|
54
|
+
source: source,
|
|
55
|
+
downgraded: false,
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
export const considerBlockedBy = (decision) => {
|
|
59
|
+
if (decision.isMe) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
decision.causes.push({
|
|
63
|
+
type: ModerationCauseType.BlockedBy,
|
|
64
|
+
priority: 4,
|
|
65
|
+
downgraded: false,
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
export const considerPermanentMute = (decision, source) => {
|
|
69
|
+
if (decision.isMe) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
decision.causes.push({
|
|
73
|
+
type: ModerationCauseType.MutedPermanent,
|
|
74
|
+
priority: 6,
|
|
75
|
+
source: source,
|
|
76
|
+
downgraded: false,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
export const considerTemporaryMute = (decision, { prefs }) => {
|
|
80
|
+
if (decision.isMe) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (prefs.temporaryMutes?.includes(decision.authorDid)) {
|
|
84
|
+
decision.causes.push({
|
|
85
|
+
type: ModerationCauseType.MutedTemporary,
|
|
86
|
+
priority: 6,
|
|
87
|
+
downgraded: false,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
export const considerKeywordMute = (decision, source) => {
|
|
92
|
+
decision.causes.push({
|
|
93
|
+
type: ModerationCauseType.MutedKeyword,
|
|
94
|
+
priority: 6,
|
|
95
|
+
source: source,
|
|
96
|
+
downgraded: false,
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
export const considerLabels = (decision, target, labels, opts) => {
|
|
100
|
+
if (labels?.length) {
|
|
101
|
+
for (let idx = 0, len = labels.length; idx < len; idx++) {
|
|
102
|
+
considerLabel(decision, target, labels[idx], opts);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
export const considerLabel = (decision, target, label, { viewerDid, prefs, labelDefs }) => {
|
|
107
|
+
const { src, val } = label;
|
|
108
|
+
/// 1. grab the label definition
|
|
109
|
+
let labelDef;
|
|
110
|
+
if (isCustomLabelValue(val)) {
|
|
111
|
+
labelDef = labelDefs?.[src]?.[val];
|
|
112
|
+
}
|
|
113
|
+
if (labelDef === undefined) {
|
|
114
|
+
labelDef = BUILTIN_LABELS[val];
|
|
115
|
+
}
|
|
116
|
+
if (labelDef === undefined) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
/// 2. check applicability
|
|
120
|
+
if (labelDef.flags & LabelFlags.UnauthenticatedOnly && viewerDid !== undefined) {
|
|
121
|
+
// skip if label is only for signed-out users
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const isConfigurable = !(labelDef.flags & LabelFlags.NoConfigurable);
|
|
125
|
+
const isAdultOnly = !!(labelDef.flags & LabelFlags.AdultOnly);
|
|
126
|
+
const isSelfApplied = src === decision.authorDid;
|
|
127
|
+
let labelerPref;
|
|
128
|
+
if (!isSelfApplied) {
|
|
129
|
+
labelerPref = prefs.prefsByLabelers?.[src];
|
|
130
|
+
if (labelerPref === undefined) {
|
|
131
|
+
// skip if we're looking at an unconfigured labeler
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
if (labelDef.flags & LabelFlags.NoSelf) {
|
|
137
|
+
// skip if label is not allowed to be self-applied
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
let pref;
|
|
142
|
+
if (isConfigurable) {
|
|
143
|
+
if (isAdultOnly && !prefs.adultContentEnabled) {
|
|
144
|
+
pref = LabelPreference.Hide;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
pref = labelerPref?.labelPrefs[val] ?? prefs.globalLabelPrefs?.[val] ?? labelDef.defaultPref;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
pref = labelDef.defaultPref;
|
|
152
|
+
}
|
|
153
|
+
// skip if label is configured to ignore
|
|
154
|
+
if (pref === LabelPreference.Ignore) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const behavior = labelDef.behavior[target];
|
|
158
|
+
const severity = getModerationSeverity(behavior);
|
|
159
|
+
let priority;
|
|
160
|
+
if (labelDef.flags & LabelFlags.NoOverride || (isAdultOnly && !prefs.adultContentEnabled)) {
|
|
161
|
+
priority = 1;
|
|
162
|
+
}
|
|
163
|
+
else if (pref === LabelPreference.Hide) {
|
|
164
|
+
priority = 2;
|
|
165
|
+
}
|
|
166
|
+
else if (severity === ModerationSeverity.High) {
|
|
167
|
+
priority = 5;
|
|
168
|
+
}
|
|
169
|
+
else if (severity === ModerationSeverity.Medium) {
|
|
170
|
+
priority = 7;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
priority = 8;
|
|
174
|
+
}
|
|
175
|
+
let noOverride = false;
|
|
176
|
+
if (labelDef.flags & LabelFlags.NoOverride || (isAdultOnly && !prefs.adultContentEnabled)) {
|
|
177
|
+
noOverride = true;
|
|
178
|
+
}
|
|
179
|
+
decision.causes.push({
|
|
180
|
+
type: ModerationCauseType.Label,
|
|
181
|
+
priority,
|
|
182
|
+
source: isSelfApplied ? label.src : null,
|
|
183
|
+
label: label,
|
|
184
|
+
labelDef: labelDef,
|
|
185
|
+
target: target,
|
|
186
|
+
pref: pref,
|
|
187
|
+
behavior: behavior,
|
|
188
|
+
noOverride: noOverride,
|
|
189
|
+
downgraded: false,
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
const getModerationSeverity = (behavior) => {
|
|
193
|
+
if (behavior[DisplayContext.ProfileView] === ModerationAction.Blur ||
|
|
194
|
+
behavior[DisplayContext.ContentView] === ModerationAction.Blur) {
|
|
195
|
+
return ModerationSeverity.High;
|
|
196
|
+
}
|
|
197
|
+
if (behavior[DisplayContext.ContentList] === ModerationAction.Blur ||
|
|
198
|
+
behavior[DisplayContext.ContentMedia] === ModerationAction.Blur) {
|
|
199
|
+
return ModerationSeverity.Medium;
|
|
200
|
+
}
|
|
201
|
+
return ModerationSeverity.Low;
|
|
202
|
+
};
|
|
203
|
+
export const downgradeDecision = (decision) => {
|
|
204
|
+
if (decision === undefined) {
|
|
205
|
+
return decision;
|
|
206
|
+
}
|
|
207
|
+
const causes = decision.causes;
|
|
208
|
+
for (let idx = 0, len = causes.length; idx < len; idx++) {
|
|
209
|
+
const cause = causes[idx];
|
|
210
|
+
cause.downgraded = true;
|
|
211
|
+
}
|
|
212
|
+
return decision;
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../lib/decision.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@atcute/bluesky/lexicons';
|
|
2
|
+
export { DisplayContext, LabelTarget, ModerationAction, type BehaviorMapping, type LabelBehaviorMatrix, } from './behaviors.js';
|
|
3
|
+
export { ModerationCauseType, type BlockedByModerationCause, type BlockingModerationCause, type HiddenModerationCause, type LabelModerationCause, type ModerationCause, type ModerationDecision, type MutedKeywordModerationCause, type MutedPermanentModerationCause, type MutedTemporaryModerationCause, } from './decision.js';
|
|
4
|
+
export { createKeywordPattern, interpretMutedWordPreference, interpretMutedWordPreferences, KeywordFilterFlags, type KeywordFilter, type KeywordMatch, } from './keyword-filter.js';
|
|
5
|
+
export { BlurLevel, interpretLabelerDefinition, interpretLabelerDefinitions, interpretLabelValueDefinition, isCustomLabelValue, LabelFlags, LabelPreference, SeverityLevel, type InterpretedLabelDefinition, type InterpretedLabelMapping, type LabelLocale, } from './label.js';
|
|
6
|
+
export { type FeedGeneratorSubject, type Label, type LabelerPreference, type ListSubject, type ModerationOptions, type ModerationPreferences, type NotificationSubject, type PostSubject, type ProfileSubject, } from './types.js';
|
|
7
|
+
export { getDisplayRestrictions, type DisplayRestrictions } from './ui.js';
|
|
8
|
+
export { moderateFeedGenerator } from './subjects/feed-generator.js';
|
|
9
|
+
export { moderateList } from './subjects/list.js';
|
|
10
|
+
export { moderateNotification } from './subjects/notification.js';
|
|
11
|
+
export { moderatePost } from './subjects/post.js';
|
|
12
|
+
export { moderateProfile } from './subjects/profile.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import '@atcute/bluesky/lexicons';
|
|
2
|
+
export { DisplayContext, LabelTarget, ModerationAction, } from './behaviors.js';
|
|
3
|
+
export { ModerationCauseType, } from './decision.js';
|
|
4
|
+
export { createKeywordPattern, interpretMutedWordPreference, interpretMutedWordPreferences, KeywordFilterFlags, } from './keyword-filter.js';
|
|
5
|
+
export { BlurLevel, interpretLabelerDefinition, interpretLabelerDefinitions, interpretLabelValueDefinition, isCustomLabelValue, LabelFlags, LabelPreference, SeverityLevel, } from './label.js';
|
|
6
|
+
export {} from './types.js';
|
|
7
|
+
export { getDisplayRestrictions } from './ui.js';
|
|
8
|
+
export { moderateFeedGenerator } from './subjects/feed-generator.js';
|
|
9
|
+
export { moderateList } from './subjects/list.js';
|
|
10
|
+
export { moderateNotification } from './subjects/notification.js';
|
|
11
|
+
export { moderatePost } from './subjects/post.js';
|
|
12
|
+
export { moderateProfile } from './subjects/profile.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,0BAA0B,CAAC;AAElC,OAAO,EACN,cAAc,EACd,WAAW,EACX,gBAAgB,GAGhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,mBAAmB,GAUnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,oBAAoB,EACpB,4BAA4B,EAC5B,6BAA6B,EAC7B,kBAAkB,GAGlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACN,SAAS,EACT,0BAA0B,EAC1B,2BAA2B,EAC3B,6BAA6B,EAC7B,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,aAAa,GAIb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAUN,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAA4B,MAAM,SAAS,CAAC;AAE3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AppBskyActorDefs } from '@atcute/client/lexicons';
|
|
2
|
+
import { type KeywordFilter } from '../keyword-filter.js';
|
|
3
|
+
export declare const matchesKeywordFilters: ({ filters, text, tags, actor, }: {
|
|
4
|
+
filters: KeywordFilter[];
|
|
5
|
+
text: string;
|
|
6
|
+
tags?: string[];
|
|
7
|
+
actor?: AppBskyActorDefs.ProfileView | AppBskyActorDefs.ProfileViewBasic;
|
|
8
|
+
}) => KeywordFilter | null;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { KeywordFilterFlags } from '../keyword-filter.js';
|
|
2
|
+
const EMPTY_ARRAY = [];
|
|
3
|
+
export const matchesKeywordFilters = ({ filters, text, tags = EMPTY_ARRAY, actor, }) => {
|
|
4
|
+
for (let i = 0, il = filters.length; i < il; i++) {
|
|
5
|
+
const filter = filters[i];
|
|
6
|
+
if (actor && filter.flags & KeywordFilterFlags.NoFollowing) {
|
|
7
|
+
if (actor.viewer?.following) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
if (filter.flags & KeywordFilterFlags.ApplyTopic) {
|
|
12
|
+
for (let j = 0, jl = tags.length; j < jl; j++) {
|
|
13
|
+
const tag = tags[j];
|
|
14
|
+
if (filter.pattern.test(tag)) {
|
|
15
|
+
return filter;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (filter.flags & KeywordFilterFlags.ApplyContent) {
|
|
20
|
+
if (filter.pattern.test(text)) {
|
|
21
|
+
return filter;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=keyword-filter.js.map
|