@takosjp/yurucommu-core 3.4.3 → 3.4.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/migrations/0023_delivery_resolution_outbox.sql +33 -0
- package/migrations/0024_delivery_fanout_outbox.sql +35 -0
- package/migrations/0025_delivery_endpoint_terminal_retention.sql +6 -0
- package/migrations/0026_remote_actor_fetch_failures.sql +29 -0
- package/migrations/0027_remote_actor_tombstones.sql +12 -0
- package/migrations/0028_remote_actor_delivery_fence.sql +30 -0
- package/migrations/0029_delivery_endpoint_recipients.sql +47 -0
- package/package.json +2 -1
- package/packages/api/package.json +1 -1
- package/packages/api/src/lib/api/communities.ts +2 -0
- package/packages/api/src/lib/api/fetch.ts +69 -13
- package/packages/api/src/lib/api/normalize.ts +32 -10
- package/packages/api/src/lib/api/notifications.ts +4 -1
- package/packages/api/src/lib/rtc-client.ts +127 -29
- package/src/backend/federation-helpers.ts +1 -0
- package/src/backend/index.ts +16 -3
- package/src/backend/lib/account-migration.ts +340 -0
- package/src/backend/lib/activity-delete-cascade.ts +193 -0
- package/src/backend/lib/activitypub-actor-cache.ts +615 -48
- package/src/backend/lib/activitypub-actor-identity-sql.ts +179 -0
- package/src/backend/lib/activitypub-actor-identity.ts +39 -0
- package/src/backend/lib/activitypub-validators.ts +62 -4
- package/src/backend/lib/ap-ids.ts +36 -6
- package/src/backend/lib/ap-verify.ts +7 -17
- package/src/backend/lib/blocklist-purge.ts +676 -42
- package/src/backend/lib/blocklist.ts +278 -39
- package/src/backend/lib/community-visibility.ts +47 -33
- package/src/backend/lib/delivery/fanout-outbox.ts +336 -0
- package/src/backend/lib/delivery/planner.ts +16 -12
- package/src/backend/lib/delivery/queue-batching.ts +389 -145
- package/src/backend/lib/delivery/queue-delivery.ts +47 -25
- package/src/backend/lib/delivery/queue.ts +479 -73
- package/src/backend/lib/delivery/resolution-outbox.ts +456 -0
- package/src/backend/lib/delivery/types.ts +31 -7
- package/src/backend/lib/feed-exclude.ts +40 -28
- package/src/backend/lib/follow-edge-mutations.ts +217 -0
- package/src/backend/lib/notification-eligibility.ts +15 -9
- package/src/backend/lib/notification-push.ts +2 -2
- package/src/backend/lib/oidc-id-token.ts +66 -0
- package/src/backend/lib/personal-actor-moderation.ts +239 -0
- package/src/backend/lib/post-visibility.ts +79 -16
- package/src/backend/lib/remote-activity-id.ts +61 -0
- package/src/backend/lib/unread-counts.ts +3 -0
- package/src/backend/retention.ts +38 -1
- package/src/backend/routes/account-teardown.ts +422 -156
- package/src/backend/routes/activitypub/handlers/actor-inbox-handlers.ts +104 -105
- package/src/backend/routes/activitypub/handlers/inbound-community-scope.ts +121 -0
- package/src/backend/routes/activitypub/handlers/inbound-object-identity.ts +54 -0
- package/src/backend/routes/activitypub/handlers/inbound-reply-target.ts +34 -0
- package/src/backend/routes/activitypub/handlers/inbound-story-projection.ts +438 -0
- package/src/backend/routes/activitypub/handlers/inbox-content-handlers.ts +1121 -806
- package/src/backend/routes/activitypub/handlers/inbox-follow-handlers.ts +118 -153
- package/src/backend/routes/activitypub/handlers/inbox-interaction-handlers.ts +185 -168
- package/src/backend/routes/activitypub/handlers/inbox-shared-helpers.ts +220 -32
- package/src/backend/routes/activitypub/inbound-activity-identity.ts +16 -0
- package/src/backend/routes/activitypub/inbound-activity-reference.ts +116 -0
- package/src/backend/routes/activitypub/inbound-addressing.ts +87 -0
- package/src/backend/routes/activitypub/inbox-addressing.ts +22 -19
- package/src/backend/routes/activitypub/inbox-types.ts +14 -2
- package/src/backend/routes/activitypub/inbox.ts +81 -105
- package/src/backend/routes/activitypub/outbox.ts +0 -0
- package/src/backend/routes/activitypub.ts +6 -5
- package/src/backend/routes/actors-helpers.ts +34 -8
- package/src/backend/routes/actors.ts +328 -164
- package/src/backend/routes/auth-helpers.ts +57 -9
- package/src/backend/routes/auth.ts +10 -2
- package/src/backend/routes/communities/membership-invites.ts +4 -1
- package/src/backend/routes/communities/membership-members.ts +201 -73
- package/src/backend/routes/communities/membership-requests.ts +141 -76
- package/src/backend/routes/communities/membership-shared.ts +228 -21
- package/src/backend/routes/communities/messages.ts +9 -2
- package/src/backend/routes/communities/routes.ts +48 -13
- package/src/backend/routes/dm/contacts.ts +29 -41
- package/src/backend/routes/dm/conversations-helpers.ts +9 -1
- package/src/backend/routes/dm/messages.ts +36 -42
- package/src/backend/routes/dm/read-archive.ts +4 -2
- package/src/backend/routes/dm/requests.ts +62 -54
- package/src/backend/routes/follow-helpers.ts +200 -60
- package/src/backend/routes/follow.ts +146 -140
- package/src/backend/routes/media.ts +20 -94
- package/src/backend/routes/moderation.ts +72 -4
- package/src/backend/routes/notes.ts +3 -4
- package/src/backend/routes/notifications.ts +209 -108
- package/src/backend/routes/posts/delete-cascade.ts +253 -89
- package/src/backend/routes/posts/federation.ts +373 -0
- package/src/backend/routes/posts/interactions.ts +160 -184
- package/src/backend/routes/posts/like-mutation.ts +240 -0
- package/src/backend/routes/posts/post-helpers.ts +112 -162
- package/src/backend/routes/posts/queries.ts +150 -54
- package/src/backend/routes/posts/routes.ts +169 -329
- package/src/backend/routes/posts/transformers.ts +61 -6
- package/src/backend/routes/recommendations.ts +37 -44
- package/src/backend/routes/rtc/index.ts +26 -6
- package/src/backend/routes/search.ts +39 -55
- package/src/backend/routes/stories/interactions.ts +22 -6
- package/src/backend/routes/stories/query-helpers.ts +28 -41
- package/src/backend/routes/stories/routes.ts +125 -108
- package/src/backend/routes/takos-tools/dm.ts +17 -17
- package/src/backend/routes/takos-tools/posts.ts +189 -106
- package/src/backend/routes/takos-tools/search.ts +13 -4
- package/src/backend/routes/takos-tools/timeline.ts +35 -27
- package/src/backend/routes/takos-tools-response.ts +6 -2
- package/src/backend/routes/timeline.ts +5 -5
- package/src/backend/runtime/call-signaling-do.ts +35 -4
- package/src/backend/runtime/one-time-ticket.ts +116 -0
- package/src/backend/runtime/realtime-stream-do.ts +5 -61
- package/src/backend/runtime/signaling-hub.ts +36 -3
- package/src/backend/server.ts +95 -80
- package/src/db/d1-write.ts +67 -43
- package/src/db/schema/federation.ts +42 -1
- package/src/db/schema/messaging.ts +110 -2
- package/src/db/schema.ts +1 -1
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
activities,
|
|
5
|
+
objects,
|
|
6
|
+
type D1Statement,
|
|
7
|
+
type Database,
|
|
8
|
+
} from "../../../db/index.ts";
|
|
9
|
+
import { OBJECT_CONTEXT } from "../../lib/ap-context.ts";
|
|
10
|
+
import {
|
|
11
|
+
activityApId,
|
|
12
|
+
formatUsername,
|
|
13
|
+
generateId,
|
|
14
|
+
isLocal,
|
|
15
|
+
isSafeRemoteUrl,
|
|
16
|
+
safeJsonParse,
|
|
17
|
+
} from "../../federation-helpers.ts";
|
|
18
|
+
import { toApAttachments } from "../../lib/activitypub-helpers.ts";
|
|
19
|
+
import { enqueueDeliveryToActor } from "../../lib/delivery/queue.ts";
|
|
20
|
+
import { logger } from "../../lib/logger.ts";
|
|
21
|
+
import type { Env } from "../../types.ts";
|
|
22
|
+
import {
|
|
23
|
+
persistPostMentionProjections,
|
|
24
|
+
resolvePostMentions,
|
|
25
|
+
} from "./post-helpers.ts";
|
|
26
|
+
import {
|
|
27
|
+
buildAddressing,
|
|
28
|
+
buildCommunityObjectAddressing,
|
|
29
|
+
mergeCc,
|
|
30
|
+
preparePersistAndFanout,
|
|
31
|
+
preparePersistAndFanoutToCommunity,
|
|
32
|
+
type CommunityAddressingTarget,
|
|
33
|
+
type MentionFailure,
|
|
34
|
+
type PostAttachment,
|
|
35
|
+
type PostTag,
|
|
36
|
+
type ProcessMentionsResult,
|
|
37
|
+
} from "./queries.ts";
|
|
38
|
+
|
|
39
|
+
const log = logger.child({ component: "posts.federation" });
|
|
40
|
+
const PUBLIC_COLLECTION = "https://www.w3.org/ns/activitystreams#Public";
|
|
41
|
+
|
|
42
|
+
export type CreatedPostFederationInput = {
|
|
43
|
+
db: Database;
|
|
44
|
+
env: Env;
|
|
45
|
+
actorApId: string;
|
|
46
|
+
objectApId: string;
|
|
47
|
+
content: string;
|
|
48
|
+
summary: string | null;
|
|
49
|
+
attachments?: PostAttachment[];
|
|
50
|
+
inReplyTo: string | null;
|
|
51
|
+
parentAuthor: string | null;
|
|
52
|
+
visibility: string;
|
|
53
|
+
community: CommunityAddressingTarget | null;
|
|
54
|
+
published: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type PreparedCreatedPostFederation = {
|
|
58
|
+
readonly to: string[];
|
|
59
|
+
readonly cc: string[];
|
|
60
|
+
readonly audience: string[];
|
|
61
|
+
readonly tags: PostTag[];
|
|
62
|
+
readonly statements: readonly D1Statement[];
|
|
63
|
+
complete(): Promise<{ mentionFailures: MentionFailure[] }>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve and prepare a post's outbound Create without writing anything. The
|
|
68
|
+
* caller co-commits these statements with the local Note/counter mutation,
|
|
69
|
+
* then invokes complete() for best-effort Queue wakeups and notifications.
|
|
70
|
+
*/
|
|
71
|
+
export async function prepareCreatedPostFederation(
|
|
72
|
+
input: CreatedPostFederationInput,
|
|
73
|
+
): Promise<PreparedCreatedPostFederation> {
|
|
74
|
+
const {
|
|
75
|
+
db,
|
|
76
|
+
env,
|
|
77
|
+
actorApId,
|
|
78
|
+
objectApId: postApId,
|
|
79
|
+
content,
|
|
80
|
+
summary,
|
|
81
|
+
attachments,
|
|
82
|
+
inReplyTo,
|
|
83
|
+
parentAuthor,
|
|
84
|
+
visibility,
|
|
85
|
+
community,
|
|
86
|
+
published,
|
|
87
|
+
} = input;
|
|
88
|
+
const baseUrl = env.APP_URL;
|
|
89
|
+
|
|
90
|
+
const {
|
|
91
|
+
failures: mentionFailures,
|
|
92
|
+
tags: mentionTags,
|
|
93
|
+
mentionedActorApIds,
|
|
94
|
+
remoteMentionedActorApIds,
|
|
95
|
+
} = await resolvePostMentions(db, {
|
|
96
|
+
content,
|
|
97
|
+
actorApId,
|
|
98
|
+
baseUrl,
|
|
99
|
+
});
|
|
100
|
+
const resolvedMentions: ProcessMentionsResult = {
|
|
101
|
+
failures: mentionFailures,
|
|
102
|
+
tags: mentionTags,
|
|
103
|
+
mentionedActorApIds,
|
|
104
|
+
remoteMentionedActorApIds,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// A non-direct reply must reach its parent author's instance even when the
|
|
108
|
+
// body does not repeat an @mention. Direct reach remains explicit-only.
|
|
109
|
+
const recipients = [...mentionedActorApIds];
|
|
110
|
+
const remoteRecipients = [...remoteMentionedActorApIds];
|
|
111
|
+
const tags = [...mentionTags];
|
|
112
|
+
if (
|
|
113
|
+
inReplyTo &&
|
|
114
|
+
parentAuthor &&
|
|
115
|
+
parentAuthor !== actorApId &&
|
|
116
|
+
visibility !== "direct" &&
|
|
117
|
+
!recipients.includes(parentAuthor)
|
|
118
|
+
) {
|
|
119
|
+
recipients.push(parentAuthor);
|
|
120
|
+
tags.push({
|
|
121
|
+
type: "Mention",
|
|
122
|
+
href: parentAuthor,
|
|
123
|
+
name: `@${formatUsername(parentAuthor)}`,
|
|
124
|
+
});
|
|
125
|
+
if (!isLocal(parentAuthor, baseUrl)) remoteRecipients.push(parentAuthor);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// A plain direct Note with no resolved recipient has no federation reach.
|
|
129
|
+
let to: string[];
|
|
130
|
+
let cc: string[];
|
|
131
|
+
let audience: string[] | undefined;
|
|
132
|
+
if (visibility === "direct") {
|
|
133
|
+
to = [];
|
|
134
|
+
cc = [];
|
|
135
|
+
} else if (community) {
|
|
136
|
+
const addressing = buildCommunityObjectAddressing(visibility, community);
|
|
137
|
+
to = addressing.to;
|
|
138
|
+
cc = addressing.cc;
|
|
139
|
+
audience = addressing.audience;
|
|
140
|
+
} else {
|
|
141
|
+
({ to, cc } = buildAddressing(visibility, `${actorApId}/followers`));
|
|
142
|
+
}
|
|
143
|
+
cc = mergeCc(cc, recipients);
|
|
144
|
+
|
|
145
|
+
const tag = tags.length > 0 ? tags : undefined;
|
|
146
|
+
const createActivity = {
|
|
147
|
+
"@context": OBJECT_CONTEXT,
|
|
148
|
+
id: activityApId(baseUrl, generateId()),
|
|
149
|
+
type: "Create",
|
|
150
|
+
actor: actorApId,
|
|
151
|
+
published,
|
|
152
|
+
to,
|
|
153
|
+
cc,
|
|
154
|
+
...(audience ? { audience } : {}),
|
|
155
|
+
...(tag ? { tag } : {}),
|
|
156
|
+
object: {
|
|
157
|
+
"@context": OBJECT_CONTEXT,
|
|
158
|
+
id: postApId,
|
|
159
|
+
type: "Note",
|
|
160
|
+
attributedTo: actorApId,
|
|
161
|
+
content,
|
|
162
|
+
summary,
|
|
163
|
+
...(summary ? { sensitive: true } : {}),
|
|
164
|
+
attachment: toApAttachments(attachments || [], baseUrl),
|
|
165
|
+
inReplyTo,
|
|
166
|
+
published,
|
|
167
|
+
to,
|
|
168
|
+
cc,
|
|
169
|
+
...(audience ? { audience } : {}),
|
|
170
|
+
...(tag ? { tag } : {}),
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
let statements: readonly D1Statement[] = [];
|
|
175
|
+
let publish = async () => {};
|
|
176
|
+
// A plain direct Note with no resolved recipient has no federation reach and
|
|
177
|
+
// therefore no outbound Activity. The local object still commits below.
|
|
178
|
+
if (visibility === "direct" && mentionedActorApIds.length === 0) {
|
|
179
|
+
statements = [];
|
|
180
|
+
} else if (visibility === "direct") {
|
|
181
|
+
statements = [
|
|
182
|
+
db.insert(activities).values({
|
|
183
|
+
apId: createActivity.id,
|
|
184
|
+
type: createActivity.type,
|
|
185
|
+
actorApId: createActivity.actor,
|
|
186
|
+
objectApId: postApId,
|
|
187
|
+
rawJson: JSON.stringify(createActivity),
|
|
188
|
+
direction: "outbound",
|
|
189
|
+
}) as D1Statement,
|
|
190
|
+
];
|
|
191
|
+
} else if (community) {
|
|
192
|
+
const prepared = await preparePersistAndFanoutToCommunity(
|
|
193
|
+
db,
|
|
194
|
+
env,
|
|
195
|
+
createActivity,
|
|
196
|
+
postApId,
|
|
197
|
+
community.apId,
|
|
198
|
+
);
|
|
199
|
+
statements = prepared.statements;
|
|
200
|
+
publish = prepared.publish;
|
|
201
|
+
} else {
|
|
202
|
+
const prepared = await preparePersistAndFanout(
|
|
203
|
+
db,
|
|
204
|
+
env,
|
|
205
|
+
createActivity,
|
|
206
|
+
postApId,
|
|
207
|
+
);
|
|
208
|
+
statements = prepared.statements;
|
|
209
|
+
publish = prepared.publish;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
to,
|
|
214
|
+
cc,
|
|
215
|
+
audience: audience ?? [],
|
|
216
|
+
tags,
|
|
217
|
+
statements,
|
|
218
|
+
async complete() {
|
|
219
|
+
await publish();
|
|
220
|
+
|
|
221
|
+
const persistedMentionFailures = await persistPostMentionProjections(db, {
|
|
222
|
+
result: resolvedMentions,
|
|
223
|
+
postApId,
|
|
224
|
+
actorApId,
|
|
225
|
+
parentAuthor,
|
|
226
|
+
baseUrl,
|
|
227
|
+
now: published,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
for (const recipient of new Set(remoteRecipients)) {
|
|
231
|
+
try {
|
|
232
|
+
await enqueueDeliveryToActor(env, createActivity.id, recipient);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
log.error("Failed to enqueue explicit Create delivery", {
|
|
235
|
+
event: "posts.create.delivery_enqueue_failed",
|
|
236
|
+
activityId: createActivity.id,
|
|
237
|
+
recipient,
|
|
238
|
+
error,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
mentionFailures: [...mentionFailures, ...persistedMentionFailures],
|
|
245
|
+
};
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export type DeletedPostFederationInput = {
|
|
251
|
+
db: Database;
|
|
252
|
+
env: Env;
|
|
253
|
+
actorApId: string;
|
|
254
|
+
post: {
|
|
255
|
+
apId: string;
|
|
256
|
+
inReplyTo: string | null;
|
|
257
|
+
visibility: string;
|
|
258
|
+
communityApId: string | null;
|
|
259
|
+
toJson: string;
|
|
260
|
+
ccJson: string;
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export type PreparedDeletedPostFederation = {
|
|
265
|
+
readonly statements: readonly [D1Statement, ...D1Statement[]];
|
|
266
|
+
complete(): Promise<string>;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/** Prepare a Tombstone Delete so its owner can co-commit local removal. */
|
|
270
|
+
export async function prepareDeletedPostFederation(
|
|
271
|
+
input: DeletedPostFederationInput,
|
|
272
|
+
): Promise<PreparedDeletedPostFederation> {
|
|
273
|
+
const { db, env, actorApId, post } = input;
|
|
274
|
+
const baseUrl = env.APP_URL;
|
|
275
|
+
const originalTo = safeJsonParse<string[]>(post.toJson, []);
|
|
276
|
+
const originalCc = safeJsonParse<string[]>(post.ccJson, []);
|
|
277
|
+
const explicitRecipients = new Set<string>();
|
|
278
|
+
|
|
279
|
+
for (const iri of [...originalTo, ...originalCc]) {
|
|
280
|
+
if (
|
|
281
|
+
iri &&
|
|
282
|
+
iri !== PUBLIC_COLLECTION &&
|
|
283
|
+
!iri.endsWith("/followers") &&
|
|
284
|
+
!isLocal(iri, baseUrl) &&
|
|
285
|
+
isSafeRemoteUrl(iri)
|
|
286
|
+
) {
|
|
287
|
+
explicitRecipients.add(iri);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (post.inReplyTo) {
|
|
292
|
+
const parent = await db
|
|
293
|
+
.select({ attributedTo: objects.attributedTo })
|
|
294
|
+
.from(objects)
|
|
295
|
+
.where(eq(objects.apId, post.inReplyTo))
|
|
296
|
+
.get();
|
|
297
|
+
if (
|
|
298
|
+
parent?.attributedTo &&
|
|
299
|
+
!isLocal(parent.attributedTo, baseUrl) &&
|
|
300
|
+
isSafeRemoteUrl(parent.attributedTo)
|
|
301
|
+
) {
|
|
302
|
+
explicitRecipients.add(parent.attributedTo);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const deleteActivity = {
|
|
307
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
308
|
+
id: activityApId(baseUrl, generateId()),
|
|
309
|
+
type: "Delete",
|
|
310
|
+
actor: actorApId,
|
|
311
|
+
to: originalTo,
|
|
312
|
+
cc: originalCc,
|
|
313
|
+
object: { id: post.apId, type: "Tombstone" },
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// Direct objects were never broadcast to followers. Persist their Delete for
|
|
317
|
+
// the ledger and send only to explicit recipients; follower fanout here would
|
|
318
|
+
// disclose the existence and id of a private object.
|
|
319
|
+
let statements: readonly [D1Statement, ...D1Statement[]];
|
|
320
|
+
let publish = async () => {};
|
|
321
|
+
if (post.visibility === "direct") {
|
|
322
|
+
statements = [
|
|
323
|
+
db.insert(activities).values({
|
|
324
|
+
apId: deleteActivity.id,
|
|
325
|
+
type: deleteActivity.type,
|
|
326
|
+
actorApId: deleteActivity.actor,
|
|
327
|
+
objectApId: post.apId,
|
|
328
|
+
rawJson: JSON.stringify(deleteActivity),
|
|
329
|
+
direction: "outbound",
|
|
330
|
+
}) as D1Statement,
|
|
331
|
+
];
|
|
332
|
+
} else if (post.communityApId) {
|
|
333
|
+
const prepared = await preparePersistAndFanoutToCommunity(
|
|
334
|
+
db,
|
|
335
|
+
env,
|
|
336
|
+
deleteActivity,
|
|
337
|
+
post.apId,
|
|
338
|
+
post.communityApId,
|
|
339
|
+
);
|
|
340
|
+
statements = prepared.statements;
|
|
341
|
+
publish = prepared.publish;
|
|
342
|
+
} else {
|
|
343
|
+
const prepared = await preparePersistAndFanout(
|
|
344
|
+
db,
|
|
345
|
+
env,
|
|
346
|
+
deleteActivity,
|
|
347
|
+
post.apId,
|
|
348
|
+
);
|
|
349
|
+
statements = prepared.statements;
|
|
350
|
+
publish = prepared.publish;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
statements,
|
|
355
|
+
async complete() {
|
|
356
|
+
await publish();
|
|
357
|
+
for (const recipient of explicitRecipients) {
|
|
358
|
+
try {
|
|
359
|
+
await enqueueDeliveryToActor(env, deleteActivity.id, recipient);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
log.error("Failed to enqueue explicit Delete delivery", {
|
|
362
|
+
event: "posts.delete.delivery_enqueue_failed",
|
|
363
|
+
activityId: deleteActivity.id,
|
|
364
|
+
recipient,
|
|
365
|
+
error,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return deleteActivity.id;
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|