@brightchain/brightchain-api-lib 0.18.2 → 0.21.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.
Files changed (160) hide show
  1. package/package.json +8 -3
  2. package/src/index.d.ts +0 -1
  3. package/src/index.d.ts.map +1 -1
  4. package/src/index.js +0 -1
  5. package/src/index.js.map +1 -1
  6. package/src/lib/application.d.ts +12 -3
  7. package/src/lib/application.d.ts.map +1 -1
  8. package/src/lib/application.js +153 -7
  9. package/src/lib/application.js.map +1 -1
  10. package/src/lib/availability/gossipService.d.ts +59 -1
  11. package/src/lib/availability/gossipService.d.ts.map +1 -1
  12. package/src/lib/availability/gossipService.js +125 -1
  13. package/src/lib/availability/gossipService.js.map +1 -1
  14. package/src/lib/availability/index.d.ts +1 -0
  15. package/src/lib/availability/index.d.ts.map +1 -1
  16. package/src/lib/availability/index.js +1 -0
  17. package/src/lib/availability/index.js.map +1 -1
  18. package/src/lib/availability/quorumGossipHandler.d.ts +126 -0
  19. package/src/lib/availability/quorumGossipHandler.d.ts.map +1 -0
  20. package/src/lib/availability/quorumGossipHandler.js +246 -0
  21. package/src/lib/availability/quorumGossipHandler.js.map +1 -0
  22. package/src/lib/constants.d.ts.map +1 -1
  23. package/src/lib/constants.js +4 -0
  24. package/src/lib/constants.js.map +1 -1
  25. package/src/lib/controllers/api/quorum.d.ts +110 -2
  26. package/src/lib/controllers/api/quorum.d.ts.map +1 -1
  27. package/src/lib/controllers/api/quorum.js +389 -0
  28. package/src/lib/controllers/api/quorum.js.map +1 -1
  29. package/src/lib/controllers/api/user.d.ts +12 -15
  30. package/src/lib/controllers/api/user.d.ts.map +1 -1
  31. package/src/lib/controllers/api/user.js +312 -94
  32. package/src/lib/controllers/api/user.js.map +1 -1
  33. package/src/lib/databaseInit.d.ts +3 -2
  34. package/src/lib/databaseInit.d.ts.map +1 -1
  35. package/src/lib/databaseInit.js +24 -12
  36. package/src/lib/databaseInit.js.map +1 -1
  37. package/src/lib/datastore/index.d.ts +0 -1
  38. package/src/lib/datastore/index.d.ts.map +1 -1
  39. package/src/lib/datastore/index.js +0 -1
  40. package/src/lib/datastore/index.js.map +1 -1
  41. package/src/lib/environment.d.ts +6 -0
  42. package/src/lib/environment.d.ts.map +1 -1
  43. package/src/lib/environment.js +14 -0
  44. package/src/lib/environment.js.map +1 -1
  45. package/src/lib/hydration/energyAccountHydration.d.ts +17 -0
  46. package/src/lib/hydration/energyAccountHydration.d.ts.map +1 -0
  47. package/src/lib/hydration/energyAccountHydration.js +24 -0
  48. package/src/lib/hydration/energyAccountHydration.js.map +1 -0
  49. package/src/lib/hydration/index.d.ts +13 -0
  50. package/src/lib/hydration/index.d.ts.map +1 -0
  51. package/src/lib/hydration/index.js +21 -0
  52. package/src/lib/hydration/index.js.map +1 -0
  53. package/src/lib/hydration/rbacHydration.d.ts +28 -0
  54. package/src/lib/hydration/rbacHydration.d.ts.map +1 -0
  55. package/src/lib/hydration/rbacHydration.js +56 -0
  56. package/src/lib/hydration/rbacHydration.js.map +1 -0
  57. package/src/lib/interfaces/environment.d.ts +7 -1
  58. package/src/lib/interfaces/environment.d.ts.map +1 -1
  59. package/src/lib/interfaces/responses/api-backup-codes-response.d.ts +1 -1
  60. package/src/lib/interfaces/responses/api-code-count-response.d.ts +1 -1
  61. package/src/lib/interfaces/responses/api-password-change-response.d.ts +9 -0
  62. package/src/lib/interfaces/responses/api-password-change-response.d.ts.map +1 -0
  63. package/src/lib/interfaces/responses/api-password-change-response.js +3 -0
  64. package/src/lib/interfaces/responses/api-password-change-response.js.map +1 -0
  65. package/src/lib/interfaces/responses/api-recovery-response.d.ts +9 -0
  66. package/src/lib/interfaces/responses/api-recovery-response.d.ts.map +1 -0
  67. package/src/lib/interfaces/responses/api-recovery-response.js +3 -0
  68. package/src/lib/interfaces/responses/api-recovery-response.js.map +1 -0
  69. package/src/lib/interfaces/responses/index.d.ts +2 -0
  70. package/src/lib/interfaces/responses/index.d.ts.map +1 -1
  71. package/src/lib/interfaces/storage/client-session.d.ts +1 -1
  72. package/src/lib/interfaces/storage/client-session.d.ts.map +1 -1
  73. package/src/lib/interfaces/storage/collection.d.ts +1 -1
  74. package/src/lib/interfaces/storage/collection.d.ts.map +1 -1
  75. package/src/lib/interfaces/storage/database-lifecycle-hooks.d.ts +1 -1
  76. package/src/lib/interfaces/storage/database-lifecycle-hooks.d.ts.map +1 -1
  77. package/src/lib/interfaces/storage/database.d.ts +1 -1
  78. package/src/lib/interfaces/storage/database.d.ts.map +1 -1
  79. package/src/lib/interfaces/storage/document-types.d.ts +1 -1
  80. package/src/lib/interfaces/storage/document-types.d.ts.map +1 -1
  81. package/src/lib/interfaces/storage/index.d.ts +1 -0
  82. package/src/lib/interfaces/storage/index.d.ts.map +1 -1
  83. package/src/lib/interfaces/storage/index.js.map +1 -1
  84. package/src/lib/interfaces/storage/storedDocumentTypes.d.ts +73 -0
  85. package/src/lib/interfaces/storage/storedDocumentTypes.d.ts.map +1 -0
  86. package/src/lib/interfaces/storage/storedDocumentTypes.js +15 -0
  87. package/src/lib/interfaces/storage/storedDocumentTypes.js.map +1 -0
  88. package/src/lib/plugins/brightchain-database-plugin.d.ts +31 -21
  89. package/src/lib/plugins/brightchain-database-plugin.d.ts.map +1 -1
  90. package/src/lib/plugins/brightchain-database-plugin.js +103 -53
  91. package/src/lib/plugins/brightchain-database-plugin.js.map +1 -1
  92. package/src/lib/plugins/configure-brightchain-app.d.ts.map +1 -1
  93. package/src/lib/plugins/configure-brightchain-app.js +5 -0
  94. package/src/lib/plugins/configure-brightchain-app.js.map +1 -1
  95. package/src/lib/services/auth.d.ts +6 -2
  96. package/src/lib/services/auth.d.ts.map +1 -1
  97. package/src/lib/services/auth.js +43 -7
  98. package/src/lib/services/auth.js.map +1 -1
  99. package/src/lib/services/backupCodeService.d.ts +35 -0
  100. package/src/lib/services/backupCodeService.d.ts.map +1 -0
  101. package/src/lib/services/backupCodeService.js +109 -0
  102. package/src/lib/services/backupCodeService.js.map +1 -0
  103. package/src/lib/services/brightchain-authentication-provider.d.ts.map +1 -1
  104. package/src/lib/services/brightchain-authentication-provider.js +28 -9
  105. package/src/lib/services/brightchain-authentication-provider.js.map +1 -1
  106. package/src/lib/services/brightchain-member-init.service.d.ts +39 -20
  107. package/src/lib/services/brightchain-member-init.service.d.ts.map +1 -1
  108. package/src/lib/services/brightchain-member-init.service.js +139 -53
  109. package/src/lib/services/brightchain-member-init.service.js.map +1 -1
  110. package/src/lib/services/cliOperatorPrompt.d.ts +81 -0
  111. package/src/lib/services/cliOperatorPrompt.d.ts.map +1 -0
  112. package/src/lib/services/cliOperatorPrompt.js +177 -0
  113. package/src/lib/services/cliOperatorPrompt.js.map +1 -0
  114. package/src/lib/services/contentAwareBlocksService.d.ts +92 -0
  115. package/src/lib/services/contentAwareBlocksService.d.ts.map +1 -0
  116. package/src/lib/services/contentAwareBlocksService.js +102 -0
  117. package/src/lib/services/contentAwareBlocksService.js.map +1 -0
  118. package/src/lib/services/contentIngestionService.d.ts +68 -0
  119. package/src/lib/services/contentIngestionService.d.ts.map +1 -0
  120. package/src/lib/services/contentIngestionService.js +139 -0
  121. package/src/lib/services/contentIngestionService.js.map +1 -0
  122. package/src/lib/services/identityExpirationScheduler.d.ts +77 -0
  123. package/src/lib/services/identityExpirationScheduler.d.ts.map +1 -0
  124. package/src/lib/services/identityExpirationScheduler.js +157 -0
  125. package/src/lib/services/identityExpirationScheduler.js.map +1 -0
  126. package/src/lib/services/index.d.ts +7 -0
  127. package/src/lib/services/index.d.ts.map +1 -1
  128. package/src/lib/services/index.js +7 -0
  129. package/src/lib/services/index.js.map +1 -1
  130. package/src/lib/services/quorumDatabaseAdapter.d.ts +60 -0
  131. package/src/lib/services/quorumDatabaseAdapter.d.ts.map +1 -0
  132. package/src/lib/services/quorumDatabaseAdapter.js +652 -0
  133. package/src/lib/services/quorumDatabaseAdapter.js.map +1 -0
  134. package/src/lib/services/secureKeyStorage.js +3 -3
  135. package/src/lib/services/secureKeyStorage.js.map +1 -1
  136. package/src/lib/services/sessionAdapter.d.ts +62 -0
  137. package/src/lib/services/sessionAdapter.d.ts.map +1 -0
  138. package/src/lib/services/sessionAdapter.js +105 -0
  139. package/src/lib/services/sessionAdapter.js.map +1 -0
  140. package/src/lib/utils/rehydration.d.ts +31 -0
  141. package/src/lib/utils/rehydration.d.ts.map +1 -0
  142. package/src/lib/utils/rehydration.js +111 -0
  143. package/src/lib/utils/rehydration.js.map +1 -0
  144. package/src/lib/utils/serialization.d.ts +21 -0
  145. package/src/lib/utils/serialization.d.ts.map +1 -0
  146. package/src/lib/utils/serialization.js +41 -0
  147. package/src/lib/utils/serialization.js.map +1 -0
  148. package/src/lib/validation/userValidation.d.ts +17 -0
  149. package/src/lib/validation/userValidation.d.ts.map +1 -1
  150. package/src/lib/validation/userValidation.js +77 -0
  151. package/src/lib/validation/userValidation.js.map +1 -1
  152. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.d.ts +0 -24
  153. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.d.ts.map +0 -1
  154. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.js +0 -53
  155. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.js.map +0 -1
  156. package/src/lib/datastore/document-model-adapter.d.ts +0 -48
  157. package/src/lib/datastore/document-model-adapter.d.ts.map +0 -1
  158. package/src/lib/datastore/document-model-adapter.js +0 -178
  159. package/src/lib/datastore/document-model-adapter.js.map +0 -1
  160. /package/{brightchain-api-lib/README.md → README.md} +0 -0
@@ -0,0 +1,652 @@
1
+ "use strict";
2
+ /**
3
+ * QuorumDatabaseAdapter — BrightChainDb-backed implementation of IQuorumDatabase.
4
+ *
5
+ * Uses a dedicated BrightChainDb instance with pool ID "quorum-system" for
6
+ * isolated storage of all quorum-related data. Each data type is stored in
7
+ * a separate collection.
8
+ *
9
+ * This is a Node.js-specific service that lives in brightchain-api-lib.
10
+ *
11
+ * @see Requirements 9, 10
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.QuorumDatabaseAdapter = exports.QUORUM_SYSTEM_POOL_ID = void 0;
15
+ // ─── Collection Names ───────────────────────────────────────────────────────
16
+ const COLLECTION_EPOCHS = 'epochs';
17
+ const COLLECTION_MEMBERS = 'members';
18
+ const COLLECTION_DOCUMENTS = 'documents';
19
+ const COLLECTION_PROPOSALS = 'proposals';
20
+ const COLLECTION_VOTES = 'votes';
21
+ const COLLECTION_IDENTITY_RECORDS = 'identity_records';
22
+ const COLLECTION_ALIASES = 'aliases';
23
+ const COLLECTION_AUDIT_LOG = 'audit_log';
24
+ const COLLECTION_REDISTRIBUTION_JOURNAL = 'redistribution_journal';
25
+ const COLLECTION_STATUTE_CONFIG = 'statute_config';
26
+ const COLLECTION_OPERATIONAL_STATE = 'operational_state';
27
+ /** Dedicated pool ID for quorum data isolation */
28
+ exports.QUORUM_SYSTEM_POOL_ID = 'quorum-system';
29
+ // ─── Serialization Helpers ──────────────────────────────────────────────────
30
+ function serializeMap(map) {
31
+ const result = {};
32
+ for (const [key, value] of map.entries()) {
33
+ result[key] = Buffer.from(value).toString('base64');
34
+ }
35
+ return result;
36
+ }
37
+ function deserializeMap(obj) {
38
+ const map = new Map();
39
+ for (const [key, value] of Object.entries(obj)) {
40
+ map.set(key, Buffer.from(value, 'base64'));
41
+ }
42
+ return map;
43
+ }
44
+ function serializeDurationsMap(map) {
45
+ const result = {};
46
+ for (const [key, value] of map.entries()) {
47
+ result[key] = value;
48
+ }
49
+ return result;
50
+ }
51
+ function deserializeDurationsMap(obj) {
52
+ const map = new Map();
53
+ for (const [key, value] of Object.entries(obj)) {
54
+ map.set(key, value);
55
+ }
56
+ return map;
57
+ }
58
+ function serializeUint8Array(arr) {
59
+ return Buffer.from(arr).toString('base64');
60
+ }
61
+ function deserializeUint8Array(str) {
62
+ return new Uint8Array(Buffer.from(str, 'base64'));
63
+ }
64
+ // ─── Epoch Serialization ────────────────────────────────────────────────────
65
+ function serializeEpoch(epoch) {
66
+ return {
67
+ epochNumber: epoch.epochNumber,
68
+ memberIds: epoch.memberIds,
69
+ threshold: epoch.threshold,
70
+ mode: epoch.mode,
71
+ createdAt: epoch.createdAt.toISOString(),
72
+ previousEpochNumber: epoch.previousEpochNumber,
73
+ innerQuorumMemberIds: epoch.innerQuorumMemberIds,
74
+ };
75
+ }
76
+ function deserializeEpoch(data) {
77
+ return {
78
+ epochNumber: data['epochNumber'],
79
+ memberIds: data['memberIds'],
80
+ threshold: data['threshold'],
81
+ mode: data['mode'],
82
+ createdAt: new Date(data['createdAt']),
83
+ previousEpochNumber: data['previousEpochNumber'],
84
+ innerQuorumMemberIds: data['innerQuorumMemberIds'],
85
+ };
86
+ }
87
+ // ─── Member Serialization ───────────────────────────────────────────────────
88
+ function serializeMember(member) {
89
+ return {
90
+ id: member.id,
91
+ publicKey: serializeUint8Array(member.publicKey),
92
+ metadata: member.metadata,
93
+ isActive: member.isActive,
94
+ createdAt: member.createdAt.toISOString(),
95
+ updatedAt: member.updatedAt.toISOString(),
96
+ };
97
+ }
98
+ function deserializeMember(data) {
99
+ return {
100
+ id: data['id'],
101
+ publicKey: deserializeUint8Array(data['publicKey']),
102
+ metadata: data['metadata'],
103
+ isActive: data['isActive'],
104
+ createdAt: new Date(data['createdAt']),
105
+ updatedAt: new Date(data['updatedAt']),
106
+ };
107
+ }
108
+ // ─── Proposal Serialization ─────────────────────────────────────────────────
109
+ function serializeProposal(proposal) {
110
+ return {
111
+ id: proposal.id,
112
+ description: proposal.description,
113
+ actionType: proposal.actionType,
114
+ actionPayload: proposal.actionPayload,
115
+ proposerMemberId: proposal.proposerMemberId,
116
+ status: proposal.status,
117
+ requiredThreshold: proposal.requiredThreshold,
118
+ expiresAt: proposal.expiresAt.toISOString(),
119
+ createdAt: proposal.createdAt.toISOString(),
120
+ attachmentCblId: proposal.attachmentCblId,
121
+ epochNumber: proposal.epochNumber,
122
+ };
123
+ }
124
+ function deserializeProposal(data) {
125
+ return {
126
+ id: data['id'],
127
+ description: data['description'],
128
+ actionType: data['actionType'],
129
+ actionPayload: data['actionPayload'],
130
+ proposerMemberId: data['proposerMemberId'],
131
+ status: data['status'],
132
+ requiredThreshold: data['requiredThreshold'],
133
+ expiresAt: new Date(data['expiresAt']),
134
+ createdAt: new Date(data['createdAt']),
135
+ attachmentCblId: data['attachmentCblId'],
136
+ epochNumber: data['epochNumber'],
137
+ };
138
+ }
139
+ // ─── Vote Serialization ─────────────────────────────────────────────────────
140
+ function serializeVote(vote) {
141
+ return {
142
+ proposalId: vote.proposalId,
143
+ voterMemberId: vote.voterMemberId,
144
+ decision: vote.decision,
145
+ comment: vote.comment,
146
+ encryptedShare: vote.encryptedShare
147
+ ? serializeUint8Array(vote.encryptedShare)
148
+ : undefined,
149
+ createdAt: vote.createdAt.toISOString(),
150
+ };
151
+ }
152
+ function deserializeVote(data) {
153
+ return {
154
+ proposalId: data['proposalId'],
155
+ voterMemberId: data['voterMemberId'],
156
+ decision: data['decision'],
157
+ comment: data['comment'],
158
+ encryptedShare: data['encryptedShare']
159
+ ? deserializeUint8Array(data['encryptedShare'])
160
+ : undefined,
161
+ createdAt: new Date(data['createdAt']),
162
+ };
163
+ }
164
+ // ─── IdentityRecoveryRecord Serialization ───────────────────────────────────
165
+ function serializeIdentityRecord(record) {
166
+ return {
167
+ id: record.id,
168
+ contentId: record.contentId,
169
+ contentType: record.contentType,
170
+ encryptedShardsByMemberId: serializeMap(record.encryptedShardsByMemberId),
171
+ memberIds: record.memberIds,
172
+ threshold: record.threshold,
173
+ epochNumber: record.epochNumber,
174
+ expiresAt: record.expiresAt.toISOString(),
175
+ createdAt: record.createdAt.toISOString(),
176
+ identityMode: record.identityMode,
177
+ aliasName: record.aliasName,
178
+ };
179
+ }
180
+ function deserializeIdentityRecord(data) {
181
+ return {
182
+ id: data['id'],
183
+ contentId: data['contentId'],
184
+ contentType: data['contentType'],
185
+ encryptedShardsByMemberId: deserializeMap(data['encryptedShardsByMemberId']),
186
+ memberIds: data['memberIds'],
187
+ threshold: data['threshold'],
188
+ epochNumber: data['epochNumber'],
189
+ expiresAt: new Date(data['expiresAt']),
190
+ createdAt: new Date(data['createdAt']),
191
+ identityMode: data['identityMode'],
192
+ aliasName: data['aliasName'],
193
+ };
194
+ }
195
+ // ─── AliasRecord Serialization ──────────────────────────────────────────────
196
+ function serializeAlias(alias) {
197
+ return {
198
+ aliasName: alias.aliasName,
199
+ ownerMemberId: alias.ownerMemberId,
200
+ aliasPublicKey: serializeUint8Array(alias.aliasPublicKey),
201
+ identityRecoveryRecordId: alias.identityRecoveryRecordId,
202
+ isActive: alias.isActive,
203
+ registeredAt: alias.registeredAt.toISOString(),
204
+ deactivatedAt: alias.deactivatedAt?.toISOString(),
205
+ epochNumber: alias.epochNumber,
206
+ };
207
+ }
208
+ function deserializeAlias(data) {
209
+ return {
210
+ aliasName: data['aliasName'],
211
+ ownerMemberId: data['ownerMemberId'],
212
+ aliasPublicKey: deserializeUint8Array(data['aliasPublicKey']),
213
+ identityRecoveryRecordId: data['identityRecoveryRecordId'],
214
+ isActive: data['isActive'],
215
+ registeredAt: new Date(data['registeredAt']),
216
+ deactivatedAt: data['deactivatedAt']
217
+ ? new Date(data['deactivatedAt'])
218
+ : undefined,
219
+ epochNumber: data['epochNumber'],
220
+ };
221
+ }
222
+ // ─── AuditLogEntry Serialization ────────────────────────────────────────────
223
+ function serializeAuditEntry(entry) {
224
+ const base = {
225
+ id: entry.id,
226
+ eventType: entry.eventType,
227
+ proposalId: entry.proposalId,
228
+ targetMemberId: entry.targetMemberId,
229
+ proposerMemberId: entry.proposerMemberId,
230
+ attachmentCblId: entry.attachmentCblId,
231
+ details: entry.details,
232
+ timestamp: entry.timestamp.toISOString(),
233
+ };
234
+ // If this is a ChainedAuditLogEntry, also serialize chain fields
235
+ const chained = entry;
236
+ if (chained.contentHash !== undefined) {
237
+ base['previousEntryHash'] = chained.previousEntryHash;
238
+ base['contentHash'] = chained.contentHash;
239
+ base['signature'] = chained.signature
240
+ ? serializeUint8Array(chained.signature)
241
+ : undefined;
242
+ base['blockId1'] = chained.blockId1;
243
+ base['blockId2'] = chained.blockId2;
244
+ }
245
+ return base;
246
+ }
247
+ function deserializeChainedAuditEntry(data) {
248
+ return {
249
+ id: data['id'],
250
+ eventType: data['eventType'],
251
+ proposalId: data['proposalId'],
252
+ targetMemberId: data['targetMemberId'],
253
+ proposerMemberId: data['proposerMemberId'],
254
+ attachmentCblId: data['attachmentCblId'],
255
+ details: data['details'],
256
+ timestamp: new Date(data['timestamp']),
257
+ previousEntryHash: data['previousEntryHash'] ?? null,
258
+ contentHash: data['contentHash'] ?? '',
259
+ signature: (data['signature']
260
+ ? deserializeUint8Array(data['signature'])
261
+ : new Uint8Array(0)),
262
+ blockId1: data['blockId1'] ?? '',
263
+ blockId2: data['blockId2'] ?? '',
264
+ };
265
+ }
266
+ // ─── RedistributionJournalEntry Serialization ───────────────────────────────
267
+ function serializeJournalEntry(entry) {
268
+ return {
269
+ documentId: entry.documentId,
270
+ oldShares: serializeMap(entry.oldShares),
271
+ oldMemberIds: entry.oldMemberIds,
272
+ oldThreshold: entry.oldThreshold,
273
+ oldEpoch: entry.oldEpoch,
274
+ };
275
+ }
276
+ function deserializeJournalEntry(data) {
277
+ return {
278
+ documentId: data['documentId'],
279
+ oldShares: deserializeMap(data['oldShares']),
280
+ oldMemberIds: data['oldMemberIds'],
281
+ oldThreshold: data['oldThreshold'],
282
+ oldEpoch: data['oldEpoch'],
283
+ };
284
+ }
285
+ // ─── StatuteOfLimitationsConfig Serialization ───────────────────────────────
286
+ function serializeStatuteConfig(config) {
287
+ return {
288
+ defaultDurations: serializeDurationsMap(config.defaultDurations),
289
+ fallbackDurationMs: config.fallbackDurationMs,
290
+ };
291
+ }
292
+ function deserializeStatuteConfig(data) {
293
+ return {
294
+ defaultDurations: deserializeDurationsMap(data['defaultDurations']),
295
+ fallbackDurationMs: data['fallbackDurationMs'],
296
+ };
297
+ }
298
+ // ─── OperationalState Serialization ─────────────────────────────────────────
299
+ function serializeOperationalState(state) {
300
+ return {
301
+ mode: state.mode,
302
+ currentEpochNumber: state.currentEpochNumber,
303
+ lastUpdated: state.lastUpdated.toISOString(),
304
+ };
305
+ }
306
+ function deserializeOperationalState(data) {
307
+ return {
308
+ mode: data['mode'],
309
+ currentEpochNumber: data['currentEpochNumber'],
310
+ lastUpdated: new Date(data['lastUpdated']),
311
+ };
312
+ }
313
+ // ─── QuorumDatabaseAdapter ──────────────────────────────────────────────────
314
+ /**
315
+ * BrightChainDb-backed implementation of IQuorumDatabase.
316
+ *
317
+ * Uses a dedicated pool ID ("quorum-system") for isolated storage.
318
+ * Each data type is stored in a separate collection.
319
+ *
320
+ * @template TID - Platform ID type for frontend/backend DTO compatibility
321
+ */
322
+ class QuorumDatabaseAdapter {
323
+ constructor(db) {
324
+ this.db = db;
325
+ }
326
+ // === Epoch Management ===
327
+ async saveEpoch(epoch) {
328
+ const col = this.db.collection(COLLECTION_EPOCHS);
329
+ const existing = await col.findOne({
330
+ epochNumber: epoch.epochNumber,
331
+ });
332
+ if (existing) {
333
+ await col.updateOne({ epochNumber: epoch.epochNumber }, { $set: { data: serializeEpoch(epoch) } });
334
+ }
335
+ else {
336
+ await col.insertOne({
337
+ epochNumber: epoch.epochNumber,
338
+ data: serializeEpoch(epoch),
339
+ });
340
+ }
341
+ }
342
+ async getEpoch(epochNumber) {
343
+ const col = this.db.collection(COLLECTION_EPOCHS);
344
+ const doc = await col.findOne({ epochNumber });
345
+ if (!doc)
346
+ return null;
347
+ return deserializeEpoch(doc.data);
348
+ }
349
+ async getCurrentEpoch() {
350
+ const col = this.db.collection(COLLECTION_EPOCHS);
351
+ const docs = await col
352
+ .find({})
353
+ .sort({ epochNumber: -1 })
354
+ .limit(1)
355
+ .toArray();
356
+ if (docs.length === 0) {
357
+ throw new Error('No epochs found in quorum database');
358
+ }
359
+ return deserializeEpoch(docs[0].data);
360
+ }
361
+ // === Member Management ===
362
+ async saveMember(member) {
363
+ const col = this.db.collection(COLLECTION_MEMBERS);
364
+ const existing = await col.findOne({ memberId: member.id });
365
+ if (existing) {
366
+ await col.updateOne({ memberId: member.id }, {
367
+ $set: {
368
+ isActive: member.isActive,
369
+ data: serializeMember(member),
370
+ },
371
+ });
372
+ }
373
+ else {
374
+ await col.insertOne({
375
+ memberId: member.id,
376
+ isActive: member.isActive,
377
+ data: serializeMember(member),
378
+ });
379
+ }
380
+ }
381
+ async getMember(memberId) {
382
+ const col = this.db.collection(COLLECTION_MEMBERS);
383
+ const doc = await col.findOne({ memberId });
384
+ if (!doc)
385
+ return null;
386
+ return deserializeMember(doc.data);
387
+ }
388
+ async listActiveMembers() {
389
+ const col = this.db.collection(COLLECTION_MEMBERS);
390
+ const docs = await col.find({ isActive: true }).toArray();
391
+ return docs.map((doc) => deserializeMember(doc.data));
392
+ }
393
+ // === Sealed Documents ===
394
+ async saveDocument(doc) {
395
+ const col = this.db.collection(COLLECTION_DOCUMENTS);
396
+ const dto = doc.toDto();
397
+ const docId = dto.id;
398
+ const existing = await col.findOne({ docId });
399
+ if (existing) {
400
+ await col.updateOne({ docId }, {
401
+ $set: {
402
+ epochNumber: dto.epochNumber,
403
+ data: dto,
404
+ },
405
+ });
406
+ }
407
+ else {
408
+ await col.insertOne({
409
+ docId,
410
+ epochNumber: dto.epochNumber,
411
+ data: dto,
412
+ });
413
+ }
414
+ }
415
+ async getDocument(docId) {
416
+ const col = this.db.collection(COLLECTION_DOCUMENTS);
417
+ const doc = await col.findOne({ docId });
418
+ if (!doc)
419
+ return null;
420
+ // Return the stored DTO data — callers use QuorumDataRecord.fromDto
421
+ // to reconstruct the full object with crypto services.
422
+ return doc.data;
423
+ }
424
+ async listDocumentsByEpoch(epochNumber, page, pageSize) {
425
+ const col = this.db.collection(COLLECTION_DOCUMENTS);
426
+ const docs = await col
427
+ .find({ epochNumber })
428
+ .skip(page * pageSize)
429
+ .limit(pageSize)
430
+ .toArray();
431
+ return docs.map((d) => d.data);
432
+ }
433
+ // === Proposals and Votes ===
434
+ async saveProposal(proposal) {
435
+ const col = this.db.collection(COLLECTION_PROPOSALS);
436
+ const existing = await col.findOne({ proposalId: proposal.id });
437
+ if (existing) {
438
+ await col.updateOne({ proposalId: proposal.id }, { $set: { data: serializeProposal(proposal) } });
439
+ }
440
+ else {
441
+ await col.insertOne({
442
+ proposalId: proposal.id,
443
+ data: serializeProposal(proposal),
444
+ });
445
+ }
446
+ }
447
+ async getProposal(proposalId) {
448
+ const col = this.db.collection(COLLECTION_PROPOSALS);
449
+ const doc = await col.findOne({ proposalId });
450
+ if (!doc)
451
+ return null;
452
+ return deserializeProposal(doc.data);
453
+ }
454
+ async saveVote(vote) {
455
+ const col = this.db.collection(COLLECTION_VOTES);
456
+ const existing = await col.findOne({
457
+ proposalId: vote.proposalId,
458
+ voterMemberId: vote.voterMemberId,
459
+ });
460
+ if (existing) {
461
+ await col.updateOne({
462
+ proposalId: vote.proposalId,
463
+ voterMemberId: vote.voterMemberId,
464
+ }, { $set: { data: serializeVote(vote) } });
465
+ }
466
+ else {
467
+ await col.insertOne({
468
+ proposalId: vote.proposalId,
469
+ voterMemberId: vote.voterMemberId,
470
+ data: serializeVote(vote),
471
+ });
472
+ }
473
+ }
474
+ async getVotesForProposal(proposalId) {
475
+ const col = this.db.collection(COLLECTION_VOTES);
476
+ const docs = await col.find({ proposalId }).toArray();
477
+ return docs.map((d) => deserializeVote(d.data));
478
+ }
479
+ // === Identity Recovery Records ===
480
+ async saveIdentityRecord(record) {
481
+ const col = this.db.collection(COLLECTION_IDENTITY_RECORDS);
482
+ const existing = await col.findOne({ recordId: record.id });
483
+ if (existing) {
484
+ await col.updateOne({ recordId: record.id }, {
485
+ $set: {
486
+ expiresAt: record.expiresAt.toISOString(),
487
+ data: serializeIdentityRecord(record),
488
+ },
489
+ });
490
+ }
491
+ else {
492
+ await col.insertOne({
493
+ recordId: record.id,
494
+ expiresAt: record.expiresAt.toISOString(),
495
+ data: serializeIdentityRecord(record),
496
+ });
497
+ }
498
+ }
499
+ async getIdentityRecord(recordId) {
500
+ const col = this.db.collection(COLLECTION_IDENTITY_RECORDS);
501
+ const doc = await col.findOne({ recordId });
502
+ if (!doc)
503
+ return null;
504
+ return deserializeIdentityRecord(doc.data);
505
+ }
506
+ async deleteIdentityRecord(recordId) {
507
+ const col = this.db.collection(COLLECTION_IDENTITY_RECORDS);
508
+ await col.deleteOne({ recordId });
509
+ }
510
+ async listExpiredIdentityRecords(before, page, pageSize) {
511
+ const col = this.db.collection(COLLECTION_IDENTITY_RECORDS);
512
+ // Fetch all records and filter in-memory since the collection
513
+ // doesn't support $lt on ISO string fields natively.
514
+ const allDocs = await col.find({}).toArray();
515
+ const beforeIso = before.toISOString();
516
+ const expired = allDocs
517
+ .filter((d) => d.expiresAt < beforeIso)
518
+ .sort((a, b) => a.expiresAt.localeCompare(b.expiresAt));
519
+ const start = page * pageSize;
520
+ const paged = expired.slice(start, start + pageSize);
521
+ return paged.map((d) => deserializeIdentityRecord(d.data));
522
+ }
523
+ // === Alias Registry ===
524
+ async saveAlias(alias) {
525
+ const col = this.db.collection(COLLECTION_ALIASES);
526
+ const existing = await col.findOne({ aliasName: alias.aliasName });
527
+ if (existing) {
528
+ await col.updateOne({ aliasName: alias.aliasName }, {
529
+ $set: {
530
+ isActive: alias.isActive,
531
+ data: serializeAlias(alias),
532
+ },
533
+ });
534
+ }
535
+ else {
536
+ await col.insertOne({
537
+ aliasName: alias.aliasName,
538
+ isActive: alias.isActive,
539
+ data: serializeAlias(alias),
540
+ });
541
+ }
542
+ }
543
+ async getAlias(aliasName) {
544
+ const col = this.db.collection(COLLECTION_ALIASES);
545
+ const doc = await col.findOne({ aliasName });
546
+ if (!doc)
547
+ return null;
548
+ return deserializeAlias(doc.data);
549
+ }
550
+ async isAliasAvailable(aliasName) {
551
+ const col = this.db.collection(COLLECTION_ALIASES);
552
+ const doc = await col.findOne({ aliasName });
553
+ // Available if no record exists or the existing record is inactive
554
+ return doc === null || !doc.isActive;
555
+ }
556
+ // === Audit Log ===
557
+ async appendAuditEntry(entry) {
558
+ const col = this.db.collection(COLLECTION_AUDIT_LOG);
559
+ await col.insertOne({
560
+ entryId: entry.id,
561
+ timestamp: entry.timestamp.toISOString(),
562
+ data: serializeAuditEntry(entry),
563
+ });
564
+ }
565
+ async getLatestAuditEntry() {
566
+ const col = this.db.collection(COLLECTION_AUDIT_LOG);
567
+ const docs = await col.find({}).sort({ timestamp: -1 }).limit(1).toArray();
568
+ if (docs.length === 0)
569
+ return null;
570
+ return deserializeChainedAuditEntry(docs[0].data);
571
+ }
572
+ // === Redistribution Journal ===
573
+ async saveJournalEntry(entry) {
574
+ const col = this.db.collection(COLLECTION_REDISTRIBUTION_JOURNAL);
575
+ await col.insertOne({
576
+ documentId: entry.documentId,
577
+ oldEpoch: entry.oldEpoch,
578
+ data: serializeJournalEntry(entry),
579
+ });
580
+ }
581
+ async getJournalEntries(epochNumber) {
582
+ const col = this.db.collection(COLLECTION_REDISTRIBUTION_JOURNAL);
583
+ const docs = await col.find({ oldEpoch: epochNumber }).toArray();
584
+ return docs.map((d) => deserializeJournalEntry(d.data));
585
+ }
586
+ async deleteJournalEntries(epochNumber) {
587
+ const col = this.db.collection(COLLECTION_REDISTRIBUTION_JOURNAL);
588
+ await col.deleteMany({ oldEpoch: epochNumber });
589
+ }
590
+ // === Statute of Limitations Configuration ===
591
+ async saveStatuteConfig(config) {
592
+ const col = this.db.collection(COLLECTION_STATUTE_CONFIG);
593
+ const existing = await col.findOne({ key: 'statute_config' });
594
+ if (existing) {
595
+ await col.updateOne({ key: 'statute_config' }, { $set: { data: serializeStatuteConfig(config) } });
596
+ }
597
+ else {
598
+ await col.insertOne({
599
+ key: 'statute_config',
600
+ data: serializeStatuteConfig(config),
601
+ });
602
+ }
603
+ }
604
+ async getStatuteConfig() {
605
+ const col = this.db.collection(COLLECTION_STATUTE_CONFIG);
606
+ const doc = await col.findOne({ key: 'statute_config' });
607
+ if (!doc)
608
+ return null;
609
+ return deserializeStatuteConfig(doc.data);
610
+ }
611
+ // === Operational State ===
612
+ async saveOperationalState(state) {
613
+ const col = this.db.collection(COLLECTION_OPERATIONAL_STATE);
614
+ const existing = await col.findOne({ key: 'operational_state' });
615
+ if (existing) {
616
+ await col.updateOne({ key: 'operational_state' }, { $set: { data: serializeOperationalState(state) } });
617
+ }
618
+ else {
619
+ await col.insertOne({
620
+ key: 'operational_state',
621
+ data: serializeOperationalState(state),
622
+ });
623
+ }
624
+ }
625
+ async getOperationalState() {
626
+ const col = this.db.collection(COLLECTION_OPERATIONAL_STATE);
627
+ const doc = await col.findOne({ key: 'operational_state' });
628
+ if (!doc)
629
+ return null;
630
+ return deserializeOperationalState(doc.data);
631
+ }
632
+ // === Transactions ===
633
+ async withTransaction(fn) {
634
+ return this.db.withTransaction(async () => {
635
+ return fn();
636
+ });
637
+ }
638
+ // === Health Check ===
639
+ async isAvailable() {
640
+ try {
641
+ // Try a simple operation to verify the database is accessible
642
+ const col = this.db.collection(COLLECTION_OPERATIONAL_STATE);
643
+ await col.estimatedDocumentCount();
644
+ return true;
645
+ }
646
+ catch {
647
+ return false;
648
+ }
649
+ }
650
+ }
651
+ exports.QuorumDatabaseAdapter = QuorumDatabaseAdapter;
652
+ //# sourceMappingURL=quorumDatabaseAdapter.js.map