@libp2p/circuit-relay-v2 0.0.0-05b52d69c

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.
Files changed (65) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +69 -0
  3. package/dist/index.min.js +45 -0
  4. package/dist/src/constants.d.ts +55 -0
  5. package/dist/src/constants.d.ts.map +1 -0
  6. package/dist/src/constants.js +61 -0
  7. package/dist/src/constants.js.map +1 -0
  8. package/dist/src/index.d.ts +56 -0
  9. package/dist/src/index.d.ts.map +1 -0
  10. package/dist/src/index.js +39 -0
  11. package/dist/src/index.js.map +1 -0
  12. package/dist/src/pb/index.d.ts +93 -0
  13. package/dist/src/pb/index.d.ts.map +1 -0
  14. package/dist/src/pb/index.js +425 -0
  15. package/dist/src/pb/index.js.map +1 -0
  16. package/dist/src/server/advert-service.d.ts +46 -0
  17. package/dist/src/server/advert-service.d.ts.map +1 -0
  18. package/dist/src/server/advert-service.js +72 -0
  19. package/dist/src/server/advert-service.js.map +1 -0
  20. package/dist/src/server/index.d.ts +67 -0
  21. package/dist/src/server/index.d.ts.map +1 -0
  22. package/dist/src/server/index.js +313 -0
  23. package/dist/src/server/index.js.map +1 -0
  24. package/dist/src/server/reservation-store.d.ts +49 -0
  25. package/dist/src/server/reservation-store.d.ts.map +1 -0
  26. package/dist/src/server/reservation-store.js +65 -0
  27. package/dist/src/server/reservation-store.js.map +1 -0
  28. package/dist/src/server/reservation-voucher.d.ts +18 -0
  29. package/dist/src/server/reservation-voucher.d.ts.map +1 -0
  30. package/dist/src/server/reservation-voucher.js +36 -0
  31. package/dist/src/server/reservation-voucher.js.map +1 -0
  32. package/dist/src/transport/discovery.d.ts +48 -0
  33. package/dist/src/transport/discovery.d.ts.map +1 -0
  34. package/dist/src/transport/discovery.js +97 -0
  35. package/dist/src/transport/discovery.js.map +1 -0
  36. package/dist/src/transport/index.d.ts +58 -0
  37. package/dist/src/transport/index.d.ts.map +1 -0
  38. package/dist/src/transport/index.js +279 -0
  39. package/dist/src/transport/index.js.map +1 -0
  40. package/dist/src/transport/listener.d.ts +11 -0
  41. package/dist/src/transport/listener.d.ts.map +1 -0
  42. package/dist/src/transport/listener.js +66 -0
  43. package/dist/src/transport/listener.js.map +1 -0
  44. package/dist/src/transport/reservation-store.d.ts +74 -0
  45. package/dist/src/transport/reservation-store.d.ts.map +1 -0
  46. package/dist/src/transport/reservation-store.js +209 -0
  47. package/dist/src/transport/reservation-store.js.map +1 -0
  48. package/dist/src/utils.d.ts +14 -0
  49. package/dist/src/utils.d.ts.map +1 -0
  50. package/dist/src/utils.js +106 -0
  51. package/dist/src/utils.js.map +1 -0
  52. package/package.json +83 -0
  53. package/src/constants.ts +79 -0
  54. package/src/index.ts +64 -0
  55. package/src/pb/index.proto +67 -0
  56. package/src/pb/index.ts +539 -0
  57. package/src/server/advert-service.ts +109 -0
  58. package/src/server/index.ts +446 -0
  59. package/src/server/reservation-store.ts +116 -0
  60. package/src/server/reservation-voucher.ts +51 -0
  61. package/src/transport/discovery.ts +138 -0
  62. package/src/transport/index.ts +399 -0
  63. package/src/transport/listener.ts +98 -0
  64. package/src/transport/reservation-store.ts +312 -0
  65. package/src/utils.ts +134 -0
@@ -0,0 +1,97 @@
1
+ import { TypedEventEmitter } from '@libp2p/interface/events';
2
+ import { RELAY_RENDEZVOUS_NS, RELAY_V2_HOP_CODEC } from '../constants.js';
3
+ import { namespaceToCid } from '../utils.js';
4
+ /**
5
+ * ReservationManager automatically makes a circuit v2 reservation on any connected
6
+ * peers that support the circuit v2 HOP protocol.
7
+ */
8
+ export class RelayDiscovery extends TypedEventEmitter {
9
+ peerId;
10
+ peerStore;
11
+ contentRouting;
12
+ registrar;
13
+ started;
14
+ topologyId;
15
+ log;
16
+ constructor(components) {
17
+ super();
18
+ this.log = components.logger.forComponent('libp2p:circuit-relay:discover-relays');
19
+ this.started = false;
20
+ this.peerId = components.peerId;
21
+ this.peerStore = components.peerStore;
22
+ this.contentRouting = components.contentRouting;
23
+ this.registrar = components.registrar;
24
+ }
25
+ isStarted() {
26
+ return this.started;
27
+ }
28
+ async start() {
29
+ // register a topology listener for when new peers are encountered
30
+ // that support the hop protocol
31
+ this.topologyId = await this.registrar.register(RELAY_V2_HOP_CODEC, {
32
+ notifyOnTransient: true,
33
+ onConnect: (peerId) => {
34
+ this.safeDispatchEvent('relay:discover', { detail: peerId });
35
+ }
36
+ });
37
+ void this.discover()
38
+ .catch(err => {
39
+ this.log.error('error listening on relays', err);
40
+ });
41
+ this.started = true;
42
+ }
43
+ stop() {
44
+ if (this.topologyId != null) {
45
+ this.registrar.unregister(this.topologyId);
46
+ }
47
+ this.started = false;
48
+ }
49
+ /**
50
+ * Try to listen on available hop relay connections.
51
+ * The following order will happen while we do not have enough relays:
52
+ *
53
+ * 1. Check the metadata store for known relays, try to listen on the ones we are already connected
54
+ * 2. Dial and try to listen on the peers we know that support hop but are not connected
55
+ * 3. Search the network
56
+ */
57
+ async discover() {
58
+ this.log('searching peer store for relays');
59
+ const peers = (await this.peerStore.all({
60
+ filters: [
61
+ // filter by a list of peers supporting RELAY_V2_HOP and ones we are not listening on
62
+ (peer) => {
63
+ return peer.protocols.includes(RELAY_V2_HOP_CODEC);
64
+ }
65
+ ],
66
+ orders: [
67
+ () => Math.random() < 0.5 ? 1 : -1
68
+ ]
69
+ }));
70
+ for (const peer of peers) {
71
+ this.log('found relay peer %p in content peer store', peer.id);
72
+ this.safeDispatchEvent('relay:discover', { detail: peer.id });
73
+ }
74
+ this.log('found %d relay peers in peer store', peers.length);
75
+ try {
76
+ this.log('searching content routing for relays');
77
+ const cid = await namespaceToCid(RELAY_RENDEZVOUS_NS);
78
+ let found = 0;
79
+ for await (const provider of this.contentRouting.findProviders(cid)) {
80
+ if (provider.multiaddrs.length > 0 && !provider.id.equals(this.peerId)) {
81
+ const peerId = provider.id;
82
+ found++;
83
+ await this.peerStore.merge(peerId, {
84
+ multiaddrs: provider.multiaddrs
85
+ });
86
+ this.log('found relay peer %p in content routing', peerId);
87
+ this.safeDispatchEvent('relay:discover', { detail: peerId });
88
+ }
89
+ }
90
+ this.log('found %d relay peers in content routing', found);
91
+ }
92
+ catch (err) {
93
+ this.log.error('failed when finding relays on the network', err);
94
+ }
95
+ }
96
+ }
97
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/transport/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAwB5C;;;GAGG;AACH,MAAM,OAAO,cAAe,SAAQ,iBAAuC;IACxD,MAAM,CAAQ;IACd,SAAS,CAAW;IACpB,cAAc,CAAgB;IAC9B,SAAS,CAAW;IAC7B,OAAO,CAAS;IAChB,UAAU,CAAS;IACV,GAAG,CAAQ;IAE5B,YAAa,UAAoC;QAC/C,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,sCAAsC,CAAC,CAAA;QACjF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAA;QAC/B,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAA;QACrC,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,cAAc,CAAA;QAC/C,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,SAAS,CAAA;IACvC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,kEAAkE;QAClE,gCAAgC;QAChC,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE;YAClE,iBAAiB,EAAE,IAAI;YACvB,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;gBACpB,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;YAC9D,CAAC;SACF,CAAC,CAAA;QAEF,KAAK,IAAI,CAAC,QAAQ,EAAE;aACjB,KAAK,CAAC,GAAG,CAAC,EAAE;YACX,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QAEJ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;IACrB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;SAC3C;QAED,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;QAC3C,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YACtC,OAAO,EAAE;gBACP,qFAAqF;gBACrF,CAAC,IAAI,EAAE,EAAE;oBACP,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAA;gBACpD,CAAC;aACF;YACD,MAAM,EAAE;gBACN,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACnC;SACF,CAAC,CAAC,CAAA;QAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,IAAI,CAAC,GAAG,CAAC,2CAA2C,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;YAC9D,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;SAC9D;QAED,IAAI,CAAC,GAAG,CAAC,oCAAoC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;QAE5D,IAAI;YACF,IAAI,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;YAChD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAA;YAErD,IAAI,KAAK,GAAG,CAAC,CAAA;YAEb,IAAI,KAAK,EAAE,MAAM,QAAQ,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE;gBACnE,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;oBACtE,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,CAAA;oBAE1B,KAAK,EAAE,CAAA;oBACP,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE;wBACjC,UAAU,EAAE,QAAQ,CAAC,UAAU;qBAChC,CAAC,CAAA;oBAEF,IAAI,CAAC,GAAG,CAAC,wCAAwC,EAAE,MAAM,CAAC,CAAA;oBAC1D,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;iBAC7D;aACF;YAED,IAAI,CAAC,GAAG,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;SAC3D;QAAC,OAAO,GAAQ,EAAE;YACjB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAA;SACjE;IACH,CAAC;CACF"}
@@ -0,0 +1,58 @@
1
+ import { type Transport, type Upgrader } from '@libp2p/interface/transport';
2
+ import { type RelayDiscoveryComponents } from './discovery.js';
3
+ import { type RelayStoreInit } from './reservation-store.js';
4
+ import type { Libp2pEvents, ComponentLogger } from '@libp2p/interface';
5
+ import type { ConnectionGater } from '@libp2p/interface/connection-gater';
6
+ import type { ContentRouting } from '@libp2p/interface/content-routing';
7
+ import type { TypedEventTarget } from '@libp2p/interface/events';
8
+ import type { PeerId } from '@libp2p/interface/peer-id';
9
+ import type { PeerStore } from '@libp2p/interface/peer-store';
10
+ import type { AddressManager } from '@libp2p/interface-internal/address-manager';
11
+ import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager';
12
+ import type { Registrar } from '@libp2p/interface-internal/registrar';
13
+ export interface CircuitRelayTransportComponents extends RelayDiscoveryComponents {
14
+ peerId: PeerId;
15
+ peerStore: PeerStore;
16
+ registrar: Registrar;
17
+ connectionManager: ConnectionManager;
18
+ upgrader: Upgrader;
19
+ addressManager: AddressManager;
20
+ contentRouting: ContentRouting;
21
+ connectionGater: ConnectionGater;
22
+ events: TypedEventTarget<Libp2pEvents>;
23
+ logger: ComponentLogger;
24
+ }
25
+ /**
26
+ * RelayConfig configures the circuit v2 relay transport.
27
+ */
28
+ export interface CircuitRelayTransportInit extends RelayStoreInit {
29
+ /**
30
+ * The number of peers running diable relays to search for and
31
+ * connect to. (default: 0)
32
+ */
33
+ discoverRelays?: number;
34
+ /**
35
+ * The maximum number of simultaneous STOP inbound streams that can be open at
36
+ * once - each inbound relayed connection uses a STOP stream (default: 300)
37
+ */
38
+ maxInboundStopStreams?: number;
39
+ /**
40
+ * The maximum number of simultaneous STOP outbound streams that can be open at
41
+ * once. If this transport is used along with the relay server these settings
42
+ * should be set to the same value (default: 300)
43
+ */
44
+ maxOutboundStopStreams?: number;
45
+ /**
46
+ * Incoming STOP requests (e.g. when a remote peer wants to dial us via a relay)
47
+ * must finish the initial protocol negotiation within this timeout in ms
48
+ * (default: 30000)
49
+ */
50
+ stopTimeout?: number;
51
+ /**
52
+ * When creating a reservation it must complete within this number of ms
53
+ * (default: 10000)
54
+ */
55
+ reservationCompletionTimeout?: number;
56
+ }
57
+ export declare function circuitRelayTransport(init?: CircuitRelayTransportInit): (components: CircuitRelayTransportComponents) => Transport;
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,KAAK,SAAS,EAA6C,KAAK,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAQ9H,OAAO,EAAkB,KAAK,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAE9E,OAAO,EAAE,KAAK,cAAc,EAAoB,MAAM,wBAAwB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAgB,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAE5F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAA;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AACtF,OAAO,KAAK,EAAsB,SAAS,EAAE,MAAM,sCAAsC,CAAA;AAiBzF,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,SAAS,CAAA;IACpB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,QAAQ,EAAE,QAAQ,CAAA;IAClB,cAAc,EAAE,cAAc,CAAA;IAC9B,cAAc,EAAE,cAAc,CAAA;IAC9B,eAAe,EAAE,eAAe,CAAA;IAChC,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACtC,MAAM,EAAE,eAAe,CAAA;CACxB;AAYD;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC/D;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAE9B;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAE/B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;OAGG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;CACtC;AA0SD,wBAAgB,qBAAqB,CAAE,IAAI,GAAE,yBAA8B,GAAG,CAAC,UAAU,EAAE,+BAA+B,KAAK,SAAS,CAIvI"}
@@ -0,0 +1,279 @@
1
+ import { CodeError } from '@libp2p/interface/errors';
2
+ import { symbol } from '@libp2p/interface/transport';
3
+ import { peerIdFromBytes, peerIdFromString } from '@libp2p/peer-id';
4
+ import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn';
5
+ import * as mafmt from '@multiformats/mafmt';
6
+ import { multiaddr } from '@multiformats/multiaddr';
7
+ import { pbStream } from 'it-protobuf-stream';
8
+ import { CIRCUIT_PROTO_CODE, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js';
9
+ import { StopMessage, HopMessage, Status } from '../pb/index.js';
10
+ import { RelayDiscovery } from './discovery.js';
11
+ import { createListener } from './listener.js';
12
+ import { ReservationStore } from './reservation-store.js';
13
+ const isValidStop = (request) => {
14
+ if (request.peer == null) {
15
+ return false;
16
+ }
17
+ try {
18
+ request.peer.addrs.forEach(multiaddr);
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ return true;
24
+ };
25
+ const defaults = {
26
+ maxInboundStopStreams: MAX_CONNECTIONS,
27
+ maxOutboundStopStreams: MAX_CONNECTIONS,
28
+ stopTimeout: 30000
29
+ };
30
+ class CircuitRelayTransport {
31
+ discovery;
32
+ registrar;
33
+ peerStore;
34
+ connectionManager;
35
+ peerId;
36
+ upgrader;
37
+ addressManager;
38
+ connectionGater;
39
+ reservationStore;
40
+ logger;
41
+ maxInboundStopStreams;
42
+ maxOutboundStopStreams;
43
+ stopTimeout;
44
+ started;
45
+ log;
46
+ constructor(components, init) {
47
+ this.log = components.logger.forComponent('libp2p:circuit-relay:transport');
48
+ this.registrar = components.registrar;
49
+ this.peerStore = components.peerStore;
50
+ this.connectionManager = components.connectionManager;
51
+ this.logger = components.logger;
52
+ this.peerId = components.peerId;
53
+ this.upgrader = components.upgrader;
54
+ this.addressManager = components.addressManager;
55
+ this.connectionGater = components.connectionGater;
56
+ this.maxInboundStopStreams = init.maxInboundStopStreams ?? defaults.maxInboundStopStreams;
57
+ this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams;
58
+ this.stopTimeout = init.stopTimeout ?? defaults.stopTimeout;
59
+ if (init.discoverRelays != null && init.discoverRelays > 0) {
60
+ this.discovery = new RelayDiscovery(components);
61
+ this.discovery.addEventListener('relay:discover', (evt) => {
62
+ this.reservationStore.addRelay(evt.detail, 'discovered')
63
+ .catch(err => {
64
+ this.log.error('could not add discovered relay %p', evt.detail, err);
65
+ });
66
+ });
67
+ }
68
+ this.reservationStore = new ReservationStore(components, init);
69
+ this.reservationStore.addEventListener('relay:not-enough-relays', () => {
70
+ this.discovery?.discover()
71
+ .catch(err => {
72
+ this.log.error('could not discover relays', err);
73
+ });
74
+ });
75
+ this.started = false;
76
+ }
77
+ isStarted() {
78
+ return this.started;
79
+ }
80
+ async start() {
81
+ await this.reservationStore.start();
82
+ await this.discovery?.start();
83
+ await this.registrar.handle(RELAY_V2_STOP_CODEC, (data) => {
84
+ void this.onStop(data).catch(err => {
85
+ this.log.error('error while handling STOP protocol', err);
86
+ data.stream.abort(err);
87
+ });
88
+ }, {
89
+ maxInboundStreams: this.maxInboundStopStreams,
90
+ maxOutboundStreams: this.maxOutboundStopStreams,
91
+ runOnTransientConnection: true
92
+ });
93
+ this.started = true;
94
+ }
95
+ async stop() {
96
+ this.discovery?.stop();
97
+ await this.reservationStore.stop();
98
+ await this.registrar.unhandle(RELAY_V2_STOP_CODEC);
99
+ this.started = false;
100
+ }
101
+ [symbol] = true;
102
+ [Symbol.toStringTag] = 'libp2p/circuit-relay-v2';
103
+ /**
104
+ * Dial a peer over a relay
105
+ */
106
+ async dial(ma, options = {}) {
107
+ if (ma.protoCodes().filter(code => code === CIRCUIT_PROTO_CODE).length !== 1) {
108
+ const errMsg = 'Invalid circuit relay address';
109
+ this.log.error(errMsg, ma);
110
+ throw new CodeError(errMsg, ERR_RELAYED_DIAL);
111
+ }
112
+ // Check the multiaddr to see if it contains a relay and a destination peer
113
+ const addrs = ma.toString().split('/p2p-circuit');
114
+ const relayAddr = multiaddr(addrs[0]);
115
+ const destinationAddr = multiaddr(addrs[addrs.length - 1]);
116
+ const relayId = relayAddr.getPeerId();
117
+ const destinationId = destinationAddr.getPeerId();
118
+ if (relayId == null || destinationId == null) {
119
+ const errMsg = `Circuit relay dial to ${ma.toString()} failed as address did not have peer ids`;
120
+ this.log.error(errMsg);
121
+ throw new CodeError(errMsg, ERR_RELAYED_DIAL);
122
+ }
123
+ const relayPeer = peerIdFromString(relayId);
124
+ const destinationPeer = peerIdFromString(destinationId);
125
+ let disconnectOnFailure = false;
126
+ const relayConnections = this.connectionManager.getConnections(relayPeer);
127
+ let relayConnection = relayConnections[0];
128
+ if (relayConnection == null) {
129
+ await this.peerStore.merge(relayPeer, {
130
+ multiaddrs: [relayAddr]
131
+ });
132
+ relayConnection = await this.connectionManager.openConnection(relayPeer, options);
133
+ disconnectOnFailure = true;
134
+ }
135
+ let stream;
136
+ try {
137
+ stream = await relayConnection.newStream([RELAY_V2_HOP_CODEC]);
138
+ return await this.connectV2({
139
+ stream,
140
+ connection: relayConnection,
141
+ destinationPeer,
142
+ destinationAddr,
143
+ relayAddr,
144
+ ma,
145
+ disconnectOnFailure
146
+ });
147
+ }
148
+ catch (err) {
149
+ this.log.error('circuit relay dial to destination %p via relay %p failed', destinationPeer, relayPeer, err);
150
+ if (stream != null) {
151
+ stream.abort(err);
152
+ }
153
+ disconnectOnFailure && await relayConnection.close();
154
+ throw err;
155
+ }
156
+ }
157
+ async connectV2({ stream, connection, destinationPeer, destinationAddr, relayAddr, ma, disconnectOnFailure }) {
158
+ try {
159
+ const pbstr = pbStream(stream);
160
+ const hopstr = pbstr.pb(HopMessage);
161
+ await hopstr.write({
162
+ type: HopMessage.Type.CONNECT,
163
+ peer: {
164
+ id: destinationPeer.toBytes(),
165
+ addrs: [multiaddr(destinationAddr).bytes]
166
+ }
167
+ });
168
+ const status = await hopstr.read();
169
+ if (status.status !== Status.OK) {
170
+ throw new CodeError(`failed to connect via relay with status ${status?.status?.toString() ?? 'undefined'}`, ERR_HOP_REQUEST_FAILED);
171
+ }
172
+ const maConn = streamToMaConnection({
173
+ stream: pbstr.unwrap(),
174
+ remoteAddr: ma,
175
+ localAddr: relayAddr.encapsulate(`/p2p-circuit/p2p/${this.peerId.toString()}`),
176
+ logger: this.logger
177
+ });
178
+ this.log('new outbound transient connection %a', maConn.remoteAddr);
179
+ return await this.upgrader.upgradeOutbound(maConn, {
180
+ transient: true
181
+ });
182
+ }
183
+ catch (err) {
184
+ this.log.error(`Circuit relay dial to destination ${destinationPeer.toString()} via relay ${connection.remotePeer.toString()} failed`, err);
185
+ disconnectOnFailure && await connection.close();
186
+ throw err;
187
+ }
188
+ }
189
+ /**
190
+ * Create a listener
191
+ */
192
+ createListener(options) {
193
+ return createListener({
194
+ connectionManager: this.connectionManager,
195
+ relayStore: this.reservationStore,
196
+ logger: this.logger
197
+ });
198
+ }
199
+ /**
200
+ * Filter check for all Multiaddrs that this transport can dial on
201
+ *
202
+ * @param {Multiaddr[]} multiaddrs
203
+ * @returns {Multiaddr[]}
204
+ */
205
+ filter(multiaddrs) {
206
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs];
207
+ return multiaddrs.filter((ma) => {
208
+ return mafmt.Circuit.matches(ma);
209
+ });
210
+ }
211
+ /**
212
+ * An incoming STOP request means a remote peer wants to dial us via a relay
213
+ */
214
+ async onStop({ connection, stream }) {
215
+ const signal = AbortSignal.timeout(this.stopTimeout);
216
+ const pbstr = pbStream(stream).pb(StopMessage);
217
+ const request = await pbstr.read({
218
+ signal
219
+ });
220
+ this.log('new circuit relay v2 stop stream from %p with type %s', connection.remotePeer, request.type);
221
+ if (request?.type === undefined) {
222
+ this.log.error('type was missing from circuit v2 stop protocol request from %s', connection.remotePeer);
223
+ await pbstr.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE }, {
224
+ signal
225
+ });
226
+ await stream.close();
227
+ return;
228
+ }
229
+ // Validate the STOP request has the required input
230
+ if (request.type !== StopMessage.Type.CONNECT) {
231
+ this.log.error('invalid stop connect request via peer %p', connection.remotePeer);
232
+ await pbstr.write({ type: StopMessage.Type.STATUS, status: Status.UNEXPECTED_MESSAGE }, {
233
+ signal
234
+ });
235
+ await stream.close();
236
+ return;
237
+ }
238
+ if (!isValidStop(request)) {
239
+ this.log.error('invalid stop connect request via peer %p', connection.remotePeer);
240
+ await pbstr.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE }, {
241
+ signal
242
+ });
243
+ await stream.close();
244
+ return;
245
+ }
246
+ const remotePeerId = peerIdFromBytes(request.peer.id);
247
+ if ((await this.connectionGater.denyInboundRelayedConnection?.(connection.remotePeer, remotePeerId)) === true) {
248
+ this.log.error('connection gater denied inbound relayed connection from %p', connection.remotePeer);
249
+ await pbstr.write({ type: StopMessage.Type.STATUS, status: Status.PERMISSION_DENIED }, {
250
+ signal
251
+ });
252
+ await stream.close();
253
+ return;
254
+ }
255
+ this.log.trace('sending success response to %p', connection.remotePeer);
256
+ await pbstr.write({ type: StopMessage.Type.STATUS, status: Status.OK }, {
257
+ signal
258
+ });
259
+ const remoteAddr = connection.remoteAddr.encapsulate(`/p2p-circuit/p2p/${remotePeerId.toString()}`);
260
+ const localAddr = this.addressManager.getAddresses()[0];
261
+ const maConn = streamToMaConnection({
262
+ stream: pbstr.unwrap().unwrap(),
263
+ remoteAddr,
264
+ localAddr,
265
+ logger: this.logger
266
+ });
267
+ this.log('new inbound transient connection %a', maConn.remoteAddr);
268
+ await this.upgrader.upgradeInbound(maConn, {
269
+ transient: true
270
+ });
271
+ this.log('%s connection %a upgraded', 'inbound', maConn.remoteAddr);
272
+ }
273
+ }
274
+ export function circuitRelayTransport(init = {}) {
275
+ return (components) => {
276
+ return new CircuitRelayTransport(components, init);
277
+ };
278
+ }
279
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ReservationStore } from './reservation-store.js';
2
+ import type { ComponentLogger } from '@libp2p/interface';
3
+ import type { Listener } from '@libp2p/interface/transport';
4
+ import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager';
5
+ export interface CircuitRelayTransportListenerComponents {
6
+ connectionManager: ConnectionManager;
7
+ relayStore: ReservationStore;
8
+ logger: ComponentLogger;
9
+ }
10
+ export declare function createListener(options: CircuitRelayTransportListenerComponents): Listener;
11
+ //# sourceMappingURL=listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../../src/transport/listener.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAEhE,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,6BAA6B,CAAA;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AAGtF,MAAM,WAAW,uCAAuC;IACtD,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,MAAM,EAAE,eAAe,CAAA;CACxB;AAgFD,wBAAgB,cAAc,CAAE,OAAO,EAAE,uCAAuC,GAAG,QAAQ,CAE1F"}
@@ -0,0 +1,66 @@
1
+ import { CodeError } from '@libp2p/interface/errors';
2
+ import { TypedEventEmitter } from '@libp2p/interface/events';
3
+ import { PeerMap } from '@libp2p/peer-collections';
4
+ import { multiaddr } from '@multiformats/multiaddr';
5
+ class CircuitRelayTransportListener extends TypedEventEmitter {
6
+ connectionManager;
7
+ relayStore;
8
+ listeningAddrs;
9
+ log;
10
+ constructor(components) {
11
+ super();
12
+ this.log = components.logger.forComponent('libp2p:circuit-relay:transport:listener');
13
+ this.connectionManager = components.connectionManager;
14
+ this.relayStore = components.relayStore;
15
+ this.listeningAddrs = new PeerMap();
16
+ // remove listening addrs when a relay is removed
17
+ this.relayStore.addEventListener('relay:removed', this._onRemoveRelayPeer);
18
+ }
19
+ _onRemoveRelayPeer = (evt) => {
20
+ this.#removeRelayPeer(evt.detail);
21
+ };
22
+ async listen(addr) {
23
+ this.log('listen on %a', addr);
24
+ // remove the circuit part to get the peer id of the relay
25
+ const relayAddr = addr.decapsulate('/p2p-circuit');
26
+ const relayConn = await this.connectionManager.openConnection(relayAddr);
27
+ if (!this.relayStore.hasReservation(relayConn.remotePeer)) {
28
+ // addRelay calls transportManager.listen which calls this listen method
29
+ await this.relayStore.addRelay(relayConn.remotePeer, 'configured');
30
+ return;
31
+ }
32
+ const reservation = this.relayStore.getReservation(relayConn.remotePeer);
33
+ if (reservation == null) {
34
+ throw new CodeError('Did not have reservation after making reservation', 'ERR_NO_RESERVATION');
35
+ }
36
+ if (this.listeningAddrs.has(relayConn.remotePeer)) {
37
+ this.log('already listening on relay %p', relayConn.remotePeer);
38
+ return;
39
+ }
40
+ // add all addresses from the relay reservation
41
+ this.listeningAddrs.set(relayConn.remotePeer, reservation.addrs.map(buf => {
42
+ return multiaddr(buf).encapsulate('/p2p-circuit');
43
+ }));
44
+ this.safeDispatchEvent('listening', {});
45
+ }
46
+ getAddrs() {
47
+ return [...this.listeningAddrs.values()].flat();
48
+ }
49
+ async close() {
50
+ }
51
+ #removeRelayPeer(peerId) {
52
+ const had = this.listeningAddrs.has(peerId);
53
+ this.log('relay peer removed %p - had reservation', peerId, had);
54
+ this.listeningAddrs.delete(peerId);
55
+ if (had) {
56
+ this.log.trace('removing relay event listener for peer %p', peerId);
57
+ this.relayStore.removeEventListener('relay:removed', this._onRemoveRelayPeer);
58
+ // Announce listen addresses change
59
+ this.safeDispatchEvent('close', {});
60
+ }
61
+ }
62
+ }
63
+ export function createListener(options) {
64
+ return new CircuitRelayTransportListener(options);
65
+ }
66
+ //# sourceMappingURL=listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.js","sourceRoot":"","sources":["../../../src/transport/listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAcnD,MAAM,6BAA8B,SAAQ,iBAAiC;IAC1D,iBAAiB,CAAmB;IACpC,UAAU,CAAkB;IAC5B,cAAc,CAAsB;IACpC,GAAG,CAAQ;IAE5B,YAAa,UAAmD;QAC9D,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,yCAAyC,CAAC,CAAA;QACpF,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,iBAAiB,CAAA;QACrD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAA;QACvC,IAAI,CAAC,cAAc,GAAG,IAAI,OAAO,EAAE,CAAA;QAEnC,iDAAiD;QACjD,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,eAAe,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAA;IAC5E,CAAC;IAED,kBAAkB,GAAG,CAAC,GAAwB,EAAQ,EAAE;QACtD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACnC,CAAC,CAAA;IAED,KAAK,CAAC,MAAM,CAAE,IAAe;QAC3B,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;QAE9B,0DAA0D;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAA;QAClD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;QAExE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;YACzD,wEAAwE;YACxE,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;YAClE,OAAM;SACP;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QAExE,IAAI,WAAW,IAAI,IAAI,EAAE;YACvB,MAAM,IAAI,SAAS,CAAC,mDAAmD,EAAE,oBAAoB,CAAC,CAAA;SAC/F;QAED,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;YACjD,IAAI,CAAC,GAAG,CAAC,+BAA+B,EAAE,SAAS,CAAC,UAAU,CAAC,CAAA;YAC/D,OAAM;SACP;QAED,+CAA+C;QAC/C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACxE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAA;QACnD,CAAC,CAAC,CAAC,CAAA;QAEH,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,QAAQ;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACjD,CAAC;IAED,KAAK,CAAC,KAAK;IAEX,CAAC;IAED,gBAAgB,CAAE,MAAc;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAE3C,IAAI,CAAC,GAAG,CAAC,yCAAyC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;QAEhE,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAElC,IAAI,GAAG,EAAE;YACP,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2CAA2C,EAAE,MAAM,CAAC,CAAA;YACnE,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,eAAe,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAA;YAC7E,mCAAmC;YACnC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;SACpC;IACH,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAE,OAAgD;IAC9E,OAAO,IAAI,6BAA6B,CAAC,OAAO,CAAC,CAAA;AACnD,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { TypedEventEmitter, type TypedEventTarget } from '@libp2p/interface/events';
2
+ import type { Reservation } from '../pb/index.js';
3
+ import type { Libp2pEvents, ComponentLogger } from '@libp2p/interface';
4
+ import type { PeerId } from '@libp2p/interface/peer-id';
5
+ import type { PeerStore } from '@libp2p/interface/peer-store';
6
+ import type { Startable } from '@libp2p/interface/startable';
7
+ import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager';
8
+ import type { TransportManager } from '@libp2p/interface-internal/transport-manager';
9
+ export interface RelayStoreComponents {
10
+ peerId: PeerId;
11
+ connectionManager: ConnectionManager;
12
+ transportManager: TransportManager;
13
+ peerStore: PeerStore;
14
+ events: TypedEventTarget<Libp2pEvents>;
15
+ logger: ComponentLogger;
16
+ }
17
+ export interface RelayStoreInit {
18
+ /**
19
+ * Multiple relays may be discovered simultaneously - to prevent listening
20
+ * on too many relays, this value controls how many to attempt to reserve a
21
+ * slot on at once. If set to more than one, we may end up listening on
22
+ * more relays than the `maxReservations` value, but on networks with poor
23
+ * connectivity the user may wish to attempt to reserve on multiple relays
24
+ * simultaneously. (default: 1)
25
+ */
26
+ reservationConcurrency?: number;
27
+ /**
28
+ * How many discovered relays to allow in the reservation store
29
+ */
30
+ discoverRelays?: number;
31
+ /**
32
+ * Limit the number of potential relays we will dial (default: 100)
33
+ */
34
+ maxReservationQueueLength?: number;
35
+ /**
36
+ * When creating a reservation it must complete within this number of ms
37
+ * (default: 5000)
38
+ */
39
+ reservationCompletionTimeout?: number;
40
+ }
41
+ export type RelayType = 'discovered' | 'configured';
42
+ export interface ReservationStoreEvents {
43
+ 'relay:not-enough-relays': CustomEvent;
44
+ 'relay:removed': CustomEvent<PeerId>;
45
+ }
46
+ export declare class ReservationStore extends TypedEventEmitter<ReservationStoreEvents> implements Startable {
47
+ #private;
48
+ private readonly peerId;
49
+ private readonly connectionManager;
50
+ private readonly transportManager;
51
+ private readonly peerStore;
52
+ private readonly events;
53
+ private readonly reserveQueue;
54
+ private readonly reservations;
55
+ private readonly maxDiscoveredRelays;
56
+ private readonly maxReservationQueueLength;
57
+ private readonly reservationCompletionTimeout;
58
+ private started;
59
+ private readonly log;
60
+ constructor(components: RelayStoreComponents, init?: RelayStoreInit);
61
+ isStarted(): boolean;
62
+ start(): Promise<void>;
63
+ stop(): Promise<void>;
64
+ /**
65
+ * If the number of current relays is beneath the configured `maxReservations`
66
+ * value, and the passed peer id is not our own, and we have a non-relayed connection
67
+ * to the remote, and the remote peer speaks the hop protocol, try to reserve a slot
68
+ * on the remote peer
69
+ */
70
+ addRelay(peerId: PeerId, type: RelayType): Promise<void>;
71
+ hasReservation(peerId: PeerId): boolean;
72
+ getReservation(peerId: PeerId): Reservation | undefined;
73
+ }
74
+ //# sourceMappingURL=reservation-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reservation-store.d.ts","sourceRoot":"","sources":["../../../src/transport/reservation-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAQnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAgB,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAE5F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAWpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;IACtC,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAE/B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;OAEG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAElC;;;OAGG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;CACtC;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,YAAY,CAAA;AAQnD,MAAM,WAAW,sBAAsB;IACrC,yBAAyB,EAAE,WAAW,CAAA;IACtC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CACrC;AAED,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,sBAAsB,CAAE,YAAW,SAAS;;IAClG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmB;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IAC5C,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAQ;IAClD,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAQ;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;gBAEf,UAAU,EAAE,oBAAoB,EAAE,IAAI,CAAC,EAAE,cAAc;IA4BpE,SAAS,IAAK,OAAO;IAIf,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAIvB,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAS5B;;;;;OAKG;IACG,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA8G/D,cAAc,CAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAIxC,cAAc,CAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;CAwDzD"}