emusks 2.3.4 → 2.3.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emusks",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
4
4
  "description": "Reverse-engineered Twitter API client. Log in and interact with the unofficial X API using any client identity - web, Android, iOS, or TweetDeck",
5
5
  "keywords": [
6
6
  "client",
@@ -12,6 +12,7 @@ import * as lists from "./lists.js";
12
12
  import * as media from "./media.js";
13
13
  import * as notes from "./notes.js";
14
14
  import * as notifications from "./notifications.js";
15
+ import * as report from "./report.js";
15
16
  import * as search from "./search.js";
16
17
  import * as spaces from "./spaces.js";
17
18
  import * as syndication from "./syndication.js";
@@ -52,6 +53,7 @@ export default function initHelpers(proto) {
52
53
  namespace(proto, "spaces", spaces);
53
54
  namespace(proto, "account", account);
54
55
  namespace(proto, "notifications", notifications);
56
+ namespace(proto, "report", report);
55
57
  namespace(proto, "trends", trends);
56
58
  namespace(proto, "topics", topics);
57
59
  namespace(proto, "media", media);
@@ -0,0 +1,100 @@
1
+ export const REPORT_REASONS = {
2
+ hate: "HateOrAbuseSimpleOption",
3
+ abuse: "HateOrAbuseSimpleOption",
4
+ harassment: "HateOrAbuseSimpleOption",
5
+ violent_speech: "ViolentSpeechSimpleOption",
6
+ child_safety: "ChildSafetySimpleOption",
7
+ private: "PrivateContentSimpleOption",
8
+ nonconsensual: "PrivateContentSimpleOption",
9
+ illegal: "IRBSimpleOption",
10
+ regulated: "IRBSimpleOption",
11
+ spam: "SpamSimpleOption",
12
+ self_harm: "SuicideSelfHarmSimpleOption",
13
+ suicide: "SuicideSelfHarmSimpleOption",
14
+ adult: "AdultContentSimpleOption",
15
+ nsfw: "AdultContentSimpleOption",
16
+ violent_media: "ViolentMediaSimpleOption",
17
+ graphic: "ViolentMediaSimpleOption",
18
+ impersonation: "ImpersonationSimpleOption",
19
+ terrorism: "TerrorismSimpleOption",
20
+ extremism: "TerrorismSimpleOption",
21
+ };
22
+
23
+ function resolveReason(reason) {
24
+ if (typeof reason !== "string" || !reason) throw new Error("a report reason is required");
25
+ if (reason.endsWith("SimpleOption")) return reason;
26
+ const mapped = REPORT_REASONS[reason.toLowerCase().replace(/[\s-]+/g, "_")];
27
+ if (!mapped) {
28
+ throw new Error(
29
+ `unknown report reason "${reason}". use a raw *SimpleOption id or one of: ${Object.keys(REPORT_REASONS).join(", ")}`,
30
+ );
31
+ }
32
+ return mapped;
33
+ }
34
+
35
+ async function submitReport(instance, { variant, startLocation, reason }) {
36
+ const init = await instance.v1_1("report/flow", {
37
+ params: { flow_name: "report-flow" },
38
+ headers: { "content-type": "application/json" },
39
+ body: JSON.stringify({
40
+ input_flow_data: {
41
+ requested_variant: JSON.stringify(variant),
42
+ flow_context: { start_location: { location: startLocation } },
43
+ },
44
+ }),
45
+ });
46
+
47
+ const { flow_token } = await init.json();
48
+ if (!flow_token) throw new Error("failed to start report flow");
49
+
50
+ const res = await instance.v1_1("report/flow", {
51
+ headers: { "content-type": "application/json" },
52
+ body: JSON.stringify({
53
+ flow_token,
54
+ subtask_inputs: [
55
+ {
56
+ subtask_id: "single-selection",
57
+ choice_selection: { link: "next_link", selected_choices: [reason] },
58
+ },
59
+ ],
60
+ }),
61
+ });
62
+
63
+ return await res.json();
64
+ }
65
+
66
+ export async function tweet(tweetId, reason, opts = {}) {
67
+ if (!tweetId) throw new Error("tweetId is required");
68
+ return await submitReport(this, {
69
+ startLocation: opts.startLocation || "home",
70
+ reason: resolveReason(reason),
71
+ variant: {
72
+ client_app_id: "3033300",
73
+ client_location: "home:home:",
74
+ client_referer: "/home",
75
+ is_media: false,
76
+ is_promoted: false,
77
+ reported_tweet_id: tweetId,
78
+ source: "reporttweet",
79
+ ...opts.variant,
80
+ },
81
+ });
82
+ }
83
+
84
+ export async function user(userId, reason, opts = {}) {
85
+ if (!userId) throw new Error("userId is required");
86
+ return await submitReport(this, {
87
+ startLocation: opts.startLocation || "profile",
88
+ reason: resolveReason(reason),
89
+ variant: {
90
+ client_app_id: "3033300",
91
+ client_location: "profile:header:",
92
+ client_referer: opts.username ? `/${opts.username}` : "/",
93
+ is_media: false,
94
+ is_promoted: false,
95
+ reported_user_id: userId,
96
+ source: "reportprofile",
97
+ ...opts.variant,
98
+ },
99
+ });
100
+ }
@@ -353,6 +353,10 @@ export async function unmoderate(tweetId) {
353
353
  });
354
354
  }
355
355
 
356
+ export async function report(tweetId, reason, opts = {}) {
357
+ return await this.report.tweet(tweetId, reason, opts);
358
+ }
359
+
356
360
  export async function pinReply(tweetId) {
357
361
  return await this.graphql("PinReply", {
358
362
  body: { variables: { tweet_id: tweetId } },
@@ -220,6 +220,10 @@ export async function unmute(userId) {
220
220
  return json ? parseUser(json) : res;
221
221
  }
222
222
 
223
+ export async function report(userId, reason, opts = {}) {
224
+ return await this.report.user(userId, reason, opts);
225
+ }
226
+
223
227
  export async function removeFollower(userId) {
224
228
  return await this.graphql("RemoveFollower", {
225
229
  body: { variables: { target_user_id: userId } },
package/src/index.js CHANGED
@@ -204,3 +204,5 @@ Emusks.prototype.v2 = v2;
204
204
  Emusks.prototype.jf = jetfuel;
205
205
  Emusks.prototype.grokApi = grokApi;
206
206
  initHelpers(Emusks.prototype);
207
+
208
+ export { REPORT_REASONS } from "./helpers/report.js";