@rmdes/indiekit-endpoint-conversations 2.1.0 → 2.1.2

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/index.js CHANGED
@@ -106,30 +106,29 @@ export default class ConversationsEndpoint {
106
106
  (process.env.BLUESKY_IDENTIFIER || process.env.BLUESKY_HANDLE) &&
107
107
  process.env.BLUESKY_PASSWORD;
108
108
 
109
- // ActivityPub: auto-detect from shared collection registry
110
- // The AP endpoint registers ap_activities via Indiekit.addCollection()
111
- const hasActivityPub = Indiekit.collections.has("ap_activities");
112
-
113
- if (hasMastodon || hasBluesky || hasActivityPub) {
114
- // Store detected platforms for dashboard status
115
- Indiekit.config.application.conversations = {
116
- ...this.options,
117
- mastodonEnabled: !!hasMastodon,
118
- blueskyEnabled: !!hasBluesky,
119
- activitypubEnabled: !!hasActivityPub,
120
- };
121
-
122
- import("./lib/polling/scheduler.js")
123
- .then(({ startPolling }) => {
124
- startPolling(Indiekit, this.options);
125
- })
126
- .catch((error) => {
127
- console.error(
128
- "[Conversations] Polling scheduler failed to start:",
129
- error.message,
130
- );
131
- });
132
- }
109
+ // Store detected platforms for dashboard status
110
+ // Note: ActivityPub detection happens at poll time (not init time)
111
+ // because the AP endpoint may register its collections after this
112
+ // plugin. The scheduler updates activitypubEnabled dynamically.
113
+ Indiekit.config.application.conversations = {
114
+ ...this.options,
115
+ mastodonEnabled: !!hasMastodon,
116
+ blueskyEnabled: !!hasBluesky,
117
+ activitypubEnabled: false,
118
+ };
119
+
120
+ // Always start polling — the scheduler detects available sources
121
+ // at runtime (Mastodon/Bluesky from env vars, AP from collections)
122
+ import("./lib/polling/scheduler.js")
123
+ .then(({ startPolling }) => {
124
+ startPolling(Indiekit, this.options);
125
+ })
126
+ .catch((error) => {
127
+ console.error(
128
+ "[Conversations] Polling scheduler failed to start:",
129
+ error.message,
130
+ );
131
+ });
133
132
  }
134
133
  }
135
134
  }
@@ -80,8 +80,18 @@ export async function runPollCycle(indiekit, options) {
80
80
  }
81
81
 
82
82
  // Poll ActivityPub (auto-detect from local collections)
83
+ // Detection runs at poll time because the AP endpoint may init after
84
+ // the conversations plugin, so the collection isn't available at init.
83
85
  const hasActivityPub = await detectActivityPubSource(indiekit);
84
86
  if (hasActivityPub) {
87
+ // Update config flag so the dashboard shows AP as enabled.
88
+ // indiekit may be the Indiekit class or the application object
89
+ // depending on whether called from startPolling or triggerPoll.
90
+ const convConfig =
91
+ indiekit.config?.application?.conversations || indiekit.conversations;
92
+ if (convConfig && !convConfig.activitypubEnabled) {
93
+ convConfig.activitypubEnabled = true;
94
+ }
85
95
  await pollActivityPub(indiekit, stateCollection, state);
86
96
  }
87
97
  }
@@ -313,6 +323,16 @@ async function pollActivityPub(indiekit, stateCollection, state) {
313
323
 
314
324
  if (!ap_activities) return;
315
325
 
326
+ // Resolve the site URL so we only store interactions about OUR content.
327
+ // indiekit may be the Indiekit class (from startPolling) or the
328
+ // application object (from triggerPoll via controller).
329
+ const siteUrl = (
330
+ indiekit.publication?.me ||
331
+ indiekit.url ||
332
+ process.env.PUBLICATION_URL ||
333
+ ""
334
+ ).replace(/\/$/, "");
335
+
316
336
  const result = await fetchActivityPubInteractions({
317
337
  ap_activities,
318
338
  ap_followers,
@@ -320,22 +340,30 @@ async function pollActivityPub(indiekit, stateCollection, state) {
320
340
  });
321
341
 
322
342
  let stored = 0;
343
+ let skipped = 0;
323
344
 
324
345
  for (const interaction of result.items) {
325
- if (interaction.canonical_url) {
326
- await upsertConversationItem(indiekit, {
327
- canonical_url: interaction.canonical_url,
328
- source: "activitypub",
329
- type: interaction.type,
330
- author: interaction.author,
331
- content: interaction.content,
332
- url: interaction.url,
333
- bridgy_url: null,
334
- platform_id: interaction.platform_id,
335
- created_at: interaction.created_at,
336
- });
337
- stored++;
346
+ if (!interaction.canonical_url) continue;
347
+
348
+ // Only store interactions targeting our own content — skip activities
349
+ // about posts on other domains (e.g. forwarded via shared inbox).
350
+ if (siteUrl && !interaction.canonical_url.startsWith(siteUrl)) {
351
+ skipped++;
352
+ continue;
338
353
  }
354
+
355
+ await upsertConversationItem(indiekit, {
356
+ canonical_url: interaction.canonical_url,
357
+ source: "activitypub",
358
+ type: interaction.type,
359
+ author: interaction.author,
360
+ content: interaction.content,
361
+ url: interaction.url,
362
+ bridgy_url: null,
363
+ platform_id: interaction.platform_id,
364
+ created_at: interaction.created_at,
365
+ });
366
+ stored++;
339
367
  }
340
368
 
341
369
  // Update cursor and status
@@ -353,9 +381,9 @@ async function pollActivityPub(indiekit, stateCollection, state) {
353
381
  { upsert: true },
354
382
  );
355
383
 
356
- if (stored > 0) {
384
+ if (stored > 0 || skipped > 0) {
357
385
  console.info(
358
- `[Conversations] ActivityPub: stored ${stored}/${result.items.length} interactions`,
386
+ `[Conversations] ActivityPub: stored ${stored}, skipped ${skipped} (not our content) of ${result.items.length} interactions`,
359
387
  );
360
388
  }
361
389
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-conversations",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Conversation aggregation endpoint for Indiekit. Backend enrichment service that polls Mastodon/Bluesky notifications and serves JF2-compatible data for the interactions page.",
5
5
  "keywords": [
6
6
  "indiekit",