@pipedream/twitter 2.3.3 → 2.3.4
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/dist/actions/add-user-to-list/add-user-to-list.mjs +545 -50
- package/dist/actions/create-tweet/create-tweet.mjs +542 -81
- package/dist/actions/delete-tweet/delete-tweet.mjs +513 -34
- package/dist/actions/follow-user/follow-user.mjs +538 -43
- package/dist/actions/get-tweet/get-tweet.mjs +622 -40
- package/dist/actions/get-user/get-user.mjs +596 -44
- package/dist/actions/like-tweet/like-tweet.mjs +515 -36
- package/dist/actions/list-favorites/list-favorites.mjs +657 -56
- package/dist/actions/list-followers/list-followers.mjs +614 -56
- package/dist/actions/list-lists/list-lists.mjs +597 -56
- package/dist/actions/list-mentions/list-mentions.mjs +657 -56
- package/dist/actions/list-user-tweets/list-user-tweets.mjs +657 -56
- package/dist/actions/retweet/retweet.mjs +519 -39
- package/dist/actions/send-dm/send-dm.mjs +546 -49
- package/dist/actions/simple-search/simple-search.mjs +646 -56
- package/dist/actions/simple-search-in-list/simple-search-in-list.mjs +656 -63
- package/dist/actions/unfollow-user/unfollow-user.mjs +533 -39
- package/dist/actions/unlike-tweet/unlike-tweet.mjs +513 -34
- package/dist/actions/upload-media/upload-media.mjs +549 -57
- package/dist/app/twitter.app.mjs +443 -342
- package/dist/common/addObjIncludes.mjs +89 -63
- package/dist/common/additionalProps.mjs +0 -138
- package/dist/common/appValidation.mjs +475 -24
- package/dist/common/constants.mjs +11 -7
- package/dist/common/dataFields.mjs +100 -89
- package/dist/common/errorMessage.mjs +32 -26
- package/dist/common/expansions.mjs +26 -19
- package/dist/common/methods.mjs +170 -81
- package/dist/common/types/fields.mjs +0 -1
- package/dist/common/types/includeMapping.mjs +0 -1
- package/dist/common/types/requestParams.mjs +0 -1
- package/dist/common/types/responseSchemas.mjs +0 -1
- package/dist/sources/common/base.mjs +546 -69
- package/dist/sources/common/cacheUserId.mjs +32 -15
- package/dist/sources/common/getItemSummary.mjs +13 -9
- package/dist/sources/new-follower-of-user/new-follower-of-user.mjs +799 -40
- package/dist/sources/new-list-followed/new-list-followed.mjs +722 -41
- package/dist/sources/new-mention-received-by-user/new-mention-received-by-user.mjs +860 -40
- package/dist/sources/new-message/new-message.mjs +738 -32
- package/dist/sources/new-tweet-in-list/new-tweet-in-list.mjs +839 -37
- package/dist/sources/new-tweet-liked-by-user/new-tweet-liked-by-user.mjs +860 -40
- package/dist/sources/new-tweet-metrics/new-tweet-metrics.mjs +629 -59
- package/dist/sources/new-tweet-posted-by-user/new-tweet-posted-by-user.mjs +860 -40
- package/dist/sources/new-tweet-posted-matching-query/new-tweet-posted-matching-query.mjs +830 -39
- package/dist/sources/new-unfollower-of-user/new-unfollower-of-user.mjs +829 -70
- package/dist/sources/new-user-followed/new-user-followed.mjs +737 -41
- package/package.json +2 -2
- package/dist/actions/add-user-to-list/add-user-to-list.d.ts +0 -6
- package/dist/actions/create-tweet/create-tweet.d.ts +0 -105
- package/dist/actions/delete-tweet/delete-tweet.d.ts +0 -4
- package/dist/actions/follow-user/follow-user.d.ts +0 -6
- package/dist/actions/get-tweet/get-tweet.d.ts +0 -6
- package/dist/actions/get-user/get-user.d.ts +0 -7
- package/dist/actions/like-tweet/like-tweet.d.ts +0 -4
- package/dist/actions/list-favorites/list-favorites.d.ts +0 -10
- package/dist/actions/list-followers/list-followers.d.ts +0 -10
- package/dist/actions/list-lists/list-lists.d.ts +0 -8
- package/dist/actions/list-mentions/list-mentions.d.ts +0 -10
- package/dist/actions/list-user-tweets/list-user-tweets.d.ts +0 -10
- package/dist/actions/retweet/retweet.d.ts +0 -4
- package/dist/actions/send-dm/send-dm.d.ts +0 -6
- package/dist/actions/simple-search/simple-search.d.ts +0 -9
- package/dist/actions/simple-search-in-list/simple-search-in-list.d.ts +0 -9
- package/dist/actions/unfollow-user/unfollow-user.d.ts +0 -6
- package/dist/actions/unlike-tweet/unlike-tweet.d.ts +0 -4
- package/dist/actions/upload-media/upload-media.d.ts +0 -4
- package/dist/app/twitter.app.d.ts +0 -69
- package/dist/common/addObjIncludes.d.ts +0 -9
- package/dist/common/additionalProps.d.ts +0 -0
- package/dist/common/appValidation.d.ts +0 -144
- package/dist/common/constants.d.ts +0 -7
- package/dist/common/dataFields.d.ts +0 -8
- package/dist/common/errorMessage.d.ts +0 -25
- package/dist/common/expansions.d.ts +0 -4
- package/dist/common/methods.d.ts +0 -27
- package/dist/common/types/fields.d.ts +0 -25
- package/dist/common/types/includeMapping.d.ts +0 -11
- package/dist/common/types/requestParams.d.ts +0 -126
- package/dist/common/types/responseSchemas.d.ts +0 -82
- package/dist/sources/common/base.d.ts +0 -163
- package/dist/sources/common/cacheUserId.d.ts +0 -7
- package/dist/sources/common/getItemSummary.d.ts +0 -4
- package/dist/sources/new-follower-of-user/new-follower-of-user.d.ts +0 -17
- package/dist/sources/new-list-followed/new-list-followed.d.ts +0 -17
- package/dist/sources/new-mention-received-by-user/new-mention-received-by-user.d.ts +0 -17
- package/dist/sources/new-message/new-message.d.ts +0 -15
- package/dist/sources/new-tweet-in-list/new-tweet-in-list.d.ts +0 -15
- package/dist/sources/new-tweet-liked-by-user/new-tweet-liked-by-user.d.ts +0 -17
- package/dist/sources/new-tweet-metrics/new-tweet-metrics.d.ts +0 -13
- package/dist/sources/new-tweet-posted-by-user/new-tweet-posted-by-user.d.ts +0 -17
- package/dist/sources/new-tweet-posted-matching-query/new-tweet-posted-matching-query.d.ts +0 -15
- package/dist/sources/new-unfollower-of-user/new-unfollower-of-user.d.ts +0 -17
- package/dist/sources/new-user-followed/new-user-followed.d.ts +0 -17
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,47 +1,743 @@
|
|
|
1
|
+
// components/twitter/sources/new-user-followed/new-user-followed.ts
|
|
1
2
|
import { defineSource } from "@pipedream/types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
|
|
4
|
+
// components/twitter/sources/common/base.ts
|
|
5
|
+
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
|
|
6
|
+
|
|
7
|
+
// components/twitter/app/twitter.app.ts
|
|
8
|
+
import OAuth from "oauth-1.0a";
|
|
9
|
+
import crypto from "crypto";
|
|
10
|
+
import { defineApp } from "@pipedream/types";
|
|
11
|
+
import {
|
|
12
|
+
axios,
|
|
13
|
+
transformConfigForOauth,
|
|
14
|
+
ConfigurationError
|
|
15
|
+
} from "@pipedream/platform";
|
|
16
|
+
|
|
17
|
+
// components/twitter/common/errorMessage.ts
|
|
18
|
+
var ERROR_URL = "https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#item0";
|
|
19
|
+
var ERROR_MESSAGE = `Check if your app is properly configured on the [Twitter Developer Portal](${ERROR_URL}), and if your plan has access to the endpoint used by this component.`;
|
|
20
|
+
var ACTION_ERROR_MESSAGE = `${ERROR_MESSAGE} Additional debugging information has been exported from the step.`;
|
|
21
|
+
var PROBLEM_BASE_URL = "https://api.twitter.com/2/problems";
|
|
22
|
+
var ERROR_BY_TYPE = {
|
|
23
|
+
[`${PROBLEM_BASE_URL}/client-forbidden`]: "This X (Twitter) account appears to be on the Free plan, which only has access to **Create Tweets**. [Refer to Twitter's developer docs](https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-leve) for the latest info on API access.",
|
|
24
|
+
["about:blank"]: "A generic problem with no additional information beyond that provided by the HTTP status code.",
|
|
25
|
+
[`${PROBLEM_BASE_URL}/invalid-request`]: "A problem that indicates this request is invalid. If your request takes a POST body, ensure the contents is valid JSON and matches the [OpenAPI spec](https://api.twitter.com/2/openapi.json).",
|
|
26
|
+
[`${PROBLEM_BASE_URL}/resource-not-found`]: "A problem that indicates that a given Post, User, etc. does not exist.",
|
|
27
|
+
[`${PROBLEM_BASE_URL}/not-authorized-for-resource`]: "A problem that indicates you are not allowed to see a particular Post, User, etc.",
|
|
28
|
+
[`${PROBLEM_BASE_URL}/disallowed-resource`]: "A problem that indicates that the resource requested violates the precepts of this API.",
|
|
29
|
+
[`${PROBLEM_BASE_URL}/unsupported-authentication`]: "A problem that indicates that the authentication used is not supported.",
|
|
30
|
+
[`${PROBLEM_BASE_URL}/usage-capped`]: "A problem that indicates that a usage cap has been exceeded.",
|
|
31
|
+
[`${PROBLEM_BASE_URL}/streaming-connection`]: "A problem that indicates something is wrong with the connection.",
|
|
32
|
+
[`${PROBLEM_BASE_URL}/client-disconnected`]: "Your client has gone away.",
|
|
33
|
+
[`${PROBLEM_BASE_URL}/operational-disconnect`]: "You have been disconnected for operational reasons.",
|
|
34
|
+
[`${PROBLEM_BASE_URL}/rule-cap`]: "You have exceeded the maximum number of rules.",
|
|
35
|
+
[`${PROBLEM_BASE_URL}/rule-length`]: "You have exceeded the maximum number of characters allowed on your query or rule based on your access level. See [access levels](https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api.html#Access).",
|
|
36
|
+
[`${PROBLEM_BASE_URL}/invalid-rules`]: "The rule you have submitted is invalid.",
|
|
37
|
+
[`${PROBLEM_BASE_URL}/duplicate-rules`]: "The rule you have submitted is a duplicate.",
|
|
38
|
+
[`${PROBLEM_BASE_URL}/conflict`]: "The rule you have submitted is in conflict with another rule.",
|
|
39
|
+
[`${PROBLEM_BASE_URL}/noncompliant-rules`]: "The rule you have submitted is not compliant with Twitter's Automation Rules",
|
|
40
|
+
[`${PROBLEM_BASE_URL}/not-authorized-for-field`]: "A problem that indicates you are not allowed to see a particular field.",
|
|
41
|
+
[`${PROBLEM_BASE_URL}/oauth1-permissions`]: "A problem that indicates you are not allowed to see a particular field.",
|
|
42
|
+
[`${PROBLEM_BASE_URL}/resource-unavailable`]: "A problem that indicates that a given Post, User, etc. is temporarily unavailable."
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// components/twitter/app/twitter.app.ts
|
|
46
|
+
var twitter_app_default = defineApp({
|
|
47
|
+
type: "app",
|
|
48
|
+
app: "twitter",
|
|
49
|
+
propDefinitions: {
|
|
50
|
+
maxResults: {
|
|
51
|
+
type: "integer",
|
|
52
|
+
label: "Max Results",
|
|
53
|
+
description: "Maximum amount of items to return. The maximum amount per request for each endpoint is included in the API documentation.",
|
|
54
|
+
optional: true
|
|
55
|
+
},
|
|
56
|
+
listId: {
|
|
57
|
+
type: "string",
|
|
58
|
+
label: "List ID",
|
|
59
|
+
description: "Select a **List** owned by the authenticated user, or use a custom *List ID*.",
|
|
60
|
+
async options() {
|
|
61
|
+
const userId = await this.getAuthenticatedUserId();
|
|
62
|
+
const lists = await this.getUserOwnedLists({
|
|
63
|
+
userId
|
|
64
|
+
});
|
|
65
|
+
return lists.data?.map(({
|
|
66
|
+
id,
|
|
67
|
+
name
|
|
68
|
+
}) => ({
|
|
69
|
+
label: name,
|
|
70
|
+
value: id
|
|
71
|
+
})) ?? [];
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
userNameOrId: {
|
|
75
|
+
type: "string",
|
|
76
|
+
label: "User Name or ID",
|
|
77
|
+
description: "A Twitter username (handle) prefixed with `@` (e.g. `@pipedream`). You can also use the string `me` to use the authenticated user (default), or a numeric User ID.",
|
|
78
|
+
optional: true,
|
|
79
|
+
default: "me"
|
|
80
|
+
},
|
|
81
|
+
// See comment on "../common/additionalProps.ts"
|
|
82
|
+
/*
|
|
83
|
+
includeAllFields: {
|
|
84
|
+
type: "boolean",
|
|
85
|
+
label: "Include All Metadata",
|
|
86
|
+
description: "If set to `false`, you can choose which fields will be returned for each data type.",
|
|
87
|
+
optional: true,
|
|
88
|
+
default: true,
|
|
89
|
+
reloadProps: true,
|
|
90
|
+
},
|
|
91
|
+
*/
|
|
92
|
+
tweetId: {
|
|
93
|
+
type: "string",
|
|
94
|
+
label: "Tweet ID",
|
|
95
|
+
description: "The numerical ID of the tweet."
|
|
96
|
+
},
|
|
97
|
+
query: {
|
|
98
|
+
type: "string",
|
|
99
|
+
label: "Query",
|
|
100
|
+
description: "One query for matching Tweets. See the [Twitter API guide on building queries](https://developer.twitter.com/en/docs/twitter-api/tweets/search/integrate/build-a-query)."
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
methods: {
|
|
104
|
+
throwError(data) {
|
|
105
|
+
const errorMessage = ERROR_BY_TYPE[data?.type];
|
|
106
|
+
if (!errorMessage) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
throw new ConfigurationError(errorMessage);
|
|
110
|
+
},
|
|
111
|
+
_getAuthHeader(config) {
|
|
112
|
+
const {
|
|
113
|
+
developer_consumer_key: devKey,
|
|
114
|
+
developer_consumer_secret: devSecret,
|
|
115
|
+
oauth_access_token: key,
|
|
116
|
+
oauth_refresh_token: secret
|
|
117
|
+
} = this.$auth;
|
|
118
|
+
const consumer = {
|
|
119
|
+
key: devKey,
|
|
120
|
+
secret: devSecret
|
|
121
|
+
};
|
|
122
|
+
const oauth = new OAuth({
|
|
123
|
+
consumer,
|
|
124
|
+
signature_method: "HMAC-SHA1",
|
|
125
|
+
hash_function(base_string, key2) {
|
|
126
|
+
return crypto.createHmac("sha1", key2).update(base_string).digest("base64");
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const token = {
|
|
130
|
+
key,
|
|
131
|
+
secret
|
|
132
|
+
};
|
|
133
|
+
const requestData = transformConfigForOauth(config);
|
|
134
|
+
return oauth.toHeader(oauth.authorize(requestData, token));
|
|
135
|
+
},
|
|
136
|
+
_getBaseUrl() {
|
|
137
|
+
return "https://api.twitter.com/2";
|
|
138
|
+
},
|
|
139
|
+
async _httpRequest({
|
|
140
|
+
$ = this,
|
|
141
|
+
headers,
|
|
142
|
+
specialAuth = false,
|
|
143
|
+
throwError = true,
|
|
144
|
+
fallbackError,
|
|
145
|
+
...args
|
|
146
|
+
}) {
|
|
147
|
+
const maxRetries = 3;
|
|
148
|
+
let response;
|
|
149
|
+
let counter = 1;
|
|
150
|
+
const config = {
|
|
151
|
+
baseURL: this._getBaseUrl(),
|
|
152
|
+
...args
|
|
153
|
+
};
|
|
154
|
+
const authConfig = specialAuth ? {
|
|
155
|
+
...config,
|
|
156
|
+
params: {},
|
|
157
|
+
data: {}
|
|
158
|
+
} : config;
|
|
159
|
+
const axiosConfig = {
|
|
160
|
+
debug: true,
|
|
161
|
+
...config,
|
|
162
|
+
headers: {
|
|
163
|
+
...headers,
|
|
164
|
+
...this._getAuthHeader(authConfig)
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
do {
|
|
168
|
+
try {
|
|
169
|
+
response = await axios($, axiosConfig);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.log(`Request error on attempt #${counter}: `, err);
|
|
172
|
+
if (counter === maxRetries) {
|
|
173
|
+
if (throwError && err.response?.data) {
|
|
174
|
+
this.throwError(err.response.data);
|
|
175
|
+
}
|
|
176
|
+
if (fallbackError) {
|
|
177
|
+
throw new ConfigurationError(fallbackError);
|
|
178
|
+
}
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} while (!response && ++counter <= maxRetries);
|
|
183
|
+
return response;
|
|
184
|
+
},
|
|
185
|
+
async _paginatedRequest({
|
|
186
|
+
maxResults = 100,
|
|
187
|
+
maxPerPage = 100,
|
|
188
|
+
params,
|
|
189
|
+
...args
|
|
190
|
+
}) {
|
|
191
|
+
const totalData = [], totalErrors = [], totalIncludes = {};
|
|
192
|
+
let paginationToken;
|
|
193
|
+
let resultCount = 0;
|
|
194
|
+
do {
|
|
195
|
+
const perPage = Math.min(maxResults - resultCount, maxPerPage);
|
|
196
|
+
const {
|
|
197
|
+
data,
|
|
198
|
+
errors,
|
|
199
|
+
meta: { next_token },
|
|
200
|
+
includes
|
|
201
|
+
} = await this._httpRequest({
|
|
202
|
+
params: {
|
|
203
|
+
...params,
|
|
204
|
+
max_results: perPage,
|
|
205
|
+
pagination_token: paginationToken
|
|
206
|
+
},
|
|
207
|
+
...args
|
|
208
|
+
});
|
|
209
|
+
if (data) {
|
|
210
|
+
totalData.push(...Array.isArray(data) ? data : [
|
|
211
|
+
data
|
|
212
|
+
]);
|
|
213
|
+
}
|
|
214
|
+
if (errors) {
|
|
215
|
+
totalErrors.push(...Array.isArray(errors) ? errors : [
|
|
216
|
+
errors
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
if (includes) {
|
|
220
|
+
Object.entries(includes).forEach(
|
|
221
|
+
([
|
|
222
|
+
key,
|
|
223
|
+
value
|
|
224
|
+
]) => {
|
|
225
|
+
if (!totalIncludes[key]) totalIncludes[key] = [];
|
|
226
|
+
totalIncludes[key].push(...value);
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
paginationToken = next_token;
|
|
231
|
+
resultCount += perPage;
|
|
232
|
+
} while (paginationToken && resultCount < maxResults);
|
|
233
|
+
return {
|
|
234
|
+
data: totalData,
|
|
235
|
+
errors: totalErrors,
|
|
236
|
+
includes: totalIncludes
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
async addUserToList({
|
|
240
|
+
listId,
|
|
241
|
+
...args
|
|
242
|
+
}) {
|
|
243
|
+
return this._httpRequest({
|
|
244
|
+
method: "POST",
|
|
245
|
+
url: `/lists/${listId}/members`,
|
|
246
|
+
...args
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
async createTweet(args) {
|
|
250
|
+
return this._httpRequest({
|
|
251
|
+
throwError: false,
|
|
252
|
+
method: "POST",
|
|
253
|
+
url: "/tweets",
|
|
254
|
+
...args
|
|
255
|
+
});
|
|
256
|
+
},
|
|
257
|
+
async deleteTweet({
|
|
258
|
+
tweetId,
|
|
259
|
+
...args
|
|
260
|
+
}) {
|
|
261
|
+
return this._httpRequest({
|
|
262
|
+
method: "DELETE",
|
|
263
|
+
url: `/tweets/${tweetId}`,
|
|
264
|
+
...args
|
|
265
|
+
});
|
|
266
|
+
},
|
|
267
|
+
async followUser(args) {
|
|
268
|
+
const id = await this.getAuthenticatedUserId();
|
|
269
|
+
return this._httpRequest({
|
|
270
|
+
method: "POST",
|
|
271
|
+
url: `/users/${id}/following`,
|
|
272
|
+
...args
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
async getListTweets({
|
|
276
|
+
listId,
|
|
277
|
+
...args
|
|
278
|
+
}) {
|
|
279
|
+
return this._paginatedRequest({
|
|
280
|
+
url: `/lists/${listId}/tweets`,
|
|
281
|
+
...args
|
|
282
|
+
});
|
|
283
|
+
},
|
|
284
|
+
async getTweet({
|
|
285
|
+
tweetId,
|
|
286
|
+
...args
|
|
287
|
+
}) {
|
|
288
|
+
return this._httpRequest({
|
|
289
|
+
url: `/tweets/${tweetId}`,
|
|
290
|
+
...args
|
|
291
|
+
});
|
|
292
|
+
},
|
|
293
|
+
async getAuthenticatedUser(args) {
|
|
294
|
+
return this._httpRequest({
|
|
295
|
+
url: "/users/me",
|
|
296
|
+
...args
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
async getAuthenticatedUserId() {
|
|
300
|
+
const response = await this.getAuthenticatedUser();
|
|
301
|
+
return response.data.id;
|
|
302
|
+
},
|
|
303
|
+
async getDirectMessages(args) {
|
|
304
|
+
return this._paginatedRequest({
|
|
305
|
+
url: "/dm_events",
|
|
306
|
+
...args
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
async getUserLikedTweets({
|
|
310
|
+
userId,
|
|
311
|
+
...args
|
|
312
|
+
}) {
|
|
313
|
+
return this._paginatedRequest({
|
|
314
|
+
url: `/users/${userId}/liked_tweets`,
|
|
315
|
+
...args
|
|
316
|
+
});
|
|
317
|
+
},
|
|
318
|
+
async getUserOwnedLists({
|
|
319
|
+
userId,
|
|
320
|
+
...args
|
|
321
|
+
}) {
|
|
322
|
+
return this._httpRequest({
|
|
323
|
+
url: `/users/${userId}/owned_lists`,
|
|
324
|
+
...args
|
|
325
|
+
});
|
|
24
326
|
},
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
327
|
+
async getUserFollowedLists({
|
|
328
|
+
userId,
|
|
329
|
+
...args
|
|
330
|
+
}) {
|
|
331
|
+
return this._paginatedRequest({
|
|
332
|
+
url: `/users/${userId}/followed_lists`,
|
|
333
|
+
...args
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
async getUserMentions({
|
|
337
|
+
userId,
|
|
338
|
+
...args
|
|
339
|
+
}) {
|
|
340
|
+
return this._paginatedRequest({
|
|
341
|
+
url: `/users/${userId}/mentions`,
|
|
342
|
+
...args
|
|
343
|
+
});
|
|
344
|
+
},
|
|
345
|
+
async getUserTweets({
|
|
346
|
+
userId,
|
|
347
|
+
...args
|
|
348
|
+
}) {
|
|
349
|
+
return this._paginatedRequest({
|
|
350
|
+
url: `/users/${userId}/tweets`,
|
|
351
|
+
...args
|
|
352
|
+
});
|
|
353
|
+
},
|
|
354
|
+
async getUserByUsername(username) {
|
|
355
|
+
return this._httpRequest({
|
|
356
|
+
url: `/users/by/username/${username}`
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
async getUser({
|
|
360
|
+
userId,
|
|
361
|
+
...args
|
|
362
|
+
}) {
|
|
363
|
+
return this._httpRequest({
|
|
364
|
+
url: `/users/${userId}`,
|
|
365
|
+
...args
|
|
366
|
+
});
|
|
367
|
+
},
|
|
368
|
+
async likeTweet(args) {
|
|
369
|
+
const id = await this.getAuthenticatedUserId();
|
|
370
|
+
return this._httpRequest({
|
|
371
|
+
method: "POST",
|
|
372
|
+
url: `/users/${id}/likes`,
|
|
373
|
+
...args
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
async getUserFollowers({
|
|
377
|
+
userId,
|
|
378
|
+
...args
|
|
379
|
+
}) {
|
|
380
|
+
return this._paginatedRequest({
|
|
381
|
+
url: `/users/${userId}/followers`,
|
|
382
|
+
...args
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
async getUserFollowing({
|
|
386
|
+
userId,
|
|
387
|
+
...args
|
|
388
|
+
}) {
|
|
389
|
+
return this._paginatedRequest({
|
|
390
|
+
url: `/users/${userId}/following`,
|
|
391
|
+
...args
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
async retweet(args) {
|
|
395
|
+
const id = await this.getAuthenticatedUserId();
|
|
396
|
+
return this._httpRequest({
|
|
397
|
+
method: "POST",
|
|
398
|
+
url: `/users/${id}/retweets`,
|
|
399
|
+
...args
|
|
400
|
+
});
|
|
401
|
+
},
|
|
402
|
+
async searchTweets(args) {
|
|
403
|
+
return this._paginatedRequest({
|
|
404
|
+
url: "/tweets/search/recent",
|
|
405
|
+
...args
|
|
406
|
+
});
|
|
407
|
+
},
|
|
408
|
+
async sendMessage({
|
|
409
|
+
userId,
|
|
410
|
+
...args
|
|
411
|
+
}) {
|
|
412
|
+
return this._httpRequest({
|
|
413
|
+
method: "POST",
|
|
414
|
+
url: `/dm_conversations/with/${userId}/messages`,
|
|
415
|
+
...args
|
|
416
|
+
});
|
|
417
|
+
},
|
|
418
|
+
async unfollowUser({
|
|
419
|
+
userId,
|
|
420
|
+
...args
|
|
421
|
+
}) {
|
|
422
|
+
const id = await this.getAuthenticatedUserId();
|
|
423
|
+
return this._httpRequest({
|
|
424
|
+
method: "DELETE",
|
|
425
|
+
url: `/users/${id}/following/${userId}`,
|
|
426
|
+
...args
|
|
427
|
+
});
|
|
428
|
+
},
|
|
429
|
+
async unlikeTweet({
|
|
430
|
+
tweetId,
|
|
431
|
+
...args
|
|
432
|
+
}) {
|
|
433
|
+
const id = await this.getAuthenticatedUserId();
|
|
434
|
+
return this._httpRequest({
|
|
435
|
+
method: "DELETE",
|
|
436
|
+
url: `/users/${id}/likes/${tweetId}`,
|
|
437
|
+
...args
|
|
438
|
+
});
|
|
439
|
+
},
|
|
440
|
+
async uploadMedia(args) {
|
|
441
|
+
return this._httpRequest({
|
|
442
|
+
baseURL: "https://upload.twitter.com/1.1",
|
|
443
|
+
url: "/media/upload.json",
|
|
444
|
+
method: "POST",
|
|
445
|
+
headers: {
|
|
446
|
+
"Content-Type": `multipart/form-data; boundary=${args.data.getBoundary()}`
|
|
31
447
|
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
448
|
+
specialAuth: true,
|
|
449
|
+
...args
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// components/twitter/common/appValidation.ts
|
|
456
|
+
var appValidation_default = {
|
|
457
|
+
props: {
|
|
458
|
+
app: {
|
|
459
|
+
...twitter_app_default,
|
|
460
|
+
reloadProps: true
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
async additionalProps() {
|
|
464
|
+
const q = "Pipedream";
|
|
465
|
+
const data = await this.getRecentTweets({
|
|
466
|
+
params: {
|
|
467
|
+
query: q
|
|
468
|
+
},
|
|
469
|
+
validateStatus: () => true
|
|
470
|
+
});
|
|
471
|
+
this.app.throwError(data);
|
|
472
|
+
return {};
|
|
473
|
+
},
|
|
474
|
+
methods: {
|
|
475
|
+
getRecentTweets(args = {}) {
|
|
476
|
+
return this.app._httpRequest({
|
|
477
|
+
url: "/tweets/search/recent",
|
|
478
|
+
...args
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// components/twitter/sources/common/base.ts
|
|
485
|
+
var base_default = {
|
|
486
|
+
...appValidation_default,
|
|
487
|
+
props: {
|
|
488
|
+
...appValidation_default.props,
|
|
489
|
+
db: "$.service.db",
|
|
490
|
+
timer: {
|
|
491
|
+
type: "$.interface.timer",
|
|
492
|
+
default: {
|
|
493
|
+
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
hooks: {
|
|
498
|
+
async deploy() {
|
|
499
|
+
const q = "Pipedream";
|
|
500
|
+
const data = await this.getRecentTweets({
|
|
501
|
+
params: {
|
|
502
|
+
query: q
|
|
45
503
|
},
|
|
504
|
+
validateStatus: () => true
|
|
505
|
+
});
|
|
506
|
+
this.app.throwError(data);
|
|
507
|
+
await this.getAndProcessData();
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
methods: {
|
|
511
|
+
...appValidation_default.methods,
|
|
512
|
+
getEntityName() {
|
|
513
|
+
return "Entity";
|
|
514
|
+
},
|
|
515
|
+
getItemSummary() {
|
|
516
|
+
throw new Error("getItemSummary() not implemented in component");
|
|
517
|
+
},
|
|
518
|
+
async getResources() {
|
|
519
|
+
throw new Error("getResources() not implemented in component");
|
|
520
|
+
},
|
|
521
|
+
getSavedIds() {
|
|
522
|
+
return this.db.get("savedEntityIds");
|
|
523
|
+
},
|
|
524
|
+
setSavedIds(data) {
|
|
525
|
+
this.db.set("savedEntityIds", data);
|
|
526
|
+
},
|
|
527
|
+
async getAndProcessData(maxResults) {
|
|
528
|
+
const data = await this.getResources(maxResults);
|
|
529
|
+
if (data) {
|
|
530
|
+
const savedIds = this.getSavedIds() ?? [];
|
|
531
|
+
data.filter(({ id }) => !savedIds.includes(id)).reverse().forEach((obj) => {
|
|
532
|
+
this.emitEvent(obj);
|
|
533
|
+
savedIds.push(obj.id);
|
|
534
|
+
});
|
|
535
|
+
this.setSavedIds(savedIds);
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
emitEvent(data) {
|
|
539
|
+
const ts = Date.now();
|
|
540
|
+
const { id } = data;
|
|
541
|
+
this.$emit(data, {
|
|
542
|
+
id,
|
|
543
|
+
summary: `New ${this.getEntityName()}: "${this.getItemSummary(data)}"`,
|
|
544
|
+
ts
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
async run() {
|
|
549
|
+
try {
|
|
550
|
+
await this.getAndProcessData(50);
|
|
551
|
+
} catch (err) {
|
|
552
|
+
throw new Error(`${ERROR_MESSAGE} Error response: ${JSON.stringify(err)}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// components/twitter/sources/common/getItemSummary.ts
|
|
558
|
+
function getUserSummary({ username }) {
|
|
559
|
+
return username;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// components/twitter/common/methods.ts
|
|
563
|
+
import { ConfigurationError as ConfigurationError2 } from "@pipedream/platform";
|
|
564
|
+
|
|
565
|
+
// components/twitter/common/dataFields.ts
|
|
566
|
+
var TWEET_FIELD_OPTIONS = [
|
|
567
|
+
"attachments",
|
|
568
|
+
"author_id",
|
|
569
|
+
"context_annotations",
|
|
570
|
+
"conversation_id",
|
|
571
|
+
"created_at",
|
|
572
|
+
"edit_controls",
|
|
573
|
+
"entities",
|
|
574
|
+
"geo",
|
|
575
|
+
"id",
|
|
576
|
+
"in_reply_to_user_id",
|
|
577
|
+
"lang",
|
|
578
|
+
// "non_public_metrics",
|
|
579
|
+
"public_metrics",
|
|
580
|
+
// "organic_metrics",
|
|
581
|
+
// "promoted_metrics",
|
|
582
|
+
"possibly_sensitive",
|
|
583
|
+
"referenced_tweets",
|
|
584
|
+
"reply_settings",
|
|
585
|
+
"source",
|
|
586
|
+
"text",
|
|
587
|
+
"withheld"
|
|
588
|
+
];
|
|
589
|
+
var USER_FIELD_OPTIONS = [
|
|
590
|
+
"created_at",
|
|
591
|
+
"description",
|
|
592
|
+
"entities",
|
|
593
|
+
"id",
|
|
594
|
+
"location",
|
|
595
|
+
"name",
|
|
596
|
+
"pinned_tweet_id",
|
|
597
|
+
"profile_image_url",
|
|
598
|
+
"protected",
|
|
599
|
+
"public_metrics",
|
|
600
|
+
"url",
|
|
601
|
+
"username",
|
|
602
|
+
"verified",
|
|
603
|
+
"verified_type",
|
|
604
|
+
"withheld"
|
|
605
|
+
];
|
|
606
|
+
|
|
607
|
+
// components/twitter/common/expansions.ts
|
|
608
|
+
var USER_EXPANSION_OPTIONS = [
|
|
609
|
+
"pinned_tweet_id"
|
|
610
|
+
];
|
|
611
|
+
|
|
612
|
+
// components/twitter/common/methods.ts
|
|
613
|
+
async function getUserId() {
|
|
614
|
+
let { userNameOrId: id } = this;
|
|
615
|
+
if (id === "me" || id === void 0) {
|
|
616
|
+
id = await this.app.getAuthenticatedUserId();
|
|
617
|
+
} else if (id.startsWith("@")) {
|
|
618
|
+
const userData = await this.app.getUserByUsername(id.slice(1));
|
|
619
|
+
id = userData?.data?.id;
|
|
620
|
+
if (!id) throw new ConfigurationError2("**User not found!** Check the `User Name or ID` prop.");
|
|
621
|
+
}
|
|
622
|
+
return id;
|
|
623
|
+
}
|
|
624
|
+
function getUserFields() {
|
|
625
|
+
return {
|
|
626
|
+
"expansions": USER_EXPANSION_OPTIONS.join(),
|
|
627
|
+
"tweet.fields": TWEET_FIELD_OPTIONS.join(),
|
|
628
|
+
"user.fields": USER_FIELD_OPTIONS.join()
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// components/twitter/sources/common/cacheUserId.ts
|
|
633
|
+
async function getCachedUserId() {
|
|
634
|
+
const { userNameOrId: name } = this;
|
|
635
|
+
const cache = this.db.get("cachedUser");
|
|
636
|
+
if (cache?.name === name) {
|
|
637
|
+
return cache.id;
|
|
638
|
+
}
|
|
639
|
+
const id = await this.getUserId();
|
|
640
|
+
this.db.set("cachedUser", {
|
|
641
|
+
id,
|
|
642
|
+
name
|
|
643
|
+
});
|
|
644
|
+
return id;
|
|
645
|
+
}
|
|
646
|
+
var cacheUserId_default = {
|
|
647
|
+
getCachedUserId,
|
|
648
|
+
getUserId
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
// components/twitter/common/addObjIncludes.ts
|
|
652
|
+
function flatClearIncludeIds(obj) {
|
|
653
|
+
return Object.fromEntries(
|
|
654
|
+
Object.entries(obj).map(([
|
|
655
|
+
key,
|
|
656
|
+
value
|
|
657
|
+
]) => [
|
|
658
|
+
key,
|
|
659
|
+
value.filter((e) => e !== void 0).flat()
|
|
660
|
+
])
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
function getUserIncludeIds(obj) {
|
|
664
|
+
return flatClearIncludeIds({
|
|
665
|
+
tweetIds: [
|
|
666
|
+
obj.pinned_tweet_id
|
|
667
|
+
]
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
function getObjIncludes(obj, includes = {}, getIncludeIds) {
|
|
671
|
+
const {
|
|
672
|
+
userIds,
|
|
673
|
+
userNames,
|
|
674
|
+
tweetIds,
|
|
675
|
+
pollIds,
|
|
676
|
+
placeIds,
|
|
677
|
+
mediaKeys
|
|
678
|
+
} = getIncludeIds(obj);
|
|
679
|
+
const result = {
|
|
680
|
+
media: includes.media?.filter((item) => mediaKeys?.includes(item.media_key)),
|
|
681
|
+
users: includes.users?.filter(
|
|
682
|
+
(item) => userIds?.includes(item.id) || userNames?.includes(item.username)
|
|
683
|
+
),
|
|
684
|
+
places: includes.places?.filter((item) => placeIds?.includes(item.id)),
|
|
685
|
+
polls: includes.polls?.filter((item) => pollIds?.includes(item.id)),
|
|
686
|
+
tweets: includes.tweets?.filter((item) => tweetIds?.includes(item.id))
|
|
687
|
+
};
|
|
688
|
+
return Object.fromEntries(
|
|
689
|
+
Object.entries(result).filter(([
|
|
690
|
+
,
|
|
691
|
+
value
|
|
692
|
+
]) => value?.length > 0)
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// components/twitter/sources/new-user-followed/new-user-followed.ts
|
|
697
|
+
var DOCS_LINK = "https://developer.twitter.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-following";
|
|
698
|
+
var MAX_RESULTS_PER_PAGE = 1e3;
|
|
699
|
+
var new_user_followed_default = defineSource({
|
|
700
|
+
...base_default,
|
|
701
|
+
key: "twitter-new-user-followed",
|
|
702
|
+
name: "New User Followed by User",
|
|
703
|
+
description: `Emit new event when the specified User follows another User [See the documentation](${DOCS_LINK})`,
|
|
704
|
+
version: "2.1.0",
|
|
705
|
+
type: "source",
|
|
706
|
+
props: {
|
|
707
|
+
...base_default.props,
|
|
708
|
+
userNameOrId: {
|
|
709
|
+
propDefinition: [
|
|
710
|
+
base_default.props.app,
|
|
711
|
+
"userNameOrId"
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
methods: {
|
|
716
|
+
...base_default.methods,
|
|
717
|
+
...cacheUserId_default,
|
|
718
|
+
getUserFields,
|
|
719
|
+
getEntityName() {
|
|
720
|
+
return "User Followed";
|
|
46
721
|
},
|
|
722
|
+
getItemSummary: getUserSummary,
|
|
723
|
+
async getResources(maxResults) {
|
|
724
|
+
const userId = await this.getCachedUserId();
|
|
725
|
+
const params = {
|
|
726
|
+
$: this,
|
|
727
|
+
maxPerPage: MAX_RESULTS_PER_PAGE,
|
|
728
|
+
maxResults: maxResults ?? MAX_RESULTS_PER_PAGE,
|
|
729
|
+
params: this.getUserFields(),
|
|
730
|
+
userId
|
|
731
|
+
};
|
|
732
|
+
const {
|
|
733
|
+
data,
|
|
734
|
+
includes
|
|
735
|
+
} = await this.app.getUserFollowing(params);
|
|
736
|
+
data.forEach((user) => user.includes = getObjIncludes(user, includes, getUserIncludeIds));
|
|
737
|
+
return data;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
47
740
|
});
|
|
741
|
+
export {
|
|
742
|
+
new_user_followed_default as default
|
|
743
|
+
};
|