@welshman/util 0.0.1
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/README.md +14 -0
- package/build/Address.cjs +44 -0
- package/build/Address.cjs.map +1 -0
- package/build/Address.d.ts +21 -0
- package/build/Address.mjs +32 -0
- package/build/Address.mjs.map +1 -0
- package/build/Events.cjs +58 -0
- package/build/Events.cjs.map +1 -0
- package/build/Events.d.ts +34 -0
- package/build/Events.mjs +42 -0
- package/build/Events.mjs.map +1 -0
- package/build/Filters.cjs +139 -0
- package/build/Filters.cjs.map +1 -0
- package/build/Filters.d.ts +39 -0
- package/build/Filters.mjs +127 -0
- package/build/Filters.mjs.map +1 -0
- package/build/Kinds.cjs +83 -0
- package/build/Kinds.cjs.map +1 -0
- package/build/Kinds.d.ts +77 -0
- package/build/Kinds.mjs +78 -0
- package/build/Kinds.mjs.map +1 -0
- package/build/Links.cjs +8 -0
- package/build/Links.cjs.map +1 -0
- package/build/Links.d.ts +2 -0
- package/build/Links.mjs +3 -0
- package/build/Links.mjs.map +1 -0
- package/build/Relay.cjs +148 -0
- package/build/Relay.cjs.map +1 -0
- package/build/Relay.d.ts +23 -0
- package/build/Relay.mjs +144 -0
- package/build/Relay.mjs.map +1 -0
- package/build/Relays.cjs +36 -0
- package/build/Relays.cjs.map +1 -0
- package/build/Relays.d.ts +6 -0
- package/build/Relays.mjs +31 -0
- package/build/Relays.mjs.map +1 -0
- package/build/Router.cjs +205 -0
- package/build/Router.cjs.map +1 -0
- package/build/Router.d.ts +128 -0
- package/build/Router.mjs +200 -0
- package/build/Router.mjs.map +1 -0
- package/build/Tags.cjs +149 -0
- package/build/Tags.cjs.map +1 -0
- package/build/Tags.d.ts +77 -0
- package/build/Tags.mjs +144 -0
- package/build/Tags.mjs.map +1 -0
- package/build/Zaps.cjs +96 -0
- package/build/Zaps.cjs.map +1 -0
- package/build/Zaps.d.ts +19 -0
- package/build/Zaps.mjs +89 -0
- package/build/Zaps.mjs.map +1 -0
- package/build/index.cjs +27 -0
- package/build/index.cjs.map +1 -0
- package/build/index.d.ts +10 -0
- package/build/index.mjs +11 -0
- package/build/index.mjs.map +1 -0
- package/package.json +38 -0
package/build/Relays.cjs
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeRelayUrl = exports.isShareableRelayUrl = void 0;
|
|
4
|
+
const lib_1 = require("@welshman/lib");
|
|
5
|
+
const isShareableRelayUrl = (url) => {
|
|
6
|
+
var _a;
|
|
7
|
+
return Boolean(typeof url === 'string' &&
|
|
8
|
+
// Is it actually a websocket url and has a dot
|
|
9
|
+
url.match(/^wss:\/\/.+\..+/) &&
|
|
10
|
+
// Sometimes bugs cause multiple relays to get concatenated
|
|
11
|
+
((_a = url.match(/:\/\//g)) === null || _a === void 0 ? void 0 : _a.length) === 1 &&
|
|
12
|
+
// It shouldn't have any whitespace, url-encoded or otherwise
|
|
13
|
+
!url.match(/\s|%/) &&
|
|
14
|
+
// Don't match stuff with a port number
|
|
15
|
+
!url.slice(6).match(/:\d+/) &&
|
|
16
|
+
// Don't match raw ip addresses
|
|
17
|
+
!url.slice(6).match(/\d+\.\d+\.\d+\.\d+/) &&
|
|
18
|
+
// Skip nostr.wine's virtual relays
|
|
19
|
+
!url.slice(6).match(/\/npub/));
|
|
20
|
+
};
|
|
21
|
+
exports.isShareableRelayUrl = isShareableRelayUrl;
|
|
22
|
+
const normalizeRelayUrl = (url, { allowInsecure = false } = {}) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const prefix = allowInsecure ? ((_a = url.match(/^wss?:\/\//)) === null || _a === void 0 ? void 0 : _a[0]) || "wss://" : "wss://";
|
|
25
|
+
// Use our library to normalize
|
|
26
|
+
url = (0, lib_1.normalizeUrl)(url, { stripHash: true, stripAuthentication: false });
|
|
27
|
+
// Strip the protocol since only wss works, lowercase
|
|
28
|
+
url = (0, lib_1.stripProtocol)(url).toLowerCase();
|
|
29
|
+
// Urls without pathnames are supposed to have a trailing slash
|
|
30
|
+
if (!url.includes("/")) {
|
|
31
|
+
url += "/";
|
|
32
|
+
}
|
|
33
|
+
return prefix + url;
|
|
34
|
+
};
|
|
35
|
+
exports.normalizeRelayUrl = normalizeRelayUrl;
|
|
36
|
+
//# sourceMappingURL=Relays.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Relays.cjs","sourceRoot":"","sources":["../Relays.ts"],"names":[],"mappings":";;;AAAA,uCAAyD;AAElD,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAE,EAAE;;IACjD,OAAA,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,+CAA+C;QAC/C,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC;QAC5B,2DAA2D;QAC3D,CAAA,MAAA,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,0CAAE,MAAM,MAAK,CAAC;QACjC,6DAA6D;QAC7D,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAClB,uCAAuC;QACvC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,+BAA+B;QAC/B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;QACzC,mCAAmC;QACnC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC9B,CAAA;CAAA,CAAA;AAfU,QAAA,mBAAmB,uBAe7B;AAMI,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAE,EAAC,aAAa,GAAG,KAAK,KAA2B,EAAE,EAAE,EAAE;;IACpG,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA,MAAA,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,0CAAG,CAAC,CAAC,KAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;IAElF,+BAA+B;IAC/B,GAAG,GAAG,IAAA,kBAAY,EAAC,GAAG,EAAE,EAAC,SAAS,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAC,CAAC,CAAA;IAEtE,qDAAqD;IACrD,GAAG,GAAG,IAAA,mBAAa,EAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IAEtC,+DAA+D;IAC/D,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACtB,GAAG,IAAI,GAAG,CAAA;KACX;IAED,OAAO,MAAM,GAAG,GAAG,CAAA;AACrB,CAAC,CAAA;AAfY,QAAA,iBAAiB,qBAe7B"}
|
package/build/Relays.mjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { normalizeUrl, stripProtocol } from '@welshman/lib';
|
|
2
|
+
export const isShareableRelayUrl = (url) => {
|
|
3
|
+
var _a;
|
|
4
|
+
return Boolean(typeof url === 'string' &&
|
|
5
|
+
// Is it actually a websocket url and has a dot
|
|
6
|
+
url.match(/^wss:\/\/.+\..+/) &&
|
|
7
|
+
// Sometimes bugs cause multiple relays to get concatenated
|
|
8
|
+
((_a = url.match(/:\/\//g)) === null || _a === void 0 ? void 0 : _a.length) === 1 &&
|
|
9
|
+
// It shouldn't have any whitespace, url-encoded or otherwise
|
|
10
|
+
!url.match(/\s|%/) &&
|
|
11
|
+
// Don't match stuff with a port number
|
|
12
|
+
!url.slice(6).match(/:\d+/) &&
|
|
13
|
+
// Don't match raw ip addresses
|
|
14
|
+
!url.slice(6).match(/\d+\.\d+\.\d+\.\d+/) &&
|
|
15
|
+
// Skip nostr.wine's virtual relays
|
|
16
|
+
!url.slice(6).match(/\/npub/));
|
|
17
|
+
};
|
|
18
|
+
export const normalizeRelayUrl = (url, { allowInsecure = false } = {}) => {
|
|
19
|
+
var _a;
|
|
20
|
+
const prefix = allowInsecure ? ((_a = url.match(/^wss?:\/\//)) === null || _a === void 0 ? void 0 : _a[0]) || "wss://" : "wss://";
|
|
21
|
+
// Use our library to normalize
|
|
22
|
+
url = normalizeUrl(url, { stripHash: true, stripAuthentication: false });
|
|
23
|
+
// Strip the protocol since only wss works, lowercase
|
|
24
|
+
url = stripProtocol(url).toLowerCase();
|
|
25
|
+
// Urls without pathnames are supposed to have a trailing slash
|
|
26
|
+
if (!url.includes("/")) {
|
|
27
|
+
url += "/";
|
|
28
|
+
}
|
|
29
|
+
return prefix + url;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=Relays.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Relays.mjs","sourceRoot":"","sources":["../Relays.ts"],"names":[],"mappings":"OAAO,EAAC,YAAY,EAAE,aAAa,EAAC,MAAM,eAAe;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAW,EAAE,EAAE;;IACjD,OAAA,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,+CAA+C;QAC/C,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC;QAC5B,2DAA2D;QAC3D,CAAA,MAAA,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,0CAAE,MAAM,MAAK,CAAC;QACjC,6DAA6D;QAC7D,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC;QAClB,uCAAuC;QACvC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAC3B,+BAA+B;QAC/B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;QACzC,mCAAmC;QACnC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAC9B,CAAA;CAAA,CAAA;AAMH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAE,EAAC,aAAa,GAAG,KAAK,KAA2B,EAAE,EAAE,EAAE;;IACpG,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA,MAAA,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,0CAAG,CAAC,CAAC,KAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;IAElF,+BAA+B;IAC/B,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,EAAC,SAAS,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAC,CAAC,CAAA;IAEtE,qDAAqD;IACrD,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IAEtC,+DAA+D;IAC/D,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACtB,GAAG,IAAI,GAAG,CAAA;KACX;IAED,OAAO,MAAM,GAAG,GAAG,CAAA;AACrB,CAAC,CAAA"}
|
package/build/Router.cjs
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouterScenario = exports.Router = exports.RelayMode = void 0;
|
|
4
|
+
const lib_1 = require("@welshman/lib");
|
|
5
|
+
const util_1 = require("@welshman/util");
|
|
6
|
+
const Events_1 = require("./Events.cjs");
|
|
7
|
+
const Relays_1 = require("./Relays.cjs");
|
|
8
|
+
const Address_1 = require("./Address.cjs");
|
|
9
|
+
var RelayMode;
|
|
10
|
+
(function (RelayMode) {
|
|
11
|
+
RelayMode["Read"] = "read";
|
|
12
|
+
RelayMode["Write"] = "write";
|
|
13
|
+
})(RelayMode || (exports.RelayMode = RelayMode = {}));
|
|
14
|
+
class Router {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
// Utilities derived from options
|
|
18
|
+
this.getPubkeySelection = (pubkey, mode) => this.selection(pubkey, this.options.getPubkeyRelays(pubkey, mode));
|
|
19
|
+
this.getPubkeySelections = (pubkeys, mode) => pubkeys.map(pubkey => this.getPubkeySelection(pubkey, mode));
|
|
20
|
+
this.getUserSelections = (mode) => this.getPubkeySelections([this.options.getUserPubkey()].filter(lib_1.identity), mode);
|
|
21
|
+
this.getContextSelections = (tags) => {
|
|
22
|
+
return [
|
|
23
|
+
...tags.communities().mapTo(t => this.selection(t.value(), this.options.getCommunityRelays(t.value()))).valueOf(),
|
|
24
|
+
...tags.groups().mapTo(t => this.selection(t.value(), this.options.getGroupRelays(t.value()))).valueOf(),
|
|
25
|
+
];
|
|
26
|
+
};
|
|
27
|
+
// Utilities for creating ValueRelays
|
|
28
|
+
this.selection = (value, relays) => ({ value, relays: Array.from(relays) });
|
|
29
|
+
this.selections = (values, relays) => values.map(value => this.selection(value, relays));
|
|
30
|
+
this.forceValue = (value, selections) => selections.map(({ relays }) => this.selection(value, relays));
|
|
31
|
+
// Utilities for processing hints
|
|
32
|
+
this.relaySelectionsFromMap = (valuesByRelay) => (0, lib_1.sortBy)(({ values }) => -values.length, Array.from(valuesByRelay)
|
|
33
|
+
.map(([relay, values]) => ({ relay, values: (0, lib_1.uniq)(values) })));
|
|
34
|
+
this.scoreRelaySelection = ({ values, relay }) => values.length * this.options.getRelayQuality(relay);
|
|
35
|
+
this.sortRelaySelections = (relaySelections) => {
|
|
36
|
+
const scores = new Map();
|
|
37
|
+
const getScore = (relayValues) => scores.get(relayValues.relay) || 0;
|
|
38
|
+
for (const relayValues of relaySelections) {
|
|
39
|
+
scores.set(relayValues.relay, this.scoreRelaySelection(relayValues));
|
|
40
|
+
}
|
|
41
|
+
return (0, lib_1.sortBy)(getScore, relaySelections.filter(getScore));
|
|
42
|
+
};
|
|
43
|
+
// Utilities for creating scenarios
|
|
44
|
+
this.scenario = (selections) => new RouterScenario(this, selections);
|
|
45
|
+
this.merge = (scenarios) => this.scenario(scenarios.flatMap((scenario) => scenario.selections));
|
|
46
|
+
this.product = (values, relays) => this.scenario(this.selections(values, relays));
|
|
47
|
+
this.fromRelays = (relays) => this.scenario([this.selection("", relays)]);
|
|
48
|
+
// Routing scenarios
|
|
49
|
+
this.User = () => this.scenario(this.getUserSelections());
|
|
50
|
+
this.ReadRelays = () => this.scenario(this.getUserSelections(RelayMode.Read));
|
|
51
|
+
this.WriteRelays = () => this.scenario(this.getUserSelections(RelayMode.Write));
|
|
52
|
+
this.Messages = (pubkeys) => this.scenario([
|
|
53
|
+
...this.getUserSelections(),
|
|
54
|
+
...this.getPubkeySelections(pubkeys),
|
|
55
|
+
]);
|
|
56
|
+
this.PublishMessage = (pubkey) => this.scenario([
|
|
57
|
+
...this.getUserSelections(RelayMode.Write),
|
|
58
|
+
this.getPubkeySelection(pubkey, RelayMode.Read),
|
|
59
|
+
]).policy(this.addMinimalFallbacks);
|
|
60
|
+
this.Event = (event) => this.scenario(this.forceValue(event.id, [
|
|
61
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Write),
|
|
62
|
+
...this.getContextSelections(util_1.Tags.fromEvent(event).context()),
|
|
63
|
+
]));
|
|
64
|
+
this.EventChildren = (event) => this.scenario(this.forceValue(event.id, [
|
|
65
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Read),
|
|
66
|
+
...this.getContextSelections(util_1.Tags.fromEvent(event).context()),
|
|
67
|
+
]));
|
|
68
|
+
this.EventAncestors = (event, type) => {
|
|
69
|
+
const tags = util_1.Tags.fromEvent(event);
|
|
70
|
+
const ancestors = tags.ancestors()[type];
|
|
71
|
+
const pubkeys = tags.whereKey("p").values().valueOf();
|
|
72
|
+
const communities = tags.communities().values().valueOf();
|
|
73
|
+
const groups = tags.groups().values().valueOf();
|
|
74
|
+
const relays = (0, lib_1.uniq)([
|
|
75
|
+
...this.options.getPubkeyRelays(event.pubkey, RelayMode.Read),
|
|
76
|
+
...pubkeys.flatMap((k) => this.options.getPubkeyRelays(k, RelayMode.Write)),
|
|
77
|
+
...communities.flatMap((a) => this.options.getCommunityRelays(a)),
|
|
78
|
+
...groups.flatMap((a) => this.options.getGroupRelays(a)),
|
|
79
|
+
...ancestors.relays().valueOf(),
|
|
80
|
+
]);
|
|
81
|
+
return this.product(ancestors.values().valueOf(), relays);
|
|
82
|
+
};
|
|
83
|
+
this.EventMentions = (event) => this.EventAncestors(event, "mentions");
|
|
84
|
+
this.EventParents = (event) => this.EventAncestors(event, "replies");
|
|
85
|
+
this.EventRoots = (event) => this.EventAncestors(event, "roots");
|
|
86
|
+
this.PublishEvent = (event) => {
|
|
87
|
+
const tags = util_1.Tags.fromEvent(event);
|
|
88
|
+
const mentions = tags.values("p").valueOf();
|
|
89
|
+
// If we're publishing to private groups, only publish to those groups' relays
|
|
90
|
+
if (tags.groups().exists()) {
|
|
91
|
+
return this
|
|
92
|
+
.scenario(this.getContextSelections(tags.groups()))
|
|
93
|
+
.policy(this.addNoFallbacks);
|
|
94
|
+
}
|
|
95
|
+
return this.scenario(this.forceValue(event.id, [
|
|
96
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Write),
|
|
97
|
+
...this.getContextSelections(tags.context()),
|
|
98
|
+
...this.getPubkeySelections(mentions, RelayMode.Read),
|
|
99
|
+
]));
|
|
100
|
+
};
|
|
101
|
+
this.FromPubkeys = (pubkeys) => this.scenario(this.getPubkeySelections(pubkeys, RelayMode.Write));
|
|
102
|
+
this.ForPubkeys = (pubkeys) => this.scenario(this.getPubkeySelections(pubkeys, RelayMode.Read));
|
|
103
|
+
this.WithinGroup = (address, relays) => this
|
|
104
|
+
.scenario(this.getContextSelections(util_1.Tags.wrap([["a", address]])))
|
|
105
|
+
.policy(this.addNoFallbacks);
|
|
106
|
+
this.WithinCommunity = (address) => this.scenario(this.getContextSelections(util_1.Tags.wrap([["a", address]])));
|
|
107
|
+
this.WithinContext = (address) => {
|
|
108
|
+
if ((0, Address_1.isGroupAddress)((0, Address_1.decodeAddress)(address))) {
|
|
109
|
+
return this.WithinGroup(address);
|
|
110
|
+
}
|
|
111
|
+
if ((0, Address_1.isCommunityAddress)((0, Address_1.decodeAddress)(address))) {
|
|
112
|
+
return this.WithinCommunity(address);
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Unknown context ${address}`);
|
|
115
|
+
};
|
|
116
|
+
this.WithinMultipleContexts = (addresses) => this.merge(addresses.map(this.WithinContext));
|
|
117
|
+
this.Search = (term, relays = []) => this.product([term], (0, lib_1.uniq)(this.options.getSearchRelays().concat(relays)));
|
|
118
|
+
this.Indexers = (relays = []) => this.fromRelays((0, lib_1.uniq)(this.options.getIndexerRelays().concat(relays)));
|
|
119
|
+
// Fallback policies
|
|
120
|
+
this.addNoFallbacks = (count, redundancy) => count;
|
|
121
|
+
this.addMinimalFallbacks = (count, redundancy) => Math.max(count, 1);
|
|
122
|
+
this.addMaximalFallbacks = (count, redundancy) => redundancy - count;
|
|
123
|
+
// Higher level utils that use hints
|
|
124
|
+
this.tagPubkey = (pubkey) => util_1.Tag.from(["p", pubkey, this.FromPubkeys([pubkey]).getUrl()]);
|
|
125
|
+
this.tagEventId = (event, ...extra) => util_1.Tag.from(["e", event.id, this.Event(event).getUrl(), ...extra]);
|
|
126
|
+
this.tagEventAddress = (event, ...extra) => util_1.Tag.from(["a", (0, Events_1.getAddress)(event), this.Event(event).getUrl(), ...extra]);
|
|
127
|
+
this.tagEvent = (event, ...extra) => {
|
|
128
|
+
const tags = [this.tagEventId(event, ...extra)];
|
|
129
|
+
if ((0, Events_1.isReplaceable)(event)) {
|
|
130
|
+
tags.push(this.tagEventAddress(event, ...extra));
|
|
131
|
+
}
|
|
132
|
+
return new util_1.Tags(tags);
|
|
133
|
+
};
|
|
134
|
+
this.address = (event) => (0, Address_1.addressFromEvent)(event, this.Event(event).redundancy(3).getUrls());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.Router = Router;
|
|
138
|
+
class RouterScenario {
|
|
139
|
+
constructor(router, selections, options = {}) {
|
|
140
|
+
this.router = router;
|
|
141
|
+
this.selections = selections;
|
|
142
|
+
this.options = options;
|
|
143
|
+
this.clone = (options) => new RouterScenario(this.router, this.selections, { ...this.options, ...options });
|
|
144
|
+
this.select = (f) => new RouterScenario(this.router, this.selections.filter(({ value }) => f(value)), this.options);
|
|
145
|
+
this.redundancy = (redundancy) => this.clone({ redundancy });
|
|
146
|
+
this.policy = (policy) => this.clone({ policy });
|
|
147
|
+
this.limit = (limit) => this.clone({ limit });
|
|
148
|
+
this.getRedundancy = () => this.options.redundancy || this.router.options.getRedundancy();
|
|
149
|
+
this.getPolicy = () => this.options.policy || this.router.addMaximalFallbacks;
|
|
150
|
+
this.getLimit = () => this.options.limit || this.router.options.getLimit();
|
|
151
|
+
this.getSelections = () => {
|
|
152
|
+
const allValues = new Set();
|
|
153
|
+
const valuesByRelay = new Map();
|
|
154
|
+
for (const { value, relays } of this.selections) {
|
|
155
|
+
allValues.add(value);
|
|
156
|
+
for (const relay of relays) {
|
|
157
|
+
if ((0, Relays_1.isShareableRelayUrl)(relay)) {
|
|
158
|
+
(0, lib_1.pushToMapKey)(valuesByRelay, relay, value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Adjust redundancy by limit, since if we're looking for very specific values odds
|
|
163
|
+
// are we're less tolerant of failure. Add more redundancy to fill our relay limit.
|
|
164
|
+
const limit = this.getLimit();
|
|
165
|
+
const redundancy = this.getRedundancy();
|
|
166
|
+
const adjustedRedundancy = Math.max(redundancy, redundancy * (limit / (allValues.size * redundancy)));
|
|
167
|
+
const seen = new Map();
|
|
168
|
+
const result = new Map();
|
|
169
|
+
const relaySelections = this.router.relaySelectionsFromMap(valuesByRelay);
|
|
170
|
+
for (const { relay } of this.router.sortRelaySelections(relaySelections)) {
|
|
171
|
+
const values = new Set();
|
|
172
|
+
for (const value of valuesByRelay.get(relay) || []) {
|
|
173
|
+
const timesSeen = seen.get(value) || 0;
|
|
174
|
+
if (timesSeen < adjustedRedundancy) {
|
|
175
|
+
seen.set(value, timesSeen + 1);
|
|
176
|
+
values.add(value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (values.size > 0) {
|
|
180
|
+
result.set(relay, Array.from(values));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const fallbacks = (0, lib_1.shuffle)(this.router.options.getStaticRelays());
|
|
184
|
+
const fallbackPolicy = this.getPolicy();
|
|
185
|
+
for (const { value } of this.selections) {
|
|
186
|
+
const timesSeen = seen.get(value) || 0;
|
|
187
|
+
const fallbacksNeeded = fallbackPolicy(timesSeen, adjustedRedundancy);
|
|
188
|
+
if (fallbacksNeeded > 0) {
|
|
189
|
+
for (const relay of fallbacks.slice(0, fallbacksNeeded)) {
|
|
190
|
+
(0, lib_1.pushToMapKey)(result, relay, value);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const [keep, discard] = (0, lib_1.splitAt)(limit, this.router.relaySelectionsFromMap(result));
|
|
195
|
+
for (const target of keep.slice(0, redundancy)) {
|
|
196
|
+
target.values = (0, lib_1.uniq)(discard.concat(target).flatMap((selection) => selection.values));
|
|
197
|
+
}
|
|
198
|
+
return keep;
|
|
199
|
+
};
|
|
200
|
+
this.getUrls = () => this.getSelections().map((selection) => selection.relay);
|
|
201
|
+
this.getUrl = () => (0, lib_1.first)(this.getUrls());
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.RouterScenario = RouterScenario;
|
|
205
|
+
//# sourceMappingURL=Router.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Router.cjs","sourceRoot":"","sources":["../Router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Tags, Tag } from '@welshman/util';
|
|
2
|
+
import type { Rumor } from './Events';
|
|
3
|
+
export declare enum RelayMode {
|
|
4
|
+
Read = "read",
|
|
5
|
+
Write = "write"
|
|
6
|
+
}
|
|
7
|
+
export type RouterOptions = {
|
|
8
|
+
getUserPubkey: () => string | null;
|
|
9
|
+
getGroupRelays: (address: string) => string[];
|
|
10
|
+
getCommunityRelays: (address: string) => string[];
|
|
11
|
+
getPubkeyRelays: (pubkey: string, mode?: RelayMode) => string[];
|
|
12
|
+
getStaticRelays: () => string[];
|
|
13
|
+
getIndexerRelays: () => string[];
|
|
14
|
+
getSearchRelays: () => string[];
|
|
15
|
+
getRelayQuality: (url: string) => number;
|
|
16
|
+
getRedundancy: () => number;
|
|
17
|
+
getLimit: () => number;
|
|
18
|
+
};
|
|
19
|
+
export type ValuesByRelay = Map<string, string[]>;
|
|
20
|
+
export type RelayValues = {
|
|
21
|
+
relay: string;
|
|
22
|
+
values: string[];
|
|
23
|
+
};
|
|
24
|
+
export type ValueRelays = {
|
|
25
|
+
value: string;
|
|
26
|
+
relays: string[];
|
|
27
|
+
};
|
|
28
|
+
export type FallbackPolicy = (count: number, limit: number) => number;
|
|
29
|
+
export declare class Router {
|
|
30
|
+
readonly options: RouterOptions;
|
|
31
|
+
constructor(options: RouterOptions);
|
|
32
|
+
getPubkeySelection: (pubkey: string, mode?: RelayMode) => {
|
|
33
|
+
value: string;
|
|
34
|
+
relays: string[];
|
|
35
|
+
};
|
|
36
|
+
getPubkeySelections: (pubkeys: string[], mode?: RelayMode) => {
|
|
37
|
+
value: string;
|
|
38
|
+
relays: string[];
|
|
39
|
+
}[];
|
|
40
|
+
getUserSelections: (mode?: RelayMode) => {
|
|
41
|
+
value: string;
|
|
42
|
+
relays: string[];
|
|
43
|
+
}[];
|
|
44
|
+
getContextSelections: (tags: Tags) => {
|
|
45
|
+
value: string;
|
|
46
|
+
relays: string[];
|
|
47
|
+
}[];
|
|
48
|
+
selection: (value: string, relays: Iterable<string>) => {
|
|
49
|
+
value: string;
|
|
50
|
+
relays: string[];
|
|
51
|
+
};
|
|
52
|
+
selections: (values: string[], relays: string[]) => {
|
|
53
|
+
value: string;
|
|
54
|
+
relays: string[];
|
|
55
|
+
}[];
|
|
56
|
+
forceValue: (value: string, selections: ValueRelays[]) => {
|
|
57
|
+
value: string;
|
|
58
|
+
relays: string[];
|
|
59
|
+
}[];
|
|
60
|
+
relaySelectionsFromMap: (valuesByRelay: ValuesByRelay) => {
|
|
61
|
+
relay: string;
|
|
62
|
+
values: string[];
|
|
63
|
+
}[];
|
|
64
|
+
scoreRelaySelection: ({ values, relay }: RelayValues) => number;
|
|
65
|
+
sortRelaySelections: (relaySelections: RelayValues[]) => RelayValues[];
|
|
66
|
+
scenario: (selections: ValueRelays[]) => RouterScenario;
|
|
67
|
+
merge: (scenarios: RouterScenario[]) => RouterScenario;
|
|
68
|
+
product: (values: string[], relays: string[]) => RouterScenario;
|
|
69
|
+
fromRelays: (relays: string[]) => RouterScenario;
|
|
70
|
+
User: () => RouterScenario;
|
|
71
|
+
ReadRelays: () => RouterScenario;
|
|
72
|
+
WriteRelays: () => RouterScenario;
|
|
73
|
+
Messages: (pubkeys: string[]) => RouterScenario;
|
|
74
|
+
PublishMessage: (pubkey: string) => RouterScenario;
|
|
75
|
+
Event: (event: Rumor) => RouterScenario;
|
|
76
|
+
EventChildren: (event: Rumor) => RouterScenario;
|
|
77
|
+
EventAncestors: (event: Rumor, type: "mentions" | "replies" | "roots") => RouterScenario;
|
|
78
|
+
EventMentions: (event: Rumor) => RouterScenario;
|
|
79
|
+
EventParents: (event: Rumor) => RouterScenario;
|
|
80
|
+
EventRoots: (event: Rumor) => RouterScenario;
|
|
81
|
+
PublishEvent: (event: Rumor) => RouterScenario;
|
|
82
|
+
FromPubkeys: (pubkeys: string[]) => RouterScenario;
|
|
83
|
+
ForPubkeys: (pubkeys: string[]) => RouterScenario;
|
|
84
|
+
WithinGroup: (address: string, relays?: string) => RouterScenario;
|
|
85
|
+
WithinCommunity: (address: string) => RouterScenario;
|
|
86
|
+
WithinContext: (address: string) => RouterScenario;
|
|
87
|
+
WithinMultipleContexts: (addresses: string[]) => RouterScenario;
|
|
88
|
+
Search: (term: string, relays?: string[]) => RouterScenario;
|
|
89
|
+
Indexers: (relays?: string[]) => RouterScenario;
|
|
90
|
+
addNoFallbacks: (count: number, redundancy: number) => number;
|
|
91
|
+
addMinimalFallbacks: (count: number, redundancy: number) => number;
|
|
92
|
+
addMaximalFallbacks: (count: number, redundancy: number) => number;
|
|
93
|
+
tagPubkey: (pubkey: string) => Tag;
|
|
94
|
+
tagEventId: (event: Rumor, ...extra: string[]) => Tag;
|
|
95
|
+
tagEventAddress: (event: Rumor, ...extra: string[]) => Tag;
|
|
96
|
+
tagEvent: (event: Rumor, ...extra: string[]) => Tags;
|
|
97
|
+
address: (event: Rumor) => {
|
|
98
|
+
kind: number;
|
|
99
|
+
pubkey: string;
|
|
100
|
+
identifier: string;
|
|
101
|
+
relays: string[];
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export type RouterScenarioOptions = {
|
|
105
|
+
redundancy?: number;
|
|
106
|
+
policy?: FallbackPolicy;
|
|
107
|
+
limit?: number;
|
|
108
|
+
};
|
|
109
|
+
export declare class RouterScenario {
|
|
110
|
+
readonly router: Router;
|
|
111
|
+
readonly selections: ValueRelays[];
|
|
112
|
+
readonly options: RouterScenarioOptions;
|
|
113
|
+
constructor(router: Router, selections: ValueRelays[], options?: RouterScenarioOptions);
|
|
114
|
+
clone: (options: RouterScenarioOptions) => RouterScenario;
|
|
115
|
+
select: (f: (selection: string) => boolean) => RouterScenario;
|
|
116
|
+
redundancy: (redundancy: number) => RouterScenario;
|
|
117
|
+
policy: (policy: FallbackPolicy) => RouterScenario;
|
|
118
|
+
limit: (limit: number) => RouterScenario;
|
|
119
|
+
getRedundancy: () => number;
|
|
120
|
+
getPolicy: () => FallbackPolicy;
|
|
121
|
+
getLimit: () => number;
|
|
122
|
+
getSelections: () => {
|
|
123
|
+
relay: string;
|
|
124
|
+
values: string[];
|
|
125
|
+
}[];
|
|
126
|
+
getUrls: () => string[];
|
|
127
|
+
getUrl: () => string;
|
|
128
|
+
}
|
package/build/Router.mjs
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { first, splitAt, identity, sortBy, uniq, shuffle, pushToMapKey } from '@welshman/lib';
|
|
2
|
+
import { Tags, Tag } from '@welshman/util';
|
|
3
|
+
import { getAddress, isReplaceable } from "./Events.mjs";
|
|
4
|
+
import { isShareableRelayUrl } from "./Relays.mjs";
|
|
5
|
+
import { addressFromEvent, decodeAddress, isCommunityAddress, isGroupAddress } from "./Address.mjs";
|
|
6
|
+
export var RelayMode;
|
|
7
|
+
(function (RelayMode) {
|
|
8
|
+
RelayMode["Read"] = "read";
|
|
9
|
+
RelayMode["Write"] = "write";
|
|
10
|
+
})(RelayMode || (RelayMode = {}));
|
|
11
|
+
export class Router {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
// Utilities derived from options
|
|
15
|
+
this.getPubkeySelection = (pubkey, mode) => this.selection(pubkey, this.options.getPubkeyRelays(pubkey, mode));
|
|
16
|
+
this.getPubkeySelections = (pubkeys, mode) => pubkeys.map(pubkey => this.getPubkeySelection(pubkey, mode));
|
|
17
|
+
this.getUserSelections = (mode) => this.getPubkeySelections([this.options.getUserPubkey()].filter(identity), mode);
|
|
18
|
+
this.getContextSelections = (tags) => {
|
|
19
|
+
return [
|
|
20
|
+
...tags.communities().mapTo(t => this.selection(t.value(), this.options.getCommunityRelays(t.value()))).valueOf(),
|
|
21
|
+
...tags.groups().mapTo(t => this.selection(t.value(), this.options.getGroupRelays(t.value()))).valueOf(),
|
|
22
|
+
];
|
|
23
|
+
};
|
|
24
|
+
// Utilities for creating ValueRelays
|
|
25
|
+
this.selection = (value, relays) => ({ value, relays: Array.from(relays) });
|
|
26
|
+
this.selections = (values, relays) => values.map(value => this.selection(value, relays));
|
|
27
|
+
this.forceValue = (value, selections) => selections.map(({ relays }) => this.selection(value, relays));
|
|
28
|
+
// Utilities for processing hints
|
|
29
|
+
this.relaySelectionsFromMap = (valuesByRelay) => sortBy(({ values }) => -values.length, Array.from(valuesByRelay)
|
|
30
|
+
.map(([relay, values]) => ({ relay, values: uniq(values) })));
|
|
31
|
+
this.scoreRelaySelection = ({ values, relay }) => values.length * this.options.getRelayQuality(relay);
|
|
32
|
+
this.sortRelaySelections = (relaySelections) => {
|
|
33
|
+
const scores = new Map();
|
|
34
|
+
const getScore = (relayValues) => scores.get(relayValues.relay) || 0;
|
|
35
|
+
for (const relayValues of relaySelections) {
|
|
36
|
+
scores.set(relayValues.relay, this.scoreRelaySelection(relayValues));
|
|
37
|
+
}
|
|
38
|
+
return sortBy(getScore, relaySelections.filter(getScore));
|
|
39
|
+
};
|
|
40
|
+
// Utilities for creating scenarios
|
|
41
|
+
this.scenario = (selections) => new RouterScenario(this, selections);
|
|
42
|
+
this.merge = (scenarios) => this.scenario(scenarios.flatMap((scenario) => scenario.selections));
|
|
43
|
+
this.product = (values, relays) => this.scenario(this.selections(values, relays));
|
|
44
|
+
this.fromRelays = (relays) => this.scenario([this.selection("", relays)]);
|
|
45
|
+
// Routing scenarios
|
|
46
|
+
this.User = () => this.scenario(this.getUserSelections());
|
|
47
|
+
this.ReadRelays = () => this.scenario(this.getUserSelections(RelayMode.Read));
|
|
48
|
+
this.WriteRelays = () => this.scenario(this.getUserSelections(RelayMode.Write));
|
|
49
|
+
this.Messages = (pubkeys) => this.scenario([
|
|
50
|
+
...this.getUserSelections(),
|
|
51
|
+
...this.getPubkeySelections(pubkeys),
|
|
52
|
+
]);
|
|
53
|
+
this.PublishMessage = (pubkey) => this.scenario([
|
|
54
|
+
...this.getUserSelections(RelayMode.Write),
|
|
55
|
+
this.getPubkeySelection(pubkey, RelayMode.Read),
|
|
56
|
+
]).policy(this.addMinimalFallbacks);
|
|
57
|
+
this.Event = (event) => this.scenario(this.forceValue(event.id, [
|
|
58
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Write),
|
|
59
|
+
...this.getContextSelections(Tags.fromEvent(event).context()),
|
|
60
|
+
]));
|
|
61
|
+
this.EventChildren = (event) => this.scenario(this.forceValue(event.id, [
|
|
62
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Read),
|
|
63
|
+
...this.getContextSelections(Tags.fromEvent(event).context()),
|
|
64
|
+
]));
|
|
65
|
+
this.EventAncestors = (event, type) => {
|
|
66
|
+
const tags = Tags.fromEvent(event);
|
|
67
|
+
const ancestors = tags.ancestors()[type];
|
|
68
|
+
const pubkeys = tags.whereKey("p").values().valueOf();
|
|
69
|
+
const communities = tags.communities().values().valueOf();
|
|
70
|
+
const groups = tags.groups().values().valueOf();
|
|
71
|
+
const relays = uniq([
|
|
72
|
+
...this.options.getPubkeyRelays(event.pubkey, RelayMode.Read),
|
|
73
|
+
...pubkeys.flatMap((k) => this.options.getPubkeyRelays(k, RelayMode.Write)),
|
|
74
|
+
...communities.flatMap((a) => this.options.getCommunityRelays(a)),
|
|
75
|
+
...groups.flatMap((a) => this.options.getGroupRelays(a)),
|
|
76
|
+
...ancestors.relays().valueOf(),
|
|
77
|
+
]);
|
|
78
|
+
return this.product(ancestors.values().valueOf(), relays);
|
|
79
|
+
};
|
|
80
|
+
this.EventMentions = (event) => this.EventAncestors(event, "mentions");
|
|
81
|
+
this.EventParents = (event) => this.EventAncestors(event, "replies");
|
|
82
|
+
this.EventRoots = (event) => this.EventAncestors(event, "roots");
|
|
83
|
+
this.PublishEvent = (event) => {
|
|
84
|
+
const tags = Tags.fromEvent(event);
|
|
85
|
+
const mentions = tags.values("p").valueOf();
|
|
86
|
+
// If we're publishing to private groups, only publish to those groups' relays
|
|
87
|
+
if (tags.groups().exists()) {
|
|
88
|
+
return this
|
|
89
|
+
.scenario(this.getContextSelections(tags.groups()))
|
|
90
|
+
.policy(this.addNoFallbacks);
|
|
91
|
+
}
|
|
92
|
+
return this.scenario(this.forceValue(event.id, [
|
|
93
|
+
this.getPubkeySelection(event.pubkey, RelayMode.Write),
|
|
94
|
+
...this.getContextSelections(tags.context()),
|
|
95
|
+
...this.getPubkeySelections(mentions, RelayMode.Read),
|
|
96
|
+
]));
|
|
97
|
+
};
|
|
98
|
+
this.FromPubkeys = (pubkeys) => this.scenario(this.getPubkeySelections(pubkeys, RelayMode.Write));
|
|
99
|
+
this.ForPubkeys = (pubkeys) => this.scenario(this.getPubkeySelections(pubkeys, RelayMode.Read));
|
|
100
|
+
this.WithinGroup = (address, relays) => this
|
|
101
|
+
.scenario(this.getContextSelections(Tags.wrap([["a", address]])))
|
|
102
|
+
.policy(this.addNoFallbacks);
|
|
103
|
+
this.WithinCommunity = (address) => this.scenario(this.getContextSelections(Tags.wrap([["a", address]])));
|
|
104
|
+
this.WithinContext = (address) => {
|
|
105
|
+
if (isGroupAddress(decodeAddress(address))) {
|
|
106
|
+
return this.WithinGroup(address);
|
|
107
|
+
}
|
|
108
|
+
if (isCommunityAddress(decodeAddress(address))) {
|
|
109
|
+
return this.WithinCommunity(address);
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`Unknown context ${address}`);
|
|
112
|
+
};
|
|
113
|
+
this.WithinMultipleContexts = (addresses) => this.merge(addresses.map(this.WithinContext));
|
|
114
|
+
this.Search = (term, relays = []) => this.product([term], uniq(this.options.getSearchRelays().concat(relays)));
|
|
115
|
+
this.Indexers = (relays = []) => this.fromRelays(uniq(this.options.getIndexerRelays().concat(relays)));
|
|
116
|
+
// Fallback policies
|
|
117
|
+
this.addNoFallbacks = (count, redundancy) => count;
|
|
118
|
+
this.addMinimalFallbacks = (count, redundancy) => Math.max(count, 1);
|
|
119
|
+
this.addMaximalFallbacks = (count, redundancy) => redundancy - count;
|
|
120
|
+
// Higher level utils that use hints
|
|
121
|
+
this.tagPubkey = (pubkey) => Tag.from(["p", pubkey, this.FromPubkeys([pubkey]).getUrl()]);
|
|
122
|
+
this.tagEventId = (event, ...extra) => Tag.from(["e", event.id, this.Event(event).getUrl(), ...extra]);
|
|
123
|
+
this.tagEventAddress = (event, ...extra) => Tag.from(["a", getAddress(event), this.Event(event).getUrl(), ...extra]);
|
|
124
|
+
this.tagEvent = (event, ...extra) => {
|
|
125
|
+
const tags = [this.tagEventId(event, ...extra)];
|
|
126
|
+
if (isReplaceable(event)) {
|
|
127
|
+
tags.push(this.tagEventAddress(event, ...extra));
|
|
128
|
+
}
|
|
129
|
+
return new Tags(tags);
|
|
130
|
+
};
|
|
131
|
+
this.address = (event) => addressFromEvent(event, this.Event(event).redundancy(3).getUrls());
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export class RouterScenario {
|
|
135
|
+
constructor(router, selections, options = {}) {
|
|
136
|
+
this.router = router;
|
|
137
|
+
this.selections = selections;
|
|
138
|
+
this.options = options;
|
|
139
|
+
this.clone = (options) => new RouterScenario(this.router, this.selections, { ...this.options, ...options });
|
|
140
|
+
this.select = (f) => new RouterScenario(this.router, this.selections.filter(({ value }) => f(value)), this.options);
|
|
141
|
+
this.redundancy = (redundancy) => this.clone({ redundancy });
|
|
142
|
+
this.policy = (policy) => this.clone({ policy });
|
|
143
|
+
this.limit = (limit) => this.clone({ limit });
|
|
144
|
+
this.getRedundancy = () => this.options.redundancy || this.router.options.getRedundancy();
|
|
145
|
+
this.getPolicy = () => this.options.policy || this.router.addMaximalFallbacks;
|
|
146
|
+
this.getLimit = () => this.options.limit || this.router.options.getLimit();
|
|
147
|
+
this.getSelections = () => {
|
|
148
|
+
const allValues = new Set();
|
|
149
|
+
const valuesByRelay = new Map();
|
|
150
|
+
for (const { value, relays } of this.selections) {
|
|
151
|
+
allValues.add(value);
|
|
152
|
+
for (const relay of relays) {
|
|
153
|
+
if (isShareableRelayUrl(relay)) {
|
|
154
|
+
pushToMapKey(valuesByRelay, relay, value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Adjust redundancy by limit, since if we're looking for very specific values odds
|
|
159
|
+
// are we're less tolerant of failure. Add more redundancy to fill our relay limit.
|
|
160
|
+
const limit = this.getLimit();
|
|
161
|
+
const redundancy = this.getRedundancy();
|
|
162
|
+
const adjustedRedundancy = Math.max(redundancy, redundancy * (limit / (allValues.size * redundancy)));
|
|
163
|
+
const seen = new Map();
|
|
164
|
+
const result = new Map();
|
|
165
|
+
const relaySelections = this.router.relaySelectionsFromMap(valuesByRelay);
|
|
166
|
+
for (const { relay } of this.router.sortRelaySelections(relaySelections)) {
|
|
167
|
+
const values = new Set();
|
|
168
|
+
for (const value of valuesByRelay.get(relay) || []) {
|
|
169
|
+
const timesSeen = seen.get(value) || 0;
|
|
170
|
+
if (timesSeen < adjustedRedundancy) {
|
|
171
|
+
seen.set(value, timesSeen + 1);
|
|
172
|
+
values.add(value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (values.size > 0) {
|
|
176
|
+
result.set(relay, Array.from(values));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const fallbacks = shuffle(this.router.options.getStaticRelays());
|
|
180
|
+
const fallbackPolicy = this.getPolicy();
|
|
181
|
+
for (const { value } of this.selections) {
|
|
182
|
+
const timesSeen = seen.get(value) || 0;
|
|
183
|
+
const fallbacksNeeded = fallbackPolicy(timesSeen, adjustedRedundancy);
|
|
184
|
+
if (fallbacksNeeded > 0) {
|
|
185
|
+
for (const relay of fallbacks.slice(0, fallbacksNeeded)) {
|
|
186
|
+
pushToMapKey(result, relay, value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const [keep, discard] = splitAt(limit, this.router.relaySelectionsFromMap(result));
|
|
191
|
+
for (const target of keep.slice(0, redundancy)) {
|
|
192
|
+
target.values = uniq(discard.concat(target).flatMap((selection) => selection.values));
|
|
193
|
+
}
|
|
194
|
+
return keep;
|
|
195
|
+
};
|
|
196
|
+
this.getUrls = () => this.getSelections().map((selection) => selection.relay);
|
|
197
|
+
this.getUrl = () => first(this.getUrls());
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=Router.mjs.map
|