@fedify/fedify 1.5.0-dev.730 → 1.5.0-dev.732
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/CHANGES.md +6 -0
- package/esm/deno.js +1 -1
- package/esm/federation/middleware.js +55 -24
- package/esm/federation/mq.js +31 -0
- package/esm/vocab/vocab.js +176 -176
- package/package.json +1 -1
- package/types/federation/context.d.ts +2 -2
- package/types/federation/context.d.ts.map +1 -1
- package/types/federation/middleware.d.ts.map +1 -1
- package/types/federation/mq.d.ts +11 -0
- package/types/federation/mq.d.ts.map +1 -1
package/CHANGES.md
CHANGED
@@ -19,6 +19,9 @@ To be released.
|
|
19
19
|
undefined`).
|
20
20
|
- Added `SendActivityOptions.fanout` option.
|
21
21
|
- Added OpenTelemetry instrumented span `activitypub.fanout`.
|
22
|
+
- The `ForwardActivityOptions` interface became a type alias of
|
23
|
+
`Omit<SendActivityOptions, "fanout"> & { skipIfUnsigned: boolean }`,
|
24
|
+
which is still compatible with the previous version.
|
22
25
|
|
23
26
|
- A `Federation` object now can have a canonical origin for web URLs and
|
24
27
|
a canonical host for fediverse handles. This affects the URLs constructed
|
@@ -61,6 +64,9 @@ To be released.
|
|
61
64
|
- Deprecated the fourth parameter of the `ObjectAuthorizePredicate` type
|
62
65
|
in favor of the `RequestContext.getSignedKeyOwner()` method.
|
63
66
|
|
67
|
+
- Added an optional method `enqueueMany()` to `MessageQueue` interface
|
68
|
+
for sending multiple activities at once.
|
69
|
+
|
64
70
|
- Fixed a bug of the `fedify inbox` command where it had failed to render
|
65
71
|
the web interface when the `fedify` command was installed using
|
66
72
|
`deno install` command from JSR.
|
package/esm/deno.js
CHANGED
@@ -322,6 +322,11 @@ export class FederationImpl {
|
|
322
322
|
});
|
323
323
|
}
|
324
324
|
async #listenFanoutMessage(data, message) {
|
325
|
+
const logger = getLogger(["fedify", "federation", "fanout"]);
|
326
|
+
logger.debug("Fanning out activity {activityId} to {inboxes} inbox(es)...", {
|
327
|
+
activityId: message.activityId,
|
328
|
+
inboxes: globalThis.Object.keys(message.inboxes).length,
|
329
|
+
});
|
325
330
|
const keys = await Promise.all(message.keys.map(async ({ keyId, privateKey }) => ({
|
326
331
|
keyId: new URL(keyId),
|
327
332
|
privateKey: await importJwk(privateKey, "private"),
|
@@ -1284,7 +1289,7 @@ export class FederationImpl {
|
|
1284
1289
|
this._startQueueInternal(ctx.data);
|
1285
1290
|
const carrier = {};
|
1286
1291
|
propagation.inject(context.active(), carrier);
|
1287
|
-
const
|
1292
|
+
const messages = [];
|
1288
1293
|
for (const inbox in inboxes) {
|
1289
1294
|
const message = {
|
1290
1295
|
type: "outbox",
|
@@ -1303,18 +1308,31 @@ export class FederationImpl {
|
|
1303
1308
|
},
|
1304
1309
|
traceContext: carrier,
|
1305
1310
|
};
|
1306
|
-
|
1311
|
+
messages.push(message);
|
1312
|
+
}
|
1313
|
+
const { outboxQueue } = this;
|
1314
|
+
if (outboxQueue.enqueueMany == null) {
|
1315
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
1316
|
+
const results = await Promise.allSettled(promises);
|
1317
|
+
const errors = results
|
1318
|
+
.filter((r) => r.status === "rejected")
|
1319
|
+
.map((r) => r.reason);
|
1320
|
+
if (errors.length > 0) {
|
1321
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {errors}", { activityId: activity.id.href, errors });
|
1322
|
+
if (errors.length > 1) {
|
1323
|
+
throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
|
1324
|
+
}
|
1325
|
+
throw errors[0];
|
1326
|
+
}
|
1307
1327
|
}
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
|
1328
|
+
else {
|
1329
|
+
try {
|
1330
|
+
await outboxQueue.enqueueMany(messages);
|
1331
|
+
}
|
1332
|
+
catch (error) {
|
1333
|
+
logger.error("Failed to enqueue activity {activityId} to send later: {error}", { activityId: activity.id.href, error });
|
1334
|
+
throw error;
|
1316
1335
|
}
|
1317
|
-
throw errors[0];
|
1318
1336
|
}
|
1319
1337
|
}
|
1320
1338
|
fetch(request, options) {
|
@@ -2511,7 +2529,7 @@ export class InboxContextImpl extends ContextImpl {
|
|
2511
2529
|
}
|
2512
2530
|
const carrier = {};
|
2513
2531
|
propagation.inject(context.active(), carrier);
|
2514
|
-
const
|
2532
|
+
const messages = [];
|
2515
2533
|
for (const inbox in inboxes) {
|
2516
2534
|
const message = {
|
2517
2535
|
type: "outbox",
|
@@ -2528,18 +2546,31 @@ export class InboxContextImpl extends ContextImpl {
|
|
2528
2546
|
headers: {},
|
2529
2547
|
traceContext: carrier,
|
2530
2548
|
};
|
2531
|
-
|
2532
|
-
}
|
2533
|
-
const
|
2534
|
-
|
2535
|
-
.
|
2536
|
-
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2549
|
+
messages.push(message);
|
2550
|
+
}
|
2551
|
+
const { outboxQueue } = this.federation;
|
2552
|
+
if (outboxQueue.enqueueMany == null) {
|
2553
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
2554
|
+
const results = await Promise.allSettled(promises);
|
2555
|
+
const errors = results
|
2556
|
+
.filter((r) => r.status === "rejected")
|
2557
|
+
.map((r) => r.reason);
|
2558
|
+
if (errors.length > 0) {
|
2559
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", { activityId: this.activityId, errors });
|
2560
|
+
if (errors.length > 1) {
|
2561
|
+
throw new AggregateError(errors, `Failed to enqueue activity ${this.activityId} to forward later.`);
|
2562
|
+
}
|
2563
|
+
throw errors[0];
|
2564
|
+
}
|
2565
|
+
}
|
2566
|
+
else {
|
2567
|
+
try {
|
2568
|
+
await outboxQueue.enqueueMany(messages);
|
2569
|
+
}
|
2570
|
+
catch (error) {
|
2571
|
+
logger.error("Failed to enqueue activity {activityId} to forward later:\n{error}", { activityId: this.activityId, error });
|
2572
|
+
throw error;
|
2573
|
+
}
|
2543
2574
|
}
|
2544
2575
|
}
|
2545
2576
|
}
|
package/esm/federation/mq.js
CHANGED
@@ -39,6 +39,22 @@ export class InProcessMessageQueue {
|
|
39
39
|
}
|
40
40
|
return Promise.resolve();
|
41
41
|
}
|
42
|
+
enqueueMany(messages, options) {
|
43
|
+
if (messages.length === 0)
|
44
|
+
return Promise.resolve();
|
45
|
+
const delay = options?.delay == null
|
46
|
+
? 0
|
47
|
+
: Math.max(options.delay.total("millisecond"), 0);
|
48
|
+
if (delay > 0) {
|
49
|
+
setTimeout(() => this.enqueueMany(messages, { ...options, delay: undefined }), delay);
|
50
|
+
return Promise.resolve();
|
51
|
+
}
|
52
|
+
this.#messages.push(...messages);
|
53
|
+
for (const monitorId in this.#monitors) {
|
54
|
+
this.#monitors[monitorId]();
|
55
|
+
}
|
56
|
+
return Promise.resolve();
|
57
|
+
}
|
42
58
|
async listen(handler, options = {}) {
|
43
59
|
const signal = options.signal;
|
44
60
|
while (signal == null || !signal.aborted) {
|
@@ -107,6 +123,21 @@ export class ParallelMessageQueue {
|
|
107
123
|
enqueue(message, options) {
|
108
124
|
return this.queue.enqueue(message, options);
|
109
125
|
}
|
126
|
+
async enqueueMany(messages, options) {
|
127
|
+
if (this.queue.enqueueMany == null) {
|
128
|
+
const results = await Promise.allSettled(messages.map((message) => this.queue.enqueue(message, options)));
|
129
|
+
const errors = results
|
130
|
+
.filter((r) => r.status === "rejected")
|
131
|
+
.map((r) => r.reason);
|
132
|
+
if (errors.length > 1) {
|
133
|
+
throw new AggregateError(errors, "Failed to enqueue messages.");
|
134
|
+
}
|
135
|
+
else if (errors.length === 1)
|
136
|
+
throw errors[0];
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
await this.queue.enqueueMany(messages, options);
|
140
|
+
}
|
110
141
|
listen(handler, options = {}) {
|
111
142
|
const workers = new Map();
|
112
143
|
return this.queue.listen(async (message) => {
|