@did-btcr2/method 0.29.0 → 0.32.0
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 +13 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser.js +8174 -7157
- package/dist/browser.mjs +8174 -7157
- package/dist/cjs/index.js +1845 -455
- package/dist/esm/core/aggregation/transport/factory.js +15 -6
- package/dist/esm/core/aggregation/transport/factory.js.map +1 -1
- package/dist/esm/core/aggregation/transport/http/client.js +350 -0
- package/dist/esm/core/aggregation/transport/http/client.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/envelope.js +126 -0
- package/dist/esm/core/aggregation/transport/http/envelope.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/errors.js +11 -0
- package/dist/esm/core/aggregation/transport/http/errors.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/inbox-buffer.js +45 -0
- package/dist/esm/core/aggregation/transport/http/inbox-buffer.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/index.js +12 -0
- package/dist/esm/core/aggregation/transport/http/index.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/nonce-cache.js +38 -0
- package/dist/esm/core/aggregation/transport/http/nonce-cache.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/protocol.js +28 -0
- package/dist/esm/core/aggregation/transport/http/protocol.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/rate-limiter.js +45 -0
- package/dist/esm/core/aggregation/transport/http/rate-limiter.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/request-auth.js +100 -0
- package/dist/esm/core/aggregation/transport/http/request-auth.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/server.js +481 -0
- package/dist/esm/core/aggregation/transport/http/server.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/sse-stream.js +110 -0
- package/dist/esm/core/aggregation/transport/http/sse-stream.js.map +1 -0
- package/dist/esm/core/aggregation/transport/http/sse-writer.js +25 -0
- package/dist/esm/core/aggregation/transport/http/sse-writer.js.map +1 -0
- package/dist/esm/core/aggregation/transport/index.js +1 -0
- package/dist/esm/core/aggregation/transport/index.js.map +1 -1
- package/dist/esm/core/beacon/beacon.js +197 -51
- package/dist/esm/core/beacon/beacon.js.map +1 -1
- package/dist/esm/core/beacon/cas-beacon.js +3 -3
- package/dist/esm/core/beacon/cas-beacon.js.map +1 -1
- package/dist/esm/core/beacon/singleton-beacon.js +3 -3
- package/dist/esm/core/beacon/singleton-beacon.js.map +1 -1
- package/dist/esm/core/beacon/smt-beacon.js +3 -3
- package/dist/esm/core/beacon/smt-beacon.js.map +1 -1
- package/dist/esm/core/updater.js +63 -55
- package/dist/esm/core/updater.js.map +1 -1
- package/dist/types/core/aggregation/transport/factory.d.ts +22 -7
- package/dist/types/core/aggregation/transport/factory.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/http/client.d.ts +48 -0
- package/dist/types/core/aggregation/transport/http/client.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/envelope.d.ts +64 -0
- package/dist/types/core/aggregation/transport/http/envelope.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/errors.d.ts +9 -0
- package/dist/types/core/aggregation/transport/http/errors.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/inbox-buffer.d.ts +32 -0
- package/dist/types/core/aggregation/transport/http/inbox-buffer.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/index.d.ts +12 -0
- package/dist/types/core/aggregation/transport/http/index.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/nonce-cache.d.ts +26 -0
- package/dist/types/core/aggregation/transport/http/nonce-cache.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/protocol.d.ts +53 -0
- package/dist/types/core/aggregation/transport/http/protocol.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/rate-limiter.d.ts +41 -0
- package/dist/types/core/aggregation/transport/http/rate-limiter.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/request-auth.d.ts +50 -0
- package/dist/types/core/aggregation/transport/http/request-auth.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/server.d.ts +110 -0
- package/dist/types/core/aggregation/transport/http/server.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/sse-stream.d.ts +34 -0
- package/dist/types/core/aggregation/transport/http/sse-stream.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/http/sse-writer.d.ts +12 -0
- package/dist/types/core/aggregation/transport/http/sse-writer.d.ts.map +1 -0
- package/dist/types/core/aggregation/transport/index.d.ts +1 -0
- package/dist/types/core/aggregation/transport/index.d.ts.map +1 -1
- package/dist/types/core/aggregation/transport/transport.d.ts +1 -1
- package/dist/types/core/aggregation/transport/transport.d.ts.map +1 -1
- package/dist/types/core/beacon/beacon.d.ts +72 -12
- package/dist/types/core/beacon/beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/cas-beacon.d.ts +3 -3
- package/dist/types/core/beacon/cas-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/singleton-beacon.d.ts +3 -3
- package/dist/types/core/beacon/singleton-beacon.d.ts.map +1 -1
- package/dist/types/core/beacon/smt-beacon.d.ts +3 -3
- package/dist/types/core/beacon/smt-beacon.d.ts.map +1 -1
- package/dist/types/core/updater.d.ts +27 -12
- package/dist/types/core/updater.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/core/aggregation/transport/factory.ts +48 -12
- package/src/core/aggregation/transport/http/client.ts +409 -0
- package/src/core/aggregation/transport/http/envelope.ts +204 -0
- package/src/core/aggregation/transport/http/errors.ts +11 -0
- package/src/core/aggregation/transport/http/inbox-buffer.ts +53 -0
- package/src/core/aggregation/transport/http/index.ts +11 -0
- package/src/core/aggregation/transport/http/nonce-cache.ts +43 -0
- package/src/core/aggregation/transport/http/protocol.ts +57 -0
- package/src/core/aggregation/transport/http/rate-limiter.ts +75 -0
- package/src/core/aggregation/transport/http/request-auth.ts +164 -0
- package/src/core/aggregation/transport/http/server.ts +615 -0
- package/src/core/aggregation/transport/http/sse-stream.ts +121 -0
- package/src/core/aggregation/transport/http/sse-writer.ts +23 -0
- package/src/core/aggregation/transport/index.ts +1 -0
- package/src/core/aggregation/transport/transport.ts +1 -1
- package/src/core/beacon/beacon.ts +255 -64
- package/src/core/beacon/cas-beacon.ts +4 -4
- package/src/core/beacon/singleton-beacon.ts +4 -4
- package/src/core/beacon/smt-beacon.ts +4 -4
- package/src/core/updater.ts +113 -67
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { NotImplementedError } from '@did-btcr2/common';
|
|
2
|
-
import { NostrTransport } from './nostr.js';
|
|
3
2
|
import { TransportError } from './error.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
3
|
+
import { HttpClientTransport } from './http/client.js';
|
|
4
|
+
import { HttpServerTransport } from './http/server.js';
|
|
5
|
+
import { NostrTransport } from './nostr.js';
|
|
6
|
+
/** Factory for creating Transport instances. */
|
|
8
7
|
export class TransportFactory {
|
|
9
8
|
static establish(config) {
|
|
10
9
|
switch (config.type) {
|
|
11
10
|
case 'nostr':
|
|
12
|
-
return new NostrTransport({
|
|
11
|
+
return new NostrTransport({
|
|
12
|
+
relays: config.relays,
|
|
13
|
+
logger: config.logger,
|
|
14
|
+
broadcastLookbackMs: config.broadcastLookbackMs,
|
|
15
|
+
});
|
|
13
16
|
case 'didcomm':
|
|
14
17
|
throw new NotImplementedError('DIDComm transport not implemented yet.');
|
|
18
|
+
case 'http':
|
|
19
|
+
if (config.role === 'client')
|
|
20
|
+
return new HttpClientTransport(config);
|
|
21
|
+
if (config.role === 'server')
|
|
22
|
+
return new HttpServerTransport(config);
|
|
23
|
+
throw new NotImplementedError(`HTTP transport role not implemented: ${config.role}`);
|
|
15
24
|
default:
|
|
16
25
|
throw new TransportError(`Invalid transport type: ${config.type}`, 'INVALID_TRANSPORT_TYPE', { config });
|
|
17
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../../../src/core/aggregation/transport/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA+B5C,gDAAgD;AAChD,MAAM,OAAO,gBAAgB;IAC3B,MAAM,CAAC,SAAS,CAAC,MAAuB;QACtC,QAAO,MAAM,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,OAAO;gBACV,OAAO,IAAI,cAAc,CAAC;oBACxB,MAAM,EAAgB,MAAM,CAAC,MAAM;oBACnC,MAAM,EAAgB,MAAM,CAAC,MAAM;oBACnC,mBAAmB,EAAG,MAAM,CAAC,mBAAmB;iBACjD,CAAC,CAAC;YACL,KAAK,SAAS;gBACZ,MAAM,IAAI,mBAAmB,CAAC,wCAAwC,CAAC,CAAC;YAC1E,KAAK,MAAM;gBACT,IAAG,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;gBACpE,IAAG,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;gBACpE,MAAM,IAAI,mBAAmB,CAC3B,wCAAyC,MAA2B,CAAC,IAAI,EAAE,CAC5E,CAAC;YACJ;gBACE,MAAM,IAAI,cAAc,CACtB,2BAA4B,MAA2B,CAAC,IAAI,EAAE,EAC9D,wBAAwB,EACxB,EAAE,MAAM,EAAE,CACX,CAAC;QACN,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { CompressedSecp256k1PublicKey } from '@did-btcr2/keypair';
|
|
2
|
+
import { Identifier } from '../../../identifier.js';
|
|
3
|
+
import { CONSOLE_LOGGER } from '../../logger.js';
|
|
4
|
+
import { reviveFromWire, signEnvelope, verifyEnvelope } from './envelope.js';
|
|
5
|
+
import { HttpTransportError } from './errors.js';
|
|
6
|
+
import { DEFAULT_CLOCK_SKEW_SEC, HTTP_ROUTE, SSE_EVENT, } from './protocol.js';
|
|
7
|
+
import { buildRequestAuth } from './request-auth.js';
|
|
8
|
+
import { parseSseStream } from './sse-stream.js';
|
|
9
|
+
/** Default exponential backoff: 1s, 2s, 4s, ..., capped at 30s, 20% jitter. */
|
|
10
|
+
export function defaultReconnectBackoff(attempt) {
|
|
11
|
+
const base = Math.min(1000 * 2 ** attempt, 30_000);
|
|
12
|
+
const jitter = base * 0.2 * Math.random();
|
|
13
|
+
return Math.floor(base + jitter);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* HTTP transport client. Implements the transport-agnostic {@link Transport}
|
|
17
|
+
* interface; the wire is fetch-based SSE for incoming events and fetch-based
|
|
18
|
+
* POST for outgoing messages. All runtime I/O goes through `fetchImpl` so
|
|
19
|
+
* tests can substitute a mock without touching the network.
|
|
20
|
+
*/
|
|
21
|
+
export class HttpClientTransport {
|
|
22
|
+
name = 'http';
|
|
23
|
+
#baseUrl;
|
|
24
|
+
#fetch;
|
|
25
|
+
#logger;
|
|
26
|
+
#backoff;
|
|
27
|
+
#clockSkewSec;
|
|
28
|
+
#actors = new Map();
|
|
29
|
+
#peers = new Map();
|
|
30
|
+
#started = false;
|
|
31
|
+
#broadcastAbort;
|
|
32
|
+
constructor(config) {
|
|
33
|
+
const base = typeof config.baseUrl === 'string' ? new URL(config.baseUrl) : new URL(config.baseUrl.href);
|
|
34
|
+
if (!base.pathname.endsWith('/'))
|
|
35
|
+
base.pathname += '/';
|
|
36
|
+
this.#baseUrl = base;
|
|
37
|
+
this.#logger = config.logger ?? CONSOLE_LOGGER;
|
|
38
|
+
this.#backoff = config.reconnectBackoff ?? defaultReconnectBackoff;
|
|
39
|
+
this.#clockSkewSec = config.clockSkewSec ?? DEFAULT_CLOCK_SKEW_SEC;
|
|
40
|
+
const fetchImpl = config.fetchImpl ?? globalThis.fetch;
|
|
41
|
+
if (typeof fetchImpl !== 'function') {
|
|
42
|
+
throw new HttpTransportError('No fetch implementation available. Pass config.fetchImpl explicitly.', 'NO_FETCH_IMPL');
|
|
43
|
+
}
|
|
44
|
+
this.#fetch = fetchImpl;
|
|
45
|
+
}
|
|
46
|
+
start() {
|
|
47
|
+
if (this.#started)
|
|
48
|
+
return;
|
|
49
|
+
this.#started = true;
|
|
50
|
+
this.#broadcastAbort = new AbortController();
|
|
51
|
+
this.#runBroadcastLoop(this.#broadcastAbort.signal);
|
|
52
|
+
for (const [did, entry] of this.#actors) {
|
|
53
|
+
this.#openInbox(did, entry);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Tear down all SSE subscriptions and stop reconnect loops. Not part of the
|
|
58
|
+
* {@link Transport} interface, but needed in tests and whenever a client
|
|
59
|
+
* wants to cleanly disconnect without unregistering every actor.
|
|
60
|
+
*
|
|
61
|
+
* Idempotent. Actors remain registered (re-call {@link start} to resume).
|
|
62
|
+
*/
|
|
63
|
+
stop() {
|
|
64
|
+
this.#broadcastAbort?.abort();
|
|
65
|
+
this.#broadcastAbort = undefined;
|
|
66
|
+
for (const entry of this.#actors.values()) {
|
|
67
|
+
entry.inboxAbort?.abort();
|
|
68
|
+
entry.inboxAbort = undefined;
|
|
69
|
+
}
|
|
70
|
+
this.#started = false;
|
|
71
|
+
}
|
|
72
|
+
registerActor(did, keys) {
|
|
73
|
+
const existing = this.#actors.get(did);
|
|
74
|
+
if (existing?.inboxAbort)
|
|
75
|
+
existing.inboxAbort.abort();
|
|
76
|
+
const entry = { keys, handlers: new Map() };
|
|
77
|
+
this.#actors.set(did, entry);
|
|
78
|
+
if (this.#started)
|
|
79
|
+
this.#openInbox(did, entry);
|
|
80
|
+
}
|
|
81
|
+
unregisterActor(did) {
|
|
82
|
+
const entry = this.#actors.get(did);
|
|
83
|
+
if (!entry)
|
|
84
|
+
return;
|
|
85
|
+
entry.inboxAbort?.abort();
|
|
86
|
+
this.#actors.delete(did);
|
|
87
|
+
this.#peers.delete(did);
|
|
88
|
+
}
|
|
89
|
+
getActorPk(did) {
|
|
90
|
+
return this.#actors.get(did)?.keys.publicKey.compressed;
|
|
91
|
+
}
|
|
92
|
+
registerPeer(did, communicationPk) {
|
|
93
|
+
try {
|
|
94
|
+
new CompressedSecp256k1PublicKey(communicationPk);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
throw new HttpTransportError(`Invalid communication public key for peer ${did}: expected a 33-byte compressed secp256k1 key.`, 'INVALID_PEER_KEY', { did, keyLength: communicationPk.length });
|
|
98
|
+
}
|
|
99
|
+
this.#peers.set(did, communicationPk);
|
|
100
|
+
}
|
|
101
|
+
getPeerPk(did) {
|
|
102
|
+
return this.#peers.get(did);
|
|
103
|
+
}
|
|
104
|
+
registerMessageHandler(actorDid, messageType, handler) {
|
|
105
|
+
const actor = this.#actors.get(actorDid);
|
|
106
|
+
if (!actor) {
|
|
107
|
+
throw new HttpTransportError(`Cannot register handler: actor ${actorDid} not registered. Call registerActor() first.`, 'UNKNOWN_ACTOR', { did: actorDid });
|
|
108
|
+
}
|
|
109
|
+
actor.handlers.set(messageType, handler);
|
|
110
|
+
}
|
|
111
|
+
unregisterMessageHandler(actorDid, messageType) {
|
|
112
|
+
this.#actors.get(actorDid)?.handlers.delete(messageType);
|
|
113
|
+
}
|
|
114
|
+
async sendMessage(message, sender, recipient) {
|
|
115
|
+
const actor = this.#actors.get(sender);
|
|
116
|
+
if (!actor) {
|
|
117
|
+
throw new HttpTransportError(`Unknown sender: ${sender}. Call registerActor() before sending messages.`, 'UNKNOWN_SENDER', { did: sender });
|
|
118
|
+
}
|
|
119
|
+
const envelope = signEnvelope(message, { did: sender, keys: actor.keys }, { to: recipient });
|
|
120
|
+
const url = this.#route(HTTP_ROUTE.MESSAGES);
|
|
121
|
+
const res = await this.#fetch(url, {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'content-type': 'application/json' },
|
|
124
|
+
body: JSON.stringify(envelope),
|
|
125
|
+
});
|
|
126
|
+
if (!res.ok) {
|
|
127
|
+
const body = await safeText(res);
|
|
128
|
+
throw new HttpTransportError(`sendMessage failed: HTTP ${res.status}`, 'SEND_MESSAGE_HTTP', { status: res.status, body: body.slice(0, 256), messageType: message.type });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
publishRepeating(message, sender, intervalMs, recipient) {
|
|
132
|
+
let stopped = false;
|
|
133
|
+
const attempt = () => {
|
|
134
|
+
if (stopped)
|
|
135
|
+
return;
|
|
136
|
+
this.sendMessage(message, sender, recipient).catch((err) => {
|
|
137
|
+
this.#logger.debug('publishRepeating send failed:', err);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
attempt();
|
|
141
|
+
const timer = setInterval(attempt, intervalMs);
|
|
142
|
+
return () => {
|
|
143
|
+
if (stopped)
|
|
144
|
+
return;
|
|
145
|
+
stopped = true;
|
|
146
|
+
clearInterval(timer);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
#route(template) {
|
|
150
|
+
// Strip the leading slash so `new URL(rel, base)` is resolved against the
|
|
151
|
+
// base's pathname instead of replacing it.
|
|
152
|
+
return new URL(template.replace(/^\//, ''), this.#baseUrl);
|
|
153
|
+
}
|
|
154
|
+
#openInbox(did, entry) {
|
|
155
|
+
const abort = new AbortController();
|
|
156
|
+
entry.inboxAbort = abort;
|
|
157
|
+
this.#runInboxLoop(did, entry, abort.signal);
|
|
158
|
+
}
|
|
159
|
+
async #runBroadcastLoop(signal) {
|
|
160
|
+
const url = this.#route(HTTP_ROUTE.ADVERTS);
|
|
161
|
+
let attempt = 0;
|
|
162
|
+
while (!signal.aborted) {
|
|
163
|
+
try {
|
|
164
|
+
const res = await this.#fetch(url, {
|
|
165
|
+
method: 'GET',
|
|
166
|
+
headers: { accept: 'text/event-stream' },
|
|
167
|
+
signal,
|
|
168
|
+
});
|
|
169
|
+
if (!res.ok || !res.body) {
|
|
170
|
+
this.#logger.warn(`Broadcast subscribe failed: HTTP ${res.status}`);
|
|
171
|
+
await sleep(this.#backoff(attempt++), signal);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
attempt = 0;
|
|
175
|
+
for await (const ev of parseSseStream(res.body)) {
|
|
176
|
+
if (signal.aborted)
|
|
177
|
+
return;
|
|
178
|
+
if (ev.event !== SSE_EVENT.ADVERT)
|
|
179
|
+
continue;
|
|
180
|
+
this.#dispatchBroadcast(ev.data);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (signal.aborted)
|
|
185
|
+
return;
|
|
186
|
+
this.#logger.debug('Broadcast loop error:', err);
|
|
187
|
+
try {
|
|
188
|
+
await sleep(this.#backoff(attempt++), signal);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return; // sleep was aborted
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async #runInboxLoop(did, entry, signal) {
|
|
197
|
+
const url = this.#route(HTTP_ROUTE.ACTOR_INBOX.replace('{did}', encodeURIComponent(did)));
|
|
198
|
+
let attempt = 0;
|
|
199
|
+
while (!signal.aborted) {
|
|
200
|
+
try {
|
|
201
|
+
const auth = buildRequestAuth(did, entry.keys, url.pathname);
|
|
202
|
+
const res = await this.#fetch(url, {
|
|
203
|
+
method: 'GET',
|
|
204
|
+
headers: { accept: 'text/event-stream', authorization: auth },
|
|
205
|
+
signal,
|
|
206
|
+
});
|
|
207
|
+
if (!res.ok || !res.body) {
|
|
208
|
+
this.#logger.warn(`Inbox subscribe failed for ${did}: HTTP ${res.status}`);
|
|
209
|
+
await sleep(this.#backoff(attempt++), signal);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
attempt = 0;
|
|
213
|
+
for await (const ev of parseSseStream(res.body)) {
|
|
214
|
+
if (signal.aborted)
|
|
215
|
+
return;
|
|
216
|
+
if (ev.event !== SSE_EVENT.MESSAGE)
|
|
217
|
+
continue;
|
|
218
|
+
await this.#dispatchInbox(ev.data, did, entry);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
if (signal.aborted)
|
|
223
|
+
return;
|
|
224
|
+
this.#logger.debug(`Inbox loop error for ${did}:`, err);
|
|
225
|
+
try {
|
|
226
|
+
await sleep(this.#backoff(attempt++), signal);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
#dispatchBroadcast(dataJson) {
|
|
235
|
+
const envelope = parseEnvelope(dataJson, this.#logger);
|
|
236
|
+
if (!envelope)
|
|
237
|
+
return;
|
|
238
|
+
const senderPk = this.#resolveSenderPk(envelope.from);
|
|
239
|
+
if (!senderPk) {
|
|
240
|
+
this.#logger.debug(`Broadcast from unresolvable DID: ${envelope.from}`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
verifyEnvelope(envelope, senderPk, { clockSkewSec: this.#clockSkewSec });
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
this.#logger.debug('Broadcast envelope verification failed:', err);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const revived = reviveFromWire(envelope.message);
|
|
251
|
+
const flat = flattenMessage(revived);
|
|
252
|
+
const messageType = typeof flat.type === 'string' ? flat.type : undefined;
|
|
253
|
+
if (!messageType)
|
|
254
|
+
return;
|
|
255
|
+
for (const actor of this.#actors.values()) {
|
|
256
|
+
const handler = actor.handlers.get(messageType);
|
|
257
|
+
if (handler)
|
|
258
|
+
void Promise.resolve(handler(flat));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async #dispatchInbox(dataJson, actorDid, entry) {
|
|
262
|
+
const envelope = parseEnvelope(dataJson, this.#logger);
|
|
263
|
+
if (!envelope)
|
|
264
|
+
return;
|
|
265
|
+
const senderPk = this.#resolveSenderPk(envelope.from);
|
|
266
|
+
if (!senderPk) {
|
|
267
|
+
this.#logger.debug(`Inbox message from unresolvable DID: ${envelope.from}`);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
try {
|
|
271
|
+
verifyEnvelope(envelope, senderPk, {
|
|
272
|
+
clockSkewSec: this.#clockSkewSec,
|
|
273
|
+
expectedTo: actorDid,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
this.#logger.debug(`Inbox envelope verification failed for ${actorDid}:`, err);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const revived = reviveFromWire(envelope.message);
|
|
281
|
+
const flat = flattenMessage(revived);
|
|
282
|
+
const messageType = typeof flat.type === 'string' ? flat.type : undefined;
|
|
283
|
+
if (!messageType)
|
|
284
|
+
return;
|
|
285
|
+
const handler = entry.handlers.get(messageType);
|
|
286
|
+
if (handler)
|
|
287
|
+
await handler(flat);
|
|
288
|
+
}
|
|
289
|
+
#resolveSenderPk(did) {
|
|
290
|
+
const peerBytes = this.#peers.get(did);
|
|
291
|
+
if (peerBytes) {
|
|
292
|
+
try {
|
|
293
|
+
return new CompressedSecp256k1PublicKey(peerBytes);
|
|
294
|
+
}
|
|
295
|
+
catch { /* fall through to DID decode */ }
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
const components = Identifier.decode(did);
|
|
299
|
+
if (components.idType === 'KEY') {
|
|
300
|
+
return new CompressedSecp256k1PublicKey(components.genesisBytes);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Not a decodable did:btcr2 KEY identifier.
|
|
305
|
+
}
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function sleep(ms, signal) {
|
|
310
|
+
if (ms <= 0)
|
|
311
|
+
return Promise.resolve();
|
|
312
|
+
return new Promise((resolve, reject) => {
|
|
313
|
+
const onAbort = () => {
|
|
314
|
+
clearTimeout(timer);
|
|
315
|
+
reject(new Error('aborted'));
|
|
316
|
+
};
|
|
317
|
+
const timer = setTimeout(() => {
|
|
318
|
+
signal.removeEventListener('abort', onAbort);
|
|
319
|
+
resolve();
|
|
320
|
+
}, ms);
|
|
321
|
+
if (signal.aborted)
|
|
322
|
+
onAbort();
|
|
323
|
+
else
|
|
324
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async function safeText(res) {
|
|
328
|
+
try {
|
|
329
|
+
return await res.text();
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
return '';
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function parseEnvelope(dataJson, logger) {
|
|
336
|
+
try {
|
|
337
|
+
return JSON.parse(dataJson);
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
logger.debug('SSE event: failed to parse envelope JSON:', err);
|
|
341
|
+
return undefined;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
function flattenMessage(msg) {
|
|
345
|
+
if (msg.body && typeof msg.body === 'object') {
|
|
346
|
+
return { ...msg, ...msg.body };
|
|
347
|
+
}
|
|
348
|
+
return msg;
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../../../src/core/aggregation/transport/http/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { canonicalHashBytes } from '@did-btcr2/common';
|
|
2
|
+
import { bytesToHex, hexToBytes, randomBytes } from '@noble/hashes/utils';
|
|
3
|
+
import { HttpTransportError } from './errors.js';
|
|
4
|
+
import { DEFAULT_CLOCK_SKEW_SEC, DEFAULT_NONCE_LEN_BYTES, HTTP_ENVELOPE_VERSION, } from './protocol.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build a {@link SignedEnvelope} around `message`.
|
|
7
|
+
*
|
|
8
|
+
* Pure function — no I/O beyond `randomBytes` for nonce generation (which
|
|
9
|
+
* uses the platform's cryptographic RNG: `crypto.getRandomValues` in browsers,
|
|
10
|
+
* `node:crypto` in Node). Deterministic when both `nonce` and `timestamp` are
|
|
11
|
+
* supplied via {@link SignEnvelopeOptions}.
|
|
12
|
+
*/
|
|
13
|
+
export function signEnvelope(message, sender, opts = {}) {
|
|
14
|
+
const timestamp = opts.timestamp ?? Math.floor(Date.now() / 1000);
|
|
15
|
+
const nonce = opts.nonce ?? bytesToHex(randomBytes(DEFAULT_NONCE_LEN_BYTES));
|
|
16
|
+
const messageJson = normalizeForWire(normalizeMessage(message));
|
|
17
|
+
const unsigned = {
|
|
18
|
+
v: HTTP_ENVELOPE_VERSION,
|
|
19
|
+
from: sender.did,
|
|
20
|
+
...(opts.to !== undefined ? { to: opts.to } : {}),
|
|
21
|
+
timestamp,
|
|
22
|
+
nonce,
|
|
23
|
+
message: messageJson,
|
|
24
|
+
};
|
|
25
|
+
const digest = canonicalHashBytes(unsigned);
|
|
26
|
+
const sig = sender.keys.secretKey.sign(digest, { scheme: 'schnorr' });
|
|
27
|
+
return { ...unsigned, sig: bytesToHex(sig) };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Verify a {@link SignedEnvelope} against the sender's compressed secp256k1
|
|
31
|
+
* communication public key. Throws {@link HttpTransportError} on any failure;
|
|
32
|
+
* returns normally on success.
|
|
33
|
+
*
|
|
34
|
+
* Does NOT check nonce uniqueness — replay protection is the caller's
|
|
35
|
+
* responsibility (the server-side transport maintains an LRU cache).
|
|
36
|
+
*/
|
|
37
|
+
export function verifyEnvelope(envelope, senderPk, opts = {}) {
|
|
38
|
+
if (envelope.v !== HTTP_ENVELOPE_VERSION) {
|
|
39
|
+
throw new HttpTransportError(`Unsupported envelope version: ${envelope.v}`, 'ENVELOPE_VERSION_MISMATCH', { version: envelope.v, expected: HTTP_ENVELOPE_VERSION });
|
|
40
|
+
}
|
|
41
|
+
if (opts.expectedFrom !== undefined && envelope.from !== opts.expectedFrom) {
|
|
42
|
+
throw new HttpTransportError(`Envelope from mismatch: expected ${opts.expectedFrom}, got ${envelope.from}`, 'ENVELOPE_FROM_MISMATCH', { expected: opts.expectedFrom, got: envelope.from });
|
|
43
|
+
}
|
|
44
|
+
if ('expectedTo' in opts && envelope.to !== opts.expectedTo) {
|
|
45
|
+
throw new HttpTransportError(`Envelope to mismatch: expected ${opts.expectedTo ?? '<broadcast>'}, got ${envelope.to ?? '<broadcast>'}`, 'ENVELOPE_TO_MISMATCH', { expected: opts.expectedTo, got: envelope.to });
|
|
46
|
+
}
|
|
47
|
+
const skewSec = opts.clockSkewSec ?? DEFAULT_CLOCK_SKEW_SEC;
|
|
48
|
+
const nowMs = opts.now ? opts.now() : Date.now();
|
|
49
|
+
const nowSec = Math.floor(nowMs / 1000);
|
|
50
|
+
const diff = Math.abs(nowSec - envelope.timestamp);
|
|
51
|
+
if (diff > skewSec) {
|
|
52
|
+
throw new HttpTransportError(`Envelope timestamp out of skew: ${diff}s > ${skewSec}s`, 'ENVELOPE_TIMESTAMP_SKEW', { diff, skewSec, timestamp: envelope.timestamp, now: nowSec });
|
|
53
|
+
}
|
|
54
|
+
let sigBytes;
|
|
55
|
+
try {
|
|
56
|
+
sigBytes = hexToBytes(envelope.sig);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new HttpTransportError('Envelope signature is not valid hex', 'ENVELOPE_SIG_HEX');
|
|
60
|
+
}
|
|
61
|
+
if (sigBytes.length !== 64) {
|
|
62
|
+
throw new HttpTransportError(`Invalid signature length: ${sigBytes.length} (expected 64)`, 'ENVELOPE_SIG_LENGTH', { length: sigBytes.length });
|
|
63
|
+
}
|
|
64
|
+
const { sig: _sig, ...unsigned } = envelope;
|
|
65
|
+
const digest = canonicalHashBytes(unsigned);
|
|
66
|
+
const ok = senderPk.verify(sigBytes, digest, { scheme: 'schnorr' });
|
|
67
|
+
if (!ok) {
|
|
68
|
+
throw new HttpTransportError('Envelope signature verification failed', 'ENVELOPE_SIG_INVALID');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function normalizeMessage(message) {
|
|
72
|
+
const maybeToJSON = message.toJSON;
|
|
73
|
+
if (typeof maybeToJSON === 'function') {
|
|
74
|
+
return maybeToJSON.call(message);
|
|
75
|
+
}
|
|
76
|
+
return message;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Recursively replace `Uint8Array` values with `{ __bytes: hex }` sentinel
|
|
80
|
+
* objects so they survive JSON canonicalization / HTTP body serialization.
|
|
81
|
+
* Pairs with {@link reviveFromWire}.
|
|
82
|
+
*
|
|
83
|
+
* Without this, `JSON.stringify` serializes a `Uint8Array` as an index-keyed
|
|
84
|
+
* object (`{"0":1,"1":2,...}`), which `canonicalize` then re-parses into a
|
|
85
|
+
* plain object — the receiver cannot reconstruct the original bytes even
|
|
86
|
+
* though the signature still verifies.
|
|
87
|
+
*/
|
|
88
|
+
export function normalizeForWire(value) {
|
|
89
|
+
if (value instanceof Uint8Array) {
|
|
90
|
+
return { __bytes: bytesToHex(value) };
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(value)) {
|
|
93
|
+
return value.map((v) => normalizeForWire(v));
|
|
94
|
+
}
|
|
95
|
+
if (value && typeof value === 'object') {
|
|
96
|
+
const out = {};
|
|
97
|
+
for (const [k, v] of Object.entries(value)) {
|
|
98
|
+
out[k] = normalizeForWire(v);
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Recursively convert `{ __bytes: hex }` sentinels back into `Uint8Array`
|
|
106
|
+
* values. Call on `envelope.message` *after* successful verification and
|
|
107
|
+
* before handing the payload to a runner's handler.
|
|
108
|
+
*/
|
|
109
|
+
export function reviveFromWire(value) {
|
|
110
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
111
|
+
const rec = value;
|
|
112
|
+
const keys = Object.keys(rec);
|
|
113
|
+
if (keys.length === 1 && keys[0] === '__bytes' && typeof rec.__bytes === 'string') {
|
|
114
|
+
return hexToBytes(rec.__bytes);
|
|
115
|
+
}
|
|
116
|
+
const out = {};
|
|
117
|
+
for (const [k, v] of Object.entries(rec))
|
|
118
|
+
out[k] = reviveFromWire(v);
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
return value.map((v) => reviveFromWire(v));
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../../../../src/core/aggregation/transport/http/envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TransportAdapterError } from '../error.js';
|
|
2
|
+
/**
|
|
3
|
+
* Errors raised by the HTTP transport adapter. Extends {@link TransportAdapterError}
|
|
4
|
+
* so callers can catch HTTP-specific failures narrowly or transport failures broadly.
|
|
5
|
+
*/
|
|
6
|
+
export class HttpTransportError extends TransportAdapterError {
|
|
7
|
+
constructor(message, type = 'HttpTransportError', data) {
|
|
8
|
+
super(message, type, { adapter: 'http', ...(data ?? {}) });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../../../src/core/aggregation/transport/http/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;GAGG;AACH,MAAM,OAAO,kBAAmB,SAAQ,qBAAqB;IAC3D,YAAY,OAAe,EAAE,OAAe,oBAAoB,EAAE,IAA0B;QAC1F,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed-capacity FIFO ring buffer of SSE events for a single actor's inbox.
|
|
3
|
+
*
|
|
4
|
+
* When a subscriber (re)connects with a `Last-Event-ID` header, the server
|
|
5
|
+
* uses {@link since} to replay everything that arrived while the subscriber
|
|
6
|
+
* was disconnected. Events older than the replay window (evicted from the
|
|
7
|
+
* ring) are unrecoverable — callers should choose `capacity` based on
|
|
8
|
+
* expected message rate × acceptable reconnect window.
|
|
9
|
+
*/
|
|
10
|
+
export class InboxBuffer {
|
|
11
|
+
#capacity;
|
|
12
|
+
#entries = [];
|
|
13
|
+
#nextId = 1;
|
|
14
|
+
constructor(capacity = 100) {
|
|
15
|
+
if (capacity < 1)
|
|
16
|
+
throw new Error(`InboxBuffer capacity must be >= 1; got ${capacity}`);
|
|
17
|
+
this.#capacity = capacity;
|
|
18
|
+
}
|
|
19
|
+
/** Append an event. Returns the stored record (including its assigned id). */
|
|
20
|
+
append(event, data) {
|
|
21
|
+
const stored = { id: String(this.#nextId++), event, data };
|
|
22
|
+
this.#entries.push(stored);
|
|
23
|
+
if (this.#entries.length > this.#capacity)
|
|
24
|
+
this.#entries.shift();
|
|
25
|
+
return stored;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Return stored events with id strictly greater than `lastEventId`. If
|
|
29
|
+
* `lastEventId` is unset or unparseable, returns everything currently
|
|
30
|
+
* retained.
|
|
31
|
+
*/
|
|
32
|
+
since(lastEventId) {
|
|
33
|
+
if (!lastEventId)
|
|
34
|
+
return this.#entries.slice();
|
|
35
|
+
const boundary = Number(lastEventId);
|
|
36
|
+
if (!Number.isFinite(boundary))
|
|
37
|
+
return this.#entries.slice();
|
|
38
|
+
return this.#entries.filter((e) => Number(e.id) > boundary);
|
|
39
|
+
}
|
|
40
|
+
/** Currently retained event count. */
|
|
41
|
+
size() {
|
|
42
|
+
return this.#entries.length;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=inbox-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-buffer.js","sourceRoot":"","sources":["../../../../../../src/core/aggregation/transport/http/inbox-buffer.ts"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,MAAM,OAAO,WAAW;IACb,SAAS,CAAS;IAClB,QAAQ,GAAkB,EAAE,CAAC;IACtC,OAAO,GAAG,CAAC,CAAC;IAEZ,YAAY,QAAQ,GAAG,GAAG;QACxB,IAAG,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,QAAQ,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAED,8EAA8E;IAC9E,MAAM,CAAC,KAAa,EAAE,IAAY;QAChC,MAAM,MAAM,GAAgB,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACxE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAoB;QACxB,IAAG,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACrC,IAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAED,sCAAsC;IACtC,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './errors.js';
|
|
2
|
+
export * from './protocol.js';
|
|
3
|
+
export * from './envelope.js';
|
|
4
|
+
export * from './sse-stream.js';
|
|
5
|
+
export * from './sse-writer.js';
|
|
6
|
+
export * from './request-auth.js';
|
|
7
|
+
export * from './nonce-cache.js';
|
|
8
|
+
export * from './rate-limiter.js';
|
|
9
|
+
export * from './inbox-buffer.js';
|
|
10
|
+
export * from './client.js';
|
|
11
|
+
export * from './server.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/core/aggregation/transport/http/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
|