@fedify/fedify 2.3.0-dev.1189 → 2.3.0-dev.1212
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-Dc6s3gPe.mjs → builder-DdbtvTFp.mjs} +2 -2
- package/dist/circuit-breaker-CSWsyoef.mjs +337 -0
- 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/{context-CRXCkTM6.d.cts → context-DMHK7jqX.d.cts} +224 -3
- package/dist/{context-MgCh7YGu.d.ts → context-K9cg8oGx.d.ts} +224 -3
- package/dist/{deno-BomxIkHS.mjs → deno-DTaoLXHr.mjs} +1 -1
- package/dist/{docloader-CzS6F5sZ.mjs → docloader-CdNiXmNg.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/circuit-breaker.test.d.mts +2 -0
- package/dist/federation/circuit-breaker.test.mjs +446 -0
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +3 -3
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/keycache.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +16 -1
- package/dist/federation/middleware.test.mjs +817 -6
- package/dist/federation/mod.cjs +4 -1
- package/dist/federation/mod.d.cts +3 -3
- package/dist/federation/mod.d.ts +3 -3
- package/dist/federation/mod.js +2 -2
- package/dist/federation/negotiation.test.mjs +1 -1
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/send.test.mjs +43 -10
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{getMachineId-bsd-BY01PL1n.mjs → getMachineId-bsd-Bn0le7-J.mjs} +1 -1
- package/dist/{getMachineId-darwin-Dr1gkBkp.mjs → getMachineId-darwin-CVjKuDgj.mjs} +1 -1
- package/dist/{getMachineId-win-QEYwcJiy.mjs → getMachineId-win-c5zxTSS1.mjs} +1 -1
- package/dist/{http-B-psRIq6.js → http-BEG9kx13.js} +25 -6
- package/dist/{http-DtWN_XvX.mjs → http-ByCfCX5K.mjs} +3 -3
- package/dist/{http-DnJyL_6c.cjs → http-Czeyq7if.cjs} +30 -5
- package/dist/{key-CT2NnJuR.mjs → key-Bhsx9PrC.mjs} +2 -2
- package/dist/{kv-cache-Bf8AoV6C.mjs → kv-cache-D4jzgeYW.mjs} +1 -1
- package/dist/{kv-cache-DKhLDCH8.js → kv-cache-D9U1AnXH.js} +1 -1
- package/dist/{kv-cache-CVre456Y.cjs → kv-cache-qRBN2G2Z.cjs} +1 -1
- package/dist/{ld-DCyQasTE.mjs → ld-CHtLb_Uh.mjs} +3 -3
- package/dist/{metrics-xgr0P4hO.mjs → metrics-uwSF8DLC.mjs} +25 -6
- package/dist/{middleware-DK0thDHX.mjs → middleware-BmSzD5U9.mjs} +279 -40
- package/dist/{middleware-DIJ_6KFI.cjs → middleware-CRORNnSU.cjs} +632 -31
- package/dist/{middleware-sgx08IEk.mjs → middleware-CyiBzIwY.mjs} +1 -1
- package/dist/{middleware-BgbdoV61.js → middleware-DrKDd2JT.js} +615 -32
- package/dist/{mod-CpQHB3Ys.d.ts → mod-CfOFqS0w.d.ts} +1 -1
- package/dist/{mod-C7HOzGqH.d.cts → mod-YLnSsEHY.d.cts} +1 -1
- package/dist/mod.cjs +7 -4
- 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.mjs +1 -1
- package/dist/{owner-BIU_Sl7y.mjs → owner-B0Zrhs0w.mjs} +2 -2
- package/dist/{proof-B5defvTr.js → proof-CZhAX94C.js} +1 -1
- package/dist/{proof-DDs7BRl7.mjs → proof-DbJFxpzD.mjs} +3 -3
- package/dist/{proof-B9xbksrX.cjs → proof-frzCtYji.cjs} +1 -1
- package/dist/{send-BuxDCpxz.mjs → send-kst2L0Df.mjs} +21 -7
- 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 +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/{temporal-DHgeMWiP.mjs → temporal-CcGypkzd.mjs} +1 -1
- package/dist/testing/mod.d.mts +36 -2
- 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.js +1 -1
- package/package.json +6 -6
- /package/dist/{collection-CA3V5zyK.mjs → collection-Cc3DVAhE.mjs} +0 -0
- /package/dist/{execAsync-Dxb7rNf3.mjs → execAsync-Dmet7-28.mjs} +0 -0
- /package/dist/{getMachineId-linux-Bbhofx-s.mjs → getMachineId-linux-DbG4BXa-.mjs} +0 -0
- /package/dist/{getMachineId-unsupported-dIOte2Ct.mjs → getMachineId-unsupported-lC8T9hPE.mjs} +0 -0
- /package/dist/{keycache-BYMd8q7F.mjs → keycache-BeU0LCII.mjs} +0 -0
- /package/dist/{negotiation-CDW-_gUU.mjs → negotiation-DDstyBvc.mjs} +0 -0
- /package/dist/{retry-_VvV0h9f.mjs → retry-CXg_MBI-.mjs} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-DTaoLXHr.mjs";
|
|
5
5
|
import { t as ActivityListenerSet } from "./activity-listener-tztVvlNb.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { Router, RouterError, assertPath } from "@fedify/uri-template";
|
|
@@ -73,7 +73,7 @@ var FederationBuilderImpl = class {
|
|
|
73
73
|
this.collectionTypeIds = {};
|
|
74
74
|
}
|
|
75
75
|
async build(options) {
|
|
76
|
-
const { FederationImpl } = await import("./middleware-
|
|
76
|
+
const { FederationImpl } = await import("./middleware-CyiBzIwY.mjs");
|
|
77
77
|
const f = new FederationImpl(options);
|
|
78
78
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
79
79
|
f.router = this.router.clone();
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { getLogger } from "@logtape/logtape";
|
|
5
|
+
//#region src/federation/circuit-breaker.ts
|
|
6
|
+
const MAX_CUSTOM_FAILURE_HISTORY = 100;
|
|
7
|
+
/**
|
|
8
|
+
* Tracks reachability state for remote outbox delivery hosts.
|
|
9
|
+
* @since 2.3.0
|
|
10
|
+
*/
|
|
11
|
+
var CircuitBreaker = class {
|
|
12
|
+
#kv;
|
|
13
|
+
#prefix;
|
|
14
|
+
#options;
|
|
15
|
+
#now;
|
|
16
|
+
#stateChangeObserver;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.#kv = options.kv;
|
|
19
|
+
this.#prefix = options.prefix;
|
|
20
|
+
this.#options = normalizeCircuitBreakerOptions(options.options ?? {});
|
|
21
|
+
this.#now = options.now ?? (() => Temporal.Now.instant());
|
|
22
|
+
this.#stateChangeObserver = options.stateChangeObserver;
|
|
23
|
+
}
|
|
24
|
+
get options() {
|
|
25
|
+
return this.#options;
|
|
26
|
+
}
|
|
27
|
+
capHeldDelay(heldSince, delay) {
|
|
28
|
+
const now = this.#now();
|
|
29
|
+
return now.until(this.#capHeldRetryAt(now, heldSince, now.add(delay)));
|
|
30
|
+
}
|
|
31
|
+
async beforeSend(remoteHost, message) {
|
|
32
|
+
const heldSince = parseHeldSince(message.circuitHeldSince);
|
|
33
|
+
const now = this.#now();
|
|
34
|
+
if (heldSince != null && Temporal.Instant.compare(heldSince.add(this.#options.heldActivityTtl), now) <= 0) return {
|
|
35
|
+
type: "drop",
|
|
36
|
+
heldSince
|
|
37
|
+
};
|
|
38
|
+
let lastConflictingState;
|
|
39
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
40
|
+
const oldState = await this.#get(remoteHost);
|
|
41
|
+
if (oldState == null || oldState.state === "closed") return {
|
|
42
|
+
type: "send",
|
|
43
|
+
probe: false
|
|
44
|
+
};
|
|
45
|
+
if (oldState.state === "half-open") {
|
|
46
|
+
const halfOpened = oldState.halfOpened == null ? void 0 : Temporal.Instant.from(oldState.halfOpened);
|
|
47
|
+
if (halfOpened != null) {
|
|
48
|
+
const staleAt = halfOpened.add(this.#options.recoveryDelay);
|
|
49
|
+
if (Temporal.Instant.compare(now, staleAt) < 0) {
|
|
50
|
+
const releaseAt = now.add(this.#options.releaseInterval);
|
|
51
|
+
const retryAt = Temporal.Instant.compare(releaseAt, staleAt) < 0 ? releaseAt : staleAt;
|
|
52
|
+
const cappedRetryAt = this.#capHeldRetryAt(now, heldSince, retryAt);
|
|
53
|
+
return {
|
|
54
|
+
type: "hold",
|
|
55
|
+
state: "half-open",
|
|
56
|
+
delay: now.until(cappedRetryAt),
|
|
57
|
+
heldSince: heldSince ?? now
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const newState = {
|
|
62
|
+
...oldState,
|
|
63
|
+
state: "half-open",
|
|
64
|
+
halfOpened: now.toString()
|
|
65
|
+
};
|
|
66
|
+
if (await this.#replace(remoteHost, oldState, newState)) return {
|
|
67
|
+
type: "send",
|
|
68
|
+
probe: true
|
|
69
|
+
};
|
|
70
|
+
lastConflictingState = "half-open";
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const probeAt = (oldState.opened == null ? now : Temporal.Instant.from(oldState.opened)).add(this.#options.recoveryDelay);
|
|
74
|
+
if (Temporal.Instant.compare(now, probeAt) < 0) {
|
|
75
|
+
const retryAt = this.#capHeldRetryAt(now, heldSince, probeAt);
|
|
76
|
+
return {
|
|
77
|
+
type: "hold",
|
|
78
|
+
state: "open",
|
|
79
|
+
delay: now.until(retryAt),
|
|
80
|
+
heldSince: heldSince ?? now
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const newState = {
|
|
84
|
+
...oldState,
|
|
85
|
+
state: "half-open",
|
|
86
|
+
halfOpened: now.toString()
|
|
87
|
+
};
|
|
88
|
+
if (await this.#replace(remoteHost, oldState, newState)) {
|
|
89
|
+
await this.#notifyStateChange(remoteHost, "open", "half-open");
|
|
90
|
+
return {
|
|
91
|
+
type: "send",
|
|
92
|
+
probe: true,
|
|
93
|
+
stateChange: {
|
|
94
|
+
previousState: "open",
|
|
95
|
+
newState: "half-open"
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
lastConflictingState = "open";
|
|
100
|
+
}
|
|
101
|
+
if (lastConflictingState != null) {
|
|
102
|
+
const retryAt = this.#capHeldRetryAt(now, heldSince, now.add(this.#options.releaseInterval));
|
|
103
|
+
return {
|
|
104
|
+
type: "hold",
|
|
105
|
+
state: lastConflictingState,
|
|
106
|
+
delay: now.until(retryAt),
|
|
107
|
+
heldSince: heldSince ?? now
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Failed to update circuit breaker state for ${remoteHost}`);
|
|
111
|
+
}
|
|
112
|
+
async recordSuccess(remoteHost) {
|
|
113
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
114
|
+
const oldState = await this.#get(remoteHost);
|
|
115
|
+
if (oldState == null) return void 0;
|
|
116
|
+
if (await this.#replace(remoteHost, oldState, void 0)) {
|
|
117
|
+
if (oldState.state !== "closed") {
|
|
118
|
+
await this.#notifyStateChange(remoteHost, oldState.state, "closed");
|
|
119
|
+
return {
|
|
120
|
+
previousState: oldState.state,
|
|
121
|
+
newState: "closed"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
throw new Error(`Failed to update circuit breaker state for ${remoteHost}`);
|
|
128
|
+
}
|
|
129
|
+
async recordReachableFailure(remoteHost) {
|
|
130
|
+
return await this.recordSuccess(remoteHost);
|
|
131
|
+
}
|
|
132
|
+
async recordFailure(remoteHost) {
|
|
133
|
+
const now = this.#now();
|
|
134
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
135
|
+
const oldState = await this.#get(remoteHost);
|
|
136
|
+
if (oldState?.state === "open") return void 0;
|
|
137
|
+
const oldFailures = oldState?.failures.map(Temporal.Instant.from) ?? [];
|
|
138
|
+
const failures = this.#options.pruneFailures([...oldFailures, now], now);
|
|
139
|
+
let newState;
|
|
140
|
+
let transition;
|
|
141
|
+
if (oldState?.state === "half-open" || this.#options.failure(failures)) {
|
|
142
|
+
newState = {
|
|
143
|
+
state: "open",
|
|
144
|
+
failures: failures.map((t) => t.toString()),
|
|
145
|
+
opened: now.toString()
|
|
146
|
+
};
|
|
147
|
+
transition = [oldState?.state ?? "closed", "open"];
|
|
148
|
+
} else newState = {
|
|
149
|
+
state: "closed",
|
|
150
|
+
failures: failures.map((t) => t.toString())
|
|
151
|
+
};
|
|
152
|
+
if (await this.#replace(remoteHost, oldState, newState)) {
|
|
153
|
+
if (transition != null) {
|
|
154
|
+
await this.#notifyStateChange(remoteHost, transition[0], transition[1]);
|
|
155
|
+
return {
|
|
156
|
+
previousState: transition[0],
|
|
157
|
+
newState: transition[1]
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
throw new Error(`Failed to update circuit breaker state for ${remoteHost}`);
|
|
164
|
+
}
|
|
165
|
+
async dropActivity(remoteHost, details) {
|
|
166
|
+
try {
|
|
167
|
+
await this.#options.onActivityDrop?.(remoteHost, details);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
getLogger([
|
|
170
|
+
"fedify",
|
|
171
|
+
"federation",
|
|
172
|
+
"circuit"
|
|
173
|
+
]).error("An unexpected error occurred in circuit breaker activity drop handler:\n{error}", {
|
|
174
|
+
remoteHost,
|
|
175
|
+
error
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async getState(remoteHost) {
|
|
180
|
+
return await this.#get(remoteHost);
|
|
181
|
+
}
|
|
182
|
+
#key(remoteHost) {
|
|
183
|
+
return [...this.#prefix, remoteHost];
|
|
184
|
+
}
|
|
185
|
+
#capHeldRetryAt(now, heldSince, retryAt) {
|
|
186
|
+
const expiresAt = (heldSince ?? now).add(this.#options.heldActivityTtl);
|
|
187
|
+
return Temporal.Instant.compare(expiresAt, retryAt) < 0 ? expiresAt : retryAt;
|
|
188
|
+
}
|
|
189
|
+
async #get(remoteHost) {
|
|
190
|
+
return parseCircuitBreakerKvState(await this.#kv.get(this.#key(remoteHost)));
|
|
191
|
+
}
|
|
192
|
+
async #replace(remoteHost, oldState, newState) {
|
|
193
|
+
const key = this.#key(remoteHost);
|
|
194
|
+
if (this.#kv.cas == null) {
|
|
195
|
+
if (newState == null) await this.#kv.delete(key);
|
|
196
|
+
else await this.#kv.set(key, newState);
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
return await this.#kv.cas(key, oldState, newState);
|
|
200
|
+
}
|
|
201
|
+
async #notifyStateChange(remoteHost, previousState, newState) {
|
|
202
|
+
try {
|
|
203
|
+
await this.#options.onStateChange?.(remoteHost, previousState, newState);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
getLogger([
|
|
206
|
+
"fedify",
|
|
207
|
+
"federation",
|
|
208
|
+
"circuit"
|
|
209
|
+
]).error("An unexpected error occurred in circuit breaker state change handler:\n{error}", {
|
|
210
|
+
remoteHost,
|
|
211
|
+
previousState,
|
|
212
|
+
newState,
|
|
213
|
+
error
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
await this.#stateChangeObserver?.(remoteHost, previousState, newState);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
getLogger([
|
|
220
|
+
"fedify",
|
|
221
|
+
"federation",
|
|
222
|
+
"circuit"
|
|
223
|
+
]).error("An unexpected error occurred in circuit breaker state change observer:\n{error}", {
|
|
224
|
+
remoteHost,
|
|
225
|
+
previousState,
|
|
226
|
+
newState,
|
|
227
|
+
error
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Normalizes user-provided circuit breaker options into the internal policy
|
|
234
|
+
* shape used while processing queued outbox deliveries.
|
|
235
|
+
*
|
|
236
|
+
* @param options The public circuit breaker options supplied to Fedify.
|
|
237
|
+
* @returns The normalized failure predicate, failure pruning function,
|
|
238
|
+
* duration values, and optional callbacks with defaults applied.
|
|
239
|
+
* @throws {RangeError} If any configured duration is not positive.
|
|
240
|
+
* @throws {TypeError} If `failureThreshold` is not a positive integer.
|
|
241
|
+
*/
|
|
242
|
+
function normalizeCircuitBreakerOptions(options) {
|
|
243
|
+
const recoveryDelay = toInstantDuration(options.recoveryDelay ?? { minutes: 30 });
|
|
244
|
+
const heldActivityTtl = toInstantDuration(options.heldActivityTtl ?? { hours: 168 });
|
|
245
|
+
const releaseInterval = toInstantDuration(options.releaseInterval ?? { seconds: 1 });
|
|
246
|
+
assertPositiveDuration(recoveryDelay, "recoveryDelay");
|
|
247
|
+
assertPositiveDuration(heldActivityTtl, "heldActivityTtl");
|
|
248
|
+
assertPositiveDuration(releaseInterval, "releaseInterval");
|
|
249
|
+
let failure;
|
|
250
|
+
let pruneFailures;
|
|
251
|
+
if (options.failure == null) {
|
|
252
|
+
const failureThreshold = options.failureThreshold ?? 5;
|
|
253
|
+
if (!Number.isInteger(failureThreshold) || failureThreshold <= 0) throw new TypeError("failureThreshold must be a positive integer.");
|
|
254
|
+
const failureWindow = toInstantDuration(options.failureWindow ?? { minutes: 10 });
|
|
255
|
+
assertPositiveDuration(failureWindow, "failureWindow");
|
|
256
|
+
pruneFailures = (timestamps, now) => {
|
|
257
|
+
const earliest = now.subtract(failureWindow);
|
|
258
|
+
return timestamps.filter((timestamp) => Temporal.Instant.compare(timestamp, earliest) >= 0).slice(-failureThreshold);
|
|
259
|
+
};
|
|
260
|
+
failure = (timestamps) => {
|
|
261
|
+
if (timestamps.length < failureThreshold) return false;
|
|
262
|
+
const first = timestamps[timestamps.length - failureThreshold];
|
|
263
|
+
const last = timestamps[timestamps.length - 1];
|
|
264
|
+
return Temporal.Duration.compare(first.until(last), failureWindow) <= 0;
|
|
265
|
+
};
|
|
266
|
+
} else {
|
|
267
|
+
failure = options.failure;
|
|
268
|
+
pruneFailures = (timestamps) => timestamps.slice(-MAX_CUSTOM_FAILURE_HISTORY);
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
failure,
|
|
272
|
+
pruneFailures,
|
|
273
|
+
recoveryDelay,
|
|
274
|
+
heldActivityTtl,
|
|
275
|
+
releaseInterval,
|
|
276
|
+
onStateChange: options.onStateChange,
|
|
277
|
+
onActivityDrop: options.onActivityDrop
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function toInstantDuration(duration) {
|
|
281
|
+
const parsed = Temporal.Duration.from(duration);
|
|
282
|
+
return Temporal.Duration.from({ milliseconds: Math.trunc(parsed.total({
|
|
283
|
+
unit: "millisecond",
|
|
284
|
+
relativeTo: Temporal.PlainDateTime.from("2026-01-01T00:00:00")
|
|
285
|
+
})) });
|
|
286
|
+
}
|
|
287
|
+
function assertPositiveDuration(duration, name) {
|
|
288
|
+
if (Temporal.Duration.compare(duration, { seconds: 0 }) <= 0) throw new RangeError(`${name} must be a positive duration.`);
|
|
289
|
+
}
|
|
290
|
+
function parseHeldSince(value) {
|
|
291
|
+
if (value == null) return void 0;
|
|
292
|
+
try {
|
|
293
|
+
return Temporal.Instant.from(value);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
getLogger([
|
|
296
|
+
"fedify",
|
|
297
|
+
"federation",
|
|
298
|
+
"circuit"
|
|
299
|
+
]).warn("Invalid circuitHeldSince value in queued outbox message: {value}", {
|
|
300
|
+
value,
|
|
301
|
+
error
|
|
302
|
+
});
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Parses a value loaded from the circuit breaker KV store.
|
|
308
|
+
*
|
|
309
|
+
* @param value The raw KV value to validate.
|
|
310
|
+
* @returns A circuit breaker state when `value` has a recognized state and
|
|
311
|
+
* valid instant strings, or `undefined` when the stored value is malformed.
|
|
312
|
+
*/
|
|
313
|
+
function parseCircuitBreakerKvState(value) {
|
|
314
|
+
const isInstantString = (v) => {
|
|
315
|
+
if (typeof v !== "string") return false;
|
|
316
|
+
try {
|
|
317
|
+
Temporal.Instant.from(v);
|
|
318
|
+
return true;
|
|
319
|
+
} catch {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
if (typeof value !== "object" || value == null) return void 0;
|
|
324
|
+
const record = value;
|
|
325
|
+
if (record.state !== "closed" && record.state !== "open" && record.state !== "half-open") return;
|
|
326
|
+
if (!Array.isArray(record.failures) || !record.failures.every((failure) => isInstantString(failure))) return;
|
|
327
|
+
if (record.opened != null && !isInstantString(record.opened)) return;
|
|
328
|
+
if (record.halfOpened != null && !isInstantString(record.halfOpened)) return;
|
|
329
|
+
return {
|
|
330
|
+
state: record.state,
|
|
331
|
+
failures: record.failures,
|
|
332
|
+
...record.opened == null ? {} : { opened: record.opened },
|
|
333
|
+
...record.halfOpened == null ? {} : { halfOpened: record.halfOpened }
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
337
|
+
export { normalizeCircuitBreakerOptions as n, parseCircuitBreakerKvState as r, CircuitBreaker as t };
|
package/dist/compat/mod.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { At as ActivityTransformer, n as Context } from "../context-DMHK7jqX.cjs";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|
package/dist/compat/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference lib="esnext.temporal" />
|
|
2
|
-
import {
|
|
2
|
+
import { At as ActivityTransformer, n as Context } from "../context-K9cg8oGx.js";
|
|
3
3
|
import { Activity } from "@fedify/vocab";
|
|
4
4
|
|
|
5
5
|
//#region src/compat/transformers.d.ts
|
|
@@ -5,7 +5,7 @@ import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
|
5
5
|
import { t as assertInstanceOf } from "../assert_instance_of-DBC5X09g.mjs";
|
|
6
6
|
import { t as assert } from "../assert-OguE97r2.mjs";
|
|
7
7
|
import { t as MemoryKvStore } from "../kv-x2IvBUyq.mjs";
|
|
8
|
-
import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-
|
|
8
|
+
import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-BmSzD5U9.mjs";
|
|
9
9
|
import { Follow, Person } from "@fedify/vocab";
|
|
10
10
|
import { test } from "@fedify/fixture";
|
|
11
11
|
//#region src/compat/transformers.test.ts
|
|
@@ -15,6 +15,177 @@ import { MeterProvider, Span, Tracer, TracerProvider } from "@opentelemetry/api"
|
|
|
15
15
|
*/
|
|
16
16
|
type ActivityTransformer<TContextData> = (activity: Activity, context: Context<TContextData>) => Activity;
|
|
17
17
|
//#endregion
|
|
18
|
+
//#region src/federation/circuit-breaker.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* The state of a remote host circuit breaker.
|
|
21
|
+
* @since 2.3.0
|
|
22
|
+
*/
|
|
23
|
+
type CircuitBreakerState = "closed" | "open" | "half-open";
|
|
24
|
+
/**
|
|
25
|
+
* The JSON-serializable state stored in the configured {@link KvStore}.
|
|
26
|
+
* @since 2.3.0
|
|
27
|
+
*/
|
|
28
|
+
interface CircuitBreakerKvState {
|
|
29
|
+
readonly state: CircuitBreakerState;
|
|
30
|
+
readonly failures: readonly string[];
|
|
31
|
+
readonly opened?: string;
|
|
32
|
+
readonly halfOpened?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Details passed to {@link CircuitBreakerOptions.onActivityDrop} when a held
|
|
36
|
+
* activity expires before the remote host recovers.
|
|
37
|
+
* @since 2.3.0
|
|
38
|
+
*/
|
|
39
|
+
interface CircuitBreakerActivityDrop {
|
|
40
|
+
/** The inbox URL that would have received the activity. */
|
|
41
|
+
readonly inbox: URL;
|
|
42
|
+
/** The activity that was dropped. */
|
|
43
|
+
readonly activity: Activity;
|
|
44
|
+
/** The activity ID, when known. */
|
|
45
|
+
readonly activityId?: string;
|
|
46
|
+
/** The activity type. */
|
|
47
|
+
readonly activityType: string;
|
|
48
|
+
/** The actor IDs represented by this inbox. */
|
|
49
|
+
readonly actorIds: readonly URL[];
|
|
50
|
+
/** The time when Fedify first held this activity. */
|
|
51
|
+
readonly heldSince: Temporal.Instant;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Configures how a remote host circuit opens after repeated delivery
|
|
55
|
+
* failures.
|
|
56
|
+
* @since 2.3.0
|
|
57
|
+
*/
|
|
58
|
+
type CircuitBreakerFailurePolicy = {
|
|
59
|
+
failure(timestamps: readonly Temporal.Instant[]): boolean;
|
|
60
|
+
readonly failureThreshold?: never;
|
|
61
|
+
readonly failureWindow?: never;
|
|
62
|
+
} | {
|
|
63
|
+
readonly failure?: never;
|
|
64
|
+
readonly failureThreshold?: number;
|
|
65
|
+
readonly failureWindow?: Temporal.Duration | Temporal.DurationLike;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Options for Fedify's outbound activity circuit breaker.
|
|
69
|
+
* @since 2.3.0
|
|
70
|
+
*/
|
|
71
|
+
type CircuitBreakerOptions = CircuitBreakerFailurePolicy & {
|
|
72
|
+
/**
|
|
73
|
+
* How long an open circuit waits before allowing a half-open recovery probe.
|
|
74
|
+
* @default `{ minutes: 30 }`
|
|
75
|
+
*/
|
|
76
|
+
readonly recoveryDelay?: Temporal.Duration | Temporal.DurationLike;
|
|
77
|
+
/**
|
|
78
|
+
* How long Fedify keeps requeueing activities held by an open circuit before
|
|
79
|
+
* dropping them.
|
|
80
|
+
* @default `{ days: 7 }`
|
|
81
|
+
*/
|
|
82
|
+
readonly heldActivityTtl?: Temporal.Duration | Temporal.DurationLike;
|
|
83
|
+
/**
|
|
84
|
+
* How often other held activities retry while a half-open probe is in
|
|
85
|
+
* flight. The probe is treated as stale after the recovery delay.
|
|
86
|
+
* @default `{ seconds: 1 }`
|
|
87
|
+
*/
|
|
88
|
+
readonly releaseInterval?: Temporal.Duration | Temporal.DurationLike;
|
|
89
|
+
/**
|
|
90
|
+
* Called whenever the circuit state changes.
|
|
91
|
+
*/
|
|
92
|
+
readonly onStateChange?: (remoteHost: string, previousState: CircuitBreakerState, newState: CircuitBreakerState) => void | Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Called when an activity held by the circuit breaker expires.
|
|
95
|
+
*/
|
|
96
|
+
readonly onActivityDrop?: (remoteHost: string, details: CircuitBreakerActivityDrop) => void | Promise<void>;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Normalized circuit breaker options used internally by Fedify.
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
interface NormalizedCircuitBreakerOptions {
|
|
103
|
+
readonly failure: (timestamps: readonly Temporal.Instant[]) => boolean;
|
|
104
|
+
readonly pruneFailures: (timestamps: readonly Temporal.Instant[], now: Temporal.Instant) => readonly Temporal.Instant[];
|
|
105
|
+
readonly recoveryDelay: Temporal.Duration;
|
|
106
|
+
readonly heldActivityTtl: Temporal.Duration;
|
|
107
|
+
readonly releaseInterval: Temporal.Duration;
|
|
108
|
+
readonly onStateChange?: CircuitBreakerOptions["onStateChange"];
|
|
109
|
+
readonly onActivityDrop?: CircuitBreakerOptions["onActivityDrop"];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Constructor options for {@link CircuitBreaker}.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
interface CircuitBreakerCreateOptions {
|
|
116
|
+
readonly kv: KvStore;
|
|
117
|
+
readonly prefix: KvKey;
|
|
118
|
+
readonly options?: CircuitBreakerOptions;
|
|
119
|
+
readonly now?: () => Temporal.Instant;
|
|
120
|
+
/**
|
|
121
|
+
* Observes state changes after user callbacks have run.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
readonly stateChangeObserver?: (remoteHost: string, previousState: CircuitBreakerState, newState: CircuitBreakerState) => void | Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The delivery decision returned by {@link CircuitBreaker.beforeSend}.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
type CircuitBreakerBeforeSendDecision = {
|
|
131
|
+
readonly type: "send";
|
|
132
|
+
readonly probe: boolean;
|
|
133
|
+
readonly stateChange?: CircuitBreakerStateChange;
|
|
134
|
+
} | {
|
|
135
|
+
readonly type: "hold";
|
|
136
|
+
readonly state: "open" | "half-open";
|
|
137
|
+
readonly delay: Temporal.Duration;
|
|
138
|
+
readonly heldSince: Temporal.Instant;
|
|
139
|
+
} | {
|
|
140
|
+
readonly type: "drop";
|
|
141
|
+
readonly heldSince: Temporal.Instant;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* A circuit breaker state transition.
|
|
145
|
+
* @since 2.3.0
|
|
146
|
+
*/
|
|
147
|
+
interface CircuitBreakerStateChange {
|
|
148
|
+
readonly previousState: CircuitBreakerState;
|
|
149
|
+
readonly newState: CircuitBreakerState;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Tracks reachability state for remote outbox delivery hosts.
|
|
153
|
+
* @since 2.3.0
|
|
154
|
+
*/
|
|
155
|
+
declare class CircuitBreaker {
|
|
156
|
+
#private;
|
|
157
|
+
constructor(options: CircuitBreakerCreateOptions);
|
|
158
|
+
get options(): NormalizedCircuitBreakerOptions;
|
|
159
|
+
capHeldDelay(heldSince: Temporal.Instant, delay: Temporal.Duration): Temporal.Duration;
|
|
160
|
+
beforeSend(remoteHost: string, message: {
|
|
161
|
+
readonly circuitHeldSince?: string;
|
|
162
|
+
}): Promise<CircuitBreakerBeforeSendDecision>;
|
|
163
|
+
recordSuccess(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>;
|
|
164
|
+
recordReachableFailure(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>;
|
|
165
|
+
recordFailure(remoteHost: string): Promise<CircuitBreakerStateChange | undefined>;
|
|
166
|
+
dropActivity(remoteHost: string, details: CircuitBreakerActivityDrop): Promise<void>;
|
|
167
|
+
getState(remoteHost: string): Promise<CircuitBreakerKvState | undefined>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Normalizes user-provided circuit breaker options into the internal policy
|
|
171
|
+
* shape used while processing queued outbox deliveries.
|
|
172
|
+
*
|
|
173
|
+
* @param options The public circuit breaker options supplied to Fedify.
|
|
174
|
+
* @returns The normalized failure predicate, failure pruning function,
|
|
175
|
+
* duration values, and optional callbacks with defaults applied.
|
|
176
|
+
* @throws {RangeError} If any configured duration is not positive.
|
|
177
|
+
* @throws {TypeError} If `failureThreshold` is not a positive integer.
|
|
178
|
+
*/
|
|
179
|
+
declare function normalizeCircuitBreakerOptions(options: CircuitBreakerOptions): NormalizedCircuitBreakerOptions;
|
|
180
|
+
/**
|
|
181
|
+
* Parses a value loaded from the circuit breaker KV store.
|
|
182
|
+
*
|
|
183
|
+
* @param value The raw KV value to validate.
|
|
184
|
+
* @returns A circuit breaker state when `value` has a recognized state and
|
|
185
|
+
* valid instant strings, or `undefined` when the stored value is malformed.
|
|
186
|
+
*/
|
|
187
|
+
declare function parseCircuitBreakerKvState(value: unknown): CircuitBreakerKvState | undefined;
|
|
188
|
+
//#endregion
|
|
18
189
|
//#region src/federation/collection.d.ts
|
|
19
190
|
/**
|
|
20
191
|
* A page of items.
|
|
@@ -81,13 +252,19 @@ declare class SendActivityError extends Error {
|
|
|
81
252
|
*/
|
|
82
253
|
readonly responseBody: string;
|
|
83
254
|
/**
|
|
255
|
+
* The response headers from the inbox.
|
|
256
|
+
* @since 2.3.0
|
|
257
|
+
*/
|
|
258
|
+
readonly responseHeaders: Headers;
|
|
259
|
+
/**
|
|
84
260
|
* Creates a new {@link SendActivityError}.
|
|
85
261
|
* @param inbox The inbox URL.
|
|
86
262
|
* @param statusCode The HTTP status code.
|
|
87
263
|
* @param message The error message.
|
|
88
264
|
* @param responseBody The response body.
|
|
265
|
+
* @param responseHeaders The response headers.
|
|
89
266
|
*/
|
|
90
|
-
constructor(inbox: URL, statusCode: number, message: string, responseBody: string);
|
|
267
|
+
constructor(inbox: URL, statusCode: number, message: string, responseBody: string, responseHeaders?: HeadersInit);
|
|
91
268
|
}
|
|
92
269
|
//#endregion
|
|
93
270
|
//#region src/federation/callback.d.ts
|
|
@@ -310,11 +487,28 @@ type OutboxErrorHandler = (error: Error, activity: Activity | null) => void | Pr
|
|
|
310
487
|
* @since 2.0.0
|
|
311
488
|
*/
|
|
312
489
|
type OutboxPermanentFailureHandler<TContextData> = (context: Context<TContextData>, values: {
|
|
313
|
-
/**
|
|
490
|
+
/**
|
|
491
|
+
* Why Fedify is giving up on delivery.
|
|
492
|
+
*
|
|
493
|
+
* `"http"` means the inbox returned a configured permanent-failure HTTP
|
|
494
|
+
* status. `"circuit-breaker-ttl"` means the outbound circuit breaker held
|
|
495
|
+
* the activity until its retention period expired.
|
|
496
|
+
*
|
|
497
|
+
* @since 2.3.0
|
|
498
|
+
*/
|
|
499
|
+
readonly reason: "http" | "circuit-breaker-ttl"; /** The inbox URL that failed. */
|
|
500
|
+
readonly inbox: URL; /** The activity that failed to deliver. */
|
|
314
501
|
readonly activity: Activity; /** The error that occurred. */
|
|
315
502
|
readonly error: SendActivityError; /** The HTTP status code returned by the inbox. */
|
|
316
503
|
readonly statusCode: number;
|
|
317
504
|
/**
|
|
505
|
+
* The time when the circuit breaker first held the activity, if
|
|
506
|
+
* {@link reason} is `"circuit-breaker-ttl"`.
|
|
507
|
+
*
|
|
508
|
+
* @since 2.3.0
|
|
509
|
+
*/
|
|
510
|
+
readonly circuitHeldSince?: Temporal.Instant;
|
|
511
|
+
/**
|
|
318
512
|
* The actor IDs that were supposed to receive the activity at this inbox.
|
|
319
513
|
*/
|
|
320
514
|
readonly actorIds: readonly URL[];
|
|
@@ -476,6 +670,17 @@ interface OutboxMessage {
|
|
|
476
670
|
readonly attempt: number;
|
|
477
671
|
readonly headers: Readonly<Record<string, string>>;
|
|
478
672
|
readonly orderingKey?: string;
|
|
673
|
+
/**
|
|
674
|
+
* Whether this message is currently held by the outbound circuit breaker.
|
|
675
|
+
* @internal
|
|
676
|
+
*/
|
|
677
|
+
readonly circuitHeld?: true;
|
|
678
|
+
/**
|
|
679
|
+
* When Fedify first held this message because the remote host circuit was
|
|
680
|
+
* open.
|
|
681
|
+
* @internal
|
|
682
|
+
*/
|
|
683
|
+
readonly circuitHeldSince?: string;
|
|
479
684
|
readonly traceContext: Readonly<Record<string, string>>;
|
|
480
685
|
}
|
|
481
686
|
interface InboxMessage {
|
|
@@ -649,6 +854,12 @@ interface FederationKvPrefixes {
|
|
|
649
854
|
* @since 2.1.0
|
|
650
855
|
*/
|
|
651
856
|
readonly acceptSignatureNonce: KvKey;
|
|
857
|
+
/**
|
|
858
|
+
* The key prefix used for storing outbound delivery circuit breaker state.
|
|
859
|
+
* @default `["_fedify", "circuit"]`
|
|
860
|
+
* @since 2.3.0
|
|
861
|
+
*/
|
|
862
|
+
readonly circuitBreaker: KvKey;
|
|
652
863
|
}
|
|
653
864
|
/**
|
|
654
865
|
* Options for {@link FederationOptions.origin} when it is not a string.
|
|
@@ -1352,6 +1563,16 @@ interface FederationOptions<TContextData> {
|
|
|
1352
1563
|
*/
|
|
1353
1564
|
outboxRetryPolicy?: RetryPolicy;
|
|
1354
1565
|
/**
|
|
1566
|
+
* The circuit breaker for queued outbound activity delivery. When enabled,
|
|
1567
|
+
* Fedify tracks repeated failures per remote host and temporarily holds
|
|
1568
|
+
* queued activities instead of repeatedly hammering an unreachable server.
|
|
1569
|
+
*
|
|
1570
|
+
* Passing `false` disables the circuit breaker.
|
|
1571
|
+
*
|
|
1572
|
+
* @since 2.3.0
|
|
1573
|
+
*/
|
|
1574
|
+
circuitBreaker?: false | CircuitBreakerOptions;
|
|
1575
|
+
/**
|
|
1355
1576
|
* The retry policy for processing incoming activities. By default, this
|
|
1356
1577
|
* uses an exponential backoff strategy with a maximum of 10 attempts and a
|
|
1357
1578
|
* maximum delay of 12 hours.
|
|
@@ -2621,4 +2842,4 @@ interface ActorKeyPair extends CryptoKeyPair {
|
|
|
2621
2842
|
readonly multikey: Multikey;
|
|
2622
2843
|
}
|
|
2623
2844
|
//#endregion
|
|
2624
|
-
export { CustomCollectionDispatcher as $, FederationKvPrefixes as A, RespondWithObjectOptions as B, IdempotencyKeyCallback as C, ObjectCallbackSetters as D, InboxListenerSetters as E, RetryContext as F, ActorHandleMapper as G, respondWithObjectIfAcceptable as H, RetryPolicy as I, CollectionCounter as J, ActorKeyPairsDispatcher as K, createExponentialBackoffPolicy as L, FederationQueueOptions as M, createFederation as N, OutboxListenerSetters as O, CreateExponentialBackoffPolicyOptions as P, CustomCollectionCursor as Q, Message as R, FederationStartQueueOptions as S, InboxChallengePolicy as T, ActorAliasMapper as U, respondWithObject as V, ActorDispatcher as W, CollectionDispatcher as X, CollectionCursor as Y, CustomCollectionCounter as Z, Federatable as _, digest as _t, GetSignedKeyOptions as a, OutboxErrorHandler as at, FederationFetchOptions as b, ParseUriResult as c, OutboxPermanentFailureHandler as ct, SendActivityOptions as d, UnverifiedActivityReason as dt, InboxErrorHandler as et, SendActivityOptionsForCollection as f, WebFingerLinksDispatcher as ft, CustomCollectionCallbackSetters as g, buildCollectionSynchronizationHeader as gt, ConstructorWithTypeId as h, PageItems as ht, GetActorOptions as i, ObjectDispatcher as it, FederationOrigin as j, Rfc6570Expression as k, RequestContext as l, SharedInboxKeyDispatcher as lt, CollectionCallbackSetters as m, SenderKeyPair as mt, Context as n, NodeInfoDispatcher as nt, InboxContext as o, OutboxListener as ot, ActorCallbackSetters as p, SendActivityError as pt, AuthorizePredicate as q, ForwardActivityOptions as r, ObjectAuthorizePredicate as rt, OutboxContext as s, OutboxListenerErrorHandler as st, ActorKeyPair as t, InboxListener as tt, RouteActivityOptions as u, UnverifiedActivityHandler as ut, Federation as v,
|
|
2845
|
+
export { CustomCollectionDispatcher as $, FederationKvPrefixes as A, ActivityTransformer as At, RespondWithObjectOptions as B, IdempotencyKeyCallback as C, CircuitBreakerKvState as Ct, ObjectCallbackSetters as D, NormalizedCircuitBreakerOptions as Dt, InboxListenerSetters as E, CircuitBreakerStateChange as Et, RetryContext as F, ActorHandleMapper as G, respondWithObjectIfAcceptable as H, RetryPolicy as I, CollectionCounter as J, ActorKeyPairsDispatcher as K, createExponentialBackoffPolicy as L, FederationQueueOptions as M, createFederation as N, OutboxListenerSetters as O, normalizeCircuitBreakerOptions as Ot, CreateExponentialBackoffPolicyOptions as P, CustomCollectionCursor as Q, Message as R, FederationStartQueueOptions as S, CircuitBreakerFailurePolicy as St, InboxChallengePolicy as T, CircuitBreakerState as Tt, ActorAliasMapper as U, respondWithObject as V, ActorDispatcher as W, CollectionDispatcher as X, CollectionCursor as Y, CustomCollectionCounter as Z, Federatable as _, digest as _t, GetSignedKeyOptions as a, OutboxErrorHandler as at, FederationFetchOptions as b, CircuitBreakerBeforeSendDecision as bt, ParseUriResult as c, OutboxPermanentFailureHandler as ct, SendActivityOptions as d, UnverifiedActivityReason as dt, InboxErrorHandler as et, SendActivityOptionsForCollection as f, WebFingerLinksDispatcher as ft, CustomCollectionCallbackSetters as g, buildCollectionSynchronizationHeader as gt, ConstructorWithTypeId as h, PageItems as ht, GetActorOptions as i, ObjectDispatcher as it, FederationOrigin as j, Rfc6570Expression as k, parseCircuitBreakerKvState as kt, RequestContext as l, SharedInboxKeyDispatcher as lt, CollectionCallbackSetters as m, SenderKeyPair as mt, Context as n, NodeInfoDispatcher as nt, InboxContext as o, OutboxListener as ot, ActorCallbackSetters as p, SendActivityError as pt, AuthorizePredicate as q, ForwardActivityOptions as r, ObjectAuthorizePredicate as rt, OutboxContext as s, OutboxListenerErrorHandler as st, ActorKeyPair as t, InboxListener as tt, RouteActivityOptions as u, UnverifiedActivityHandler as ut, Federation as v, CircuitBreaker as vt, IdempotencyStrategy as w, CircuitBreakerOptions as wt, FederationOptions as x, CircuitBreakerCreateOptions as xt, FederationBuilder as y, CircuitBreakerActivityDrop as yt, createFederationBuilder as z };
|