@rmdes/indiekit-endpoint-conversations 2.1.4 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -120,20 +120,16 @@ async function backfillMissingAvatars(indiekit, stateCollection) {
120
120
  const state = await stateCollection.findOne({ _id: "poll_cursors" });
121
121
  if (state?.avatar_backfill_complete) return;
122
122
 
123
- // Find conversation_items with empty author.photo
124
- const itemsWithoutPhoto = await itemsCollection
125
- .find({
126
- $or: [
127
- { "author.photo": "" },
128
- { "author.photo": null },
129
- { "author.photo": { $exists: false } },
130
- ],
131
- })
132
- .limit(200)
133
- .toArray();
134
-
135
- if (itemsWithoutPhoto.length === 0) {
136
- // Mark backfill as complete so we don't query every cycle
123
+ // Get unique actor URLs with empty photos (deduplicate)
124
+ const actorUrls = await itemsCollection.distinct("author.url", {
125
+ $or: [
126
+ { "author.photo": "" },
127
+ { "author.photo": null },
128
+ { "author.photo": { $exists: false } },
129
+ ],
130
+ });
131
+
132
+ if (actorUrls.length === 0) {
137
133
  await stateCollection.findOneAndUpdate(
138
134
  { _id: "poll_cursors" },
139
135
  { $set: { avatar_backfill_complete: true } },
@@ -144,13 +140,12 @@ async function backfillMissingAvatars(indiekit, stateCollection) {
144
140
 
145
141
  let updated = 0;
146
142
 
147
- for (const item of itemsWithoutPhoto) {
148
- const actorUrl = item.author?.url;
143
+ for (const actorUrl of actorUrls) {
149
144
  if (!actorUrl) continue;
150
145
 
151
146
  let photo = "";
152
147
 
153
- // Strategy 1: Check ap_notifications (most reliable — has actorPhoto for all interaction types)
148
+ // Strategy 1: Check ap_notifications
154
149
  if (!photo && notificationsCollection) {
155
150
  try {
156
151
  const notification = await notificationsCollection.findOne({
@@ -161,7 +156,7 @@ async function backfillMissingAvatars(indiekit, stateCollection) {
161
156
  } catch { /* ignore */ }
162
157
  }
163
158
 
164
- // Strategy 2: Check ap_activities for actorAvatar (new field from inbox handler fix)
159
+ // Strategy 2: Check ap_activities for actorAvatar
165
160
  if (!photo && activitiesCollection) {
166
161
  try {
167
162
  const activity = await activitiesCollection.findOne({
@@ -181,7 +176,7 @@ async function backfillMissingAvatars(indiekit, stateCollection) {
181
176
  }
182
177
 
183
178
  // Strategy 4: Fetch actor profile from the fediverse (last resort)
184
- if (!photo && actorUrl) {
179
+ if (!photo) {
185
180
  try {
186
181
  const resp = await fetch(actorUrl, {
187
182
  headers: { Accept: "application/activity+json, application/ld+json" },
@@ -210,18 +205,16 @@ async function backfillMissingAvatars(indiekit, stateCollection) {
210
205
 
211
206
  if (updated > 0) {
212
207
  console.info(
213
- `[Conversations] Avatar backfill: updated ${updated} actors with photos`,
208
+ `[Conversations] Avatar backfill: updated ${updated}/${actorUrls.length} actors with photos`,
214
209
  );
215
210
  }
216
211
 
217
- // If fewer than 200 items found, backfill is complete
218
- if (itemsWithoutPhoto.length < 200) {
219
- await stateCollection.findOneAndUpdate(
220
- { _id: "poll_cursors" },
221
- { $set: { avatar_backfill_complete: true } },
222
- { upsert: true },
223
- );
224
- }
212
+ // Mark complete all actors have been attempted
213
+ await stateCollection.findOneAndUpdate(
214
+ { _id: "poll_cursors" },
215
+ { $set: { avatar_backfill_complete: true } },
216
+ { upsert: true },
217
+ );
225
218
  } catch (error) {
226
219
  // Non-critical — log and continue
227
220
  console.warn("[Conversations] Avatar backfill error:", error.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-conversations",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
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",