@brightchain/brightchain-api-lib 0.25.0 → 0.27.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/package.json +4 -3
- package/src/lib/appConstants.d.ts +1 -1
- package/src/lib/appConstants.js +1 -1
- package/src/lib/application.d.ts +3 -14
- package/src/lib/application.d.ts.map +1 -1
- package/src/lib/application.js +91 -34
- package/src/lib/application.js.map +1 -1
- package/src/lib/constants.d.ts.map +1 -1
- package/src/lib/constants.js +1 -1
- package/src/lib/constants.js.map +1 -1
- package/src/lib/databaseInit.d.ts +7 -11
- package/src/lib/databaseInit.d.ts.map +1 -1
- package/src/lib/databaseInit.js +41 -107
- package/src/lib/databaseInit.js.map +1 -1
- package/src/lib/datastore/block-document-store-factory.d.ts +3 -0
- package/src/lib/datastore/block-document-store-factory.d.ts.map +1 -1
- package/src/lib/datastore/block-document-store-factory.js +15 -18
- package/src/lib/datastore/block-document-store-factory.js.map +1 -1
- package/src/lib/datastore/block-document-store.d.ts +2 -191
- package/src/lib/datastore/block-document-store.d.ts.map +1 -1
- package/src/lib/datastore/block-document-store.js +4 -628
- package/src/lib/datastore/block-document-store.js.map +1 -1
- package/src/lib/datastore/document-store.d.ts +1 -62
- package/src/lib/datastore/document-store.d.ts.map +1 -1
- package/src/lib/datastore/memory-document-store.d.ts +1 -8
- package/src/lib/datastore/memory-document-store.d.ts.map +1 -1
- package/src/lib/datastore/memory-document-store.js +3 -214
- package/src/lib/datastore/memory-document-store.js.map +1 -1
- package/src/lib/environment.d.ts +4 -47
- package/src/lib/environment.d.ts.map +1 -1
- package/src/lib/environment.js +2 -136
- package/src/lib/environment.js.map +1 -1
- package/src/lib/interfaces/environment.d.ts +3 -25
- package/src/lib/interfaces/environment.d.ts.map +1 -1
- package/src/lib/interfaces/responses/emailGatewayResponses.d.ts +30 -0
- package/src/lib/interfaces/responses/emailGatewayResponses.d.ts.map +1 -0
- package/src/lib/interfaces/responses/emailGatewayResponses.js +3 -0
- package/src/lib/interfaces/responses/emailGatewayResponses.js.map +1 -0
- package/src/lib/interfaces/responses/index.d.ts +1 -0
- package/src/lib/interfaces/responses/index.d.ts.map +1 -1
- package/src/lib/middleware/index.d.ts +1 -1
- package/src/lib/middleware/index.d.ts.map +1 -1
- package/src/lib/middleware/index.js +3 -2
- package/src/lib/middleware/index.js.map +1 -1
- package/src/lib/middleware/validateBody.d.ts +1 -12
- package/src/lib/middleware/validateBody.d.ts.map +1 -1
- package/src/lib/middleware/validateBody.js +4 -32
- package/src/lib/middleware/validateBody.js.map +1 -1
- package/src/lib/middlewares.d.ts.map +1 -1
- package/src/lib/middlewares.js +7 -1
- package/src/lib/middlewares.js.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.d.ts +27 -79
- package/src/lib/plugins/brightchain-database-plugin.d.ts.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.js +32 -103
- package/src/lib/plugins/brightchain-database-plugin.js.map +1 -1
- package/src/lib/routers/app.d.ts.map +1 -1
- package/src/lib/routers/app.js +1 -0
- package/src/lib/routers/app.js.map +1 -1
- package/src/lib/services/emailGateway/antiSpamFilter.d.ts +229 -0
- package/src/lib/services/emailGateway/antiSpamFilter.d.ts.map +1 -0
- package/src/lib/services/emailGateway/antiSpamFilter.js +325 -0
- package/src/lib/services/emailGateway/antiSpamFilter.js.map +1 -0
- package/src/lib/services/emailGateway/bounceProcessor.d.ts +182 -0
- package/src/lib/services/emailGateway/bounceProcessor.d.ts.map +1 -0
- package/src/lib/services/emailGateway/bounceProcessor.js +391 -0
- package/src/lib/services/emailGateway/bounceProcessor.js.map +1 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.d.ts +99 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.js +202 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.js.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.d.ts +74 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.js +107 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.js.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayService.d.ts +209 -0
- package/src/lib/services/emailGateway/emailGatewayService.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayService.js +254 -0
- package/src/lib/services/emailGateway/emailGatewayService.js.map +1 -0
- package/src/lib/services/emailGateway/gatewayObservability.d.ts +123 -0
- package/src/lib/services/emailGateway/gatewayObservability.d.ts.map +1 -0
- package/src/lib/services/emailGateway/gatewayObservability.js +186 -0
- package/src/lib/services/emailGateway/gatewayObservability.js.map +1 -0
- package/src/lib/services/emailGateway/inboundProcessor.d.ts +113 -0
- package/src/lib/services/emailGateway/inboundProcessor.d.ts.map +1 -0
- package/src/lib/services/emailGateway/inboundProcessor.js +298 -0
- package/src/lib/services/emailGateway/inboundProcessor.js.map +1 -0
- package/src/lib/services/emailGateway/index.d.ts +23 -0
- package/src/lib/services/emailGateway/index.d.ts.map +1 -0
- package/src/lib/services/emailGateway/index.js +26 -0
- package/src/lib/services/emailGateway/index.js.map +1 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts +122 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.js +110 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.js.map +1 -0
- package/src/lib/services/emailGateway/outboundQueue.d.ts +135 -0
- package/src/lib/services/emailGateway/outboundQueue.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundQueue.js +227 -0
- package/src/lib/services/emailGateway/outboundQueue.js.map +1 -0
- package/src/lib/services/emailGateway/outboundQueueStore.d.ts +110 -0
- package/src/lib/services/emailGateway/outboundQueueStore.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundQueueStore.js +131 -0
- package/src/lib/services/emailGateway/outboundQueueStore.js.map +1 -0
- package/src/lib/services/emailGateway/recipientLookupService.d.ts +146 -0
- package/src/lib/services/emailGateway/recipientLookupService.d.ts.map +1 -0
- package/src/lib/services/emailGateway/recipientLookupService.js +307 -0
- package/src/lib/services/emailGateway/recipientLookupService.js.map +1 -0
- package/src/lib/services/emailGateway/retryBackoff.d.ts +79 -0
- package/src/lib/services/emailGateway/retryBackoff.d.ts.map +1 -0
- package/src/lib/services/emailGateway/retryBackoff.js +77 -0
- package/src/lib/services/emailGateway/retryBackoff.js.map +1 -0
- package/src/lib/services/index.d.ts +1 -0
- package/src/lib/services/index.d.ts.map +1 -1
- package/src/lib/services/index.js +1 -0
- package/src/lib/services/index.js.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.d.ts +7 -1
- package/src/lib/services/quorumDatabaseAdapter.d.ts.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.js +83 -0
- package/src/lib/services/quorumDatabaseAdapter.js.map +1 -1
- package/src/lib/services/sessionAdapter.d.ts +2 -61
- package/src/lib/services/sessionAdapter.d.ts.map +1 -1
- package/src/lib/services/sessionAdapter.js +2 -102
- package/src/lib/services/sessionAdapter.js.map +1 -1
- package/src/lib/shared-types.d.ts +7 -15
- package/src/lib/shared-types.d.ts.map +1 -1
- package/src/lib/types/backend-id.d.ts +1 -2
- package/src/lib/types/backend-id.d.ts.map +1 -1
- package/src/lib/validation/userValidation.d.ts +2 -43
- package/src/lib/validation/userValidation.d.ts.map +1 -1
- package/src/lib/validation/userValidation.js +6 -144
- package/src/lib/validation/userValidation.js.map +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RecipientLookupService — TCP socketmap server for Postfix recipient validation.
|
|
4
|
+
*
|
|
5
|
+
* Implements the Postfix `socketmap` lookup protocol over TCP so that Postfix
|
|
6
|
+
* can validate whether a recipient address corresponds to a registered
|
|
7
|
+
* BrightChain user *before* accepting the message (preventing backscatter).
|
|
8
|
+
*
|
|
9
|
+
* Protocol (simplified):
|
|
10
|
+
* Client sends: `<name> <key>\n` (e.g. `virtual alice@brightchain.org\n`)
|
|
11
|
+
* Server responds: `OK <value>\n` | `NOTFOUND \n` | `TEMP <reason>\n`
|
|
12
|
+
*
|
|
13
|
+
* The service:
|
|
14
|
+
* - Listens on a configurable TCP port (default 2526) on localhost
|
|
15
|
+
* - Queries a user-registry dependency for the local part at the canonical domain
|
|
16
|
+
* - Caches positive results in an LRU cache with configurable TTL (default 300 s)
|
|
17
|
+
* - Responds within 5 seconds (timeout handling)
|
|
18
|
+
*
|
|
19
|
+
* @see Requirements 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7, 4.1, 4.2, 4.3
|
|
20
|
+
* @module recipientLookupService
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.RecipientLookupService = exports.RecipientLookupCache = void 0;
|
|
24
|
+
const tslib_1 = require("tslib");
|
|
25
|
+
const net = tslib_1.__importStar(require("net"));
|
|
26
|
+
/**
|
|
27
|
+
* Simple LRU cache for positive recipient lookup results.
|
|
28
|
+
*
|
|
29
|
+
* Only positive (`OK`) results are cached — negative and temporary results
|
|
30
|
+
* are always re-queried so that newly registered users are found promptly.
|
|
31
|
+
*
|
|
32
|
+
* @see Requirement 13.6
|
|
33
|
+
*/
|
|
34
|
+
class RecipientLookupCache {
|
|
35
|
+
maxSize;
|
|
36
|
+
ttlMs;
|
|
37
|
+
cache = new Map();
|
|
38
|
+
constructor(maxSize, ttlMs) {
|
|
39
|
+
this.maxSize = maxSize;
|
|
40
|
+
this.ttlMs = ttlMs;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Retrieve a cached positive result for `key`.
|
|
44
|
+
*
|
|
45
|
+
* @returns `true` if the key is cached and not expired, `false` otherwise.
|
|
46
|
+
*/
|
|
47
|
+
get(key) {
|
|
48
|
+
const entry = this.cache.get(key);
|
|
49
|
+
if (!entry) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (Date.now() >= entry.expiresAt) {
|
|
53
|
+
this.cache.delete(key);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
// Move to end (most-recently used) by re-inserting.
|
|
57
|
+
this.cache.delete(key);
|
|
58
|
+
this.cache.set(key, entry);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Store a positive lookup result for `key`.
|
|
63
|
+
*/
|
|
64
|
+
set(key) {
|
|
65
|
+
// If already present, delete first so insertion order is refreshed.
|
|
66
|
+
if (this.cache.has(key)) {
|
|
67
|
+
this.cache.delete(key);
|
|
68
|
+
}
|
|
69
|
+
// Evict the least-recently used entry if at capacity.
|
|
70
|
+
if (this.cache.size >= this.maxSize) {
|
|
71
|
+
const oldest = this.cache.keys().next().value;
|
|
72
|
+
if (oldest !== undefined) {
|
|
73
|
+
this.cache.delete(oldest);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
this.cache.set(key, { expiresAt: Date.now() + this.ttlMs });
|
|
77
|
+
}
|
|
78
|
+
/** Number of entries currently in the cache. */
|
|
79
|
+
get size() {
|
|
80
|
+
return this.cache.size;
|
|
81
|
+
}
|
|
82
|
+
/** Remove all entries. */
|
|
83
|
+
clear() {
|
|
84
|
+
this.cache.clear();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.RecipientLookupCache = RecipientLookupCache;
|
|
88
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
89
|
+
/** Maximum time (ms) to wait for a registry lookup before returning TEMP. */
|
|
90
|
+
const LOOKUP_TIMEOUT_MS = 5_000;
|
|
91
|
+
/** Default maximum number of entries in the LRU cache. */
|
|
92
|
+
const DEFAULT_CACHE_MAX_SIZE = 10_000;
|
|
93
|
+
// ─── RecipientLookupService ─────────────────────────────────────────────────
|
|
94
|
+
/**
|
|
95
|
+
* TCP socketmap server that Postfix queries to validate recipient addresses
|
|
96
|
+
* against the BrightChain user registry.
|
|
97
|
+
*
|
|
98
|
+
* Implements `IRecipientLookupService` from brightchain-lib for the `lookup`
|
|
99
|
+
* contract, and adds TCP server lifecycle (`start` / `stop`).
|
|
100
|
+
*
|
|
101
|
+
* @see Requirements 13.1, 13.2, 13.3, 13.4, 13.5, 13.6, 13.7
|
|
102
|
+
*/
|
|
103
|
+
class RecipientLookupService {
|
|
104
|
+
config;
|
|
105
|
+
userRegistry;
|
|
106
|
+
server = null;
|
|
107
|
+
cache;
|
|
108
|
+
port;
|
|
109
|
+
canonicalDomain;
|
|
110
|
+
constructor(config, userRegistry) {
|
|
111
|
+
this.config = config;
|
|
112
|
+
this.userRegistry = userRegistry;
|
|
113
|
+
this.port = config.recipientLookupPort;
|
|
114
|
+
this.canonicalDomain = config.canonicalDomain.toLowerCase();
|
|
115
|
+
this.cache = new RecipientLookupCache(DEFAULT_CACHE_MAX_SIZE, config.recipientLookupCacheTtlSeconds * 1_000);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update the canonical domain used for recipient validation.
|
|
119
|
+
*
|
|
120
|
+
* Clears the lookup cache since cached entries may belong to the old domain.
|
|
121
|
+
*
|
|
122
|
+
* @param newDomain - The new canonical domain
|
|
123
|
+
*
|
|
124
|
+
* @see Requirement 8.5 — hot-reload canonical domain without restart
|
|
125
|
+
*/
|
|
126
|
+
updateCanonicalDomain(newDomain) {
|
|
127
|
+
this.canonicalDomain = newDomain.toLowerCase();
|
|
128
|
+
this.cache.clear();
|
|
129
|
+
}
|
|
130
|
+
// ─── IRecipientLookupService ────────────────────────────────────────
|
|
131
|
+
/**
|
|
132
|
+
* Look up whether `emailAddress` corresponds to a registered BrightChain
|
|
133
|
+
* user at the canonical domain.
|
|
134
|
+
*
|
|
135
|
+
* 1. Check the LRU cache for a positive hit.
|
|
136
|
+
* 2. Query the user registry (with a 5-second timeout).
|
|
137
|
+
* 3. Cache positive results.
|
|
138
|
+
*
|
|
139
|
+
* @returns `'OK'` | `'NOTFOUND'` | `'TEMP'`
|
|
140
|
+
*
|
|
141
|
+
* @see Requirements 13.2, 13.3, 13.4, 13.5, 13.6
|
|
142
|
+
*/
|
|
143
|
+
async lookup(emailAddress) {
|
|
144
|
+
const normalised = emailAddress.toLowerCase().trim();
|
|
145
|
+
// Validate that the address belongs to the canonical domain.
|
|
146
|
+
const atIndex = normalised.lastIndexOf('@');
|
|
147
|
+
if (atIndex === -1) {
|
|
148
|
+
return 'NOTFOUND';
|
|
149
|
+
}
|
|
150
|
+
const domain = normalised.slice(atIndex + 1);
|
|
151
|
+
if (domain !== this.canonicalDomain) {
|
|
152
|
+
return 'NOTFOUND';
|
|
153
|
+
}
|
|
154
|
+
// 1. Cache hit → return OK immediately (Req 13.6).
|
|
155
|
+
if (this.cache.get(normalised)) {
|
|
156
|
+
return 'OK';
|
|
157
|
+
}
|
|
158
|
+
// 2. Query registry with timeout (Req 4.3 — respond within 5 s).
|
|
159
|
+
try {
|
|
160
|
+
const found = await this.withTimeout(this.userRegistry.hasUser(normalised), LOOKUP_TIMEOUT_MS);
|
|
161
|
+
if (found) {
|
|
162
|
+
this.cache.set(normalised);
|
|
163
|
+
return 'OK';
|
|
164
|
+
}
|
|
165
|
+
return 'NOTFOUND';
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// Registry unreachable or timeout → TEMP (Req 13.5).
|
|
169
|
+
return 'TEMP';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// ─── TCP Server Lifecycle ───────────────────────────────────────────
|
|
173
|
+
/**
|
|
174
|
+
* Start the TCP socketmap server on the configured port (localhost only).
|
|
175
|
+
*
|
|
176
|
+
* @see Requirement 13.1
|
|
177
|
+
*/
|
|
178
|
+
start() {
|
|
179
|
+
return new Promise((resolve, reject) => {
|
|
180
|
+
if (this.server) {
|
|
181
|
+
resolve();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.server = net.createServer((socket) => this.handleConnection(socket));
|
|
185
|
+
this.server.on('error', (err) => {
|
|
186
|
+
reject(err);
|
|
187
|
+
});
|
|
188
|
+
this.server.listen(this.port, '127.0.0.1', () => {
|
|
189
|
+
resolve();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Stop the TCP server and clear the cache.
|
|
195
|
+
*/
|
|
196
|
+
stop() {
|
|
197
|
+
return new Promise((resolve) => {
|
|
198
|
+
this.cache.clear();
|
|
199
|
+
if (!this.server) {
|
|
200
|
+
resolve();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.server.close(() => {
|
|
204
|
+
this.server = null;
|
|
205
|
+
resolve();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** Whether the TCP server is currently listening. */
|
|
210
|
+
isRunning() {
|
|
211
|
+
return this.server !== null && this.server.listening;
|
|
212
|
+
}
|
|
213
|
+
/** Expose cache for testing purposes. */
|
|
214
|
+
getCache() {
|
|
215
|
+
return this.cache;
|
|
216
|
+
}
|
|
217
|
+
// ─── Connection Handler ─────────────────────────────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Handle a single TCP connection from Postfix.
|
|
220
|
+
*
|
|
221
|
+
* Postfix socketmap protocol:
|
|
222
|
+
* Request: `<mapname> <key>\n`
|
|
223
|
+
* Response: `OK <value>\n` | `NOTFOUND \n` | `TEMP <reason>\n`
|
|
224
|
+
*
|
|
225
|
+
* The connection may carry multiple newline-delimited requests.
|
|
226
|
+
*/
|
|
227
|
+
handleConnection(socket) {
|
|
228
|
+
let buffer = '';
|
|
229
|
+
socket.setEncoding('utf-8');
|
|
230
|
+
socket.on('data', (data) => {
|
|
231
|
+
buffer += data;
|
|
232
|
+
// Process all complete lines in the buffer.
|
|
233
|
+
let newlineIdx;
|
|
234
|
+
while ((newlineIdx = buffer.indexOf('\n')) !== -1) {
|
|
235
|
+
const line = buffer.slice(0, newlineIdx).trim();
|
|
236
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
237
|
+
if (line.length === 0) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
this.handleRequest(line)
|
|
241
|
+
.then((response) => {
|
|
242
|
+
if (!socket.destroyed) {
|
|
243
|
+
socket.write(response + '\n');
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
.catch(() => {
|
|
247
|
+
if (!socket.destroyed) {
|
|
248
|
+
socket.write('TEMP internal error\n');
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
socket.on('error', () => {
|
|
254
|
+
// Silently handle socket errors (e.g. client disconnect).
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Parse a socketmap request line and return the response string.
|
|
259
|
+
*
|
|
260
|
+
* @param line - A single request line, e.g. `virtual alice@brightchain.org`
|
|
261
|
+
* @returns The response string, e.g. `OK alice@brightchain.org`
|
|
262
|
+
*/
|
|
263
|
+
async handleRequest(line) {
|
|
264
|
+
// Format: `<mapname> <key>`
|
|
265
|
+
const spaceIdx = line.indexOf(' ');
|
|
266
|
+
if (spaceIdx === -1) {
|
|
267
|
+
return 'TEMP malformed request';
|
|
268
|
+
}
|
|
269
|
+
const key = line.slice(spaceIdx + 1).trim();
|
|
270
|
+
if (key.length === 0) {
|
|
271
|
+
return 'TEMP malformed request';
|
|
272
|
+
}
|
|
273
|
+
const result = await this.lookup(key);
|
|
274
|
+
switch (result) {
|
|
275
|
+
case 'OK':
|
|
276
|
+
return `OK ${key}`;
|
|
277
|
+
case 'NOTFOUND':
|
|
278
|
+
return 'NOTFOUND ';
|
|
279
|
+
case 'TEMP':
|
|
280
|
+
return 'TEMP registry unavailable';
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// ─── Helpers ────────────────────────────────────────────────────────
|
|
284
|
+
/**
|
|
285
|
+
* Race a promise against a timeout.
|
|
286
|
+
*
|
|
287
|
+
* @throws If the timeout fires first.
|
|
288
|
+
*/
|
|
289
|
+
withTimeout(promise, ms) {
|
|
290
|
+
return new Promise((resolve, reject) => {
|
|
291
|
+
const timer = setTimeout(() => {
|
|
292
|
+
reject(new Error(`Lookup timed out after ${ms}ms`));
|
|
293
|
+
}, ms);
|
|
294
|
+
promise
|
|
295
|
+
.then((value) => {
|
|
296
|
+
clearTimeout(timer);
|
|
297
|
+
resolve(value);
|
|
298
|
+
})
|
|
299
|
+
.catch((err) => {
|
|
300
|
+
clearTimeout(timer);
|
|
301
|
+
reject(err);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
exports.RecipientLookupService = RecipientLookupService;
|
|
307
|
+
//# sourceMappingURL=recipientLookupService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipientLookupService.js","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/recipientLookupService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Back-Off Utilities — exponential back-off with jitter for outbound
|
|
3
|
+
* email delivery retries.
|
|
4
|
+
*
|
|
5
|
+
* Provides pure utility functions that the OutboundDeliveryWorker and
|
|
6
|
+
* OutboundQueue use to compute retry delays and determine whether a
|
|
7
|
+
* message should be retried or permanently failed.
|
|
8
|
+
*
|
|
9
|
+
* Back-off formula: baseInterval × 2^retryCount + random jitter (0–25%)
|
|
10
|
+
*
|
|
11
|
+
* @see Requirements 3.1, 3.2, 3.3, 3.4, 3.5
|
|
12
|
+
* @module retryBackoff
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Configuration for retry back-off behaviour.
|
|
16
|
+
*
|
|
17
|
+
* Extracted from `IEmailGatewayConfig` so the utility functions remain
|
|
18
|
+
* decoupled from the full gateway config.
|
|
19
|
+
*/
|
|
20
|
+
export interface IRetryConfig {
|
|
21
|
+
/** Maximum number of delivery retry attempts (default: 5). Req 3.3 */
|
|
22
|
+
retryMaxCount: number;
|
|
23
|
+
/** Maximum total retry duration in milliseconds (default: 48h). Req 3.3 */
|
|
24
|
+
retryMaxDurationMs: number;
|
|
25
|
+
/** Base interval in milliseconds for exponential back-off (default: 60000). Req 3.2 */
|
|
26
|
+
retryBaseIntervalMs: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Minimal item shape needed by `shouldRetry`.
|
|
30
|
+
*/
|
|
31
|
+
export interface IRetryableItem {
|
|
32
|
+
/** Number of delivery attempts made so far. */
|
|
33
|
+
retryCount: number;
|
|
34
|
+
/** Timestamp when the item was first enqueued. */
|
|
35
|
+
enqueuedAt: Date;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Compute the exponential back-off delay for a retry attempt.
|
|
39
|
+
*
|
|
40
|
+
* Formula: `baseIntervalMs × 2^retryCount + jitter`
|
|
41
|
+
* where jitter is a random value between 0% and 25% of the base delay.
|
|
42
|
+
*
|
|
43
|
+
* @param baseIntervalMs - Base interval in milliseconds (e.g. 60000)
|
|
44
|
+
* @param retryCount - Current retry attempt number (0-based: first retry = 0)
|
|
45
|
+
* @param randomFn - Optional random function for deterministic testing (default: Math.random)
|
|
46
|
+
* @returns Delay in milliseconds before the next retry attempt
|
|
47
|
+
*
|
|
48
|
+
* @see Requirement 3.2
|
|
49
|
+
*/
|
|
50
|
+
export declare function computeBackoffDelay(baseIntervalMs: number, retryCount: number, randomFn?: () => number): number;
|
|
51
|
+
/**
|
|
52
|
+
* Determine whether a queue item should be retried or permanently failed.
|
|
53
|
+
*
|
|
54
|
+
* An item should be retried when BOTH conditions are met:
|
|
55
|
+
* 1. `retryCount < config.retryMaxCount`
|
|
56
|
+
* 2. Time since `enqueuedAt` has not exceeded `config.retryMaxDurationMs`
|
|
57
|
+
*
|
|
58
|
+
* @param item - The queue item to evaluate
|
|
59
|
+
* @param config - Retry configuration limits
|
|
60
|
+
* @param nowMs - Current time in epoch milliseconds (default: Date.now())
|
|
61
|
+
* @returns `true` if the item is eligible for another retry attempt
|
|
62
|
+
*
|
|
63
|
+
* @see Requirements 3.3, 3.4
|
|
64
|
+
*/
|
|
65
|
+
export declare function shouldRetry(item: IRetryableItem, config: IRetryConfig, nowMs?: number): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Compute the `nextAttemptAt` timestamp for a requeued item.
|
|
68
|
+
*
|
|
69
|
+
* Convenience wrapper that combines `computeBackoffDelay` with the
|
|
70
|
+
* current time to produce an absolute `Date`.
|
|
71
|
+
*
|
|
72
|
+
* @param baseIntervalMs - Base interval in milliseconds
|
|
73
|
+
* @param retryCount - Current retry count (before increment)
|
|
74
|
+
* @param nowMs - Current time in epoch milliseconds (default: Date.now())
|
|
75
|
+
* @param randomFn - Optional random function for deterministic testing
|
|
76
|
+
* @returns The `Date` at which the next attempt should be made
|
|
77
|
+
*/
|
|
78
|
+
export declare function computeNextAttemptAt(baseIntervalMs: number, retryCount: number, nowMs?: number, randomFn?: () => number): Date;
|
|
79
|
+
//# sourceMappingURL=retryBackoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryBackoff.d.ts","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/retryBackoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC;IAEtB,2EAA2E;IAC3E,kBAAkB,EAAE,MAAM,CAAC;IAE3B,uFAAuF;IACvF,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IAEnB,kDAAkD;IAClD,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAM,MAAoB,GACnC,MAAM,CAIR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,YAAY,EACpB,KAAK,GAAE,MAAmB,GACzB,OAAO,CAST;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAmB,EAC1B,QAAQ,CAAC,EAAE,MAAM,MAAM,GACtB,IAAI,CAGN"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Retry Back-Off Utilities — exponential back-off with jitter for outbound
|
|
4
|
+
* email delivery retries.
|
|
5
|
+
*
|
|
6
|
+
* Provides pure utility functions that the OutboundDeliveryWorker and
|
|
7
|
+
* OutboundQueue use to compute retry delays and determine whether a
|
|
8
|
+
* message should be retried or permanently failed.
|
|
9
|
+
*
|
|
10
|
+
* Back-off formula: baseInterval × 2^retryCount + random jitter (0–25%)
|
|
11
|
+
*
|
|
12
|
+
* @see Requirements 3.1, 3.2, 3.3, 3.4, 3.5
|
|
13
|
+
* @module retryBackoff
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.computeBackoffDelay = computeBackoffDelay;
|
|
17
|
+
exports.shouldRetry = shouldRetry;
|
|
18
|
+
exports.computeNextAttemptAt = computeNextAttemptAt;
|
|
19
|
+
/**
|
|
20
|
+
* Compute the exponential back-off delay for a retry attempt.
|
|
21
|
+
*
|
|
22
|
+
* Formula: `baseIntervalMs × 2^retryCount + jitter`
|
|
23
|
+
* where jitter is a random value between 0% and 25% of the base delay.
|
|
24
|
+
*
|
|
25
|
+
* @param baseIntervalMs - Base interval in milliseconds (e.g. 60000)
|
|
26
|
+
* @param retryCount - Current retry attempt number (0-based: first retry = 0)
|
|
27
|
+
* @param randomFn - Optional random function for deterministic testing (default: Math.random)
|
|
28
|
+
* @returns Delay in milliseconds before the next retry attempt
|
|
29
|
+
*
|
|
30
|
+
* @see Requirement 3.2
|
|
31
|
+
*/
|
|
32
|
+
function computeBackoffDelay(baseIntervalMs, retryCount, randomFn = Math.random) {
|
|
33
|
+
const baseDelay = baseIntervalMs * Math.pow(2, retryCount);
|
|
34
|
+
const jitter = baseDelay * 0.25 * randomFn();
|
|
35
|
+
return baseDelay + jitter;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Determine whether a queue item should be retried or permanently failed.
|
|
39
|
+
*
|
|
40
|
+
* An item should be retried when BOTH conditions are met:
|
|
41
|
+
* 1. `retryCount < config.retryMaxCount`
|
|
42
|
+
* 2. Time since `enqueuedAt` has not exceeded `config.retryMaxDurationMs`
|
|
43
|
+
*
|
|
44
|
+
* @param item - The queue item to evaluate
|
|
45
|
+
* @param config - Retry configuration limits
|
|
46
|
+
* @param nowMs - Current time in epoch milliseconds (default: Date.now())
|
|
47
|
+
* @returns `true` if the item is eligible for another retry attempt
|
|
48
|
+
*
|
|
49
|
+
* @see Requirements 3.3, 3.4
|
|
50
|
+
*/
|
|
51
|
+
function shouldRetry(item, config, nowMs = Date.now()) {
|
|
52
|
+
if (item.retryCount >= config.retryMaxCount) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const age = nowMs - item.enqueuedAt.getTime();
|
|
56
|
+
if (age > config.retryMaxDurationMs) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Compute the `nextAttemptAt` timestamp for a requeued item.
|
|
63
|
+
*
|
|
64
|
+
* Convenience wrapper that combines `computeBackoffDelay` with the
|
|
65
|
+
* current time to produce an absolute `Date`.
|
|
66
|
+
*
|
|
67
|
+
* @param baseIntervalMs - Base interval in milliseconds
|
|
68
|
+
* @param retryCount - Current retry count (before increment)
|
|
69
|
+
* @param nowMs - Current time in epoch milliseconds (default: Date.now())
|
|
70
|
+
* @param randomFn - Optional random function for deterministic testing
|
|
71
|
+
* @returns The `Date` at which the next attempt should be made
|
|
72
|
+
*/
|
|
73
|
+
function computeNextAttemptAt(baseIntervalMs, retryCount, nowMs = Date.now(), randomFn) {
|
|
74
|
+
const delay = computeBackoffDelay(baseIntervalMs, retryCount, randomFn);
|
|
75
|
+
return new Date(nowMs + delay);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=retryBackoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retryBackoff.js","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/retryBackoff.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AA2CH,kDAQC;AAgBD,kCAaC;AAcD,oDAQC;AAxED;;;;;;;;;;;;GAYG;AACH,SAAgB,mBAAmB,CACjC,cAAsB,EACtB,UAAkB,EAClB,WAAyB,IAAI,CAAC,MAAM;IAEpC,MAAM,SAAS,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC;IAC7C,OAAO,SAAS,GAAG,MAAM,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,WAAW,CACzB,IAAoB,EACpB,MAAoB,EACpB,QAAgB,IAAI,CAAC,GAAG,EAAE;IAE1B,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;IAC9C,IAAI,GAAG,GAAG,MAAM,CAAC,kBAAkB,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,oBAAoB,CAClC,cAAsB,EACtB,UAAkB,EAClB,QAAgB,IAAI,CAAC,GAAG,EAAE,EAC1B,QAAuB;IAEvB,MAAM,KAAK,GAAG,mBAAmB,CAAC,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IACxE,OAAO,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -12,6 +12,7 @@ export * from './contentAwareBlocksService';
|
|
|
12
12
|
export * from './contentIngestionService';
|
|
13
13
|
export * from './diskQuorumService';
|
|
14
14
|
export * from './email';
|
|
15
|
+
export * from './emailGateway';
|
|
15
16
|
export * from './eventNotificationSystem';
|
|
16
17
|
export * from './fakeEmailService';
|
|
17
18
|
export { WasmFecService } from './fec';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,aAAa,CAAC;AAC5B,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC"}
|
|
@@ -16,6 +16,7 @@ tslib_1.__exportStar(require("./contentAwareBlocksService"), exports);
|
|
|
16
16
|
tslib_1.__exportStar(require("./contentIngestionService"), exports);
|
|
17
17
|
tslib_1.__exportStar(require("./diskQuorumService"), exports);
|
|
18
18
|
tslib_1.__exportStar(require("./email"), exports);
|
|
19
|
+
tslib_1.__exportStar(require("./emailGateway"), exports);
|
|
19
20
|
tslib_1.__exportStar(require("./eventNotificationSystem"), exports);
|
|
20
21
|
tslib_1.__exportStar(require("./fakeEmailService"), exports);
|
|
21
22
|
var fec_1 = require("./fec");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/index.ts"],"names":[],"mappings":";;;;AAAA,iDAAuB;AACvB,iDAAuB;AACvB,mDAAyB;AACzB,gEAAsC;AACtC,uDAA6B;AAC7B,4EAAkD;AAClD,yEAA+C;AAC/C,sDAA4B;AAC5B,kEAAwC;AACxC,8DAAoC;AACpC,sEAA4C;AAC5C,oEAA0C;AAC1C,8DAAoC;AACpC,kDAAwB;AACxB,oEAA0C;AAC1C,6DAAmC;AACnC,6BAAuC;AAA9B,qGAAA,cAAc,OAAA;AACvB,8DAAoC;AACpC,4DAAkC;AAClC,wEAA8C;AAC9C,0EAAgD;AAChD,kEAAwC;AACxC,+DAAqC;AACrC,4DAAkC;AAClC,mDAAyB;AACzB,kEAAwC;AACxC,+DAAqC;AACrC,wDAA8B;AAC9B,iDAAuB;AACvB,6DAAmC;AACnC,2DAAiC;AACjC,6DAAmC;AACnC,mEAAyC;AACzC,kEAAwC;AACxC,sEAA4C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/index.ts"],"names":[],"mappings":";;;;AAAA,iDAAuB;AACvB,iDAAuB;AACvB,mDAAyB;AACzB,gEAAsC;AACtC,uDAA6B;AAC7B,4EAAkD;AAClD,yEAA+C;AAC/C,sDAA4B;AAC5B,kEAAwC;AACxC,8DAAoC;AACpC,sEAA4C;AAC5C,oEAA0C;AAC1C,8DAAoC;AACpC,kDAAwB;AACxB,yDAA+B;AAC/B,oEAA0C;AAC1C,6DAAmC;AACnC,6BAAuC;AAA9B,qGAAA,cAAc,OAAA;AACvB,8DAAoC;AACpC,4DAAkC;AAClC,wEAA8C;AAC9C,0EAAgD;AAChD,kEAAwC;AACxC,+DAAqC;AACrC,4DAAkC;AAClC,mDAAyB;AACzB,kEAAwC;AACxC,+DAAqC;AACrC,wDAA8B;AAC9B,iDAAuB;AACvB,6DAAmC;AACnC,2DAAiC;AACjC,6DAAmC;AACnC,mEAAyC;AACzC,kEAAwC;AACxC,sEAA4C"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @see Requirements 9, 10
|
|
11
11
|
*/
|
|
12
|
-
import { AliasRecord, ChainedAuditLogEntry, IdentityRecoveryRecord, IQuorumDatabase, IQuorumMember, OperationalState, Proposal, QuorumAuditLogEntry, QuorumDataRecord, QuorumEpoch, RedistributionJournalEntry, StatuteOfLimitationsConfig, Vote } from '@brightchain/brightchain-lib';
|
|
12
|
+
import { AliasRecord, ChainedAuditLogEntry, IdentityRecoveryRecord, IQuorumDatabase, IQuorumMember, OperationalState, Proposal, QuorumAuditLogEntry, QuorumDataRecord, QuorumEpoch, RedistributionJournalEntry, StatuteOfLimitationsConfig, Vote, IBanRecord } from '@brightchain/brightchain-lib';
|
|
13
13
|
import type { BrightDb } from '@brightchain/db';
|
|
14
14
|
import { IIdProvider, PlatformID } from '@digitaldefiance/ecies-lib';
|
|
15
15
|
/** Dedicated pool ID for quorum data isolation */
|
|
@@ -57,5 +57,11 @@ export declare class QuorumDatabaseAdapter<TID extends PlatformID = Uint8Array>
|
|
|
57
57
|
getOperationalState(): Promise<OperationalState | null>;
|
|
58
58
|
withTransaction<R>(fn: () => Promise<R>): Promise<R>;
|
|
59
59
|
isAvailable(): Promise<boolean>;
|
|
60
|
+
saveBanRecord(record: IBanRecord<TID>): Promise<void>;
|
|
61
|
+
deleteBanRecord(memberId: TID): Promise<void>;
|
|
62
|
+
getBanRecord(memberId: TID): Promise<IBanRecord<TID> | null>;
|
|
63
|
+
getAllBanRecords(): Promise<IBanRecord<TID>[]>;
|
|
64
|
+
getMemberAdmissionProposerId(memberId: TID): Promise<TID | null>;
|
|
65
|
+
private deserializeBanRecord;
|
|
60
66
|
}
|
|
61
67
|
//# sourceMappingURL=quorumDatabaseAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quorumDatabaseAdapter.d.ts","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/quorumDatabaseAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EACX,0BAA0B,EAC1B,0BAA0B,EAC1B,IAAI,
|
|
1
|
+
{"version":3,"file":"quorumDatabaseAdapter.d.ts","sourceRoot":"","sources":["../../../../../brightchain-api-lib/src/lib/services/quorumDatabaseAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,7 @@ const COLLECTION_AUDIT_LOG = 'audit_log';
|
|
|
24
24
|
const COLLECTION_REDISTRIBUTION_JOURNAL = 'redistribution_journal';
|
|
25
25
|
const COLLECTION_STATUTE_CONFIG = 'statute_config';
|
|
26
26
|
const COLLECTION_OPERATIONAL_STATE = 'operational_state';
|
|
27
|
+
const COLLECTION_BAN_RECORDS = 'ban_records';
|
|
27
28
|
/** Dedicated pool ID for quorum data isolation */
|
|
28
29
|
exports.QUORUM_SYSTEM_POOL_ID = 'quorum-system';
|
|
29
30
|
// ─── Serialization Helpers ──────────────────────────────────────────────────
|
|
@@ -735,6 +736,88 @@ class QuorumDatabaseAdapter {
|
|
|
735
736
|
return false;
|
|
736
737
|
}
|
|
737
738
|
}
|
|
739
|
+
// === Ban Records ===
|
|
740
|
+
async saveBanRecord(record) {
|
|
741
|
+
const col = this.db.collection(COLLECTION_BAN_RECORDS);
|
|
742
|
+
const memberId = this.idProvider.idToString(record.memberId);
|
|
743
|
+
const data = {
|
|
744
|
+
memberId: memberId,
|
|
745
|
+
reason: record.reason,
|
|
746
|
+
proposalId: this.idProvider.idToString(record.proposalId),
|
|
747
|
+
epoch: record.epoch,
|
|
748
|
+
bannedAt: record.bannedAt.toISOString(),
|
|
749
|
+
evidenceBlockIds: record.evidenceBlockIds,
|
|
750
|
+
approvalSignatures: record.approvalSignatures.map((sig) => ({
|
|
751
|
+
memberId: this.idProvider.idToString(sig.memberId),
|
|
752
|
+
signature: serializeUint8Array(sig.signature),
|
|
753
|
+
})),
|
|
754
|
+
requiredSignatures: record.requiredSignatures,
|
|
755
|
+
};
|
|
756
|
+
const existing = await col.findOne({ memberId });
|
|
757
|
+
if (existing) {
|
|
758
|
+
await col.updateOne({ memberId }, { $set: { data } });
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
await col.insertOne({ memberId, data });
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
async deleteBanRecord(memberId) {
|
|
765
|
+
const col = this.db.collection(COLLECTION_BAN_RECORDS);
|
|
766
|
+
const id = this.idProvider.idToString(memberId);
|
|
767
|
+
await col.deleteOne({ memberId: id });
|
|
768
|
+
}
|
|
769
|
+
async getBanRecord(memberId) {
|
|
770
|
+
const col = this.db.collection(COLLECTION_BAN_RECORDS);
|
|
771
|
+
const id = this.idProvider.idToString(memberId);
|
|
772
|
+
const doc = await col.findOne({ memberId: id });
|
|
773
|
+
if (!doc)
|
|
774
|
+
return null;
|
|
775
|
+
return this.deserializeBanRecord(doc.data);
|
|
776
|
+
}
|
|
777
|
+
async getAllBanRecords() {
|
|
778
|
+
const col = this.db.collection(COLLECTION_BAN_RECORDS);
|
|
779
|
+
const docs = await col.find({}).toArray();
|
|
780
|
+
return docs.map((doc) => this.deserializeBanRecord(doc.data));
|
|
781
|
+
}
|
|
782
|
+
async getMemberAdmissionProposerId(memberId) {
|
|
783
|
+
// Look up the ADD_MEMBER proposal that admitted this member.
|
|
784
|
+
// If no such proposal exists, the member is a founder.
|
|
785
|
+
const col = this.db.collection(COLLECTION_PROPOSALS);
|
|
786
|
+
const memberIdStr = this.idProvider.idToString(memberId);
|
|
787
|
+
const docs = await col
|
|
788
|
+
.find({})
|
|
789
|
+
.toArray();
|
|
790
|
+
for (const doc of docs) {
|
|
791
|
+
const data = doc.data;
|
|
792
|
+
if (data['actionType'] === 'ADD_MEMBER' &&
|
|
793
|
+
data['status'] === 'APPROVED') {
|
|
794
|
+
const payload = data['actionPayload'];
|
|
795
|
+
if (payload && payload['targetMemberId'] === memberIdStr) {
|
|
796
|
+
const proposerId = data['proposerMemberId'];
|
|
797
|
+
if (proposerId) {
|
|
798
|
+
return this.idProvider.idFromString(proposerId);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
deserializeBanRecord(data) {
|
|
806
|
+
const sigs = data['approvalSignatures'] ?? [];
|
|
807
|
+
return {
|
|
808
|
+
memberId: this.idProvider.idFromString(data['memberId']),
|
|
809
|
+
reason: data['reason'],
|
|
810
|
+
proposalId: this.idProvider.idFromString(data['proposalId']),
|
|
811
|
+
epoch: data['epoch'],
|
|
812
|
+
bannedAt: new Date(data['bannedAt']),
|
|
813
|
+
evidenceBlockIds: data['evidenceBlockIds'],
|
|
814
|
+
approvalSignatures: sigs.map((sig) => ({
|
|
815
|
+
memberId: this.idProvider.idFromString(sig.memberId),
|
|
816
|
+
signature: deserializeUint8Array(sig.signature),
|
|
817
|
+
})),
|
|
818
|
+
requiredSignatures: data['requiredSignatures'],
|
|
819
|
+
};
|
|
820
|
+
}
|
|
738
821
|
}
|
|
739
822
|
exports.QuorumDatabaseAdapter = QuorumDatabaseAdapter;
|
|
740
823
|
//# sourceMappingURL=quorumDatabaseAdapter.js.map
|