@fedify/fedify 2.4.0-dev.2065 → 2.4.0-dev.2073
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-CMkrnYbY.mjs → builder-CVHpPAjK.mjs} +6 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-Dj3DCsoj.mjs → compound-proof-B5Skp-vE.mjs} +1 -1
- package/dist/{context-D_gg4M0n.d.ts → context-BSywYspi.d.ts} +153 -2
- package/dist/{context-b36TpPoG.d.cts → context-CZjZYXFC.d.cts} +153 -2
- package/dist/{context-DG5QeQ8W.mjs → context-DlZhxdFT.mjs} +2 -1
- package/dist/{deno-BuRFI7wk.mjs → deno-LYTbBhYV.mjs} +1 -1
- package/dist/{docloader-_aSNLA90.mjs → docloader-C0SWQylk.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +4 -4
- package/dist/federation/handler-compound-proof.test.mjs +4 -4
- package/dist/federation/handler.test.mjs +6 -6
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +9 -9
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +1 -1
- package/dist/federation/outgoing-proof.test.mjs +6 -6
- package/dist/federation/portable-gateway-keys.test.d.mts +2 -0
- package/dist/federation/portable-gateway-keys.test.mjs +363 -0
- package/dist/federation/portable-inbox.test.d.mts +2 -0
- package/dist/federation/portable-inbox.test.mjs +546 -0
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +2 -2
- package/dist/federation/tasks/tasks.test.mjs +3 -3
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +2 -2
- package/dist/{federation-Coi_bg12.cjs → federation-B1aeTKKN.cjs} +631 -145
- package/dist/{http-f1qaBtOh.mjs → http-C7qHlv-b.mjs} +20 -5
- package/dist/{http-BGShIsd6.cjs → http-DGk8XI38.cjs} +2684 -48
- package/dist/{http-65PYi9jY.d.ts → http-n2v6DPxu.d.ts} +52 -2
- package/dist/http-vfTpzGEq.js +5087 -0
- package/dist/{http-CP-7OdSq.d.cts → http-xlG-jRdB.d.cts} +52 -2
- package/dist/{key-BxHsA1s9.mjs → key-BYXnTGro.mjs} +147 -7
- package/dist/{kv-cache-Cgj-kpQS.js → kv-cache-DCJuwdnB.js} +1 -1
- package/dist/{kv-cache-C9IY-FMN.mjs → kv-cache-DEH5jyND.mjs} +1 -1
- package/dist/{kv-cache-CY6pDNoS.cjs → kv-cache-DvqkKNIj.cjs} +1 -1
- package/dist/{ld-CqJq5erX.mjs → ld-DT3e2hOv.mjs} +3 -3
- package/dist/{metrics-DOqknlZd.mjs → metrics-DvlvYpq_.mjs} +1 -1
- package/dist/{middleware-VOCZN3SO.mjs → middleware-BJcez_E3.mjs} +1 -1
- package/dist/{middleware-1h_LgwXC.js → middleware-CCbyUF4c.js} +547 -62
- package/dist/{middleware-s-AZzx4r.mjs → middleware-CpyCNOW_.mjs} +549 -72
- package/dist/{mod-BhMvsgdF.d.ts → mod-B2h2KY0q.d.ts} +1 -1
- package/dist/{mod-Dhm7SqyE.d.ts → mod-C9WSpZWm.d.ts} +1 -1
- package/dist/{mod-C0BYc0OU.d.ts → mod-CVZrXSdm.d.ts} +1 -1
- package/dist/{mod-pLbeNwcC.d.cts → mod-HDSvS-ww.d.cts} +1 -1
- package/dist/{mod-Bfenkg_c.d.cts → mod-JzkaEXsi.d.cts} +1 -1
- package/dist/{mod-CyiSjRkk.d.cts → mod-xGFCHqq_.d.cts} +1 -1
- package/dist/mod.cjs +18 -18
- package/dist/mod.d.cts +7 -7
- package/dist/mod.d.ts +7 -7
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/handler.test.mjs +2 -2
- package/dist/{owner-D_F22lfM.mjs → owner-CDsVeZI7.mjs} +45 -2
- package/dist/owner-DCIH7Iq0.cjs +225 -0
- package/dist/owner-DfGz0cXm.js +215 -0
- package/dist/portable-key-DCyKGCQd.mjs +194 -0
- package/dist/{proof-B03JXhrk.mjs → proof-CxsVG6vM.mjs} +5 -5
- package/dist/{send-NNkfKtVN.mjs → send-BZJ7NsVV.mjs} +8 -4
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +2 -2
- package/dist/sig/compound-proof.test.mjs +3 -3
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +16 -16
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +3 -3
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +3 -3
- package/dist/sig/portable-key.test.d.mts +2 -0
- package/dist/sig/portable-key.test.mjs +275 -0
- package/dist/sig/proof.test.mjs +4 -4
- package/dist/{sig-B1E2uyhQ.cjs → sig-C6TnADze.cjs} +4 -4
- package/dist/{sig-Bb20Pyrd.js → sig-Cs9_ecdh.js} +2 -2
- package/dist/{temporal-VVVSuruq.mjs → temporal-CLzSfIOV.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +151 -0
- package/dist/testing/mod.mjs +2 -2
- package/dist/{testing-By1YYsIK.mjs → testing-CO_cEvQc.mjs} +1 -1
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
- package/dist/http-z5n7chWw.js +0 -2647
- package/dist/owner-BLBWXCNt.js +0 -2276
- package/dist/owner-D8ZpRusc.cjs +0 -2446
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import { Temporal } from "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as esm_default } from "../esm-BHXXx4Wx.mjs";
|
|
5
|
+
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
6
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
7
|
+
import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
|
|
8
|
+
import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
|
|
9
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
10
|
+
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
11
|
+
import { p as signJsonLd } from "../ld-DT3e2hOv.mjs";
|
|
12
|
+
import { r as signObject } from "../proof-CxsVG6vM.mjs";
|
|
13
|
+
import { s as signRequest } from "../http-C7qHlv-b.mjs";
|
|
14
|
+
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
15
|
+
import { c as forwardPortableInboxActivity, l as resolvePortableInboxForwardingOptions, o as createFederation } from "../middleware-CpyCNOW_.mjs";
|
|
16
|
+
import { Create, Follow, Note, Person, Tombstone } from "@fedify/vocab";
|
|
17
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
18
|
+
import { exportDidKey, formatIri, parseIri } from "@fedify/vocab-runtime";
|
|
19
|
+
//#region src/federation/portable-inbox.test.ts
|
|
20
|
+
const did = await exportDidKey(ed25519PublicKey.publicKey);
|
|
21
|
+
const keyId = new URL(`${did}#${did.substring(8)}`);
|
|
22
|
+
const otherKeyPair = await crypto.subtle.generateKey("Ed25519", true, ["sign", "verify"]);
|
|
23
|
+
const otherDid = await exportDidKey(otherKeyPair.publicKey);
|
|
24
|
+
const LOCAL = "https://example.com";
|
|
25
|
+
const GATEWAY2 = "https://example.org";
|
|
26
|
+
const GATEWAY3 = "https://example.net";
|
|
27
|
+
function inboxUrl(authority = did, path = "/users/alice/inbox", origin = LOCAL) {
|
|
28
|
+
return `${origin}/.well-known/apgateway/${authority}${path}`;
|
|
29
|
+
}
|
|
30
|
+
function post(url, body, headers = {}) {
|
|
31
|
+
return new Request(url, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: {
|
|
34
|
+
"Content-Type": "application/activity+json",
|
|
35
|
+
...headers
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify(body)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
var RecordingQueue = class {
|
|
41
|
+
messages = [];
|
|
42
|
+
failFor;
|
|
43
|
+
enqueue(message) {
|
|
44
|
+
if (this.failFor != null && message.type === "outbox" && message.inbox.startsWith(this.failFor)) return Promise.reject(/* @__PURE__ */ new Error("Enqueue failed."));
|
|
45
|
+
this.messages.push(message);
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
listen() {
|
|
49
|
+
return Promise.resolve();
|
|
50
|
+
}
|
|
51
|
+
get outbox() {
|
|
52
|
+
return this.messages.filter((m) => m.type === "outbox");
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
function setup({ gateways = [
|
|
56
|
+
LOCAL,
|
|
57
|
+
GATEWAY2,
|
|
58
|
+
GATEWAY3
|
|
59
|
+
], kv = new MemoryKvStore(), queue, options = {}, actor, listenerError = false, keyPairs = true, onSharedInboxKey } = {}) {
|
|
60
|
+
const federation = createFederation({
|
|
61
|
+
kv,
|
|
62
|
+
...options.allowPrivateAddress ? {} : {
|
|
63
|
+
documentLoaderFactory: () => mockDocumentLoader,
|
|
64
|
+
contextLoaderFactory: () => mockDocumentLoader
|
|
65
|
+
},
|
|
66
|
+
manuallyStartQueue: true,
|
|
67
|
+
...queue == null ? {} : { queue: { outbox: queue } },
|
|
68
|
+
...options
|
|
69
|
+
});
|
|
70
|
+
const received = [];
|
|
71
|
+
const actorCallbacks = federation.setActorDispatcher("/users/{identifier}", actor ?? ((ctx, identifier) => {
|
|
72
|
+
if (identifier === "ordinary") return new Person({
|
|
73
|
+
id: ctx.getActorUri(identifier),
|
|
74
|
+
inbox: ctx.getInboxUri(identifier)
|
|
75
|
+
});
|
|
76
|
+
if (identifier !== "alice") return null;
|
|
77
|
+
return new Person({
|
|
78
|
+
id: parseIri(`ap+ef61://${did}/users/alice`),
|
|
79
|
+
inbox: ctx.getPortableInboxUri(identifier, did),
|
|
80
|
+
gateways: gateways.map((g) => new URL(g))
|
|
81
|
+
});
|
|
82
|
+
}));
|
|
83
|
+
if (keyPairs) actorCallbacks.setKeyPairsDispatcher((_ctx, identifier) => identifier === "ordinary" ? [{
|
|
84
|
+
privateKey: rsaPrivateKey2,
|
|
85
|
+
publicKey: rsaPublicKey2.publicKey
|
|
86
|
+
}] : []);
|
|
87
|
+
const inboxListeners = federation.setInboxListeners("/users/{identifier}/inbox", "/inbox");
|
|
88
|
+
if (onSharedInboxKey != null) inboxListeners.setSharedKeyDispatcher(() => {
|
|
89
|
+
onSharedInboxKey();
|
|
90
|
+
return null;
|
|
91
|
+
});
|
|
92
|
+
inboxListeners.on(Follow, (ctx, activity) => {
|
|
93
|
+
received.push({
|
|
94
|
+
activity,
|
|
95
|
+
recipient: ctx.recipient
|
|
96
|
+
});
|
|
97
|
+
if (listenerError) throw new Error("Listener failed.");
|
|
98
|
+
}).on(Create, (ctx, activity) => {
|
|
99
|
+
received.push({
|
|
100
|
+
activity,
|
|
101
|
+
recipient: ctx.recipient
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
federation,
|
|
106
|
+
received,
|
|
107
|
+
kv,
|
|
108
|
+
queue
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
let activityCounter = 0;
|
|
112
|
+
async function signedFollow(authority = did, privateKey = ed25519PrivateKey, signingKeyId = keyId) {
|
|
113
|
+
return await (await signObject(new Follow({
|
|
114
|
+
id: parseIri(`ap+ef61://${authority}/follows/${++activityCounter}`),
|
|
115
|
+
actor: parseIri(`ap+ef61://${authority}/users/bob`),
|
|
116
|
+
object: parseIri(`ap+ef61://${did}/users/alice`)
|
|
117
|
+
}), privateKey, signingKeyId, { contextLoader: mockDocumentLoader })).toJsonLd({ contextLoader: mockDocumentLoader });
|
|
118
|
+
}
|
|
119
|
+
test("Federation.fetch() delivers to portable inboxes", async (t) => {
|
|
120
|
+
const queue = new RecordingQueue();
|
|
121
|
+
const { federation, received } = setup({ queue });
|
|
122
|
+
const json = await signedFollow();
|
|
123
|
+
await t.step("routes to the existing inbox listeners", async () => {
|
|
124
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 202);
|
|
125
|
+
assertEquals(received.length, 1);
|
|
126
|
+
assertEquals(received[0].recipient, "alice");
|
|
127
|
+
assert(received[0].activity instanceof Follow);
|
|
128
|
+
});
|
|
129
|
+
await t.step("forwards the activity to the other gateways", () => {
|
|
130
|
+
assertEquals(queue.outbox.map((m) => m.inbox).sort(), [inboxUrl(did, "/users/alice/inbox", GATEWAY3), inboxUrl(did, "/users/alice/inbox", GATEWAY2)]);
|
|
131
|
+
for (const message of queue.outbox) {
|
|
132
|
+
assertEquals(message.keys, []);
|
|
133
|
+
assertEquals(message.activity, json);
|
|
134
|
+
assertFalse(message.sharedInbox);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
await t.step("neither forwards nor dispatches duplicates", async () => {
|
|
138
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 202);
|
|
139
|
+
assertEquals(received.length, 1);
|
|
140
|
+
assertEquals(queue.outbox.length, 2);
|
|
141
|
+
});
|
|
142
|
+
await t.step("accepts ap: and percent-encoded DIDs", async () => {
|
|
143
|
+
assertEquals((await federation.fetch(post(inboxUrl(did.replaceAll(":", "%3A")), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
144
|
+
assertEquals(received.length, 2);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
test("Federation.fetch() delivers to portable inboxes without key pairs", async () => {
|
|
148
|
+
const queue = new RecordingQueue();
|
|
149
|
+
const { federation, received } = setup({
|
|
150
|
+
queue,
|
|
151
|
+
keyPairs: false
|
|
152
|
+
});
|
|
153
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
154
|
+
assertEquals(received.length, 1);
|
|
155
|
+
assertEquals(queue.outbox.length, 2);
|
|
156
|
+
});
|
|
157
|
+
test("Federation.fetch() refuses portable inbox deliveries it does not accept", async (t) => {
|
|
158
|
+
const { federation, received } = setup({ gateways: [GATEWAY2] });
|
|
159
|
+
const json = await signedFollow();
|
|
160
|
+
await t.step("this server is not a gateway of the actor", async () => {
|
|
161
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 404);
|
|
162
|
+
});
|
|
163
|
+
const accepting = setup();
|
|
164
|
+
const cases = [
|
|
165
|
+
["unknown actor", inboxUrl(did, "/users/unknown/inbox")],
|
|
166
|
+
["non-portable actor", inboxUrl(did, "/users/ordinary/inbox")],
|
|
167
|
+
["DID mismatch", inboxUrl(otherDid)],
|
|
168
|
+
["shared inbox", inboxUrl(did, "/inbox")],
|
|
169
|
+
["actor path", inboxUrl(did, "/users/alice")],
|
|
170
|
+
["unregistered path", inboxUrl(did, "/unknown/alice/inbox")]
|
|
171
|
+
];
|
|
172
|
+
for (const [name, url] of cases) await t.step(name, async () => {
|
|
173
|
+
assertEquals((await accepting.federation.fetch(post(url, json), { contextData: void 0 })).status, 404);
|
|
174
|
+
});
|
|
175
|
+
await t.step("inbox mismatch", async () => {
|
|
176
|
+
const { federation } = setup({ actor: () => new Person({
|
|
177
|
+
id: parseIri(`ap+ef61://${did}/users/alice`),
|
|
178
|
+
inbox: parseIri(`ap+ef61://${did}/users/alice/other-inbox`),
|
|
179
|
+
gateways: [new URL(LOCAL)]
|
|
180
|
+
}) });
|
|
181
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 404);
|
|
182
|
+
});
|
|
183
|
+
await t.step("tombstone", async () => {
|
|
184
|
+
const { federation } = setup({ actor: () => new Tombstone({ id: parseIri(`ap+ef61://${did}/users/alice`) }) });
|
|
185
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 404);
|
|
186
|
+
});
|
|
187
|
+
await t.step("malformed DID", async () => {
|
|
188
|
+
assertEquals((await accepting.federation.fetch(post(`${LOCAL}/.well-known/apgateway/did:key:/users/alice/inbox`, json), { contextData: void 0 })).status, 400);
|
|
189
|
+
});
|
|
190
|
+
await t.step("listeners are not called", () => {
|
|
191
|
+
assertEquals(received.length, 0);
|
|
192
|
+
assertEquals(accepting.received.length, 0);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
test("Federation.fetch() applies the proof policy to portable inbox deliveries", async (t) => {
|
|
196
|
+
const queue = new RecordingQueue();
|
|
197
|
+
const { federation, received } = setup({ queue });
|
|
198
|
+
await t.step("unsigned portable activity", async () => {
|
|
199
|
+
const json = await new Follow({
|
|
200
|
+
id: parseIri(`ap+ef61://${did}/follows/unsigned`),
|
|
201
|
+
actor: parseIri(`ap+ef61://${did}/users/bob`),
|
|
202
|
+
object: parseIri(`ap+ef61://${did}/users/alice`)
|
|
203
|
+
}).toJsonLd({ contextLoader: mockDocumentLoader });
|
|
204
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 401);
|
|
205
|
+
});
|
|
206
|
+
await t.step("proof made by another DID", async () => {
|
|
207
|
+
const json = await signedFollow(did, otherKeyPair.privateKey, new URL(`${otherDid}#${otherDid.substring(8)}`));
|
|
208
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 401);
|
|
209
|
+
});
|
|
210
|
+
await t.step("unsigned portable object in a signed activity", async () => {
|
|
211
|
+
const json = await (await signObject(new Create({
|
|
212
|
+
id: parseIri(`ap+ef61://${did}/creates/1`),
|
|
213
|
+
actor: parseIri(`ap+ef61://${did}/users/bob`),
|
|
214
|
+
object: new Note({
|
|
215
|
+
id: parseIri(`ap+ef61://${did}/notes/1`),
|
|
216
|
+
content: "Hello"
|
|
217
|
+
})
|
|
218
|
+
}), ed25519PrivateKey, keyId, { contextLoader: mockDocumentLoader })).toJsonLd({ contextLoader: mockDocumentLoader });
|
|
219
|
+
assertEquals((await federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 401);
|
|
220
|
+
});
|
|
221
|
+
await t.step("nothing is dispatched or forwarded", () => {
|
|
222
|
+
assertEquals(received.length, 0);
|
|
223
|
+
assertEquals(queue.outbox.length, 0);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
test("Federation.fetch() does not forward activities authenticated only by HTTP Signatures", async () => {
|
|
227
|
+
const queue = new RecordingQueue();
|
|
228
|
+
const { federation, received } = setup({ queue });
|
|
229
|
+
const activity = {
|
|
230
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
231
|
+
id: "https://example.com/follows/http",
|
|
232
|
+
type: "Follow",
|
|
233
|
+
actor: "https://example.com/person2",
|
|
234
|
+
object: formatIri(parseIri(`ap+ef61://${did}/users/alice`))
|
|
235
|
+
};
|
|
236
|
+
const request = await signRequest(post(inboxUrl(), activity), rsaPrivateKey3, new URL("https://example.com/person2#key3"));
|
|
237
|
+
assertEquals((await federation.fetch(request, { contextData: void 0 })).status, 202);
|
|
238
|
+
assertEquals(received.length, 1);
|
|
239
|
+
assertEquals(queue.outbox.length, 0);
|
|
240
|
+
});
|
|
241
|
+
test("Federation.fetch() forwards activities authenticated by Linked Data Signatures", async () => {
|
|
242
|
+
const queue = new RecordingQueue();
|
|
243
|
+
const { federation, received } = setup({ queue });
|
|
244
|
+
const activity = await signJsonLd({
|
|
245
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
246
|
+
id: "https://example.com/follows/lds",
|
|
247
|
+
type: "Follow",
|
|
248
|
+
actor: "https://example.com/person2",
|
|
249
|
+
object: formatIri(parseIri(`ap+ef61://${did}/users/alice`))
|
|
250
|
+
}, rsaPrivateKey3, rsaPublicKey3.id, { contextLoader: mockDocumentLoader });
|
|
251
|
+
assertEquals((await federation.fetch(post(inboxUrl(), activity), { contextData: void 0 })).status, 202);
|
|
252
|
+
assertEquals(received.length, 1);
|
|
253
|
+
assertEquals(queue.outbox.length, 2);
|
|
254
|
+
for (const message of queue.outbox) assertEquals(message.activity, activity);
|
|
255
|
+
});
|
|
256
|
+
test("Federation.fetch() does not forward portable inbox deliveries without verification", async () => {
|
|
257
|
+
const queue = new RecordingQueue();
|
|
258
|
+
const { federation, received } = setup({
|
|
259
|
+
queue,
|
|
260
|
+
options: { skipSignatureVerification: true }
|
|
261
|
+
});
|
|
262
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
263
|
+
assertEquals(received.length, 1);
|
|
264
|
+
assertEquals(queue.outbox.length, 0);
|
|
265
|
+
});
|
|
266
|
+
test("Federation.fetch() does not forward portable inbox deliveries whose listener failed", async () => {
|
|
267
|
+
const queue = new RecordingQueue();
|
|
268
|
+
const { federation } = setup({
|
|
269
|
+
queue,
|
|
270
|
+
listenerError: true
|
|
271
|
+
});
|
|
272
|
+
const json = await signedFollow();
|
|
273
|
+
let response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
274
|
+
assertEquals(response.status, 500);
|
|
275
|
+
assertEquals(queue.outbox.length, 0);
|
|
276
|
+
response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
277
|
+
assertEquals(response.status, 500);
|
|
278
|
+
assertEquals(queue.outbox.length, 0);
|
|
279
|
+
});
|
|
280
|
+
test("Federation.fetch() forwards each portable inbox delivery at most once", async (t) => {
|
|
281
|
+
await t.step("concurrent deliveries", async () => {
|
|
282
|
+
const queue = new RecordingQueue();
|
|
283
|
+
const { federation } = setup({ queue });
|
|
284
|
+
const json = await signedFollow();
|
|
285
|
+
const responses = await Promise.all([
|
|
286
|
+
federation.fetch(post(inboxUrl(), json), { contextData: void 0 }),
|
|
287
|
+
federation.fetch(post(inboxUrl(), json), { contextData: void 0 }),
|
|
288
|
+
federation.fetch(post(inboxUrl(), json), { contextData: void 0 })
|
|
289
|
+
]);
|
|
290
|
+
for (const response of responses) assertEquals(response.status, 202);
|
|
291
|
+
assertEquals(queue.outbox.map((m) => m.inbox).sort(), [inboxUrl(did, "/users/alice/inbox", GATEWAY3), inboxUrl(did, "/users/alice/inbox", GATEWAY2)]);
|
|
292
|
+
});
|
|
293
|
+
await t.step("failed hand-offs are not retried", async () => {
|
|
294
|
+
const queue = new RecordingQueue();
|
|
295
|
+
queue.failFor = GATEWAY2;
|
|
296
|
+
const { federation, received } = setup({ queue });
|
|
297
|
+
const json = await signedFollow();
|
|
298
|
+
let response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
299
|
+
assertEquals(response.status, 202);
|
|
300
|
+
assertEquals(queue.outbox.map((m) => m.inbox), [inboxUrl(did, "/users/alice/inbox", GATEWAY3)]);
|
|
301
|
+
queue.failFor = void 0;
|
|
302
|
+
response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
303
|
+
assertEquals(response.status, 202);
|
|
304
|
+
assertEquals(queue.outbox.length, 1);
|
|
305
|
+
assertEquals(received.length, 1);
|
|
306
|
+
});
|
|
307
|
+
await t.step("a delivery forwarded back is not forwarded again", async () => {
|
|
308
|
+
const queue = new RecordingQueue();
|
|
309
|
+
const local = setup({
|
|
310
|
+
queue,
|
|
311
|
+
kv: new MemoryKvStore()
|
|
312
|
+
});
|
|
313
|
+
const json = await signedFollow();
|
|
314
|
+
await local.federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
315
|
+
assertEquals(queue.outbox.length, 2);
|
|
316
|
+
assertEquals((await local.federation.fetch(post(inboxUrl(), json), { contextData: void 0 })).status, 202);
|
|
317
|
+
assertEquals(queue.outbox.length, 2);
|
|
318
|
+
assertEquals(local.received.length, 1);
|
|
319
|
+
});
|
|
320
|
+
await t.step("without KvStore.cas()", async () => {
|
|
321
|
+
const queue = new RecordingQueue();
|
|
322
|
+
const memory = new MemoryKvStore();
|
|
323
|
+
const { federation, received } = setup({
|
|
324
|
+
queue,
|
|
325
|
+
kv: {
|
|
326
|
+
get: (key) => memory.get(key),
|
|
327
|
+
set: (key, value, options) => memory.set(key, value, options),
|
|
328
|
+
delete: (key) => memory.delete(key),
|
|
329
|
+
list: (prefix) => memory.list(prefix)
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
333
|
+
assertEquals(received.length, 1);
|
|
334
|
+
assertEquals(queue.outbox.length, 0);
|
|
335
|
+
});
|
|
336
|
+
await t.step("configured origin", async () => {
|
|
337
|
+
const queue = new RecordingQueue();
|
|
338
|
+
const { federation } = setup({
|
|
339
|
+
queue,
|
|
340
|
+
gateways: [
|
|
341
|
+
GATEWAY2,
|
|
342
|
+
LOCAL,
|
|
343
|
+
GATEWAY3
|
|
344
|
+
],
|
|
345
|
+
options: { origin: GATEWAY2 }
|
|
346
|
+
});
|
|
347
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
348
|
+
assertEquals(queue.outbox.map((m) => m.inbox), [inboxUrl(did, "/users/alice/inbox", GATEWAY3)]);
|
|
349
|
+
});
|
|
350
|
+
await t.step("gateway cap", async () => {
|
|
351
|
+
const queue = new RecordingQueue();
|
|
352
|
+
const gateways = [LOCAL];
|
|
353
|
+
for (let i = 0; i < 15; i++) gateways.push(`https://gw${i}.example.net`);
|
|
354
|
+
const { federation } = setup({
|
|
355
|
+
queue,
|
|
356
|
+
gateways
|
|
357
|
+
});
|
|
358
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
359
|
+
assertEquals(queue.outbox.length, 10);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
test("FederationOptions.portableInboxForwarding", async (t) => {
|
|
363
|
+
await t.step("maxTargets", async () => {
|
|
364
|
+
const queue = new RecordingQueue();
|
|
365
|
+
const { federation } = setup({
|
|
366
|
+
queue,
|
|
367
|
+
options: { portableInboxForwarding: { maxTargets: 1 } }
|
|
368
|
+
});
|
|
369
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
370
|
+
assertEquals(queue.outbox.map((m) => m.inbox), [inboxUrl(did, "/users/alice/inbox", GATEWAY2)]);
|
|
371
|
+
});
|
|
372
|
+
await t.step("maxTargets: 0 turns off forwarding", async () => {
|
|
373
|
+
const queue = new RecordingQueue();
|
|
374
|
+
const { federation, received } = setup({
|
|
375
|
+
queue,
|
|
376
|
+
options: { portableInboxForwarding: { maxTargets: 0 } }
|
|
377
|
+
});
|
|
378
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
379
|
+
assertEquals(received.length, 1);
|
|
380
|
+
assertEquals(queue.outbox.length, 0);
|
|
381
|
+
});
|
|
382
|
+
await t.step("ttl", async () => {
|
|
383
|
+
const queue = new RecordingQueue();
|
|
384
|
+
const memory = new MemoryKvStore();
|
|
385
|
+
const claimTtls = [];
|
|
386
|
+
const { federation } = setup({
|
|
387
|
+
queue,
|
|
388
|
+
kv: {
|
|
389
|
+
get: (key) => memory.get(key),
|
|
390
|
+
set: (key, value, options) => memory.set(key, value, options),
|
|
391
|
+
delete: (key) => memory.delete(key),
|
|
392
|
+
list: (prefix) => memory.list(prefix),
|
|
393
|
+
cas: (key, expected, value, options) => {
|
|
394
|
+
if (key[1] === "portableInboxForwarding") claimTtls.push(options?.ttl);
|
|
395
|
+
return memory.cas(key, expected, value, options);
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
options: { portableInboxForwarding: { ttl: Temporal.Duration.from({ days: 7 }) } }
|
|
399
|
+
});
|
|
400
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
401
|
+
assertEquals(queue.outbox.length, 2);
|
|
402
|
+
assertEquals(claimTtls.map((ttl) => ttl?.total("day")), [7, 7]);
|
|
403
|
+
});
|
|
404
|
+
await t.step("longest deadline", () => {
|
|
405
|
+
assertEquals(resolvePortableInboxForwardingOptions({ deadline: { milliseconds: 2 ** 31 - 1 } }).deadline.total("millisecond"), 2 ** 31 - 1);
|
|
406
|
+
});
|
|
407
|
+
await t.step("defaults", () => {
|
|
408
|
+
const resolved = resolvePortableInboxForwardingOptions();
|
|
409
|
+
assertEquals(resolved.maxTargets, 10);
|
|
410
|
+
assertEquals(resolved.ttl.total("day"), 30);
|
|
411
|
+
assertEquals(resolved.deadline.total("second"), 10);
|
|
412
|
+
});
|
|
413
|
+
await t.step("invalid values", () => {
|
|
414
|
+
for (const portableInboxForwarding of [
|
|
415
|
+
{ maxTargets: -1 },
|
|
416
|
+
{ maxTargets: 1.5 },
|
|
417
|
+
{ maxTargets: NaN },
|
|
418
|
+
{ ttl: { seconds: 0 } },
|
|
419
|
+
{ ttl: { weeks: 1 } },
|
|
420
|
+
{ ttl: { months: 1 } },
|
|
421
|
+
{ deadline: { seconds: -1 } },
|
|
422
|
+
{ deadline: { years: 1 } },
|
|
423
|
+
{ deadline: { milliseconds: 2 ** 31 } }
|
|
424
|
+
]) assertThrows(() => setup({ options: { portableInboxForwarding } }), RangeError);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
test("Federation.fetch() forwards portable inbox deliveries immediately without a queue", async () => {
|
|
428
|
+
esm_default.spyGlobal();
|
|
429
|
+
const requests = [];
|
|
430
|
+
esm_default.post(`begin:${GATEWAY2}/`, async (callLog) => {
|
|
431
|
+
const request = callLog.request;
|
|
432
|
+
requests.push({
|
|
433
|
+
url: request.url,
|
|
434
|
+
headers: new Headers(request.headers),
|
|
435
|
+
body: await request.json()
|
|
436
|
+
});
|
|
437
|
+
return new Response(null, { status: 202 });
|
|
438
|
+
});
|
|
439
|
+
esm_default.post(`begin:${GATEWAY3}/`, () => {
|
|
440
|
+
throw new TypeError("Connection refused.");
|
|
441
|
+
});
|
|
442
|
+
try {
|
|
443
|
+
const { federation, received } = setup({ options: { allowPrivateAddress: true } });
|
|
444
|
+
const json = await signedFollow();
|
|
445
|
+
let response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
446
|
+
assertEquals(response.status, 202);
|
|
447
|
+
assertEquals(received.length, 1);
|
|
448
|
+
assertEquals(requests.length, 1);
|
|
449
|
+
assertEquals(requests[0].url, inboxUrl(did, "/users/alice/inbox", GATEWAY2));
|
|
450
|
+
assertFalse(requests[0].headers.has("Signature"));
|
|
451
|
+
assertFalse(requests[0].headers.has("Signature-Input"));
|
|
452
|
+
assertEquals(requests[0].body, json);
|
|
453
|
+
response = await federation.fetch(post(inboxUrl(), json), { contextData: void 0 });
|
|
454
|
+
assertEquals(response.status, 202);
|
|
455
|
+
assertEquals(requests.length, 1);
|
|
456
|
+
assertEquals(esm_default.callHistory.calls(`begin:${GATEWAY3}/`).length, 1);
|
|
457
|
+
} finally {
|
|
458
|
+
esm_default.hardReset();
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
test("Federation.fetch() forwards portable inbox deliveries when it enqueues them", async () => {
|
|
462
|
+
const queue = new RecordingQueue();
|
|
463
|
+
const inboxQueue = new RecordingQueue();
|
|
464
|
+
let sharedInboxKeyCalls = 0;
|
|
465
|
+
const { federation, received } = setup({
|
|
466
|
+
queue,
|
|
467
|
+
keyPairs: false,
|
|
468
|
+
onSharedInboxKey: () => sharedInboxKeyCalls++,
|
|
469
|
+
options: { queue: {
|
|
470
|
+
inbox: inboxQueue,
|
|
471
|
+
outbox: queue
|
|
472
|
+
} }
|
|
473
|
+
});
|
|
474
|
+
assertEquals((await federation.fetch(post(inboxUrl(), await signedFollow()), { contextData: void 0 })).status, 202);
|
|
475
|
+
assertEquals(received.length, 0);
|
|
476
|
+
assertEquals(inboxQueue.messages.length, 1);
|
|
477
|
+
assertEquals(inboxQueue.messages[0].type, "inbox");
|
|
478
|
+
assertEquals(queue.outbox.length, 2);
|
|
479
|
+
await federation.processQueuedTask(void 0, inboxQueue.messages[0]);
|
|
480
|
+
assertEquals(received.length, 1);
|
|
481
|
+
assertEquals(received[0].recipient, "alice");
|
|
482
|
+
assertEquals(sharedInboxKeyCalls, 0);
|
|
483
|
+
});
|
|
484
|
+
test("forwardPortableInboxActivity() does not wait for slow gateways", async () => {
|
|
485
|
+
esm_default.spyGlobal();
|
|
486
|
+
let release = () => {};
|
|
487
|
+
const pending = new Promise((resolve) => release = resolve);
|
|
488
|
+
esm_default.post(`begin:${GATEWAY2}/`, async () => {
|
|
489
|
+
await pending;
|
|
490
|
+
throw new TypeError("Connection reset.");
|
|
491
|
+
});
|
|
492
|
+
try {
|
|
493
|
+
const kv = new MemoryKvStore();
|
|
494
|
+
const activityId = parseIri(`ap+ef61://${did}/follows/slow`);
|
|
495
|
+
const parameters = {
|
|
496
|
+
recipient: {
|
|
497
|
+
inboxId: parseIri(`ap+ef61://${did}/users/alice/inbox`),
|
|
498
|
+
canonicalInboxId: `ap://${did}/users/alice/inbox`,
|
|
499
|
+
gateways: [new URL(LOCAL), new URL(GATEWAY2)]
|
|
500
|
+
},
|
|
501
|
+
activity: { id: formatIri(activityId) },
|
|
502
|
+
activityId,
|
|
503
|
+
activityType: "https://www.w3.org/ns/activitystreams#Follow",
|
|
504
|
+
excludedOrigins: [LOCAL],
|
|
505
|
+
baseUrl: LOCAL,
|
|
506
|
+
kv,
|
|
507
|
+
kvPrefix: ["_fedify", "portableInboxForwarding"],
|
|
508
|
+
options: resolvePortableInboxForwardingOptions({ deadline: { milliseconds: 10 } }),
|
|
509
|
+
allowPrivateAddress: true
|
|
510
|
+
};
|
|
511
|
+
const started = performance.now();
|
|
512
|
+
const forwarded = await forwardPortableInboxActivity(parameters);
|
|
513
|
+
assert(performance.now() - started < 5e3);
|
|
514
|
+
assertEquals(forwarded.map((u) => u.href), [inboxUrl(did, "/users/alice/inbox", GATEWAY2)]);
|
|
515
|
+
release();
|
|
516
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
517
|
+
assertEquals(await forwardPortableInboxActivity(parameters), []);
|
|
518
|
+
assertEquals(esm_default.callHistory.calls().length, 1);
|
|
519
|
+
} finally {
|
|
520
|
+
esm_default.hardReset();
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
test("Context.getPortableInboxUri()", async (t) => {
|
|
524
|
+
const { federation } = setup();
|
|
525
|
+
await t.step("Context", () => {
|
|
526
|
+
const ctx = federation.createContext(new URL(LOCAL), void 0);
|
|
527
|
+
const uri = ctx.getPortableInboxUri("alice", did);
|
|
528
|
+
assertEquals(uri.protocol, "ap+ef61:");
|
|
529
|
+
assertEquals(formatIri(uri), `ap+ef61://${did}/users/alice/inbox`);
|
|
530
|
+
assertThrows(() => ctx.getPortableInboxUri("alice", "not-a-did"), TypeError);
|
|
531
|
+
});
|
|
532
|
+
await t.step("RequestContext without portable request", () => {
|
|
533
|
+
const ctx = federation.createContext(new Request(LOCAL), void 0);
|
|
534
|
+
assertThrows(() => ctx.getPortableInboxUri("alice"), TypeError);
|
|
535
|
+
assertEquals(formatIri(ctx.getPortableInboxUri("alice", did)), `ap+ef61://${did}/users/alice/inbox`);
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
test("Federation.fetch() keeps ordinary inbox deliveries unchanged", async () => {
|
|
539
|
+
const queue = new RecordingQueue();
|
|
540
|
+
const { federation, received } = setup({ queue });
|
|
541
|
+
assertEquals((await federation.fetch(post(`${LOCAL}/users/alice/inbox`, await signedFollow()), { contextData: void 0 })).status, 202);
|
|
542
|
+
assertEquals(received.length, 1);
|
|
543
|
+
assertEquals(queue.outbox.length, 0);
|
|
544
|
+
});
|
|
545
|
+
//#endregion
|
|
546
|
+
export {};
|
|
@@ -7,10 +7,10 @@ import { t as assertInstanceOf } from "../assert_instance_of-mrXWWNY-.mjs";
|
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-BYITOvPO.mjs";
|
|
8
8
|
import "../std__assert-DvMDRPes.mjs";
|
|
9
9
|
import { t as assertStrictEquals } from "../assert_strict_equals-CYvBmkpC.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import { o as verifyPortableObjectProof, r as signObject } from "../proof-CxsVG6vM.mjs";
|
|
11
|
+
import { s as signRequest } from "../http-C7qHlv-b.mjs";
|
|
11
12
|
import { a as rsaPrivateKey3, c as rsaPublicKey3, i as rsaPrivateKey2, n as ed25519PrivateKey, r as ed25519PublicKey, s as rsaPublicKey2 } from "../keys-DIJNHW-Y.mjs";
|
|
12
|
-
import {
|
|
13
|
-
import { o as verifyPortableObjectProof, r as signObject } from "../proof-B03JXhrk.mjs";
|
|
13
|
+
import { o as createFederation, v as PORTABLE_OBJECT_CONTENT_TYPE } from "../middleware-CpyCNOW_.mjs";
|
|
14
14
|
import { Collection, Create, Note, Object as Object$1, Person, Tombstone, lookupObject } from "@fedify/vocab";
|
|
15
15
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
16
16
|
import { exportDidKey, formatIri, parseIri } from "@fedify/vocab-runtime";
|
|
@@ -10,10 +10,10 @@ import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
|
|
|
10
10
|
import "../std__assert-DvMDRPes.mjs";
|
|
11
11
|
import { t as assertRejects } from "../assert_rejects-CTptdYck.mjs";
|
|
12
12
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
13
|
-
import { l as verifyRequest } from "../http-
|
|
13
|
+
import { l as verifyRequest } from "../http-C7qHlv-b.mjs";
|
|
14
14
|
import { i as rsaPrivateKey2, n as ed25519PrivateKey, s as rsaPublicKey2, t as ed25519Multikey } from "../keys-DIJNHW-Y.mjs";
|
|
15
|
-
import { t as doesActorOwnKey } from "../owner-
|
|
16
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-
|
|
15
|
+
import { t as doesActorOwnKey } from "../owner-CDsVeZI7.mjs";
|
|
16
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "../send-BZJ7NsVV.mjs";
|
|
17
17
|
import { Activity, Application, Endpoints, Group, Person, Service } from "@fedify/vocab";
|
|
18
18
|
import { createTestMeterProvider, createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
19
19
|
import { FetchError, UrlError } from "@fedify/vocab-runtime";
|
|
@@ -3,8 +3,8 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
|
|
5
5
|
import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
|
|
6
|
-
import "../../testing-
|
|
7
|
-
import { o as createFederation } from "../../middleware-
|
|
6
|
+
import "../../testing-CO_cEvQc.mjs";
|
|
7
|
+
import { o as createFederation } from "../../middleware-CpyCNOW_.mjs";
|
|
8
8
|
import { n as ParallelMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
|
|
9
9
|
import { configure, reset } from "@logtape/logtape";
|
|
10
10
|
import { delay } from "es-toolkit";
|
|
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as MemoryKvStore } from "../../kv-DCHkaJ9-.mjs";
|
|
5
5
|
import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, t as MockQueue } from "../../tasks-dbCShlCb.mjs";
|
|
6
|
-
import "../../testing-
|
|
7
|
-
import { o as createFederation } from "../../middleware-
|
|
8
|
-
import { r as createFederationBuilder } from "../../builder-
|
|
6
|
+
import "../../testing-CO_cEvQc.mjs";
|
|
7
|
+
import { o as createFederation } from "../../middleware-CpyCNOW_.mjs";
|
|
8
|
+
import { r as createFederationBuilder } from "../../builder-CVHpPAjK.mjs";
|
|
9
9
|
import { t as TaskCodec } from "../../codec-C6rTrpIp.mjs";
|
|
10
10
|
import { t as InProcessMessageQueue } from "../../mq-Dm1Wmtm-.mjs";
|
|
11
11
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
@@ -4,7 +4,7 @@ globalThis.addEventListener = () => {};
|
|
|
4
4
|
import { t as assertFalse } from "../assert_false-CPdRnc3E.mjs";
|
|
5
5
|
import "../std__assert-DvMDRPes.mjs";
|
|
6
6
|
import { t as assert } from "../assert-D1Eafmd_.mjs";
|
|
7
|
-
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-
|
|
7
|
+
import { t as hasMalformedKnownTemporalLiteral } from "../temporal-CLzSfIOV.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/federation/temporal.test.ts
|
|
10
10
|
test("hasMalformedKnownTemporalLiteral() detects expanded proof timestamps", async () => {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { r as createRequestContext } from "../context-
|
|
4
|
+
import { r as createRequestContext } from "../context-DlZhxdFT.mjs";
|
|
5
5
|
import { t as MemoryKvStore } from "../kv-DCHkaJ9-.mjs";
|
|
6
6
|
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
7
7
|
import { t as assertNotEquals } from "../assert_not_equals-CpPK2t89.mjs";
|
|
8
8
|
import "../std__assert-DvMDRPes.mjs";
|
|
9
|
-
import { o as createFederation, s as handleWebFinger } from "../middleware-
|
|
9
|
+
import { o as createFederation, s as handleWebFinger } from "../middleware-CpyCNOW_.mjs";
|
|
10
10
|
import { Image, Link, Person, Tombstone } from "@fedify/vocab";
|
|
11
11
|
import { createTestMeterProvider, test } from "@fedify/fixture";
|
|
12
12
|
import { parseIri } from "@fedify/vocab-runtime";
|