@auxiora/connector-social 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/instagram.d.ts +2 -0
- package/dist/instagram.d.ts.map +1 -0
- package/dist/instagram.js +205 -0
- package/dist/instagram.js.map +1 -0
- package/dist/linkedin.d.ts +2 -0
- package/dist/linkedin.d.ts.map +1 -0
- package/dist/linkedin.js +239 -0
- package/dist/linkedin.js.map +1 -0
- package/dist/reddit.d.ts +2 -0
- package/dist/reddit.d.ts.map +1 -0
- package/dist/reddit.js +259 -0
- package/dist/reddit.js.map +1 -0
- package/dist/twitter.d.ts +2 -0
- package/dist/twitter.d.ts.map +1 -0
- package/dist/twitter.js +245 -0
- package/dist/twitter.js.map +1 -0
- package/package.json +25 -0
- package/src/index.ts +4 -0
- package/src/instagram.ts +212 -0
- package/src/linkedin.ts +243 -0
- package/src/reddit.ts +268 -0
- package/src/twitter.ts +253 -0
- package/tests/instagram.test.ts +108 -0
- package/tests/linkedin.test.ts +104 -0
- package/tests/reddit.test.ts +127 -0
- package/tests/twitter.test.ts +120 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
package/dist/twitter.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { defineConnector } from '@auxiora/connectors';
|
|
2
|
+
async function twitterFetch(token, path, options) {
|
|
3
|
+
const res = await fetch(`https://api.twitter.com/2${path}`, {
|
|
4
|
+
method: options?.method ?? 'GET',
|
|
5
|
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
6
|
+
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
7
|
+
});
|
|
8
|
+
if (!res.ok)
|
|
9
|
+
throw new Error(`Twitter API error: ${res.status} ${await res.text().catch(() => res.statusText)}`);
|
|
10
|
+
return res.json();
|
|
11
|
+
}
|
|
12
|
+
async function getMyUserId(token) {
|
|
13
|
+
const res = await twitterFetch(token, '/users/me');
|
|
14
|
+
const data = res.data;
|
|
15
|
+
return data.id;
|
|
16
|
+
}
|
|
17
|
+
export const twitterConnector = defineConnector({
|
|
18
|
+
id: 'twitter',
|
|
19
|
+
name: 'Twitter / X',
|
|
20
|
+
description: 'Integration with Twitter/X for tweets, mentions, and direct messages',
|
|
21
|
+
version: '1.0.0',
|
|
22
|
+
category: 'social',
|
|
23
|
+
icon: 'twitter',
|
|
24
|
+
auth: {
|
|
25
|
+
type: 'oauth2',
|
|
26
|
+
oauth2: {
|
|
27
|
+
authUrl: 'https://twitter.com/i/oauth2/authorize',
|
|
28
|
+
tokenUrl: 'https://api.twitter.com/2/oauth2/token',
|
|
29
|
+
scopes: ['tweet.read', 'tweet.write', 'users.read', 'dm.read', 'dm.write', 'offline.access'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
actions: [
|
|
33
|
+
{
|
|
34
|
+
id: 'timeline-read',
|
|
35
|
+
name: 'Read Timeline',
|
|
36
|
+
description: 'Read the authenticated user timeline',
|
|
37
|
+
trustMinimum: 1,
|
|
38
|
+
trustDomain: 'messaging',
|
|
39
|
+
reversible: false,
|
|
40
|
+
sideEffects: false,
|
|
41
|
+
params: {},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'mentions-list',
|
|
45
|
+
name: 'List Mentions',
|
|
46
|
+
description: 'List recent mentions of the authenticated user',
|
|
47
|
+
trustMinimum: 1,
|
|
48
|
+
trustDomain: 'messaging',
|
|
49
|
+
reversible: false,
|
|
50
|
+
sideEffects: false,
|
|
51
|
+
params: {},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'post-tweet',
|
|
55
|
+
name: 'Post Tweet',
|
|
56
|
+
description: 'Post a new tweet',
|
|
57
|
+
trustMinimum: 3,
|
|
58
|
+
trustDomain: 'messaging',
|
|
59
|
+
reversible: false,
|
|
60
|
+
sideEffects: true,
|
|
61
|
+
params: {
|
|
62
|
+
text: { type: 'string', description: 'Tweet text', required: true },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'reply-tweet',
|
|
67
|
+
name: 'Reply to Tweet',
|
|
68
|
+
description: 'Reply to an existing tweet',
|
|
69
|
+
trustMinimum: 3,
|
|
70
|
+
trustDomain: 'messaging',
|
|
71
|
+
reversible: false,
|
|
72
|
+
sideEffects: true,
|
|
73
|
+
params: {
|
|
74
|
+
tweetId: { type: 'string', description: 'Tweet ID to reply to', required: true },
|
|
75
|
+
text: { type: 'string', description: 'Reply text', required: true },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'delete-tweet',
|
|
80
|
+
name: 'Delete Tweet',
|
|
81
|
+
description: 'Delete an existing tweet',
|
|
82
|
+
trustMinimum: 3,
|
|
83
|
+
trustDomain: 'messaging',
|
|
84
|
+
reversible: false,
|
|
85
|
+
sideEffects: true,
|
|
86
|
+
params: {
|
|
87
|
+
tweetId: { type: 'string', description: 'Tweet ID to delete', required: true },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'search-tweets',
|
|
92
|
+
name: 'Search Tweets',
|
|
93
|
+
description: 'Search for tweets matching a query',
|
|
94
|
+
trustMinimum: 1,
|
|
95
|
+
trustDomain: 'messaging',
|
|
96
|
+
reversible: false,
|
|
97
|
+
sideEffects: false,
|
|
98
|
+
params: {
|
|
99
|
+
query: { type: 'string', description: 'Search query', required: true },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 'dm-list',
|
|
104
|
+
name: 'List Direct Messages',
|
|
105
|
+
description: 'List recent direct messages',
|
|
106
|
+
trustMinimum: 1,
|
|
107
|
+
trustDomain: 'messaging',
|
|
108
|
+
reversible: false,
|
|
109
|
+
sideEffects: false,
|
|
110
|
+
params: {},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'dm-send',
|
|
114
|
+
name: 'Send Direct Message',
|
|
115
|
+
description: 'Send a direct message to a user',
|
|
116
|
+
trustMinimum: 3,
|
|
117
|
+
trustDomain: 'messaging',
|
|
118
|
+
reversible: false,
|
|
119
|
+
sideEffects: true,
|
|
120
|
+
params: {
|
|
121
|
+
recipientId: { type: 'string', description: 'Recipient user ID', required: true },
|
|
122
|
+
text: { type: 'string', description: 'Message text', required: true },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
triggers: [
|
|
127
|
+
{
|
|
128
|
+
id: 'new-mention',
|
|
129
|
+
name: 'New Mention',
|
|
130
|
+
description: 'Triggered when the user is mentioned in a tweet',
|
|
131
|
+
type: 'poll',
|
|
132
|
+
pollIntervalMs: 60_000,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'new-dm',
|
|
136
|
+
name: 'New Direct Message',
|
|
137
|
+
description: 'Triggered when a new direct message is received',
|
|
138
|
+
type: 'poll',
|
|
139
|
+
pollIntervalMs: 120_000,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
entities: [
|
|
143
|
+
{
|
|
144
|
+
id: 'tweet',
|
|
145
|
+
name: 'Tweet',
|
|
146
|
+
description: 'A tweet on Twitter/X',
|
|
147
|
+
fields: { id: 'string', text: 'string', authorId: 'string', createdAt: 'string', likeCount: 'number', retweetCount: 'number' },
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'direct-message',
|
|
151
|
+
name: 'Direct Message',
|
|
152
|
+
description: 'A direct message on Twitter/X',
|
|
153
|
+
fields: { id: 'string', text: 'string', senderId: 'string', createdAt: 'string' },
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
async executeAction(actionId, params, token) {
|
|
157
|
+
switch (actionId) {
|
|
158
|
+
case 'timeline-read': {
|
|
159
|
+
const userId = await getMyUserId(token);
|
|
160
|
+
const res = await twitterFetch(token, `/users/${userId}/timelines/reverse_chronological`);
|
|
161
|
+
return { tweets: res.data };
|
|
162
|
+
}
|
|
163
|
+
case 'mentions-list': {
|
|
164
|
+
const userId = await getMyUserId(token);
|
|
165
|
+
const res = await twitterFetch(token, `/users/${userId}/mentions`);
|
|
166
|
+
return { mentions: res.data };
|
|
167
|
+
}
|
|
168
|
+
case 'post-tweet': {
|
|
169
|
+
const res = await twitterFetch(token, '/tweets', {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
body: { text: params.text },
|
|
172
|
+
});
|
|
173
|
+
const data = res.data;
|
|
174
|
+
return { tweetId: data.id, status: 'posted' };
|
|
175
|
+
}
|
|
176
|
+
case 'reply-tweet': {
|
|
177
|
+
const res = await twitterFetch(token, '/tweets', {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
body: { text: params.text, reply: { in_reply_to_tweet_id: params.tweetId } },
|
|
180
|
+
});
|
|
181
|
+
const data = res.data;
|
|
182
|
+
return { tweetId: data.id, status: 'replied' };
|
|
183
|
+
}
|
|
184
|
+
case 'delete-tweet': {
|
|
185
|
+
await twitterFetch(token, `/tweets/${params.tweetId}`, { method: 'DELETE' });
|
|
186
|
+
return { tweetId: params.tweetId, status: 'deleted' };
|
|
187
|
+
}
|
|
188
|
+
case 'search-tweets': {
|
|
189
|
+
const query = encodeURIComponent(params.query);
|
|
190
|
+
const res = await twitterFetch(token, `/tweets/search/recent?query=${query}`);
|
|
191
|
+
return { tweets: res.data };
|
|
192
|
+
}
|
|
193
|
+
case 'dm-list': {
|
|
194
|
+
const res = await twitterFetch(token, '/dm_events');
|
|
195
|
+
return { messages: res.data };
|
|
196
|
+
}
|
|
197
|
+
case 'dm-send': {
|
|
198
|
+
const res = await twitterFetch(token, `/dm_conversations/with/${params.recipientId}/messages`, {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
body: { text: params.text },
|
|
201
|
+
});
|
|
202
|
+
const data = res.data;
|
|
203
|
+
return { messageId: data.dm_event_id ?? data.id, status: 'sent' };
|
|
204
|
+
}
|
|
205
|
+
default:
|
|
206
|
+
throw new Error(`Unknown action: ${actionId}`);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
async pollTrigger(triggerId, token, lastPollAt) {
|
|
210
|
+
switch (triggerId) {
|
|
211
|
+
case 'new-mention': {
|
|
212
|
+
const userId = await getMyUserId(token);
|
|
213
|
+
const startTime = lastPollAt ? new Date(lastPollAt).toISOString() : undefined;
|
|
214
|
+
const query = startTime ? `?start_time=${startTime}` : '';
|
|
215
|
+
const res = await twitterFetch(token, `/users/${userId}/mentions${query}`);
|
|
216
|
+
const mentions = (res.data ?? []);
|
|
217
|
+
return mentions.map((m) => ({
|
|
218
|
+
triggerId: 'new-mention',
|
|
219
|
+
connectorId: 'twitter',
|
|
220
|
+
data: m,
|
|
221
|
+
timestamp: m.created_at ? new Date(m.created_at).getTime() : Date.now(),
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
case 'new-dm': {
|
|
225
|
+
const res = await twitterFetch(token, '/dm_events?event_types=MessageCreate');
|
|
226
|
+
const events = (res.data ?? []);
|
|
227
|
+
const cutoff = lastPollAt ?? 0;
|
|
228
|
+
return events
|
|
229
|
+
.filter((e) => {
|
|
230
|
+
const ts = e.created_at ? new Date(e.created_at).getTime() : 0;
|
|
231
|
+
return ts > cutoff;
|
|
232
|
+
})
|
|
233
|
+
.map((e) => ({
|
|
234
|
+
triggerId: 'new-dm',
|
|
235
|
+
connectorId: 'twitter',
|
|
236
|
+
data: e,
|
|
237
|
+
timestamp: e.created_at ? new Date(e.created_at).getTime() : Date.now(),
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
default:
|
|
241
|
+
return [];
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
//# sourceMappingURL=twitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twitter.js","sourceRoot":"","sources":["../src/twitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,IAAY,EAAE,OAA6C;IACpG,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,4BAA4B,IAAI,EAAE,EAAE;QAC1D,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,KAAK;QAChC,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QACnF,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/D,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjH,OAAO,GAAG,CAAC,IAAI,EAAsC,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAa;IACtC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;IACjD,OAAO,IAAI,CAAC,EAAY,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC;IAC9C,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,sEAAsE;IACnF,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,SAAS;IAEf,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE;YACN,OAAO,EAAE,wCAAwC;YACjD,QAAQ,EAAE,wCAAwC;YAClD,MAAM,EAAE,CAAC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,CAAC;SAC7F;KACF;IAED,OAAO,EAAE;QACP;YACE,EAAE,EAAE,eAAe;YACnB,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,sCAAsC;YACnD,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,EAAE;SACX;QACD;YACE,EAAE,EAAE,eAAe;YACnB,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,gDAAgD;YAC7D,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,EAAE;SACX;QACD;YACE,EAAE,EAAE,YAAY;YAChB,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,kBAAkB;YAC/B,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE;aACpE;SACF;QACD;YACE,EAAE,EAAE,aAAa;YACjB,IAAI,EAAE,gBAAgB;YACtB,WAAW,EAAE,4BAA4B;YACzC,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAChF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE;aACpE;SACF;QACD;YACE,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,0BAA0B;YACvC,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE;aAC/E;SACF;QACD;YACE,EAAE,EAAE,eAAe;YACnB,IAAI,EAAE,eAAe;YACrB,WAAW,EAAE,oCAAoC;YACjD,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE;gBACN,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE;aACvE;SACF;QACD;YACE,EAAE,EAAE,SAAS;YACb,IAAI,EAAE,sBAAsB;YAC5B,WAAW,EAAE,6BAA6B;YAC1C,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,EAAE;SACX;QACD;YACE,EAAE,EAAE,SAAS;YACb,IAAI,EAAE,qBAAqB;YAC3B,WAAW,EAAE,iCAAiC;YAC9C,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE;gBACN,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE;gBACjF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE;aACtE;SACF;KACF;IAED,QAAQ,EAAE;QACR;YACE,EAAE,EAAE,aAAa;YACjB,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,iDAAiD;YAC9D,IAAI,EAAE,MAAM;YACZ,cAAc,EAAE,MAAM;SACvB;QACD;YACE,EAAE,EAAE,QAAQ;YACZ,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EAAE,iDAAiD;YAC9D,IAAI,EAAE,MAAM;YACZ,cAAc,EAAE,OAAO;SACxB;KACF;IAED,QAAQ,EAAE;QACR;YACE,EAAE,EAAE,OAAO;YACX,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,sBAAsB;YACnC,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE;SAC/H;QACD;YACE,EAAE,EAAE,gBAAgB;YACpB,IAAI,EAAE,gBAAgB;YACtB,WAAW,EAAE,+BAA+B;YAC5C,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE;SAClF;KACF;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,MAA+B,EAAE,KAAa;QAClF,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,UAAU,MAAM,kCAAkC,CAAC,CAAC;gBAC1F,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,CAAC;YACD,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,UAAU,MAAM,WAAW,CAAC,CAAC;gBACnE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;YAChC,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE;oBAC/C,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;iBAC5B,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;gBACjD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;YAChD,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE;oBAC/C,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,oBAAoB,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE;iBAC7E,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;gBACjD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACjD,CAAC;YACD,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,MAAM,YAAY,CAAC,KAAK,EAAE,WAAW,MAAM,CAAC,OAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvF,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACxD,CAAC;YACD,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,KAAe,CAAC,CAAC;gBACzD,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,+BAA+B,KAAK,EAAE,CAAC,CAAC;gBAC9E,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;YAC9B,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;gBACpD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;YAChC,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,0BAA0B,MAAM,CAAC,WAAqB,WAAW,EAAE;oBACvG,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;iBAC5B,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;gBACjD,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YACpE,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,KAAa,EAAE,UAAmB;QACrE,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC9E,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1D,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,UAAU,MAAM,YAAY,KAAK,EAAE,CAAC,CAAC;gBAC3E,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAmC,CAAC;gBACpE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC1B,SAAS,EAAE,aAAa;oBACxB,WAAW,EAAE,SAAS;oBACtB,IAAI,EAAE,CAAC;oBACP,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;iBAClF,CAAC,CAAC,CAAC;YACN,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,sCAAsC,CAAC,CAAC;gBAC9E,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAmC,CAAC;gBAClE,MAAM,MAAM,GAAG,UAAU,IAAI,CAAC,CAAC;gBAC/B,OAAO,MAAM;qBACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;oBACZ,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oBACzE,OAAO,EAAE,GAAG,MAAM,CAAC;gBACrB,CAAC,CAAC;qBACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACX,SAAS,EAAE,QAAQ;oBACnB,WAAW,EAAE,SAAS;oBACtB,IAAI,EAAE,CAAC;oBACP,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;iBAClF,CAAC,CAAC,CAAC;YACR,CAAC;YACD;gBACE,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auxiora/connector-social",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Social media connectors: Twitter/X, LinkedIn, Reddit, Instagram",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@auxiora/connectors": "1.0.0"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22.0.0"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"clean": "rm -rf dist",
|
|
23
|
+
"typecheck": "tsc --noEmit"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/index.ts
ADDED
package/src/instagram.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { defineConnector } from '@auxiora/connectors';
|
|
2
|
+
import type { TriggerEvent } from '@auxiora/connectors';
|
|
3
|
+
|
|
4
|
+
async function instagramFetch(token: string, path: string, options?: { method?: string; body?: unknown }) {
|
|
5
|
+
const url = new URL(`https://graph.instagram.com${path}`);
|
|
6
|
+
if (!options?.method || options.method === 'GET') {
|
|
7
|
+
url.searchParams.set('access_token', token);
|
|
8
|
+
}
|
|
9
|
+
const res = await fetch(url.toString(), {
|
|
10
|
+
method: options?.method ?? 'GET',
|
|
11
|
+
headers: options?.body ? { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } : { 'Authorization': `Bearer ${token}` },
|
|
12
|
+
body: options?.body ? JSON.stringify(options.body) : undefined,
|
|
13
|
+
});
|
|
14
|
+
if (!res.ok) throw new Error(`Instagram API error: ${res.status} ${await res.text().catch(() => res.statusText)}`);
|
|
15
|
+
return res.json() as Promise<Record<string, unknown>>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const instagramConnector = defineConnector({
|
|
19
|
+
id: 'instagram',
|
|
20
|
+
name: 'Instagram',
|
|
21
|
+
description: 'Integration with Instagram for posts, stories, and direct messages',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
category: 'social',
|
|
24
|
+
icon: 'instagram',
|
|
25
|
+
|
|
26
|
+
auth: {
|
|
27
|
+
type: 'oauth2',
|
|
28
|
+
oauth2: {
|
|
29
|
+
authUrl: 'https://api.instagram.com/oauth/authorize',
|
|
30
|
+
tokenUrl: 'https://api.instagram.com/oauth/access_token',
|
|
31
|
+
scopes: ['user_profile', 'user_media', 'instagram_basic', 'instagram_manage_messages'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
actions: [
|
|
36
|
+
{
|
|
37
|
+
id: 'feed-read',
|
|
38
|
+
name: 'Read Feed',
|
|
39
|
+
description: 'Read the Instagram feed',
|
|
40
|
+
trustMinimum: 1,
|
|
41
|
+
trustDomain: 'messaging',
|
|
42
|
+
reversible: false,
|
|
43
|
+
sideEffects: false,
|
|
44
|
+
params: {},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'stories-read',
|
|
48
|
+
name: 'Read Stories',
|
|
49
|
+
description: 'Read Instagram stories',
|
|
50
|
+
trustMinimum: 1,
|
|
51
|
+
trustDomain: 'messaging',
|
|
52
|
+
reversible: false,
|
|
53
|
+
sideEffects: false,
|
|
54
|
+
params: {},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'dm-list',
|
|
58
|
+
name: 'List Direct Messages',
|
|
59
|
+
description: 'List Instagram direct messages',
|
|
60
|
+
trustMinimum: 1,
|
|
61
|
+
trustDomain: 'messaging',
|
|
62
|
+
reversible: false,
|
|
63
|
+
sideEffects: false,
|
|
64
|
+
params: {},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'dm-send',
|
|
68
|
+
name: 'Send Direct Message',
|
|
69
|
+
description: 'Send an Instagram direct message',
|
|
70
|
+
trustMinimum: 3,
|
|
71
|
+
trustDomain: 'messaging',
|
|
72
|
+
reversible: false,
|
|
73
|
+
sideEffects: true,
|
|
74
|
+
params: {
|
|
75
|
+
recipientId: { type: 'string', description: 'Recipient user ID', required: true },
|
|
76
|
+
text: { type: 'string', description: 'Message text', required: true },
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'post-schedule',
|
|
81
|
+
name: 'Schedule Post',
|
|
82
|
+
description: 'Schedule a post on Instagram',
|
|
83
|
+
trustMinimum: 3,
|
|
84
|
+
trustDomain: 'messaging',
|
|
85
|
+
reversible: false,
|
|
86
|
+
sideEffects: true,
|
|
87
|
+
params: {
|
|
88
|
+
caption: { type: 'string', description: 'Post caption', required: true },
|
|
89
|
+
mediaUrl: { type: 'string', description: 'Media URL', required: true },
|
|
90
|
+
scheduledAt: { type: 'string', description: 'Scheduled time (ISO 8601)' },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'profile-get',
|
|
95
|
+
name: 'Get Profile',
|
|
96
|
+
description: 'Get an Instagram profile',
|
|
97
|
+
trustMinimum: 1,
|
|
98
|
+
trustDomain: 'messaging',
|
|
99
|
+
reversible: false,
|
|
100
|
+
sideEffects: false,
|
|
101
|
+
params: {
|
|
102
|
+
userId: { type: 'string', description: 'User ID (default: authenticated user)' },
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
|
|
107
|
+
triggers: [
|
|
108
|
+
{
|
|
109
|
+
id: 'new-dm',
|
|
110
|
+
name: 'New Direct Message',
|
|
111
|
+
description: 'Triggered when a new direct message is received',
|
|
112
|
+
type: 'poll',
|
|
113
|
+
pollIntervalMs: 120_000,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'new-comment',
|
|
117
|
+
name: 'New Comment',
|
|
118
|
+
description: 'Triggered when a new comment is posted on your content',
|
|
119
|
+
type: 'poll',
|
|
120
|
+
pollIntervalMs: 300_000,
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
|
|
124
|
+
entities: [
|
|
125
|
+
{
|
|
126
|
+
id: 'post',
|
|
127
|
+
name: 'Post',
|
|
128
|
+
description: 'An Instagram post',
|
|
129
|
+
fields: { id: 'string', caption: 'string', mediaUrl: 'string', likeCount: 'number', commentCount: 'number' },
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'story',
|
|
133
|
+
name: 'Story',
|
|
134
|
+
description: 'An Instagram story',
|
|
135
|
+
fields: { id: 'string', mediaUrl: 'string', expiresAt: 'string' },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
|
|
139
|
+
async executeAction(actionId: string, params: Record<string, unknown>, token: string): Promise<unknown> {
|
|
140
|
+
switch (actionId) {
|
|
141
|
+
case 'feed-read': {
|
|
142
|
+
const res = await instagramFetch(token, '/me/media?fields=id,caption,media_url,timestamp,like_count,comments_count');
|
|
143
|
+
return { posts: res.data };
|
|
144
|
+
}
|
|
145
|
+
case 'stories-read': {
|
|
146
|
+
const res = await instagramFetch(token, '/me/stories?fields=id,media_url,timestamp');
|
|
147
|
+
return { stories: res.data };
|
|
148
|
+
}
|
|
149
|
+
case 'dm-list': {
|
|
150
|
+
return { messages: [], note: 'Instagram Messaging API requires approved app access' };
|
|
151
|
+
}
|
|
152
|
+
case 'dm-send': {
|
|
153
|
+
return { error: 'Instagram Messaging API requires approved app access', status: 'unavailable' };
|
|
154
|
+
}
|
|
155
|
+
case 'post-schedule': {
|
|
156
|
+
// Step 1: Create media container
|
|
157
|
+
const container = await instagramFetch(token, '/me/media', {
|
|
158
|
+
method: 'POST',
|
|
159
|
+
body: {
|
|
160
|
+
caption: params.caption,
|
|
161
|
+
image_url: params.mediaUrl,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
const creationId = container.id as string;
|
|
165
|
+
// Step 2: Publish the media
|
|
166
|
+
const published = await instagramFetch(token, '/me/media_publish', {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
body: { creation_id: creationId },
|
|
169
|
+
});
|
|
170
|
+
return { postId: published.id, status: 'published' };
|
|
171
|
+
}
|
|
172
|
+
case 'profile-get': {
|
|
173
|
+
const userId = (params.userId as string | undefined) ?? 'me';
|
|
174
|
+
const fields = 'id,username,name,biography,media_count,followers_count,follows_count';
|
|
175
|
+
const res = await instagramFetch(token, `/${userId}?fields=${fields}`);
|
|
176
|
+
return res;
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
throw new Error(`Unknown action: ${actionId}`);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
async pollTrigger(triggerId: string, token: string, lastPollAt?: number): Promise<TriggerEvent[]> {
|
|
184
|
+
switch (triggerId) {
|
|
185
|
+
case 'new-dm':
|
|
186
|
+
// Instagram Messaging API requires approved access
|
|
187
|
+
return [];
|
|
188
|
+
case 'new-comment': {
|
|
189
|
+
const media = await instagramFetch(token, '/me/media?fields=id&limit=10');
|
|
190
|
+
const posts = (media.data ?? []) as Array<Record<string, unknown>>;
|
|
191
|
+
const events: TriggerEvent[] = [];
|
|
192
|
+
const since = lastPollAt ? new Date(lastPollAt).toISOString() : undefined;
|
|
193
|
+
for (const post of posts) {
|
|
194
|
+
const sinceParam = since ? `&since=${since}` : '';
|
|
195
|
+
const commentsRes = await instagramFetch(token, `/${post.id as string}/comments?fields=id,text,username,timestamp${sinceParam}`);
|
|
196
|
+
const comments = (commentsRes.data ?? []) as Array<Record<string, unknown>>;
|
|
197
|
+
for (const comment of comments) {
|
|
198
|
+
events.push({
|
|
199
|
+
triggerId: 'new-comment',
|
|
200
|
+
connectorId: 'instagram',
|
|
201
|
+
data: { ...comment, mediaId: post.id },
|
|
202
|
+
timestamp: comment.timestamp ? new Date(comment.timestamp as string).getTime() : Date.now(),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return events;
|
|
207
|
+
}
|
|
208
|
+
default:
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
});
|