@cogitator-ai/channels 0.9.3 → 0.10.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.
Files changed (102) hide show
  1. package/README.md +101 -11
  2. package/dist/assistant-config.d.ts +16 -0
  3. package/dist/assistant-config.d.ts.map +1 -1
  4. package/dist/assistant-config.js +22 -0
  5. package/dist/assistant-config.js.map +1 -1
  6. package/dist/channels/bluesky/account.d.ts +18 -0
  7. package/dist/channels/bluesky/account.d.ts.map +1 -0
  8. package/dist/channels/bluesky/account.js +25 -0
  9. package/dist/channels/bluesky/account.js.map +1 -0
  10. package/dist/channels/bluesky/channel.d.ts +89 -0
  11. package/dist/channels/bluesky/channel.d.ts.map +1 -0
  12. package/dist/channels/bluesky/channel.js +427 -0
  13. package/dist/channels/bluesky/channel.js.map +1 -0
  14. package/dist/channels/bluesky/config.d.ts +16 -0
  15. package/dist/channels/bluesky/config.d.ts.map +1 -0
  16. package/dist/channels/bluesky/config.js +2 -0
  17. package/dist/channels/bluesky/config.js.map +1 -0
  18. package/dist/channels/bluesky/connection.d.ts +40 -0
  19. package/dist/channels/bluesky/connection.d.ts.map +1 -0
  20. package/dist/channels/bluesky/connection.js +159 -0
  21. package/dist/channels/bluesky/connection.js.map +1 -0
  22. package/dist/channels/bluesky/feed.d.ts +59 -0
  23. package/dist/channels/bluesky/feed.d.ts.map +1 -0
  24. package/dist/channels/bluesky/feed.js +324 -0
  25. package/dist/channels/bluesky/feed.js.map +1 -0
  26. package/dist/channels/bluesky/index.d.ts +5 -0
  27. package/dist/channels/bluesky/index.d.ts.map +1 -0
  28. package/dist/channels/bluesky/index.js +4 -0
  29. package/dist/channels/bluesky/index.js.map +1 -0
  30. package/dist/channels/threads/account.d.ts +42 -0
  31. package/dist/channels/threads/account.d.ts.map +1 -0
  32. package/dist/channels/threads/account.js +64 -0
  33. package/dist/channels/threads/account.js.map +1 -0
  34. package/dist/channels/threads/channel.d.ts +119 -0
  35. package/dist/channels/threads/channel.d.ts.map +1 -0
  36. package/dist/channels/threads/channel.js +405 -0
  37. package/dist/channels/threads/channel.js.map +1 -0
  38. package/dist/channels/threads/client.d.ts +42 -0
  39. package/dist/channels/threads/client.d.ts.map +1 -0
  40. package/dist/channels/threads/client.js +97 -0
  41. package/dist/channels/threads/client.js.map +1 -0
  42. package/dist/channels/threads/feed.d.ts +74 -0
  43. package/dist/channels/threads/feed.d.ts.map +1 -0
  44. package/dist/channels/threads/feed.js +372 -0
  45. package/dist/channels/threads/feed.js.map +1 -0
  46. package/dist/channels/threads/index.d.ts +6 -0
  47. package/dist/channels/threads/index.d.ts.map +1 -0
  48. package/dist/channels/threads/index.js +6 -0
  49. package/dist/channels/threads/index.js.map +1 -0
  50. package/dist/channels/threads/token.d.ts +51 -0
  51. package/dist/channels/threads/token.d.ts.map +1 -0
  52. package/dist/channels/threads/token.js +128 -0
  53. package/dist/channels/threads/token.js.map +1 -0
  54. package/dist/feeds/attachments.d.ts +15 -0
  55. package/dist/feeds/attachments.d.ts.map +1 -0
  56. package/dist/feeds/attachments.js +85 -0
  57. package/dist/feeds/attachments.js.map +1 -0
  58. package/dist/feeds/errors.d.ts +39 -0
  59. package/dist/feeds/errors.d.ts.map +1 -0
  60. package/dist/feeds/errors.js +62 -0
  61. package/dist/feeds/errors.js.map +1 -0
  62. package/dist/feeds/index.d.ts +8 -0
  63. package/dist/feeds/index.d.ts.map +1 -0
  64. package/dist/feeds/index.js +6 -0
  65. package/dist/feeds/index.js.map +1 -0
  66. package/dist/feeds/publish-store.d.ts +148 -0
  67. package/dist/feeds/publish-store.d.ts.map +1 -0
  68. package/dist/feeds/publish-store.js +345 -0
  69. package/dist/feeds/publish-store.js.map +1 -0
  70. package/dist/feeds/publisher.d.ts +118 -0
  71. package/dist/feeds/publisher.d.ts.map +1 -0
  72. package/dist/feeds/publisher.js +308 -0
  73. package/dist/feeds/publisher.js.map +1 -0
  74. package/dist/feeds/storage.d.ts +33 -0
  75. package/dist/feeds/storage.d.ts.map +1 -0
  76. package/dist/feeds/storage.js +61 -0
  77. package/dist/feeds/storage.js.map +1 -0
  78. package/dist/feeds/text.d.ts +26 -0
  79. package/dist/feeds/text.d.ts.map +1 -0
  80. package/dist/feeds/text.js +126 -0
  81. package/dist/feeds/text.js.map +1 -0
  82. package/dist/feeds/token-store.d.ts +45 -0
  83. package/dist/feeds/token-store.d.ts.map +1 -0
  84. package/dist/feeds/token-store.js +128 -0
  85. package/dist/feeds/token-store.js.map +1 -0
  86. package/dist/formatters/markdown.d.ts.map +1 -1
  87. package/dist/formatters/markdown.js +6 -0
  88. package/dist/formatters/markdown.js.map +1 -1
  89. package/dist/formatters/plain-text.d.ts +7 -0
  90. package/dist/formatters/plain-text.d.ts.map +1 -0
  91. package/dist/formatters/plain-text.js +38 -0
  92. package/dist/formatters/plain-text.js.map +1 -0
  93. package/dist/gateway.js +1 -1
  94. package/dist/gateway.js.map +1 -1
  95. package/dist/index.d.ts +5 -1
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +4 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/runtime-builder.d.ts.map +1 -1
  100. package/dist/runtime-builder.js +54 -0
  101. package/dist/runtime-builder.js.map +1 -1
  102. package/package.json +23 -15
@@ -0,0 +1,64 @@
1
+ import { nextPageQuery, ThreadsClient } from './client.js';
2
+ import { ThreadsTokenManager } from './token.js';
3
+ /**
4
+ * One Threads account: its API client and its long-lived token, kept fresh.
5
+ * Share it between `ThreadsFeed` and `ThreadsChannel` so they renew one
6
+ * token.
7
+ */
8
+ export class ThreadsAccount {
9
+ userId;
10
+ client;
11
+ tokens;
12
+ holders = new Set();
13
+ constructor(config) {
14
+ this.userId = config.userId ?? 'me';
15
+ this.client = new ThreadsClient({
16
+ ...(config.apiBase && { base: config.apiBase }),
17
+ ...(config.fetch && { fetch: config.fetch }),
18
+ });
19
+ this.tokens = new ThreadsTokenManager(this.client, config);
20
+ }
21
+ /**
22
+ * Loads the token, renewing it if due, and checks it daily while anyone
23
+ * holds the account. `holder` is who holds it, the caller unless said: a
24
+ * feed and a channel sharing the account each hold it.
25
+ */
26
+ async connect(holder = this) {
27
+ await this.tokens.token();
28
+ this.holders.add(holder);
29
+ this.tokens.start();
30
+ }
31
+ /** Lets `holder` go. The daily token check stops once no one holds the account. */
32
+ close(holder = this) {
33
+ this.holders.delete(holder);
34
+ if (this.holders.size === 0)
35
+ this.tokens.stop();
36
+ }
37
+ /** Renews the token now, whatever its age. */
38
+ async renewToken() {
39
+ await this.tokens.renew();
40
+ }
41
+ async get(path, params, signal) {
42
+ return this.client.get(path, await this.tokens.token(), params, signal);
43
+ }
44
+ /** The items of a listing, page by page, following its cursors for `maxPages` at most. */
45
+ async *pages(path, params, maxPages, signal) {
46
+ let query = params;
47
+ for (let page = 0; page < maxPages && query; page++) {
48
+ const response = await this.get(path, query, signal);
49
+ yield response.data ?? [];
50
+ query = nextPageQuery(response, query);
51
+ }
52
+ }
53
+ async post(path, params, signal) {
54
+ return this.client.post(path, await this.tokens.token(), params, signal);
55
+ }
56
+ async delete(path, signal) {
57
+ return this.client.delete(path, await this.tokens.token(), signal);
58
+ }
59
+ }
60
+ /** The account a feed or channel config names, or a new one for its token. */
61
+ export function threadsAccountOf(config) {
62
+ return 'account' in config ? config.account : new ThreadsAccount(config);
63
+ }
64
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../../../src/channels/threads/account.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import type { Attachment, Channel, ChannelMessage, SendOptions } from '@cogitator-ai/types';
2
+ import { type ThreadsAccount, type ThreadsAccountConfig } from './account.js';
3
+ export interface ThreadsWebhookConfig {
4
+ /** The app secret that signs Meta's deliveries. */
5
+ appSecret: string;
6
+ /** The verify token set for the callback URL in the app dashboard. */
7
+ verifyToken: string;
8
+ }
9
+ export type ThreadsChannelConfig = ({
10
+ account: ThreadsAccount;
11
+ } | ThreadsAccountConfig) & {
12
+ /**
13
+ * Takes replies and mentions from Meta's webhooks, on its own HTTP server
14
+ * when `port` is set, or through `handleWebhook` mounted in your server.
15
+ * Without it the channel polls.
16
+ */
17
+ webhook?: ThreadsWebhookConfig & {
18
+ port?: number;
19
+ path?: string;
20
+ host?: string;
21
+ };
22
+ /** How often to poll mentions and replies when there is no webhook, in ms (default 60 000). */
23
+ pollInterval?: number;
24
+ /** How many of the account's latest posts polling watches for replies (default 10). */
25
+ watchPosts?: number;
26
+ };
27
+ /** A webhook delivery, as any HTTP server hands it over. */
28
+ export interface ThreadsWebhookRequest {
29
+ method: string;
30
+ /** The query string parameters. */
31
+ query: Record<string, string | undefined>;
32
+ headers: Record<string, string | string[] | undefined>;
33
+ /** The body exactly as received, which the signature covers. */
34
+ rawBody?: string | Uint8Array;
35
+ }
36
+ export interface ThreadsWebhookResponse {
37
+ status: number;
38
+ body: string;
39
+ }
40
+ /** Whether `signature` (`sha256=<hex>`) is the HMAC of `body` with `secret`. */
41
+ export declare function verifyThreadsSignature(body: string | Uint8Array, signature: string | undefined, secret: string): boolean;
42
+ /**
43
+ * A conversational Threads channel: an agent answers replies to the
44
+ * account's posts and mentions of it, under the post it answers. Replies and
45
+ * mentions come from Meta's webhooks (signed with the app secret) or, without
46
+ * them, from polling. Threads has no direct messages in its API and cannot
47
+ * edit posts, so answers are sent once finished, as several replies when
48
+ * long. A message's `channelId` is `post:<media id>` to answer under that
49
+ * post, or `feed` for a new post.
50
+ */
51
+ export declare class ThreadsChannel implements Channel {
52
+ readonly type = "threads";
53
+ readonly editable = false;
54
+ readonly nativeMarkdown = false;
55
+ readonly maxMessageChars: number;
56
+ readonly account: ThreadsAccount;
57
+ private readonly feed;
58
+ private readonly config;
59
+ private handler;
60
+ private readonly seen;
61
+ private readonly backlogs;
62
+ private mentionsAllowed;
63
+ private server?;
64
+ private timer?;
65
+ private polling?;
66
+ private identity?;
67
+ private username?;
68
+ private since;
69
+ private running;
70
+ constructor(config: ThreadsChannelConfig);
71
+ onMessage(handler: (msg: ChannelMessage) => Promise<void>): void;
72
+ start(): Promise<void>;
73
+ stop(): Promise<void>;
74
+ /**
75
+ * Answers a webhook request: the verification Meta sends when the callback
76
+ * URL is set, and signed deliveries of replies and mentions. Mount it in
77
+ * any HTTP server, with the raw body unparsed. It works before `start()`
78
+ * too: the first delivery loads the account's username, so the bot's own
79
+ * replies are skipped.
80
+ */
81
+ handleWebhook(request: ThreadsWebhookRequest): Promise<ThreadsWebhookResponse>;
82
+ /**
83
+ * Looks for new replies and mentions once. A started channel without
84
+ * webhooks polls on a timer. Of the conversations under the bot's latest
85
+ * posts it takes the replies to the bot's posts and the posts that mention
86
+ * it, not what people answer each other.
87
+ */
88
+ poll(): Promise<void>;
89
+ /**
90
+ * The bot's new mentions. An app without the `threads_manage_mentions`
91
+ * permission cannot read them: that is said once and mentions are left
92
+ * out from then on, while replies under the bot's posts are still read.
93
+ */
94
+ private pollMentions;
95
+ /**
96
+ * The posts of a listing that runs newest first, paging back until a page
97
+ * reaches a post already answered or older than the start, so a burst of
98
+ * replies between two polls is read in full. A burst longer than one poll
99
+ * reads is carried on from where this poll stopped by the next one, before
100
+ * that listing is read from its newest post again.
101
+ */
102
+ private newest;
103
+ sendText(channelId: string, text: string, options?: SendOptions): Promise<string>;
104
+ editText(): Promise<void>;
105
+ sendFile(channelId: string, file: Attachment, options?: SendOptions): Promise<string>;
106
+ sendTyping(): Promise<void>;
107
+ deleteMessage(_channelId: string, messageId: string): Promise<void>;
108
+ private receive;
109
+ /** Loads the account's username once, for telling its own posts and its mentions apart. */
110
+ private identify;
111
+ private isOwn;
112
+ private mentionsBot;
113
+ private stripMention;
114
+ private remember;
115
+ private listen;
116
+ }
117
+ /** A conversational Threads channel. */
118
+ export declare function threadsChannel(config: ThreadsChannelConfig): ThreadsChannel;
119
+ //# sourceMappingURL=channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/threads/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,405 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ import { createServer } from 'node:http';
3
+ import { FeedError } from '../../feeds/errors.js';
4
+ import { splitText, threadsLength } from '../../feeds/text.js';
5
+ import { threadsAccountOf } from './account.js';
6
+ import { nextPageQuery } from './client.js';
7
+ import { ThreadsFeed } from './feed.js';
8
+ const MAX_TRACKED = 1000;
9
+ const MAX_POLL_PAGES = 10;
10
+ const POST_LIMIT = 500;
11
+ const POST_FIELDS = 'id,text,username,timestamp,permalink,replied_to,root_post,is_reply';
12
+ /** A header by its name in any letter case, as HTTP header names are. */
13
+ function header(headers, name) {
14
+ const wanted = name.toLowerCase();
15
+ const key = Object.keys(headers).find((candidate) => candidate.toLowerCase() === wanted);
16
+ const value = key === undefined ? undefined : headers[key];
17
+ return Array.isArray(value) ? value[0] : value;
18
+ }
19
+ /** Whether `signature` (`sha256=<hex>`) is the HMAC of `body` with `secret`. */
20
+ export function verifyThreadsSignature(body, signature, secret) {
21
+ if (!signature?.startsWith('sha256='))
22
+ return false;
23
+ const expected = Buffer.from(createHmac('sha256', secret).update(body).digest('hex'));
24
+ const given = Buffer.from(signature.slice('sha256='.length));
25
+ return given.length === expected.length && timingSafeEqual(given, expected);
26
+ }
27
+ /** The posts a webhook payload carries, in Threads' shape or Meta's `entry` wrapping. */
28
+ function postsOf(payload) {
29
+ if (typeof payload !== 'object' || payload === null)
30
+ return [];
31
+ const record = payload;
32
+ const values = [];
33
+ const collect = (value) => {
34
+ if (Array.isArray(value))
35
+ value.forEach(collect);
36
+ else if (typeof value === 'object' && value !== null) {
37
+ const inner = value.value;
38
+ values.push(inner ?? value);
39
+ }
40
+ };
41
+ if (record.values)
42
+ collect(record.values);
43
+ if (Array.isArray(record.entry)) {
44
+ for (const entry of record.entry) {
45
+ if (typeof entry === 'object' && entry !== null) {
46
+ const { changes, values: entryValues } = entry;
47
+ if (changes)
48
+ collect(changes);
49
+ if (entryValues)
50
+ collect(entryValues);
51
+ }
52
+ }
53
+ }
54
+ return values.filter((value) => typeof value === 'object' && value !== null && typeof value.id === 'string');
55
+ }
56
+ /**
57
+ * A conversational Threads channel: an agent answers replies to the
58
+ * account's posts and mentions of it, under the post it answers. Replies and
59
+ * mentions come from Meta's webhooks (signed with the app secret) or, without
60
+ * them, from polling. Threads has no direct messages in its API and cannot
61
+ * edit posts, so answers are sent once finished, as several replies when
62
+ * long. A message's `channelId` is `post:<media id>` to answer under that
63
+ * post, or `feed` for a new post.
64
+ */
65
+ export class ThreadsChannel {
66
+ type = 'threads';
67
+ editable = false;
68
+ nativeMarkdown = false;
69
+ maxMessageChars = Infinity;
70
+ account;
71
+ feed;
72
+ config;
73
+ handler = null;
74
+ seen = new Map();
75
+ backlogs = new Map();
76
+ mentionsAllowed = true;
77
+ server;
78
+ timer;
79
+ polling;
80
+ identity;
81
+ username;
82
+ since = 0;
83
+ running = false;
84
+ constructor(config) {
85
+ this.config = config;
86
+ this.account = threadsAccountOf(config);
87
+ this.feed = new ThreadsFeed({ account: this.account });
88
+ }
89
+ onMessage(handler) {
90
+ this.handler = handler;
91
+ }
92
+ async start() {
93
+ if (this.running)
94
+ return;
95
+ await this.account.connect(this);
96
+ await this.identify();
97
+ this.since = Date.now();
98
+ this.running = true;
99
+ const webhook = this.config.webhook;
100
+ if (webhook?.port !== undefined) {
101
+ await this.listen(webhook.port, webhook.path ?? '/threads/webhook', webhook.host);
102
+ }
103
+ else if (!webhook) {
104
+ this.timer = setInterval(() => void this.poll(), this.config.pollInterval ?? 60_000);
105
+ }
106
+ }
107
+ async stop() {
108
+ this.running = false;
109
+ if (this.timer)
110
+ clearInterval(this.timer);
111
+ this.timer = undefined;
112
+ const server = this.server;
113
+ this.server = undefined;
114
+ if (server)
115
+ await new Promise((resolve) => server.close(() => resolve()));
116
+ await this.polling;
117
+ this.account.close(this);
118
+ }
119
+ /**
120
+ * Answers a webhook request: the verification Meta sends when the callback
121
+ * URL is set, and signed deliveries of replies and mentions. Mount it in
122
+ * any HTTP server, with the raw body unparsed. It works before `start()`
123
+ * too: the first delivery loads the account's username, so the bot's own
124
+ * replies are skipped.
125
+ */
126
+ async handleWebhook(request) {
127
+ const webhook = this.config.webhook;
128
+ if (!webhook)
129
+ return { status: 404, body: 'Webhooks are not configured' };
130
+ if (request.method === 'GET') {
131
+ const { 'hub.mode': mode, 'hub.verify_token': token, 'hub.challenge': challenge, } = request.query;
132
+ if (mode === 'subscribe' && token === webhook.verifyToken && challenge) {
133
+ return { status: 200, body: challenge };
134
+ }
135
+ return { status: 403, body: 'Verification failed' };
136
+ }
137
+ if (request.method !== 'POST')
138
+ return { status: 405, body: 'Method not allowed' };
139
+ const raw = request.rawBody ?? '';
140
+ if (!verifyThreadsSignature(raw, header(request.headers, 'x-hub-signature-256'), webhook.appSecret)) {
141
+ return { status: 401, body: 'Invalid signature' };
142
+ }
143
+ let payload;
144
+ try {
145
+ payload = JSON.parse(typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf-8'));
146
+ }
147
+ catch {
148
+ return { status: 400, body: 'Invalid JSON' };
149
+ }
150
+ try {
151
+ await this.identify();
152
+ }
153
+ catch (error) {
154
+ console.error('[threads] Could not load the account for a webhook delivery:', error);
155
+ return { status: 503, body: 'The account could not be loaded' };
156
+ }
157
+ void this.receive(postsOf(payload)).catch((error) => console.error('[threads] Webhook delivery failed:', error));
158
+ return { status: 200, body: 'OK' };
159
+ }
160
+ /**
161
+ * Looks for new replies and mentions once. A started channel without
162
+ * webhooks polls on a timer. Of the conversations under the bot's latest
163
+ * posts it takes the replies to the bot's posts and the posts that mention
164
+ * it, not what people answer each other.
165
+ */
166
+ poll() {
167
+ this.polling ??= (async () => {
168
+ try {
169
+ await this.identify();
170
+ const user = this.account.userId;
171
+ const mentions = await this.pollMentions(user);
172
+ const own = await this.account.get(`${user}/threads`, {
173
+ fields: 'id,timestamp',
174
+ limit: this.config.watchPosts ?? 10,
175
+ });
176
+ const conversations = [];
177
+ for (const post of own.data ?? []) {
178
+ conversations.push(...(await this.newest(`${post.id}/conversation`, {
179
+ fields: POST_FIELDS,
180
+ limit: 50,
181
+ reverse: true,
182
+ })));
183
+ }
184
+ const botPosts = new Set((own.data ?? []).map((post) => post.id));
185
+ for (const post of conversations)
186
+ if (this.isOwn(post))
187
+ botPosts.add(post.id);
188
+ const replies = conversations.filter((post) => (post.replied_to !== undefined && botPosts.has(post.replied_to.id)) ||
189
+ this.mentionsBot(post.text));
190
+ await this.receive([...mentions, ...replies].filter((post) => post.timestamp === undefined || Date.parse(post.timestamp) >= this.since));
191
+ }
192
+ catch (error) {
193
+ console.error('[threads] Polling failed:', error);
194
+ }
195
+ })().finally(() => {
196
+ this.polling = undefined;
197
+ });
198
+ return this.polling;
199
+ }
200
+ /**
201
+ * The bot's new mentions. An app without the `threads_manage_mentions`
202
+ * permission cannot read them: that is said once and mentions are left
203
+ * out from then on, while replies under the bot's posts are still read.
204
+ */
205
+ async pollMentions(user) {
206
+ if (!this.mentionsAllowed)
207
+ return [];
208
+ try {
209
+ return await this.newest(`${user}/mentions`, { fields: POST_FIELDS, limit: 25 });
210
+ }
211
+ catch (error) {
212
+ if (error instanceof FeedError && error.code === 'auth') {
213
+ this.mentionsAllowed = false;
214
+ console.warn(`[threads] Mentions are not read: the app lacks the threads_manage_mentions permission (${error.message})`);
215
+ }
216
+ else {
217
+ console.error('[threads] Reading mentions failed:', error);
218
+ }
219
+ return [];
220
+ }
221
+ }
222
+ /**
223
+ * The posts of a listing that runs newest first, paging back until a page
224
+ * reaches a post already answered or older than the start, so a burst of
225
+ * replies between two polls is read in full. A burst longer than one poll
226
+ * reads is carried on from where this poll stopped by the next one, before
227
+ * that listing is read from its newest post again.
228
+ */
229
+ async newest(path, params) {
230
+ const posts = [];
231
+ let query = this.backlogs.get(path) ?? params;
232
+ for (let page = 0; page < MAX_POLL_PAGES && query; page++) {
233
+ const response = await this.account.get(path, query);
234
+ const items = response.data ?? [];
235
+ posts.push(...items);
236
+ const reachedKnown = items.some((post) => this.seen.has(post.id) ||
237
+ (post.timestamp !== undefined && Date.parse(post.timestamp) < this.since));
238
+ query = reachedKnown ? undefined : nextPageQuery(response, query);
239
+ }
240
+ if (query) {
241
+ this.backlogs.set(path, query);
242
+ console.warn(`[threads] More new posts under ${path} than one poll reads: the next poll reads on`);
243
+ }
244
+ else {
245
+ this.backlogs.delete(path);
246
+ }
247
+ return posts;
248
+ }
249
+ async sendText(channelId, text, options) {
250
+ const target = parseTarget(channelId);
251
+ const parts = splitText(text, POST_LIMIT, threadsLength);
252
+ if (parts.length === 0)
253
+ throw new Error('[threads] Nothing to send');
254
+ let replyTo = options?.replyTo ?? target;
255
+ let first;
256
+ for (const part of parts) {
257
+ const published = await this.feed.publish({ text: part, ...(replyTo && { replyTo }) });
258
+ first ??= published.id;
259
+ replyTo = published.id;
260
+ }
261
+ return first ?? '';
262
+ }
263
+ editText() {
264
+ return Promise.reject(new Error('[threads] Threads posts cannot be edited'));
265
+ }
266
+ async sendFile(channelId, file, options) {
267
+ const replyTo = options?.replyTo ?? parseTarget(channelId);
268
+ const published = await this.feed.publish({
269
+ text: file.caption ?? '',
270
+ images: [{ image: file }],
271
+ ...(replyTo && { replyTo }),
272
+ });
273
+ return published.id;
274
+ }
275
+ async sendTyping() { }
276
+ async deleteMessage(_channelId, messageId) {
277
+ await this.feed.delete(messageId);
278
+ }
279
+ async receive(posts) {
280
+ const fresh = posts
281
+ .filter((post) => !this.isOwn(post))
282
+ .sort((a, b) => (a.timestamp ?? '').localeCompare(b.timestamp ?? ''));
283
+ for (const post of fresh) {
284
+ if (!this.remember(post.id) || !post.text?.trim() || !this.handler)
285
+ continue;
286
+ const root = post.root_post?.id ?? post.id;
287
+ const message = {
288
+ id: post.id,
289
+ channelType: this.type,
290
+ channelId: `post:${post.id}`,
291
+ userId: post.username ?? '',
292
+ ...(post.username && { userName: post.username }),
293
+ groupId: `thread:${root}`,
294
+ text: this.stripMention(post.text),
295
+ ...(post.replied_to && { replyTo: post.replied_to.id }),
296
+ raw: post,
297
+ };
298
+ try {
299
+ await this.handler(message);
300
+ }
301
+ catch (error) {
302
+ console.error('[threads] Message handler error:', error);
303
+ }
304
+ }
305
+ }
306
+ /** Loads the account's username once, for telling its own posts and its mentions apart. */
307
+ identify() {
308
+ this.identity ??= this.account
309
+ .get(this.account.userId, { fields: 'id,username' })
310
+ .then((me) => {
311
+ this.username = me.username;
312
+ })
313
+ .catch((error) => {
314
+ this.identity = undefined;
315
+ throw error;
316
+ });
317
+ return this.identity;
318
+ }
319
+ isOwn(post) {
320
+ return (this.username !== undefined && post.username?.toLowerCase() === this.username.toLowerCase());
321
+ }
322
+ mentionsBot(text) {
323
+ if (!this.username || !text)
324
+ return false;
325
+ const escaped = this.username.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
326
+ return new RegExp(`(^|[^\\w.@])@${escaped}(?![\\w]|\\.[\\w])`, 'iu').test(text);
327
+ }
328
+ stripMention(text) {
329
+ if (!this.username)
330
+ return text.trim();
331
+ const escaped = this.username.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
332
+ return text.replace(new RegExp(`^\\s*@${escaped}\\b[\\s,:]*`, 'i'), '').trim() || text.trim();
333
+ }
334
+ remember(id) {
335
+ if (this.seen.has(id))
336
+ return false;
337
+ this.seen.set(id, true);
338
+ if (this.seen.size > MAX_TRACKED) {
339
+ const oldest = this.seen.keys().next().value;
340
+ if (oldest !== undefined)
341
+ this.seen.delete(oldest);
342
+ }
343
+ return true;
344
+ }
345
+ listen(port, path, host) {
346
+ const server = createServer((req, res) => {
347
+ const url = new URL(req.url ?? '/', 'http://localhost');
348
+ if (url.pathname !== path) {
349
+ res.writeHead(404).end();
350
+ return;
351
+ }
352
+ readBody(req)
353
+ .then((rawBody) => this.handleWebhook({
354
+ method: req.method ?? 'GET',
355
+ query: Object.fromEntries(url.searchParams),
356
+ headers: req.headers,
357
+ rawBody,
358
+ }))
359
+ .then((response) => res.writeHead(response.status, { 'content-type': 'text/plain' }).end(response.body))
360
+ .catch((error) => {
361
+ console.error('[threads] Webhook request failed:', error);
362
+ res.writeHead(500).end();
363
+ });
364
+ });
365
+ this.server = server;
366
+ return new Promise((resolve, reject) => {
367
+ server.once('error', reject);
368
+ server.listen(port, host, () => {
369
+ server.off('error', reject);
370
+ resolve();
371
+ });
372
+ });
373
+ }
374
+ }
375
+ const MAX_BODY = 1024 * 1024;
376
+ function readBody(req) {
377
+ return new Promise((resolve, reject) => {
378
+ const chunks = [];
379
+ let size = 0;
380
+ req.on('data', (chunk) => {
381
+ size += chunk.length;
382
+ if (size > MAX_BODY) {
383
+ reject(new Error('Webhook body too large'));
384
+ req.destroy();
385
+ return;
386
+ }
387
+ chunks.push(chunk);
388
+ });
389
+ req.on('end', () => resolve(Buffer.concat(chunks)));
390
+ req.on('error', reject);
391
+ });
392
+ }
393
+ /** The post a `channelId` answers under, or none for a new post. */
394
+ function parseTarget(channelId) {
395
+ if (channelId === 'feed')
396
+ return undefined;
397
+ if (channelId.startsWith('post:'))
398
+ return channelId.slice(5);
399
+ throw new Error(`[threads] Unknown channel id "${channelId}": use post:<media id> or feed`);
400
+ }
401
+ /** A conversational Threads channel. */
402
+ export function threadsChannel(config) {
403
+ return new ThreadsChannel(config);
404
+ }
405
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/channels/threads/channel.ts"],"names":[],"mappings":"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"}