emusks 2.0.4 → 2.0.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/build/graphql.js CHANGED
@@ -3,21 +3,13 @@ const URL = `https://raw.githubusercontent.com/fa0311/TwitterInternalAPIDocument
3
3
  const json = await fetch(URL).then((r) => r.json());
4
4
  const graphql = json.graphql;
5
5
 
6
- const buildUrl = (base, features) => {
7
- const params = new URLSearchParams();
8
-
9
- if (features && Object.keys(features).length) {
10
- params.set(`features`, JSON.stringify(features));
11
- }
12
-
13
- const query = params.toString();
14
- return query ? `${base}?${query}` : base;
15
- };
16
-
17
6
  const transformed = Object.fromEntries(
18
7
  Object.entries(graphql).map(([name, data]) => {
19
- const constructedUrl = buildUrl(data.url, data.features);
20
- return [name, [data.method, constructedUrl]];
8
+ const features = data.features
9
+ ? Object.fromEntries(Object.keys(data.features).map((k) => [k, true]))
10
+ : undefined;
11
+ const queryId = data.url.match(/\/graphql\/([^\/]+)\//)?.[1];
12
+ return [name, [data.method, data.url, features, queryId]];
21
13
  }),
22
14
  );
23
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emusks",
3
- "version": "2.0.4",
3
+ "version": "2.0.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",
package/src/graphql.js CHANGED
@@ -7,18 +7,35 @@ export default async function graphql(queryName, { variables, fieldToggles, body
7
7
  throw new Error(`graphql query ${queryName} not found`);
8
8
  }
9
9
 
10
- const [method, baseUrl] = entry;
10
+ const [method, baseUrl, features, queryId] = entry;
11
+ const isPost = method.toLowerCase() === "post";
11
12
 
12
13
  let finalUrl = baseUrl;
14
+ let requestBody;
13
15
 
14
- if (variables && Object.keys(variables).length) {
15
- const separator = baseUrl.includes("?") ? "&" : "?";
16
- finalUrl = `${baseUrl}${separator}variables=${encodeURIComponent(JSON.stringify(variables))}`;
17
- }
18
-
19
- if (fieldToggles && Object.keys(fieldToggles).length) {
20
- const separator = finalUrl.includes("?") ? "&" : "?";
21
- finalUrl = `${finalUrl}${separator}fieldToggles=${encodeURIComponent(JSON.stringify(fieldToggles))}`;
16
+ if (isPost) {
17
+ requestBody = {
18
+ ...body,
19
+ variables: { ...variables, ...body?.variables },
20
+ queryId,
21
+ };
22
+ if (features) requestBody.features = features;
23
+ if (fieldToggles && Object.keys(fieldToggles).length) {
24
+ requestBody.fieldToggles = fieldToggles;
25
+ }
26
+ } else {
27
+ if (variables && Object.keys(variables).length) {
28
+ const separator = finalUrl.includes("?") ? "&" : "?";
29
+ finalUrl = `${finalUrl}${separator}variables=${encodeURIComponent(JSON.stringify(variables))}`;
30
+ }
31
+ if (features) {
32
+ const separator = finalUrl.includes("?") ? "&" : "?";
33
+ finalUrl = `${finalUrl}${separator}features=${encodeURIComponent(JSON.stringify(features))}`;
34
+ }
35
+ if (fieldToggles && Object.keys(fieldToggles).length) {
36
+ const separator = finalUrl.includes("?") ? "&" : "?";
37
+ finalUrl = `${finalUrl}${separator}fieldToggles=${encodeURIComponent(JSON.stringify(fieldToggles))}`;
38
+ }
22
39
  }
23
40
 
24
41
  const url = new URL(finalUrl);
@@ -51,8 +68,7 @@ export default async function graphql(queryName, { variables, fieldToggles, body
51
68
  };
52
69
 
53
70
  const cycleTLS = await getCycleTLS();
54
-
55
- return await (
71
+ const res = await (
56
72
  await cycleTLS(
57
73
  finalUrl,
58
74
  {
@@ -60,11 +76,17 @@ export default async function graphql(queryName, { variables, fieldToggles, body
60
76
  userAgent: this.auth.client.fingerprints.userAgent,
61
77
  ja3: this.auth.client.fingerprints.ja3,
62
78
  ja4r: this.auth.client.fingerprints.ja4r,
63
- body: typeof body === "object" ? JSON.stringify(body) : undefined,
79
+ body: isPost ? JSON.stringify(requestBody) : undefined,
64
80
  proxy: this.proxy || undefined,
65
81
  referrer: "https://x.com/",
66
82
  },
67
83
  method,
68
84
  )
69
85
  ).json();
86
+
87
+ if (res?.errors?.[0]) {
88
+ throw new Error(res.errors.map((err) => err.message).join(", "));
89
+ }
90
+
91
+ return res;
70
92
  }
@@ -1,271 +1,269 @@
1
1
  import parseUser from "../parsers/user.js";
2
2
 
3
- export default (client) => ({
4
- async settings() {
5
- const res = await client.v1_1("get:account/settings", {});
6
- return await res.json();
7
- },
8
-
9
- async updateSettings(params = {}) {
10
- const res = await client.v1_1("post:account/settings", {
11
- body: JSON.stringify(params),
12
- });
13
- return await res.json();
14
- },
15
-
16
- async verifyPassword(password) {
17
- const res = await client.v1_1("account/verify_password", {
18
- body: `password=${encodeURIComponent(password)}`,
19
- headers: { "content-type": "application/x-www-form-urlencoded" },
20
- });
21
- return await res.json();
22
- },
23
-
24
- async changePassword(currentPassword, newPassword) {
25
- const res = await client.v1_1("account/change_password", {
26
- body: JSON.stringify({
27
- current_password: currentPassword,
28
- password: newPassword,
29
- password_confirmation: newPassword,
30
- }),
31
- });
32
- return await res.json();
33
- },
34
-
35
- async deactivate() {
36
- const res = await client.v1_1("account/deactivate", {});
37
- return await res.json();
38
- },
39
-
40
- async logout() {
41
- const res = await client.v1_1("account/logout", {});
42
- return await res.json();
43
- },
44
-
45
- async rateLimitStatus(params = {}) {
46
- const res = await client.v1_1("application/rate_limit_status", { params });
47
- return await res.json();
48
- },
49
-
50
- async viewer() {
51
- const res = await client.graphql("Viewer", {
52
- variables: { withCommunitiesMemberships: true },
53
- fieldToggles: { withAuxiliaryUserLabels: false },
54
- });
55
- const user = res?.data?.viewer?.user_results?.result;
56
- return user ? parseUser(user) : res;
57
- },
58
-
59
- async sessions() {
60
- return await client.graphql("UserSessionsList", {
61
- variables: {},
62
- });
63
- },
64
-
65
- async preferences() {
66
- return await client.graphql("UserPreferences", {
67
- variables: {},
68
- });
69
- },
70
-
71
- async claims() {
72
- return await client.graphql("GetUserClaims", {
73
- variables: {},
74
- });
75
- },
76
-
77
- async phoneState() {
78
- return await client.graphql("ProfileUserPhoneState", {
79
- variables: {},
80
- });
81
- },
82
-
83
- async passwordStrength(password) {
84
- const res = await client.v1_1("account/password_strength", {
85
- body: JSON.stringify({ password }),
86
- });
87
- return await res.json();
88
- },
89
-
90
- async resendConfirmationEmail() {
91
- const res = await client.v1_1("account/resend_confirmation_email", {});
92
- return await res.json();
93
- },
94
-
95
- async emailPhoneInfo(params = {}) {
96
- const res = await client.v1_1("users/email_phone_info", { params });
97
- return await res.json();
98
- },
99
-
100
- async emailAvailable(email) {
101
- const res = await client.v1_1("users/email_available", {
102
- params: { email },
103
- });
104
- return await res.json();
105
- },
106
-
107
- async phoneAvailable(phone) {
108
- const res = await client.v1_1("users/phone_number_available", {
109
- params: { phone_number: phone },
110
- });
111
- return await res.json();
112
- },
113
-
114
- async usernameAvailable(username) {
115
- return await client.graphql("GetUsernameAvailabilityAndSuggestions", {
116
- body: { variables: { username } },
117
- });
118
- },
119
-
120
- async backupCode() {
121
- const res = await client.v1_1("get:account/backup_code", {});
122
- return await res.json();
123
- },
124
-
125
- async generateBackupCode() {
126
- const res = await client.v1_1("post:account/backup_code", {});
127
- return await res.json();
128
- },
129
-
130
- async disable2FA() {
131
- const res = await client.v1_1("account/login_verification_enrollment", {});
132
- return await res.json();
133
- },
134
-
135
- async remove2FAMethod(methodId) {
136
- const res = await client.v1_1("account/login_verification/remove_method", {
137
- body: JSON.stringify({ method_id: methodId }),
138
- });
139
- return await res.json();
140
- },
141
-
142
- async tempPassword() {
143
- const res = await client.v1_1("account/login_verification/temporary_password", {});
144
- return await res.json();
145
- },
146
-
147
- async renameSecurityKey(methodId, name) {
148
- const res = await client.v1_1("account/login_verification/rename_security_key_method", {
149
- body: JSON.stringify({ method_id: methodId, name }),
150
- });
151
- return await res.json();
152
- },
153
-
154
- async connectedApps() {
155
- const res = await client.v1_1("oauth/list", {});
156
- return await res.json();
157
- },
158
-
159
- async revokeApp(token) {
160
- const res = await client.v1_1("oauth/revoke", {
161
- body: JSON.stringify({ token }),
162
- });
163
- return await res.json();
164
- },
165
-
166
- async deleteSSOConnection(connectionId) {
167
- const res = await client.v1_1("sso/delete_connection", {
168
- body: JSON.stringify({ connection_id: connectionId }),
169
- });
170
- return await res.json();
171
- },
172
-
173
- async personalizationInterests() {
174
- const res = await client.v1_1("account/personalization/twitter_interests", {});
175
- return await res.json();
176
- },
177
-
178
- async emailYourData() {
179
- const res = await client.v1_1("account/personalization/email_your_data", {});
180
- return await res.json();
181
- },
182
-
183
- async multiList() {
184
- const res = await client.v1_1("account/multi/list", {});
185
- return await res.json();
186
- },
187
-
188
- async enableVerifiedPhoneLabel() {
189
- return await client.graphql("EnableVerifiedPhoneLabel", {
190
- body: { variables: {} },
191
- });
192
- },
193
-
194
- async disableVerifiedPhoneLabel() {
195
- return await client.graphql("DisableVerifiedPhoneLabel", {
196
- body: { variables: {} },
197
- });
198
- },
199
-
200
- async dataSaverMode() {
201
- return await client.graphql("DataSaverMode", {
202
- variables: {},
203
- });
204
- },
205
-
206
- async setDataSaver(dataSaverMode) {
207
- return await client.graphql("WriteDataSaverPreferences", {
208
- body: { variables: { dataSaverMode } },
209
- });
210
- },
211
-
212
- async mutedKeywords() {
213
- const res = await client.v1_1("mutes/keywords/list", {});
214
- return await res.json();
215
- },
216
-
217
- async deleteMutedKeyword(keywordId) {
218
- const res = await client.v1_1("mutes/keywords/destroy", {
219
- body: JSON.stringify({ ids: keywordId }),
220
- });
221
- return await res.json();
222
- },
223
-
224
- async updateMutedKeyword(params = {}) {
225
- const res = await client.v1_1("mutes/keywords/update", {
226
- body: JSON.stringify(params),
227
- });
228
- return await res.json();
229
- },
230
-
231
- async advancedFilters() {
232
- const res = await client.v1_1("get:mutes/advanced_filters", {});
233
- return await res.json();
234
- },
235
-
236
- async updateAdvancedFilters(params = {}) {
237
- const res = await client.v1_1("post:mutes/advanced_filters", {
238
- body: JSON.stringify(params),
239
- });
240
- return await res.json();
241
- },
242
-
243
- async helpSettings() {
244
- const res = await client.v1_1("help/settings", {});
245
- return await res.json();
246
- },
247
-
248
- async emailNotificationSettings(params = {}) {
249
- return await client.graphql("WriteEmailNotificationSettings", {
250
- body: { variables: { ...params } },
251
- });
252
- },
253
-
254
- async viewerEmailSettings() {
255
- return await client.graphql("ViewerEmailSettings", {
256
- variables: {},
257
- });
258
- },
259
-
260
- async accountLabel() {
261
- return await client.graphql("UserAccountLabel", {
262
- variables: {},
263
- });
264
- },
265
-
266
- async disableAccountLabel() {
267
- return await client.graphql("DisableUserAccountLabel", {
268
- body: { variables: {} },
269
- });
270
- },
271
- });
3
+ export async function settings() {
4
+ const res = await this.v1_1("get:account/settings", {});
5
+ return await res.json();
6
+ }
7
+
8
+ export async function updateSettings(params = {}) {
9
+ const res = await this.v1_1("post:account/settings", {
10
+ body: JSON.stringify(params),
11
+ });
12
+ return await res.json();
13
+ }
14
+
15
+ export async function verifyPassword(password) {
16
+ const res = await this.v1_1("account/verify_password", {
17
+ body: `password=${encodeURIComponent(password)}`,
18
+ headers: { "content-type": "application/x-www-form-urlencoded" },
19
+ });
20
+ return await res.json();
21
+ }
22
+
23
+ export async function changePassword(currentPassword, newPassword) {
24
+ const res = await this.v1_1("account/change_password", {
25
+ body: JSON.stringify({
26
+ current_password: currentPassword,
27
+ password: newPassword,
28
+ password_confirmation: newPassword,
29
+ }),
30
+ });
31
+ return await res.json();
32
+ }
33
+
34
+ export async function deactivate() {
35
+ const res = await this.v1_1("account/deactivate", {});
36
+ return await res.json();
37
+ }
38
+
39
+ export async function logout() {
40
+ const res = await this.v1_1("account/logout", {});
41
+ return await res.json();
42
+ }
43
+
44
+ export async function rateLimitStatus(params = {}) {
45
+ const res = await this.v1_1("application/rate_limit_status", { params });
46
+ return await res.json();
47
+ }
48
+
49
+ export async function viewer() {
50
+ const res = await this.graphql("Viewer", {
51
+ variables: { withCommunitiesMemberships: true },
52
+ fieldToggles: { withAuxiliaryUserLabels: false },
53
+ });
54
+ const user = res?.data?.viewer?.user_results?.result;
55
+ return user ? parseUser(user) : res;
56
+ }
57
+
58
+ export async function sessions() {
59
+ return await this.graphql("UserSessionsList", {
60
+ variables: {},
61
+ });
62
+ }
63
+
64
+ export async function preferences() {
65
+ return await this.graphql("UserPreferences", {
66
+ variables: {},
67
+ });
68
+ }
69
+
70
+ export async function claims() {
71
+ return await this.graphql("GetUserClaims", {
72
+ variables: {},
73
+ });
74
+ }
75
+
76
+ export async function phoneState() {
77
+ return await this.graphql("ProfileUserPhoneState", {
78
+ variables: {},
79
+ });
80
+ }
81
+
82
+ export async function passwordStrength(password) {
83
+ const res = await this.v1_1("account/password_strength", {
84
+ body: JSON.stringify({ password }),
85
+ });
86
+ return await res.json();
87
+ }
88
+
89
+ export async function resendConfirmationEmail() {
90
+ const res = await this.v1_1("account/resend_confirmation_email", {});
91
+ return await res.json();
92
+ }
93
+
94
+ export async function emailPhoneInfo(params = {}) {
95
+ const res = await this.v1_1("users/email_phone_info", { params });
96
+ return await res.json();
97
+ }
98
+
99
+ export async function emailAvailable(email) {
100
+ const res = await this.v1_1("users/email_available", {
101
+ params: { email },
102
+ });
103
+ return await res.json();
104
+ }
105
+
106
+ export async function phoneAvailable(phone) {
107
+ const res = await this.v1_1("users/phone_number_available", {
108
+ params: { phone_number: phone },
109
+ });
110
+ return await res.json();
111
+ }
112
+
113
+ export async function usernameAvailable(username) {
114
+ return await this.graphql("GetUsernameAvailabilityAndSuggestions", {
115
+ body: { variables: { username } },
116
+ });
117
+ }
118
+
119
+ export async function backupCode() {
120
+ const res = await this.v1_1("get:account/backup_code", {});
121
+ return await res.json();
122
+ }
123
+
124
+ export async function generateBackupCode() {
125
+ const res = await this.v1_1("post:account/backup_code", {});
126
+ return await res.json();
127
+ }
128
+
129
+ export async function disable2FA() {
130
+ const res = await this.v1_1("account/login_verification_enrollment", {});
131
+ return await res.json();
132
+ }
133
+
134
+ export async function remove2FAMethod(methodId) {
135
+ const res = await this.v1_1("account/login_verification/remove_method", {
136
+ body: JSON.stringify({ method_id: methodId }),
137
+ });
138
+ return await res.json();
139
+ }
140
+
141
+ export async function tempPassword() {
142
+ const res = await this.v1_1("account/login_verification/temporary_password", {});
143
+ return await res.json();
144
+ }
145
+
146
+ export async function renameSecurityKey(methodId, name) {
147
+ const res = await this.v1_1("account/login_verification/rename_security_key_method", {
148
+ body: JSON.stringify({ method_id: methodId, name }),
149
+ });
150
+ return await res.json();
151
+ }
152
+
153
+ export async function connectedApps() {
154
+ const res = await this.v1_1("oauth/list", {});
155
+ return await res.json();
156
+ }
157
+
158
+ export async function revokeApp(token) {
159
+ const res = await this.v1_1("oauth/revoke", {
160
+ body: JSON.stringify({ token }),
161
+ });
162
+ return await res.json();
163
+ }
164
+
165
+ export async function deleteSSOConnection(connectionId) {
166
+ const res = await this.v1_1("sso/delete_connection", {
167
+ body: JSON.stringify({ connection_id: connectionId }),
168
+ });
169
+ return await res.json();
170
+ }
171
+
172
+ export async function personalizationInterests() {
173
+ const res = await this.v1_1("account/personalization/twitter_interests", {});
174
+ return await res.json();
175
+ }
176
+
177
+ export async function emailYourData() {
178
+ const res = await this.v1_1("account/personalization/email_your_data", {});
179
+ return await res.json();
180
+ }
181
+
182
+ export async function multiList() {
183
+ const res = await this.v1_1("account/multi/list", {});
184
+ return await res.json();
185
+ }
186
+
187
+ export async function enableVerifiedPhoneLabel() {
188
+ return await this.graphql("EnableVerifiedPhoneLabel", {
189
+ body: { variables: {} },
190
+ });
191
+ }
192
+
193
+ export async function disableVerifiedPhoneLabel() {
194
+ return await this.graphql("DisableVerifiedPhoneLabel", {
195
+ body: { variables: {} },
196
+ });
197
+ }
198
+
199
+ export async function dataSaverMode() {
200
+ return await this.graphql("DataSaverMode", {
201
+ variables: {},
202
+ });
203
+ }
204
+
205
+ export async function setDataSaver(dataSaverMode) {
206
+ return await this.graphql("WriteDataSaverPreferences", {
207
+ body: { variables: { dataSaverMode } },
208
+ });
209
+ }
210
+
211
+ export async function mutedKeywords() {
212
+ const res = await this.v1_1("mutes/keywords/list", {});
213
+ return await res.json();
214
+ }
215
+
216
+ export async function deleteMutedKeyword(keywordId) {
217
+ const res = await this.v1_1("mutes/keywords/destroy", {
218
+ body: JSON.stringify({ ids: keywordId }),
219
+ });
220
+ return await res.json();
221
+ }
222
+
223
+ export async function updateMutedKeyword(params = {}) {
224
+ const res = await this.v1_1("mutes/keywords/update", {
225
+ body: JSON.stringify(params),
226
+ });
227
+ return await res.json();
228
+ }
229
+
230
+ export async function advancedFilters() {
231
+ const res = await this.v1_1("get:mutes/advanced_filters", {});
232
+ return await res.json();
233
+ }
234
+
235
+ export async function updateAdvancedFilters(params = {}) {
236
+ const res = await this.v1_1("post:mutes/advanced_filters", {
237
+ body: JSON.stringify(params),
238
+ });
239
+ return await res.json();
240
+ }
241
+
242
+ export async function helpSettings() {
243
+ const res = await this.v1_1("help/settings", {});
244
+ return await res.json();
245
+ }
246
+
247
+ export async function emailNotificationSettings(params = {}) {
248
+ return await this.graphql("WriteEmailNotificationSettings", {
249
+ body: { variables: { ...params } },
250
+ });
251
+ }
252
+
253
+ export async function viewerEmailSettings() {
254
+ return await this.graphql("ViewerEmailSettings", {
255
+ variables: {},
256
+ });
257
+ }
258
+
259
+ export async function accountLabel() {
260
+ return await this.graphql("UserAccountLabel", {
261
+ variables: {},
262
+ });
263
+ }
264
+
265
+ export async function disableAccountLabel() {
266
+ return await this.graphql("DisableUserAccountLabel", {
267
+ body: { variables: {} },
268
+ });
269
+ }