@fedify/fedify 2.0.0-dev.237 → 2.0.0-dev.279
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/dist/{builder-D9GtbwtV.js → builder-B7WWCOdc.js} +3 -3
- package/dist/compat/mod.d.cts +2 -2
- package/dist/compat/mod.d.ts +2 -2
- package/dist/compat/transformers.test.js +12 -12
- package/dist/{context-C7vzWilY.d.ts → context-BNNWbaZL.d.ts} +51 -8
- package/dist/{context-Bns6uTJq.js → context-CZ5llAss.js} +12 -12
- package/dist/{context-CrB9RFy5.d.cts → context-D7JEVvXJ.d.cts} +51 -8
- package/dist/{deno-RfS7RWmL.js → deno-fe0u4LiE.js} +8 -2
- package/dist/{docloader-DvECEZ5H.js → docloader-C9Dmxf-K.js} +2 -2
- package/dist/federation/builder.test.js +3 -3
- package/dist/federation/handler.test.js +13 -13
- package/dist/federation/idempotency.test.js +12 -12
- package/dist/federation/inbox.test.js +2 -2
- package/dist/federation/middleware.test.js +64 -12
- package/dist/federation/mod.cjs +5 -5
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +5 -5
- package/dist/federation/mq.test.js +162 -10
- package/dist/federation/send.test.js +5 -5
- package/dist/federation/webfinger.test.js +13 -13
- package/dist/{federation-B431K2gm.cjs → federation-CE0CJ_0G.cjs} +94 -10
- package/dist/{federation-BbZwNNWj.js → federation-D6FVaeAR.js} +94 -10
- package/dist/{http-Cc7n4Qoh.js → http-7r8B3dF_.js} +8 -2
- package/dist/{http-8TlrsZoL.cjs → http-DMi5iyiI.cjs} +8 -2
- package/dist/{http-CE72P83O.js → http-oCBlFLKT.js} +2 -2
- package/dist/{inbox-CgoFwrkP.js → inbox-Dm1rfkdg.js} +1 -1
- package/dist/{key-COCrawtF.js → key-BGzsKfpZ.js} +1 -1
- package/dist/{kv-cache-BEeqyGER.js → kv-cache-B__dHl7g.js} +1 -1
- package/dist/{kv-cache-BV0LKQyf.cjs → kv-cache-C0AvpI7U.cjs} +2 -2
- package/dist/{kv-cache-DRGsvqdV.js → kv-cache-CETRZwoP.js} +2 -2
- package/dist/{ld-BaGGiySp.js → ld-BaO1-A5Y.js} +2 -2
- package/dist/{middleware-C1a3efyY.js → middleware-BDJNulB_.js} +4 -4
- package/dist/{middleware-BNd2OPEY.js → middleware-BlOT9luD.js} +66 -23
- package/dist/{middleware-DJQ_PWmN.cjs → middleware-C0Vj7vNo.cjs} +59 -16
- package/dist/{middleware-CmBe73ju.js → middleware-CnGBoMop.js} +12 -12
- package/dist/middleware-DT3JkH-g.cjs +12 -0
- package/dist/{middleware-B_oUqHDl.js → middleware-R0w-WauH.js} +59 -16
- package/dist/{mod-0qnPv4EC.d.cts → mod-054TSUXs.d.cts} +1 -1
- package/dist/{mod-0p9zUdzg.d.cts → mod-BHXq4Q3x.d.cts} +1 -1
- package/dist/{mod-C3SOvTD1.d.ts → mod-BhDb3RBS.d.ts} +1 -1
- package/dist/{mod-D6pS5_xJ.d.cts → mod-C74sRHP8.d.cts} +1 -1
- package/dist/{mod-xc20HhMD.d.ts → mod-DZmuPaKv.d.ts} +1 -1
- package/dist/{mod-waqu-BL_.d.ts → mod-YpmzboJc.d.ts} +1 -1
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +4 -4
- package/dist/mod.d.ts +4 -4
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/handler.test.js +13 -13
- package/dist/{owner-UVBc7UEt.js → owner-BqIhDQWW.js} +1 -1
- package/dist/{proof-CPysx9bF.js → proof-Cg6AAAWI.js} +1 -1
- package/dist/{proof-DSF9PSv9.js → proof-DoHt7qrS.js} +2 -2
- package/dist/{proof-Cu_UY89a.cjs → proof-vSvvLbTh.cjs} +1 -1
- package/dist/{send-DoACJ0D8.js → send-CO2ZYT96.js} +2 -2
- package/dist/sig/http.test.js +3 -3
- package/dist/sig/key.test.js +2 -2
- package/dist/sig/ld.test.js +3 -3
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.js +3 -3
- package/dist/sig/proof.test.js +3 -3
- package/dist/testing/mod.d.ts +23 -7
- package/dist/testing/mod.js +1 -1
- package/dist/utils/docloader.test.js +4 -4
- package/dist/utils/kv-cache.test.js +1 -1
- package/dist/utils/mod.cjs +2 -2
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +2 -2
- package/package.json +12 -9
- package/dist/middleware-XqO4Y-9s.cjs +0 -12
|
@@ -105,6 +105,11 @@ var InProcessMessageQueue = class {
|
|
|
105
105
|
#monitors;
|
|
106
106
|
#pollIntervalMs;
|
|
107
107
|
/**
|
|
108
|
+
* Tracks which ordering keys are currently being processed to ensure
|
|
109
|
+
* sequential processing for messages with the same key.
|
|
110
|
+
*/
|
|
111
|
+
#processingKeys;
|
|
112
|
+
/**
|
|
108
113
|
* In-process message queue does not provide native retry mechanisms.
|
|
109
114
|
* @since 1.7.0
|
|
110
115
|
*/
|
|
@@ -117,6 +122,7 @@ var InProcessMessageQueue = class {
|
|
|
117
122
|
this.#messages = [];
|
|
118
123
|
this.#monitors = {};
|
|
119
124
|
this.#pollIntervalMs = Temporal.Duration.from(options.pollInterval ?? { seconds: 5 }).total("millisecond");
|
|
125
|
+
this.#processingKeys = /* @__PURE__ */ new Set();
|
|
120
126
|
}
|
|
121
127
|
enqueue(message, options) {
|
|
122
128
|
const delay = options?.delay == null ? 0 : Math.max(options.delay.total("millisecond"), 0);
|
|
@@ -127,7 +133,11 @@ var InProcessMessageQueue = class {
|
|
|
127
133
|
}), delay);
|
|
128
134
|
return Promise.resolve();
|
|
129
135
|
}
|
|
130
|
-
|
|
136
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
137
|
+
this.#messages.push({
|
|
138
|
+
message,
|
|
139
|
+
orderingKey
|
|
140
|
+
});
|
|
131
141
|
for (const monitorId in this.#monitors) this.#monitors[monitorId]();
|
|
132
142
|
return Promise.resolve();
|
|
133
143
|
}
|
|
@@ -141,18 +151,29 @@ var InProcessMessageQueue = class {
|
|
|
141
151
|
}), delay);
|
|
142
152
|
return Promise.resolve();
|
|
143
153
|
}
|
|
144
|
-
|
|
154
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
155
|
+
for (const message of messages) this.#messages.push({
|
|
156
|
+
message,
|
|
157
|
+
orderingKey
|
|
158
|
+
});
|
|
145
159
|
for (const monitorId in this.#monitors) this.#monitors[monitorId]();
|
|
146
160
|
return Promise.resolve();
|
|
147
161
|
}
|
|
148
162
|
async listen(handler, options = {}) {
|
|
149
163
|
const signal = options.signal;
|
|
150
164
|
while (signal == null || !signal.aborted) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
165
|
+
const idx = this.#messages.findIndex((m) => m.orderingKey == null || !this.#processingKeys.has(m.orderingKey));
|
|
166
|
+
if (idx >= 0) {
|
|
167
|
+
const queued = this.#messages.splice(idx, 1)[0];
|
|
168
|
+
const { message, orderingKey } = queued;
|
|
169
|
+
if (orderingKey != null) this.#processingKeys.add(orderingKey);
|
|
170
|
+
try {
|
|
171
|
+
await handler(message);
|
|
172
|
+
} finally {
|
|
173
|
+
if (orderingKey != null) this.#processingKeys.delete(orderingKey);
|
|
174
|
+
}
|
|
175
|
+
} else if (this.#messages.length === 0) await this.#wait(this.#pollIntervalMs, signal);
|
|
176
|
+
else await this.#wait(10, signal);
|
|
156
177
|
}
|
|
157
178
|
}
|
|
158
179
|
#wait(ms, signal) {
|
|
@@ -184,6 +205,21 @@ var InProcessMessageQueue = class {
|
|
|
184
205
|
* for I/O-bound tasks, but not for CPU-bound tasks, which is okay for Fedify's
|
|
185
206
|
* workloads.
|
|
186
207
|
*
|
|
208
|
+
* When using `ParallelMessageQueue`, the ordering guarantee is preserved
|
|
209
|
+
* *only if* the underlying queue implementation delivers messages in a wrapper
|
|
210
|
+
* format that includes the `__fedify_ordering_key__` property. Currently,
|
|
211
|
+
* only `DenoKvMessageQueue` and `WorkersMessageQueue` use this format.
|
|
212
|
+
* For other queue implementations (e.g., `InProcessMessageQueue`,
|
|
213
|
+
* `RedisMessageQueue`, `PostgresMessageQueue`, `SqliteMessageQueue`,
|
|
214
|
+
* `AmqpMessageQueue`), the ordering key cannot be detected by
|
|
215
|
+
* `ParallelMessageQueue`, so ordering guarantees are handled by those
|
|
216
|
+
* implementations directly rather than at the `ParallelMessageQueue` level.
|
|
217
|
+
*
|
|
218
|
+
* Messages with the same ordering key will never be processed concurrently
|
|
219
|
+
* by different workers, ensuring sequential processing within each key.
|
|
220
|
+
* Messages with different ordering keys (or no ordering key) can still be
|
|
221
|
+
* processed in parallel.
|
|
222
|
+
*
|
|
187
223
|
* @since 1.0.0
|
|
188
224
|
*/
|
|
189
225
|
var ParallelMessageQueue = class ParallelMessageQueue {
|
|
@@ -195,6 +231,15 @@ var ParallelMessageQueue = class ParallelMessageQueue {
|
|
|
195
231
|
*/
|
|
196
232
|
nativeRetrial;
|
|
197
233
|
/**
|
|
234
|
+
* Tracks which ordering keys are currently being processed to ensure
|
|
235
|
+
* sequential processing for messages with the same key.
|
|
236
|
+
*/
|
|
237
|
+
#processingKeys = /* @__PURE__ */ new Set();
|
|
238
|
+
/**
|
|
239
|
+
* Pending messages waiting for their ordering key to become available.
|
|
240
|
+
*/
|
|
241
|
+
#pendingMessages = [];
|
|
242
|
+
/**
|
|
198
243
|
* Constructs a new {@link ParallelMessageQueue} with the given queue and
|
|
199
244
|
* number of workers.
|
|
200
245
|
* @param queue The message queue to use under the hood. Note that
|
|
@@ -222,6 +267,25 @@ var ParallelMessageQueue = class ParallelMessageQueue {
|
|
|
222
267
|
}
|
|
223
268
|
await this.queue.enqueueMany(messages, options);
|
|
224
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Extracts ordering key from a message if present.
|
|
272
|
+
*
|
|
273
|
+
* This method only works for queue implementations that deliver messages
|
|
274
|
+
* in the wrapper format with `__fedify_ordering_key__` property. Currently,
|
|
275
|
+
* only `DenoKvMessageQueue` and `WorkersMessageQueue` use this format.
|
|
276
|
+
*
|
|
277
|
+
* For other queue implementations (`InProcessMessageQueue`,
|
|
278
|
+
* `RedisMessageQueue`, `PostgresMessageQueue`, `SqliteMessageQueue`,
|
|
279
|
+
* `AmqpMessageQueue`), messages are delivered as raw payloads without the
|
|
280
|
+
* wrapper, so the ordering key cannot be detected here. Those
|
|
281
|
+
* implementations handle ordering guarantees internally.
|
|
282
|
+
*/
|
|
283
|
+
#extractOrderingKey(message) {
|
|
284
|
+
if (message != null && typeof message === "object") {
|
|
285
|
+
if ("__fedify_ordering_key__" in message) return message.__fedify_ordering_key__;
|
|
286
|
+
}
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
225
289
|
listen(handler, options = {}) {
|
|
226
290
|
const workers = /* @__PURE__ */ new Map();
|
|
227
291
|
return this.queue.listen(async (message) => {
|
|
@@ -230,13 +294,33 @@ var ParallelMessageQueue = class ParallelMessageQueue {
|
|
|
230
294
|
workers.delete(consumedId);
|
|
231
295
|
}
|
|
232
296
|
const workerId = crypto.randomUUID();
|
|
233
|
-
const
|
|
297
|
+
const orderingKey = this.#extractOrderingKey(message);
|
|
298
|
+
if (orderingKey != null && this.#processingKeys.has(orderingKey)) await new Promise((resolve) => {
|
|
299
|
+
this.#pendingMessages.push({
|
|
300
|
+
message,
|
|
301
|
+
orderingKey,
|
|
302
|
+
resolve
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
if (orderingKey != null) this.#processingKeys.add(orderingKey);
|
|
306
|
+
const promise = this.#work(workerId, handler, message, orderingKey);
|
|
234
307
|
workers.set(workerId, promise);
|
|
235
308
|
}, options);
|
|
236
309
|
}
|
|
237
|
-
async #work(workerId, handler, message) {
|
|
310
|
+
async #work(workerId, handler, message, orderingKey) {
|
|
238
311
|
await this.#sleep(0);
|
|
239
|
-
|
|
312
|
+
try {
|
|
313
|
+
await handler(message);
|
|
314
|
+
} finally {
|
|
315
|
+
if (orderingKey != null) {
|
|
316
|
+
this.#processingKeys.delete(orderingKey);
|
|
317
|
+
const pendingIdx = this.#pendingMessages.findIndex((p) => p.orderingKey === orderingKey);
|
|
318
|
+
if (pendingIdx >= 0) {
|
|
319
|
+
const pending = this.#pendingMessages.splice(pendingIdx, 1)[0];
|
|
320
|
+
pending.resolve();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
240
324
|
return workerId;
|
|
241
325
|
}
|
|
242
326
|
#sleep(ms) {
|
|
@@ -13,7 +13,7 @@ import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
|
13
13
|
|
|
14
14
|
//#region deno.json
|
|
15
15
|
var name = "@fedify/fedify";
|
|
16
|
-
var version = "2.0.0-dev.
|
|
16
|
+
var version = "2.0.0-dev.279+ce1bdc22";
|
|
17
17
|
var license = "MIT";
|
|
18
18
|
var exports = {
|
|
19
19
|
".": "./src/mod.ts",
|
|
@@ -57,7 +57,13 @@ var exclude = [
|
|
|
57
57
|
"src/cfworkers/server.js",
|
|
58
58
|
"src/cfworkers/server.js.map"
|
|
59
59
|
];
|
|
60
|
-
var publish = { "exclude": [
|
|
60
|
+
var publish = { "exclude": [
|
|
61
|
+
"**/*.test.ts",
|
|
62
|
+
"src/testing/",
|
|
63
|
+
"tsdown.config.ts",
|
|
64
|
+
"scripts/",
|
|
65
|
+
"wrangler.toml"
|
|
66
|
+
] };
|
|
61
67
|
var tasks = {
|
|
62
68
|
"codegen": "deno task -f @fedify/vocab compile",
|
|
63
69
|
"cache": {
|
|
@@ -14,7 +14,7 @@ const __fedify_vocab_runtime = require_chunk.__toESM(require("@fedify/vocab-runt
|
|
|
14
14
|
|
|
15
15
|
//#region deno.json
|
|
16
16
|
var name = "@fedify/fedify";
|
|
17
|
-
var version = "2.0.0-dev.
|
|
17
|
+
var version = "2.0.0-dev.279+ce1bdc22";
|
|
18
18
|
var license = "MIT";
|
|
19
19
|
var exports$1 = {
|
|
20
20
|
".": "./src/mod.ts",
|
|
@@ -58,7 +58,13 @@ var exclude = [
|
|
|
58
58
|
"src/cfworkers/server.js",
|
|
59
59
|
"src/cfworkers/server.js.map"
|
|
60
60
|
];
|
|
61
|
-
var publish = { "exclude": [
|
|
61
|
+
var publish = { "exclude": [
|
|
62
|
+
"**/*.test.ts",
|
|
63
|
+
"src/testing/",
|
|
64
|
+
"tsdown.config.ts",
|
|
65
|
+
"scripts/",
|
|
66
|
+
"wrangler.toml"
|
|
67
|
+
] };
|
|
62
68
|
var tasks = {
|
|
63
69
|
"codegen": "deno task -f @fedify/vocab compile",
|
|
64
70
|
"cache": {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { deno_default } from "./deno-
|
|
7
|
-
import { fetchKey, validateCryptoKey } from "./key-
|
|
6
|
+
import { deno_default } from "./deno-fe0u4LiE.js";
|
|
7
|
+
import { fetchKey, validateCryptoKey } from "./key-BGzsKfpZ.js";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { CryptographicKey } from "@fedify/vocab";
|
|
10
10
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { deno_default } from "./deno-
|
|
6
|
+
import { deno_default } from "./deno-fe0u4LiE.js";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { Activity, getTypeId } from "@fedify/vocab";
|
|
9
9
|
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { deno_default } from "./deno-
|
|
6
|
+
import { deno_default } from "./deno-fe0u4LiE.js";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
9
9
|
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -43,7 +43,7 @@ var MockKvStore = class {
|
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Decorates a {@link DocumentLoader} with a cache backed by a {@link
|
|
46
|
+
* Decorates a {@link DocumentLoader} with a cache backed by a {@link KvStore}.
|
|
47
47
|
* @param parameters The parameters for the cache.
|
|
48
48
|
* @returns The decorated document loader which is cache-enabled.
|
|
49
49
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
4
4
|
|
|
5
5
|
const require_chunk = require('./chunk-DqRYRqnO.cjs');
|
|
6
|
-
const require_http = require('./http-
|
|
6
|
+
const require_http = require('./http-DMi5iyiI.cjs');
|
|
7
7
|
const __logtape_logtape = require_chunk.__toESM(require("@logtape/logtape"));
|
|
8
8
|
const es_toolkit = require_chunk.__toESM(require("es-toolkit"));
|
|
9
9
|
const __fedify_vocab_runtime = require_chunk.__toESM(require("@fedify/vocab-runtime"));
|
|
@@ -59,7 +59,7 @@ const logger = (0, __logtape_logtape.getLogger)([
|
|
|
59
59
|
"kv-cache"
|
|
60
60
|
]);
|
|
61
61
|
/**
|
|
62
|
-
* Decorates a {@link DocumentLoader} with a cache backed by a {@link
|
|
62
|
+
* Decorates a {@link DocumentLoader} with a cache backed by a {@link KvStore}.
|
|
63
63
|
* @param parameters The parameters for the cache.
|
|
64
64
|
* @returns The decorated document loader which is cache-enabled.
|
|
65
65
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
|
|
5
|
-
import { doubleKnock, validateCryptoKey } from "./http-
|
|
5
|
+
import { doubleKnock, validateCryptoKey } from "./http-7r8B3dF_.js";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { curry } from "es-toolkit";
|
|
8
8
|
import { UrlError, createActivityPubRequest, getDocumentLoader, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
@@ -58,7 +58,7 @@ const logger = getLogger([
|
|
|
58
58
|
"kv-cache"
|
|
59
59
|
]);
|
|
60
60
|
/**
|
|
61
|
-
* Decorates a {@link DocumentLoader} with a cache backed by a {@link
|
|
61
|
+
* Decorates a {@link DocumentLoader} with a cache backed by a {@link KvStore}.
|
|
62
62
|
* @param parameters The parameters for the cache.
|
|
63
63
|
* @returns The decorated document loader which is cache-enabled.
|
|
64
64
|
*/
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { deno_default } from "./deno-
|
|
7
|
-
import { fetchKey, validateCryptoKey } from "./key-
|
|
6
|
+
import { deno_default } from "./deno-fe0u4LiE.js";
|
|
7
|
+
import { fetchKey, validateCryptoKey } from "./key-BGzsKfpZ.js";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
|
|
10
10
|
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
|
|
5
5
|
import "./transformers-N_ip_y4P.js";
|
|
6
|
-
import "./http-
|
|
7
|
-
import { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, createFederation } from "./middleware-
|
|
8
|
-
import "./proof-
|
|
6
|
+
import "./http-7r8B3dF_.js";
|
|
7
|
+
import { ContextImpl, FederationImpl, InboxContextImpl, KvSpecDeterminer, createFederation } from "./middleware-R0w-WauH.js";
|
|
8
|
+
import "./proof-Cg6AAAWI.js";
|
|
9
9
|
import "./types-8l28uC8o.js";
|
|
10
|
-
import "./kv-cache-
|
|
10
|
+
import "./kv-cache-CETRZwoP.js";
|
|
11
11
|
|
|
12
12
|
export { FederationImpl };
|
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
import { URLPattern } from "urlpattern-polyfill";
|
|
4
4
|
globalThis.addEventListener = () => {};
|
|
5
5
|
|
|
6
|
-
import { deno_default } from "./deno-
|
|
6
|
+
import { deno_default } from "./deno-fe0u4LiE.js";
|
|
7
7
|
import { getNodeInfo } from "./client-Dg7OfUDA.js";
|
|
8
8
|
import { RouterError } from "./router-D9eI0s4b.js";
|
|
9
9
|
import { nodeInfoToJson } from "./types-CPz01LGH.js";
|
|
10
|
-
import { exportJwk, importJwk, validateCryptoKey } from "./key-
|
|
11
|
-
import { verifyRequest } from "./http-
|
|
12
|
-
import { detachSignature, hasSignature, signJsonLd, verifyJsonLd } from "./ld-
|
|
13
|
-
import { doesActorOwnKey, getKeyOwner } from "./owner-
|
|
14
|
-
import { signObject, verifyObject } from "./proof-
|
|
15
|
-
import { getAuthenticatedDocumentLoader } from "./docloader-
|
|
16
|
-
import { kvCache } from "./kv-cache-
|
|
17
|
-
import { routeActivity } from "./inbox-
|
|
18
|
-
import { FederationBuilderImpl } from "./builder-
|
|
10
|
+
import { exportJwk, importJwk, validateCryptoKey } from "./key-BGzsKfpZ.js";
|
|
11
|
+
import { verifyRequest } from "./http-oCBlFLKT.js";
|
|
12
|
+
import { detachSignature, hasSignature, signJsonLd, verifyJsonLd } from "./ld-BaO1-A5Y.js";
|
|
13
|
+
import { doesActorOwnKey, getKeyOwner } from "./owner-BqIhDQWW.js";
|
|
14
|
+
import { signObject, verifyObject } from "./proof-DoHt7qrS.js";
|
|
15
|
+
import { getAuthenticatedDocumentLoader } from "./docloader-C9Dmxf-K.js";
|
|
16
|
+
import { kvCache } from "./kv-cache-B__dHl7g.js";
|
|
17
|
+
import { routeActivity } from "./inbox-Dm1rfkdg.js";
|
|
18
|
+
import { FederationBuilderImpl } from "./builder-B7WWCOdc.js";
|
|
19
19
|
import { buildCollectionSynchronizationHeader } from "./collection-CcnIw1qY.js";
|
|
20
20
|
import { KvKeyCache } from "./keycache-DRxpZ5r9.js";
|
|
21
21
|
import { acceptsJsonLd } from "./negotiation-5NPJL6zp.js";
|
|
22
22
|
import { createExponentialBackoffPolicy } from "./retry-D4GJ670a.js";
|
|
23
|
-
import { extractInboxes, sendActivity } from "./send-
|
|
23
|
+
import { extractInboxes, sendActivity } from "./send-CO2ZYT96.js";
|
|
24
24
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
25
25
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
26
26
|
import { getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -1518,6 +1518,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1518
1518
|
}) });
|
|
1519
1519
|
await this.sendActivity(keys, message.inboxes, activity, {
|
|
1520
1520
|
collectionSync: message.collectionSync,
|
|
1521
|
+
orderingKey: message.orderingKey,
|
|
1521
1522
|
context: context$1
|
|
1522
1523
|
});
|
|
1523
1524
|
}
|
|
@@ -1766,7 +1767,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1766
1767
|
"federation",
|
|
1767
1768
|
"outbox"
|
|
1768
1769
|
]);
|
|
1769
|
-
const { immediate, collectionSync, context: ctx } = options;
|
|
1770
|
+
const { immediate, collectionSync, orderingKey, context: ctx } = options;
|
|
1770
1771
|
if (activity.id == null) throw new TypeError("The activity to send must have an id.");
|
|
1771
1772
|
if (activity.actorId == null) throw new TypeError("The activity to send must have at least one actor property.");
|
|
1772
1773
|
else if (keys.length < 1) throw new TypeError("The keys must not be empty.");
|
|
@@ -1854,6 +1855,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1854
1855
|
propagation.inject(context.active(), carrier);
|
|
1855
1856
|
const messages = [];
|
|
1856
1857
|
for (const inbox in inboxes) {
|
|
1858
|
+
const inboxOrigin = new URL(inbox).origin;
|
|
1859
|
+
const messageOrderingKey = orderingKey == null ? void 0 : `${orderingKey}\n${inboxOrigin}`;
|
|
1857
1860
|
const message = {
|
|
1858
1861
|
type: "outbox",
|
|
1859
1862
|
id: crypto.randomUUID(),
|
|
@@ -1867,13 +1870,29 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1867
1870
|
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1868
1871
|
attempt: 0,
|
|
1869
1872
|
headers: collectionSync == null ? {} : { "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) },
|
|
1873
|
+
orderingKey: messageOrderingKey,
|
|
1870
1874
|
traceContext: carrier
|
|
1871
1875
|
};
|
|
1872
|
-
messages.push(
|
|
1876
|
+
messages.push({
|
|
1877
|
+
message,
|
|
1878
|
+
orderingKey: messageOrderingKey
|
|
1879
|
+
});
|
|
1873
1880
|
}
|
|
1874
1881
|
const { outboxQueue } = this;
|
|
1875
1882
|
if (outboxQueue.enqueueMany == null) {
|
|
1876
|
-
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
|
1883
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
1884
|
+
const results = await Promise.allSettled(promises);
|
|
1885
|
+
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
1886
|
+
if (errors.length > 0) {
|
|
1887
|
+
logger$2.error("Failed to enqueue activity {activityId} to send later: {errors}", {
|
|
1888
|
+
activityId: activity.id.href,
|
|
1889
|
+
errors
|
|
1890
|
+
});
|
|
1891
|
+
if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${activityId} to send later.`);
|
|
1892
|
+
throw errors[0];
|
|
1893
|
+
}
|
|
1894
|
+
} else if (orderingKey != null) {
|
|
1895
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
1877
1896
|
const results = await Promise.allSettled(promises);
|
|
1878
1897
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
1879
1898
|
if (errors.length > 0) {
|
|
@@ -1885,7 +1904,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
1885
1904
|
throw errors[0];
|
|
1886
1905
|
}
|
|
1887
1906
|
} else try {
|
|
1888
|
-
await outboxQueue.enqueueMany(messages);
|
|
1907
|
+
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
1889
1908
|
} catch (error) {
|
|
1890
1909
|
logger$2.error("Failed to enqueue activity {activityId} to send later: {error}", {
|
|
1891
1910
|
activityId: activity.id.href,
|
|
@@ -2601,20 +2620,25 @@ var ContextImpl = class ContextImpl {
|
|
|
2601
2620
|
} else keys = [sender];
|
|
2602
2621
|
if (keys.length < 1) throw new TypeError("The sender's keys must not be empty.");
|
|
2603
2622
|
for (const { privateKey } of keys) validateCryptoKey(privateKey, "private");
|
|
2604
|
-
const opts = { context: this };
|
|
2605
2623
|
let expandedRecipients;
|
|
2624
|
+
let collectionSync;
|
|
2606
2625
|
if (Array.isArray(recipients)) expandedRecipients = recipients;
|
|
2607
2626
|
else if (recipients === "followers") {
|
|
2608
2627
|
if (identifier == null) throw new Error("If recipients is \"followers\", sender must be an actor identifier or username.");
|
|
2609
2628
|
expandedRecipients = [];
|
|
2610
2629
|
for await (const recipient of this.getFollowers(identifier)) expandedRecipients.push(recipient);
|
|
2611
2630
|
if (options.syncCollection) try {
|
|
2612
|
-
|
|
2631
|
+
collectionSync = this.getFollowersUri(identifier).href;
|
|
2613
2632
|
} catch (error) {
|
|
2614
|
-
if (error instanceof RouterError)
|
|
2615
|
-
else throw error;
|
|
2633
|
+
if (!(error instanceof RouterError)) throw error;
|
|
2616
2634
|
}
|
|
2617
2635
|
} else expandedRecipients = [recipients];
|
|
2636
|
+
const opts = {
|
|
2637
|
+
context: this,
|
|
2638
|
+
orderingKey: options.orderingKey,
|
|
2639
|
+
collectionSync,
|
|
2640
|
+
immediate: options.immediate
|
|
2641
|
+
};
|
|
2618
2642
|
span.setAttribute("activitypub.inboxes", expandedRecipients.length);
|
|
2619
2643
|
for (const activityTransformer of this.federation.activityTransformers) activity = activityTransformer(activity, this);
|
|
2620
2644
|
span?.setAttribute("activitypub.activity.id", activity?.id?.href ?? "");
|
|
@@ -2661,10 +2685,11 @@ var ContextImpl = class ContextImpl {
|
|
|
2661
2685
|
activityId: activity.id?.href,
|
|
2662
2686
|
activityType: getTypeId(activity).href,
|
|
2663
2687
|
collectionSync: opts.collectionSync,
|
|
2688
|
+
orderingKey: options.orderingKey,
|
|
2664
2689
|
traceContext: carrier
|
|
2665
2690
|
};
|
|
2666
2691
|
if (!this.federation.manuallyStartQueue) this.federation._startQueueInternal(this.data);
|
|
2667
|
-
this.federation.fanoutQueue.enqueue(message);
|
|
2692
|
+
this.federation.fanoutQueue.enqueue(message, { orderingKey: options.orderingKey });
|
|
2668
2693
|
}
|
|
2669
2694
|
async *getFollowers(identifier) {
|
|
2670
2695
|
if (this.federation.followersCallbacks == null) throw new Error("No followers collection dispatcher registered.");
|
|
@@ -3016,8 +3041,10 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3016
3041
|
}
|
|
3017
3042
|
const carrier = {};
|
|
3018
3043
|
propagation.inject(context.active(), carrier);
|
|
3044
|
+
const orderingKey = options?.orderingKey;
|
|
3019
3045
|
const messages = [];
|
|
3020
3046
|
for (const inbox in inboxes) {
|
|
3047
|
+
const inboxUrl = new URL(inbox);
|
|
3021
3048
|
const message = {
|
|
3022
3049
|
type: "outbox",
|
|
3023
3050
|
id: crypto.randomUUID(),
|
|
@@ -3031,13 +3058,29 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3031
3058
|
started: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3032
3059
|
attempt: 0,
|
|
3033
3060
|
headers: {},
|
|
3061
|
+
orderingKey: orderingKey == null ? void 0 : `${orderingKey}\n${inboxUrl.origin}`,
|
|
3034
3062
|
traceContext: carrier
|
|
3035
3063
|
};
|
|
3036
|
-
messages.push(
|
|
3064
|
+
messages.push({
|
|
3065
|
+
message,
|
|
3066
|
+
orderingKey: message.orderingKey
|
|
3067
|
+
});
|
|
3037
3068
|
}
|
|
3038
3069
|
const { outboxQueue } = this.federation;
|
|
3039
3070
|
if (outboxQueue.enqueueMany == null) {
|
|
3040
|
-
const promises = messages.map((m) => outboxQueue.enqueue(m));
|
|
3071
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
3072
|
+
const results = await Promise.allSettled(promises);
|
|
3073
|
+
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3074
|
+
if (errors.length > 0) {
|
|
3075
|
+
logger$2.error("Failed to enqueue activity {activityId} to forward later:\n{errors}", {
|
|
3076
|
+
activityId: this.activityId,
|
|
3077
|
+
errors
|
|
3078
|
+
});
|
|
3079
|
+
if (errors.length > 1) throw new AggregateError(errors, `Failed to enqueue activity ${this.activityId} to forward later.`);
|
|
3080
|
+
throw errors[0];
|
|
3081
|
+
}
|
|
3082
|
+
} else if (orderingKey != null) {
|
|
3083
|
+
const promises = messages.map((m) => outboxQueue.enqueue(m.message, { orderingKey: m.orderingKey }));
|
|
3041
3084
|
const results = await Promise.allSettled(promises);
|
|
3042
3085
|
const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason);
|
|
3043
3086
|
if (errors.length > 0) {
|
|
@@ -3049,7 +3092,7 @@ var InboxContextImpl = class InboxContextImpl extends ContextImpl {
|
|
|
3049
3092
|
throw errors[0];
|
|
3050
3093
|
}
|
|
3051
3094
|
} else try {
|
|
3052
|
-
await outboxQueue.enqueueMany(messages);
|
|
3095
|
+
await outboxQueue.enqueueMany(messages.map((m) => m.message));
|
|
3053
3096
|
} catch (error) {
|
|
3054
3097
|
logger$2.error("Failed to enqueue activity {activityId} to forward later:\n{error}", {
|
|
3055
3098
|
activityId: this.activityId,
|