@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.
Files changed (112) hide show
  1. package/migrations/0023_delivery_resolution_outbox.sql +33 -0
  2. package/migrations/0024_delivery_fanout_outbox.sql +35 -0
  3. package/migrations/0025_delivery_endpoint_terminal_retention.sql +6 -0
  4. package/migrations/0026_remote_actor_fetch_failures.sql +29 -0
  5. package/migrations/0027_remote_actor_tombstones.sql +12 -0
  6. package/migrations/0028_remote_actor_delivery_fence.sql +30 -0
  7. package/migrations/0029_delivery_endpoint_recipients.sql +47 -0
  8. package/package.json +2 -1
  9. package/packages/api/package.json +1 -1
  10. package/packages/api/src/lib/api/communities.ts +2 -0
  11. package/packages/api/src/lib/api/fetch.ts +69 -13
  12. package/packages/api/src/lib/api/normalize.ts +32 -10
  13. package/packages/api/src/lib/api/notifications.ts +4 -1
  14. package/packages/api/src/lib/rtc-client.ts +127 -29
  15. package/src/backend/federation-helpers.ts +1 -0
  16. package/src/backend/index.ts +16 -3
  17. package/src/backend/lib/account-migration.ts +340 -0
  18. package/src/backend/lib/activity-delete-cascade.ts +193 -0
  19. package/src/backend/lib/activitypub-actor-cache.ts +615 -48
  20. package/src/backend/lib/activitypub-actor-identity-sql.ts +179 -0
  21. package/src/backend/lib/activitypub-actor-identity.ts +39 -0
  22. package/src/backend/lib/activitypub-validators.ts +62 -4
  23. package/src/backend/lib/ap-ids.ts +36 -6
  24. package/src/backend/lib/ap-verify.ts +7 -17
  25. package/src/backend/lib/blocklist-purge.ts +676 -42
  26. package/src/backend/lib/blocklist.ts +278 -39
  27. package/src/backend/lib/community-visibility.ts +47 -33
  28. package/src/backend/lib/delivery/fanout-outbox.ts +336 -0
  29. package/src/backend/lib/delivery/planner.ts +16 -12
  30. package/src/backend/lib/delivery/queue-batching.ts +389 -145
  31. package/src/backend/lib/delivery/queue-delivery.ts +47 -25
  32. package/src/backend/lib/delivery/queue.ts +479 -73
  33. package/src/backend/lib/delivery/resolution-outbox.ts +456 -0
  34. package/src/backend/lib/delivery/types.ts +31 -7
  35. package/src/backend/lib/feed-exclude.ts +40 -28
  36. package/src/backend/lib/follow-edge-mutations.ts +217 -0
  37. package/src/backend/lib/notification-eligibility.ts +15 -9
  38. package/src/backend/lib/notification-push.ts +2 -2
  39. package/src/backend/lib/oidc-id-token.ts +66 -0
  40. package/src/backend/lib/personal-actor-moderation.ts +239 -0
  41. package/src/backend/lib/post-visibility.ts +79 -16
  42. package/src/backend/lib/remote-activity-id.ts +61 -0
  43. package/src/backend/lib/unread-counts.ts +3 -0
  44. package/src/backend/retention.ts +38 -1
  45. package/src/backend/routes/account-teardown.ts +422 -156
  46. package/src/backend/routes/activitypub/handlers/actor-inbox-handlers.ts +104 -105
  47. package/src/backend/routes/activitypub/handlers/inbound-community-scope.ts +121 -0
  48. package/src/backend/routes/activitypub/handlers/inbound-object-identity.ts +54 -0
  49. package/src/backend/routes/activitypub/handlers/inbound-reply-target.ts +34 -0
  50. package/src/backend/routes/activitypub/handlers/inbound-story-projection.ts +438 -0
  51. package/src/backend/routes/activitypub/handlers/inbox-content-handlers.ts +1121 -806
  52. package/src/backend/routes/activitypub/handlers/inbox-follow-handlers.ts +118 -153
  53. package/src/backend/routes/activitypub/handlers/inbox-interaction-handlers.ts +185 -168
  54. package/src/backend/routes/activitypub/handlers/inbox-shared-helpers.ts +220 -32
  55. package/src/backend/routes/activitypub/inbound-activity-identity.ts +16 -0
  56. package/src/backend/routes/activitypub/inbound-activity-reference.ts +116 -0
  57. package/src/backend/routes/activitypub/inbound-addressing.ts +87 -0
  58. package/src/backend/routes/activitypub/inbox-addressing.ts +22 -19
  59. package/src/backend/routes/activitypub/inbox-types.ts +14 -2
  60. package/src/backend/routes/activitypub/inbox.ts +81 -105
  61. package/src/backend/routes/activitypub/outbox.ts +0 -0
  62. package/src/backend/routes/activitypub.ts +6 -5
  63. package/src/backend/routes/actors-helpers.ts +34 -8
  64. package/src/backend/routes/actors.ts +328 -164
  65. package/src/backend/routes/auth-helpers.ts +57 -9
  66. package/src/backend/routes/auth.ts +10 -2
  67. package/src/backend/routes/communities/membership-invites.ts +4 -1
  68. package/src/backend/routes/communities/membership-members.ts +201 -73
  69. package/src/backend/routes/communities/membership-requests.ts +141 -76
  70. package/src/backend/routes/communities/membership-shared.ts +228 -21
  71. package/src/backend/routes/communities/messages.ts +9 -2
  72. package/src/backend/routes/communities/routes.ts +48 -13
  73. package/src/backend/routes/dm/contacts.ts +29 -41
  74. package/src/backend/routes/dm/conversations-helpers.ts +9 -1
  75. package/src/backend/routes/dm/messages.ts +36 -42
  76. package/src/backend/routes/dm/read-archive.ts +4 -2
  77. package/src/backend/routes/dm/requests.ts +62 -54
  78. package/src/backend/routes/follow-helpers.ts +200 -60
  79. package/src/backend/routes/follow.ts +146 -140
  80. package/src/backend/routes/media.ts +20 -94
  81. package/src/backend/routes/moderation.ts +72 -4
  82. package/src/backend/routes/notes.ts +3 -4
  83. package/src/backend/routes/notifications.ts +209 -108
  84. package/src/backend/routes/posts/delete-cascade.ts +253 -89
  85. package/src/backend/routes/posts/federation.ts +373 -0
  86. package/src/backend/routes/posts/interactions.ts +160 -184
  87. package/src/backend/routes/posts/like-mutation.ts +240 -0
  88. package/src/backend/routes/posts/post-helpers.ts +112 -162
  89. package/src/backend/routes/posts/queries.ts +150 -54
  90. package/src/backend/routes/posts/routes.ts +169 -329
  91. package/src/backend/routes/posts/transformers.ts +61 -6
  92. package/src/backend/routes/recommendations.ts +37 -44
  93. package/src/backend/routes/rtc/index.ts +26 -6
  94. package/src/backend/routes/search.ts +39 -55
  95. package/src/backend/routes/stories/interactions.ts +22 -6
  96. package/src/backend/routes/stories/query-helpers.ts +28 -41
  97. package/src/backend/routes/stories/routes.ts +125 -108
  98. package/src/backend/routes/takos-tools/dm.ts +17 -17
  99. package/src/backend/routes/takos-tools/posts.ts +189 -106
  100. package/src/backend/routes/takos-tools/search.ts +13 -4
  101. package/src/backend/routes/takos-tools/timeline.ts +35 -27
  102. package/src/backend/routes/takos-tools-response.ts +6 -2
  103. package/src/backend/routes/timeline.ts +5 -5
  104. package/src/backend/runtime/call-signaling-do.ts +35 -4
  105. package/src/backend/runtime/one-time-ticket.ts +116 -0
  106. package/src/backend/runtime/realtime-stream-do.ts +5 -61
  107. package/src/backend/runtime/signaling-hub.ts +36 -3
  108. package/src/backend/server.ts +95 -80
  109. package/src/db/d1-write.ts +67 -43
  110. package/src/db/schema/federation.ts +42 -1
  111. package/src/db/schema/messaging.ts +110 -2
  112. package/src/db/schema.ts +1 -1
@@ -0,0 +1,193 @@
1
+ import { and, inArray, notExists, or, type SQL } from "drizzle-orm";
2
+
3
+ import {
4
+ activities,
5
+ deliveryFanouts,
6
+ deliveryQueue,
7
+ deliveryResolutions,
8
+ inboundActivityClaims,
9
+ inbox,
10
+ notificationArchived,
11
+ notificationPushJobs,
12
+ runBatch,
13
+ type Database,
14
+ type D1Statement,
15
+ } from "../../db/index.ts";
16
+
17
+ /**
18
+ * A write-time fence for deleting an Activity actor's signing material.
19
+ *
20
+ * Preliminary reads are not sufficient: a fanout/resolution worker can
21
+ * materialize an endpoint after the reaper checked delivery_queue and then
22
+ * mark its own outbox terminal before the reaper checks that table. Reuse this
23
+ * predicate on EVERY statement in the atomic cleanup batch so newly active
24
+ * work stops the remaining deletes before the Activity or signer disappears.
25
+ */
26
+ export function activityDeliveryDrainedGuard(
27
+ db: Database,
28
+ activityWhere: SQL,
29
+ ): SQL {
30
+ const targetActivityIds = () =>
31
+ db.select({ apId: activities.apId }).from(activities).where(activityWhere);
32
+
33
+ return and(
34
+ notExists(
35
+ db
36
+ .select({ id: deliveryQueue.id })
37
+ .from(deliveryQueue)
38
+ .where(
39
+ and(
40
+ inArray(deliveryQueue.activityApId, targetActivityIds()),
41
+ inArray(deliveryQueue.status, [
42
+ "pending",
43
+ "processing",
44
+ "retry_wait",
45
+ ]),
46
+ ),
47
+ ),
48
+ ),
49
+ notExists(
50
+ db
51
+ .select({ id: deliveryResolutions.id })
52
+ .from(deliveryResolutions)
53
+ .where(
54
+ and(
55
+ inArray(deliveryResolutions.activityApId, targetActivityIds()),
56
+ inArray(deliveryResolutions.status, [
57
+ "pending",
58
+ "queued",
59
+ "processing",
60
+ "retry_wait",
61
+ ]),
62
+ ),
63
+ ),
64
+ ),
65
+ notExists(
66
+ db
67
+ .select({ id: deliveryFanouts.id })
68
+ .from(deliveryFanouts)
69
+ .where(
70
+ and(
71
+ or(
72
+ inArray(deliveryFanouts.activityApId, targetActivityIds()),
73
+ inArray(
74
+ deliveryFanouts.announceActivityApId,
75
+ targetActivityIds(),
76
+ ),
77
+ ),
78
+ inArray(deliveryFanouts.status, ["pending", "published"]),
79
+ ),
80
+ ),
81
+ ),
82
+ )!;
83
+ }
84
+
85
+ /**
86
+ * Build the atomic cleanup unit for every durable projection of matching
87
+ * activities while retaining the activity ledger rows themselves.
88
+ *
89
+ * The inbox FK/trigger only removes push jobs in selected non-terminal states;
90
+ * delivery work, archived markers, in-flight/terminal push jobs, and inbound
91
+ * claim leases otherwise survive. This projection-only form is also used when
92
+ * an object is deleted but its historical Activity must remain available.
93
+ */
94
+ export function activityProjectionDeleteStatements(
95
+ db: Database,
96
+ activityWhere: SQL,
97
+ options: { readonly guard?: SQL } = {},
98
+ ): readonly [D1Statement, ...D1Statement[]] {
99
+ const targetActivityIds = () =>
100
+ db.select({ apId: activities.apId }).from(activities).where(activityWhere);
101
+ const guarded = (where: SQL): SQL =>
102
+ options.guard ? and(where, options.guard)! : where;
103
+
104
+ return [
105
+ db
106
+ .delete(notificationPushJobs)
107
+ .where(
108
+ guarded(
109
+ inArray(notificationPushJobs.activityApId, targetActivityIds()),
110
+ ),
111
+ ) as D1Statement,
112
+ db
113
+ .delete(notificationArchived)
114
+ .where(
115
+ guarded(
116
+ inArray(notificationArchived.activityApId, targetActivityIds()),
117
+ ),
118
+ ) as D1Statement,
119
+ db
120
+ .delete(inboundActivityClaims)
121
+ .where(
122
+ guarded(
123
+ inArray(inboundActivityClaims.activityApId, targetActivityIds()),
124
+ ),
125
+ ) as D1Statement,
126
+ db
127
+ .delete(deliveryQueue)
128
+ .where(
129
+ guarded(inArray(deliveryQueue.activityApId, targetActivityIds())),
130
+ ) as D1Statement,
131
+ db
132
+ .delete(deliveryResolutions)
133
+ .where(
134
+ guarded(inArray(deliveryResolutions.activityApId, targetActivityIds())),
135
+ ) as D1Statement,
136
+ db
137
+ .delete(deliveryFanouts)
138
+ .where(
139
+ guarded(inArray(deliveryFanouts.activityApId, targetActivityIds())),
140
+ ) as D1Statement,
141
+ // Keep the secondary Announce reference in its own statement. Combining
142
+ // both predicates with OR duplicates every bound value in D1, so a normal
143
+ // 90-id cascade would exceed the platform's 100-parameter ceiling.
144
+ db
145
+ .delete(deliveryFanouts)
146
+ .where(
147
+ guarded(
148
+ inArray(deliveryFanouts.announceActivityApId, targetActivityIds()),
149
+ ),
150
+ ) as D1Statement,
151
+ db
152
+ .delete(inbox)
153
+ .where(
154
+ guarded(inArray(inbox.activityApId, targetActivityIds())),
155
+ ) as D1Statement,
156
+ ];
157
+ }
158
+
159
+ /**
160
+ * Build one atomic hard-delete unit for activities and every durable
161
+ * projection keyed by their AP IDs.
162
+ *
163
+ * Keep the activities rows until the final statement so every preceding
164
+ * subquery sees the same target set. Semantic edges (`likes`, `announces`,
165
+ * `follows`) are intentionally caller-owned because removing them also
166
+ * requires domain-specific counter repair.
167
+ */
168
+ export function activityDeleteCascadeStatements(
169
+ db: Database,
170
+ activityWhere: SQL,
171
+ options: { readonly guard?: SQL } = {},
172
+ ): readonly [D1Statement, ...D1Statement[]] {
173
+ return [
174
+ ...activityProjectionDeleteStatements(db, activityWhere, options),
175
+ db
176
+ .delete(activities)
177
+ .where(
178
+ options.guard ? and(activityWhere, options.guard) : activityWhere,
179
+ ) as D1Statement,
180
+ ];
181
+ }
182
+
183
+ /**
184
+ * Atomically hard-delete matching activities and all of their projections.
185
+ * A failed final activity delete rolls the preceding cleanup back, so the
186
+ * caller can retry the same idempotent predicate without partial state.
187
+ */
188
+ export async function deleteActivitiesCascade(
189
+ db: Database,
190
+ activityWhere: SQL,
191
+ ): Promise<void> {
192
+ await runBatch(db, activityDeleteCascadeStatements(db, activityWhere));
193
+ }