@brightchain/brightchain-api-lib 0.15.0 → 0.17.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 (315) hide show
  1. package/package.json +4 -4
  2. package/src/browser.d.ts +13 -0
  3. package/src/browser.d.ts.map +1 -0
  4. package/src/browser.js +16 -0
  5. package/src/browser.js.map +1 -0
  6. package/src/index.d.ts +5 -1
  7. package/src/index.d.ts.map +1 -1
  8. package/src/index.js +7 -1
  9. package/src/index.js.map +1 -1
  10. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.d.ts +24 -0
  11. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.d.ts.map +1 -0
  12. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.js +53 -0
  13. package/src/lib/adapters/brightChainDbDocumentStoreAdapter.js.map +1 -0
  14. package/src/lib/application-base.d.ts +8 -37
  15. package/src/lib/application-base.d.ts.map +1 -1
  16. package/src/lib/application-base.js +8 -80
  17. package/src/lib/application-base.js.map +1 -1
  18. package/src/lib/application.d.ts +56 -7
  19. package/src/lib/application.d.ts.map +1 -1
  20. package/src/lib/application.js +169 -134
  21. package/src/lib/application.js.map +1 -1
  22. package/src/lib/availability/gossipService.d.ts +20 -1
  23. package/src/lib/availability/gossipService.d.ts.map +1 -1
  24. package/src/lib/availability/gossipService.js +59 -0
  25. package/src/lib/availability/gossipService.js.map +1 -1
  26. package/src/lib/availability/index.d.ts +1 -0
  27. package/src/lib/availability/index.d.ts.map +1 -1
  28. package/src/lib/availability/index.js +1 -0
  29. package/src/lib/availability/index.js.map +1 -1
  30. package/src/lib/availability/poolDiscoveryService.d.ts +117 -0
  31. package/src/lib/availability/poolDiscoveryService.d.ts.map +1 -0
  32. package/src/lib/availability/poolDiscoveryService.js +218 -0
  33. package/src/lib/availability/poolDiscoveryService.js.map +1 -0
  34. package/src/lib/blockFetch/httpBlockFetchTransport.d.ts.map +1 -1
  35. package/src/lib/blockFetch/httpBlockFetchTransport.js.map +1 -1
  36. package/src/lib/constants.js +2 -2
  37. package/src/lib/constants.js.map +1 -1
  38. package/src/lib/controllers/api/blocks.d.ts.map +1 -1
  39. package/src/lib/controllers/api/blocks.js +290 -290
  40. package/src/lib/controllers/api/blocks.js.map +1 -1
  41. package/src/lib/controllers/api/brightpass.d.ts.map +1 -1
  42. package/src/lib/controllers/api/brightpass.js +270 -274
  43. package/src/lib/controllers/api/brightpass.js.map +1 -1
  44. package/src/lib/controllers/api/energy.d.ts.map +1 -1
  45. package/src/lib/controllers/api/energy.js +93 -93
  46. package/src/lib/controllers/api/energy.js.map +1 -1
  47. package/src/lib/controllers/api/health.d.ts +4 -4
  48. package/src/lib/controllers/api/health.d.ts.map +1 -1
  49. package/src/lib/controllers/api/health.js.map +1 -1
  50. package/src/lib/controllers/api/i18n.d.ts.map +1 -1
  51. package/src/lib/controllers/api/i18n.js +8 -8
  52. package/src/lib/controllers/api/i18n.js.map +1 -1
  53. package/src/lib/controllers/api/index.d.ts +1 -0
  54. package/src/lib/controllers/api/index.d.ts.map +1 -1
  55. package/src/lib/controllers/api/index.js +1 -0
  56. package/src/lib/controllers/api/index.js.map +1 -1
  57. package/src/lib/controllers/api/introspection.d.ts +60 -0
  58. package/src/lib/controllers/api/introspection.d.ts.map +1 -0
  59. package/src/lib/controllers/api/introspection.js +375 -0
  60. package/src/lib/controllers/api/introspection.js.map +1 -0
  61. package/src/lib/controllers/api/nodes.d.ts +7 -6
  62. package/src/lib/controllers/api/nodes.d.ts.map +1 -1
  63. package/src/lib/controllers/api/nodes.js.map +1 -1
  64. package/src/lib/controllers/api/quorum.d.ts.map +1 -1
  65. package/src/lib/controllers/api/quorum.js +483 -483
  66. package/src/lib/controllers/api/quorum.js.map +1 -1
  67. package/src/lib/controllers/api/sessions.d.ts.map +1 -1
  68. package/src/lib/controllers/api/sessions.js +8 -8
  69. package/src/lib/controllers/api/sessions.js.map +1 -1
  70. package/src/lib/controllers/api/sync.d.ts +6 -5
  71. package/src/lib/controllers/api/sync.d.ts.map +1 -1
  72. package/src/lib/controllers/api/sync.js.map +1 -1
  73. package/src/lib/controllers/api/user.d.ts.map +1 -1
  74. package/src/lib/controllers/api/user.js +260 -180
  75. package/src/lib/controllers/api/user.js.map +1 -1
  76. package/src/lib/controllers/base.d.ts +1 -2
  77. package/src/lib/controllers/base.d.ts.map +1 -1
  78. package/src/lib/controllers/base.js +0 -1
  79. package/src/lib/controllers/base.js.map +1 -1
  80. package/src/lib/databaseInit.d.ts +28 -0
  81. package/src/lib/databaseInit.d.ts.map +1 -0
  82. package/src/lib/databaseInit.js +107 -0
  83. package/src/lib/databaseInit.js.map +1 -0
  84. package/src/lib/enumerations/brightChainApiStrings.d.ts +4 -0
  85. package/src/lib/enumerations/brightChainApiStrings.d.ts.map +1 -1
  86. package/src/lib/enumerations/brightChainApiStrings.js +4 -0
  87. package/src/lib/enumerations/brightChainApiStrings.js.map +1 -1
  88. package/src/lib/enumerations/index.d.ts +1 -0
  89. package/src/lib/enumerations/index.d.ts.map +1 -1
  90. package/src/lib/enumerations/index.js +1 -0
  91. package/src/lib/enumerations/index.js.map +1 -1
  92. package/src/lib/enumerations/websocketMessageType.d.ts +5 -1
  93. package/src/lib/enumerations/websocketMessageType.d.ts.map +1 -1
  94. package/src/lib/enumerations/websocketMessageType.js +4 -0
  95. package/src/lib/enumerations/websocketMessageType.js.map +1 -1
  96. package/src/lib/environment.d.ts +5 -0
  97. package/src/lib/environment.d.ts.map +1 -1
  98. package/src/lib/environment.js +7 -0
  99. package/src/lib/environment.js.map +1 -1
  100. package/src/lib/errors/index.d.ts +1 -0
  101. package/src/lib/errors/index.d.ts.map +1 -1
  102. package/src/lib/errors/index.js +1 -0
  103. package/src/lib/errors/index.js.map +1 -1
  104. package/src/lib/errors/memberIndexSchemaValidationError.d.ts +6 -0
  105. package/src/lib/errors/memberIndexSchemaValidationError.d.ts.map +1 -0
  106. package/src/lib/errors/memberIndexSchemaValidationError.js +15 -0
  107. package/src/lib/errors/memberIndexSchemaValidationError.js.map +1 -0
  108. package/src/lib/factories/blockStoreFactory.d.ts +2 -13
  109. package/src/lib/factories/blockStoreFactory.d.ts.map +1 -1
  110. package/src/lib/factories/blockStoreFactory.js +5 -10
  111. package/src/lib/factories/blockStoreFactory.js.map +1 -1
  112. package/src/lib/interfaces/application.d.ts +7 -1
  113. package/src/lib/interfaces/application.d.ts.map +1 -1
  114. package/src/lib/interfaces/blocksHandlers.d.ts +3 -3
  115. package/src/lib/interfaces/blocksHandlers.d.ts.map +1 -1
  116. package/src/lib/interfaces/brightchain-init-result.d.ts +17 -0
  117. package/src/lib/interfaces/brightchain-init-result.d.ts.map +1 -0
  118. package/src/lib/interfaces/brightchain-init-result.js +9 -0
  119. package/src/lib/interfaces/brightchain-init-result.js.map +1 -0
  120. package/src/lib/interfaces/cblHandlers.d.ts +3 -2
  121. package/src/lib/interfaces/cblHandlers.d.ts.map +1 -1
  122. package/src/lib/interfaces/environment.d.ts +4 -0
  123. package/src/lib/interfaces/environment.d.ts.map +1 -1
  124. package/src/lib/interfaces/index.d.ts +5 -0
  125. package/src/lib/interfaces/index.d.ts.map +1 -1
  126. package/src/lib/interfaces/introspectionApiResponses.d.ts +66 -0
  127. package/src/lib/interfaces/introspectionApiResponses.d.ts.map +1 -0
  128. package/src/lib/interfaces/introspectionApiResponses.js +3 -0
  129. package/src/lib/interfaces/introspectionApiResponses.js.map +1 -0
  130. package/src/lib/interfaces/members-handlers.d.ts +11 -0
  131. package/src/lib/interfaces/members-handlers.d.ts.map +1 -0
  132. package/src/lib/interfaces/members-handlers.js +3 -0
  133. package/src/lib/interfaces/members-handlers.js.map +1 -0
  134. package/src/lib/interfaces/responses/api-backup-codes-response.d.ts +2 -5
  135. package/src/lib/interfaces/responses/api-backup-codes-response.d.ts.map +1 -1
  136. package/src/lib/interfaces/responses/api-challenge-response.d.ts +2 -5
  137. package/src/lib/interfaces/responses/api-challenge-response.d.ts.map +1 -1
  138. package/src/lib/interfaces/responses/api-code-count-response.d.ts +2 -5
  139. package/src/lib/interfaces/responses/api-code-count-response.d.ts.map +1 -1
  140. package/src/lib/interfaces/responses/api-detailed-health-response.d.ts +5 -0
  141. package/src/lib/interfaces/responses/api-detailed-health-response.d.ts.map +1 -0
  142. package/src/lib/interfaces/responses/api-detailed-health-response.js +3 -0
  143. package/src/lib/interfaces/responses/api-detailed-health-response.js.map +1 -0
  144. package/src/lib/interfaces/responses/api-discover-block-response.d.ts +5 -0
  145. package/src/lib/interfaces/responses/api-discover-block-response.d.ts.map +1 -0
  146. package/src/lib/interfaces/responses/api-discover-block-response.js +3 -0
  147. package/src/lib/interfaces/responses/api-discover-block-response.js.map +1 -0
  148. package/src/lib/interfaces/responses/api-error.d.ts +5 -0
  149. package/src/lib/interfaces/responses/api-error.d.ts.map +1 -0
  150. package/src/lib/interfaces/responses/api-error.js +3 -0
  151. package/src/lib/interfaces/responses/api-error.js.map +1 -0
  152. package/src/lib/interfaces/responses/api-express-validation-error.d.ts +7 -0
  153. package/src/lib/interfaces/responses/api-express-validation-error.d.ts.map +1 -0
  154. package/src/lib/interfaces/responses/api-express-validation-error.js +3 -0
  155. package/src/lib/interfaces/responses/api-express-validation-error.js.map +1 -0
  156. package/src/lib/interfaces/responses/api-get-block-response.d.ts +5 -0
  157. package/src/lib/interfaces/responses/api-get-block-response.d.ts.map +1 -0
  158. package/src/lib/interfaces/responses/api-get-block-response.js +3 -0
  159. package/src/lib/interfaces/responses/api-get-block-response.js.map +1 -0
  160. package/src/lib/interfaces/responses/api-get-node-response.d.ts +5 -0
  161. package/src/lib/interfaces/responses/api-get-node-response.d.ts.map +1 -0
  162. package/src/lib/interfaces/responses/api-get-node-response.js +3 -0
  163. package/src/lib/interfaces/responses/api-get-node-response.js.map +1 -0
  164. package/src/lib/interfaces/responses/api-health-response.d.ts +5 -0
  165. package/src/lib/interfaces/responses/api-health-response.d.ts.map +1 -0
  166. package/src/lib/interfaces/responses/api-health-response.js +3 -0
  167. package/src/lib/interfaces/responses/api-health-response.js.map +1 -0
  168. package/src/lib/interfaces/responses/api-list-nodes-response.d.ts +5 -0
  169. package/src/lib/interfaces/responses/api-list-nodes-response.d.ts.map +1 -0
  170. package/src/lib/interfaces/responses/api-list-nodes-response.js +3 -0
  171. package/src/lib/interfaces/responses/api-list-nodes-response.js.map +1 -0
  172. package/src/lib/interfaces/responses/api-login-response.d.ts +2 -14
  173. package/src/lib/interfaces/responses/api-login-response.d.ts.map +1 -1
  174. package/src/lib/interfaces/responses/api-members-response.d.ts +8 -0
  175. package/src/lib/interfaces/responses/api-members-response.d.ts.map +1 -0
  176. package/src/lib/interfaces/responses/api-members-response.js +3 -0
  177. package/src/lib/interfaces/responses/api-members-response.js.map +1 -0
  178. package/src/lib/interfaces/responses/api-mnemonic-response.d.ts +2 -5
  179. package/src/lib/interfaces/responses/api-mnemonic-response.d.ts.map +1 -1
  180. package/src/lib/interfaces/responses/api-reconcile-response.d.ts +5 -0
  181. package/src/lib/interfaces/responses/api-reconcile-response.d.ts.map +1 -0
  182. package/src/lib/interfaces/responses/api-reconcile-response.js +3 -0
  183. package/src/lib/interfaces/responses/api-reconcile-response.js.map +1 -0
  184. package/src/lib/interfaces/responses/api-register-node-response.d.ts +5 -0
  185. package/src/lib/interfaces/responses/api-register-node-response.d.ts.map +1 -0
  186. package/src/lib/interfaces/responses/api-register-node-response.js +3 -0
  187. package/src/lib/interfaces/responses/api-register-node-response.js.map +1 -0
  188. package/src/lib/interfaces/responses/api-registration-response.d.ts +2 -10
  189. package/src/lib/interfaces/responses/api-registration-response.d.ts.map +1 -1
  190. package/src/lib/interfaces/responses/api-replicate-block-response.d.ts +5 -0
  191. package/src/lib/interfaces/responses/api-replicate-block-response.d.ts.map +1 -0
  192. package/src/lib/interfaces/responses/api-replicate-block-response.js +3 -0
  193. package/src/lib/interfaces/responses/api-replicate-block-response.js.map +1 -0
  194. package/src/lib/interfaces/responses/api-request-user-response.d.ts +2 -6
  195. package/src/lib/interfaces/responses/api-request-user-response.d.ts.map +1 -1
  196. package/src/lib/interfaces/responses/api-status-code-response.d.ts +7 -0
  197. package/src/lib/interfaces/responses/api-status-code-response.d.ts.map +1 -0
  198. package/src/lib/interfaces/responses/api-status-code-response.js +3 -0
  199. package/src/lib/interfaces/responses/api-status-code-response.js.map +1 -0
  200. package/src/lib/interfaces/responses/api-store-block-response.d.ts +5 -0
  201. package/src/lib/interfaces/responses/api-store-block-response.d.ts.map +1 -0
  202. package/src/lib/interfaces/responses/api-store-block-response.js +3 -0
  203. package/src/lib/interfaces/responses/api-store-block-response.js.map +1 -0
  204. package/src/lib/interfaces/responses/api-store-cbl-response.d.ts +5 -0
  205. package/src/lib/interfaces/responses/api-store-cbl-response.d.ts.map +1 -0
  206. package/src/lib/interfaces/responses/api-store-cbl-response.js +3 -0
  207. package/src/lib/interfaces/responses/api-store-cbl-response.js.map +1 -0
  208. package/src/lib/interfaces/responses/api-sync-request-response.d.ts +5 -0
  209. package/src/lib/interfaces/responses/api-sync-request-response.d.ts.map +1 -0
  210. package/src/lib/interfaces/responses/api-sync-request-response.js +3 -0
  211. package/src/lib/interfaces/responses/api-sync-request-response.js.map +1 -0
  212. package/src/lib/interfaces/responses/block-data-response.d.ts +11 -0
  213. package/src/lib/interfaces/responses/block-data-response.d.ts.map +1 -0
  214. package/src/lib/interfaces/responses/block-data-response.js +3 -0
  215. package/src/lib/interfaces/responses/block-data-response.js.map +1 -0
  216. package/src/lib/interfaces/responses/block-location-response.d.ts +11 -0
  217. package/src/lib/interfaces/responses/block-location-response.d.ts.map +1 -0
  218. package/src/lib/interfaces/responses/block-location-response.js +3 -0
  219. package/src/lib/interfaces/responses/block-location-response.js.map +1 -0
  220. package/src/lib/interfaces/responses/index.d.ts +18 -0
  221. package/src/lib/interfaces/responses/index.d.ts.map +1 -1
  222. package/src/lib/interfaces/status-code-response.d.ts +1 -6
  223. package/src/lib/interfaces/status-code-response.d.ts.map +1 -1
  224. package/src/lib/interfaces/storage/client-session.d.ts +8 -0
  225. package/src/lib/interfaces/storage/client-session.d.ts.map +1 -0
  226. package/src/lib/interfaces/storage/client-session.js +3 -0
  227. package/src/lib/interfaces/storage/client-session.js.map +1 -0
  228. package/src/lib/interfaces/storage/collection.d.ts +9 -0
  229. package/src/lib/interfaces/storage/collection.d.ts.map +1 -0
  230. package/src/lib/interfaces/storage/collection.js +3 -0
  231. package/src/lib/interfaces/storage/collection.js.map +1 -0
  232. package/src/lib/interfaces/storage/database-lifecycle-hooks.d.ts +8 -0
  233. package/src/lib/interfaces/storage/database-lifecycle-hooks.d.ts.map +1 -0
  234. package/src/lib/interfaces/storage/database-lifecycle-hooks.js +3 -0
  235. package/src/lib/interfaces/storage/database-lifecycle-hooks.js.map +1 -0
  236. package/src/lib/interfaces/storage/database.d.ts +9 -0
  237. package/src/lib/interfaces/storage/database.d.ts.map +1 -0
  238. package/src/lib/interfaces/storage/database.js +3 -0
  239. package/src/lib/interfaces/storage/database.js.map +1 -0
  240. package/src/lib/interfaces/storage/document-types.d.ts +9 -0
  241. package/src/lib/interfaces/storage/document-types.d.ts.map +1 -0
  242. package/src/lib/interfaces/storage/document-types.js +10 -0
  243. package/src/lib/interfaces/storage/document-types.js.map +1 -0
  244. package/src/lib/interfaces/storage/index.d.ts +7 -0
  245. package/src/lib/interfaces/storage/index.d.ts.map +1 -0
  246. package/src/lib/interfaces/storage/index.js +7 -0
  247. package/src/lib/interfaces/storage/index.js.map +1 -0
  248. package/src/lib/interfaces/storage/memberIndexSchema.d.ts +11 -0
  249. package/src/lib/interfaces/storage/memberIndexSchema.d.ts.map +1 -0
  250. package/src/lib/interfaces/storage/memberIndexSchema.js +26 -0
  251. package/src/lib/interfaces/storage/memberIndexSchema.js.map +1 -0
  252. package/src/lib/interfaces/userApiResponse.d.ts +17 -0
  253. package/src/lib/interfaces/userApiResponse.d.ts.map +1 -0
  254. package/src/lib/interfaces/userApiResponse.js +3 -0
  255. package/src/lib/interfaces/userApiResponse.js.map +1 -0
  256. package/src/lib/interfaces/websocketMessages.d.ts +64 -1
  257. package/src/lib/interfaces/websocketMessages.d.ts.map +1 -1
  258. package/src/lib/middleware/index.d.ts +2 -0
  259. package/src/lib/middleware/index.d.ts.map +1 -0
  260. package/src/lib/middleware/index.js +6 -0
  261. package/src/lib/middleware/index.js.map +1 -0
  262. package/src/lib/middleware/validateBody.d.ts +13 -0
  263. package/src/lib/middleware/validateBody.d.ts.map +1 -0
  264. package/src/lib/middleware/validateBody.js +35 -0
  265. package/src/lib/middleware/validateBody.js.map +1 -0
  266. package/src/lib/middlewares/authentication.d.ts +2 -0
  267. package/src/lib/middlewares/authentication.d.ts.map +1 -1
  268. package/src/lib/middlewares/authentication.js.map +1 -1
  269. package/src/lib/routers/api.d.ts +27 -0
  270. package/src/lib/routers/api.d.ts.map +1 -1
  271. package/src/lib/routers/api.js +44 -0
  272. package/src/lib/routers/api.js.map +1 -1
  273. package/src/lib/routers/app.d.ts +22 -14
  274. package/src/lib/routers/app.d.ts.map +1 -1
  275. package/src/lib/routers/app.js +28 -116
  276. package/src/lib/routers/app.js.map +1 -1
  277. package/src/lib/services/auth.d.ts +3 -1
  278. package/src/lib/services/auth.d.ts.map +1 -1
  279. package/src/lib/services/auth.js +51 -4
  280. package/src/lib/services/auth.js.map +1 -1
  281. package/src/lib/services/brightchain-member-init.service.d.ts +66 -0
  282. package/src/lib/services/brightchain-member-init.service.d.ts.map +1 -0
  283. package/src/lib/services/brightchain-member-init.service.js +152 -0
  284. package/src/lib/services/brightchain-member-init.service.js.map +1 -0
  285. package/src/lib/services/brightpass.property.helpers.d.ts +23 -0
  286. package/src/lib/services/brightpass.property.helpers.d.ts.map +1 -0
  287. package/src/lib/services/brightpass.property.helpers.js +113 -0
  288. package/src/lib/services/brightpass.property.helpers.js.map +1 -0
  289. package/src/lib/services/clientWebSocketServer.d.ts +147 -0
  290. package/src/lib/services/clientWebSocketServer.d.ts.map +1 -0
  291. package/src/lib/services/clientWebSocketServer.js +437 -0
  292. package/src/lib/services/clientWebSocketServer.js.map +1 -0
  293. package/src/lib/services/index.d.ts +2 -0
  294. package/src/lib/services/index.d.ts.map +1 -1
  295. package/src/lib/services/index.js +2 -0
  296. package/src/lib/services/index.js.map +1 -1
  297. package/src/lib/stores/diskBlockAsyncStore.d.ts +4 -4
  298. package/src/lib/stores/diskBlockAsyncStore.d.ts.map +1 -1
  299. package/src/lib/stores/diskBlockAsyncStore.js.map +1 -1
  300. package/src/lib/stores/diskBlockStore.d.ts +82 -17
  301. package/src/lib/stores/diskBlockStore.d.ts.map +1 -1
  302. package/src/lib/stores/diskBlockStore.js +787 -19
  303. package/src/lib/stores/diskBlockStore.js.map +1 -1
  304. package/src/lib/stores/diskBlockSyncStore.d.ts +24 -5
  305. package/src/lib/stores/diskBlockSyncStore.d.ts.map +1 -1
  306. package/src/lib/stores/diskBlockSyncStore.js +30 -13
  307. package/src/lib/stores/diskBlockSyncStore.js.map +1 -1
  308. package/src/lib/upstream-stubs.d.ts +36 -0
  309. package/src/lib/upstream-stubs.d.ts.map +1 -0
  310. package/src/lib/upstream-stubs.js +43 -0
  311. package/src/lib/upstream-stubs.js.map +1 -0
  312. package/src/lib/validation/userValidation.d.ts +27 -0
  313. package/src/lib/validation/userValidation.d.ts.map +1 -0
  314. package/src/lib/validation/userValidation.js +70 -0
  315. package/src/lib/validation/userValidation.js.map +1 -0
@@ -118,489 +118,6 @@ function serializeMember(member) {
118
118
  class QuorumController extends base_1.BaseController {
119
119
  constructor(application) {
120
120
  super(application);
121
- // === Member Management Handlers ===
122
- /**
123
- * POST /api/quorum/members
124
- * Add a new member to the quorum with generated cryptographic keys.
125
- *
126
- * Creates a new member with ECIES key pair and adds them to the quorum.
127
- * The mnemonic phrase is returned for key recovery - it should be stored
128
- * securely by the user as it cannot be retrieved later.
129
- *
130
- * @param req - Request containing member name and optional metadata
131
- * @returns Member details and mnemonic on success
132
- *
133
- * @example
134
- * ```json
135
- * // Request
136
- * POST /api/quorum/members
137
- * {
138
- * "name": "Alice",
139
- * "email": "alice@example.com",
140
- * "role": "admin"
141
- * }
142
- *
143
- * // Response
144
- * {
145
- * "message": "Member added successfully",
146
- * "member": {
147
- * "id": "abc123...",
148
- * "publicKey": "04...",
149
- * "metadata": { "name": "Alice", "email": "alice@example.com", "role": "admin" },
150
- * "isActive": true,
151
- * "createdAt": "2025-01-16T10:00:00Z",
152
- * "updatedAt": "2025-01-16T10:00:00Z"
153
- * },
154
- * "mnemonic": "word1 word2 word3..."
155
- * }
156
- * ```
157
- */
158
- this.handleAddMember = async (req) => {
159
- try {
160
- const { name, email, role } = req.body;
161
- // Validate required fields
162
- if (!name) {
163
- return (0, errorResponse_1.validationError)('Missing required field: name');
164
- }
165
- // Create a new member with generated keys
166
- const eciesService = brightchain_lib_1.ServiceProvider.getInstance().eciesService;
167
- const emailString = email
168
- ? new ecies_lib_1.EmailString(email)
169
- : new ecies_lib_1.EmailString(`${name.toLowerCase().replace(/\s+/g, '.')}@placeholder.local`);
170
- const memberWithMnemonic = ecies_lib_1.Member.newMember(eciesService, ecies_lib_1.MemberType.User, name, emailString);
171
- const metadata = {
172
- name,
173
- email,
174
- role,
175
- };
176
- const quorumService = this.quorumServiceWrapper.getService();
177
- const quorumMember = await quorumService.addMember(memberWithMnemonic.member, metadata);
178
- return {
179
- statusCode: 201,
180
- response: {
181
- message: 'Member added successfully',
182
- member: serializeMember(quorumMember),
183
- mnemonic: memberWithMnemonic.mnemonic.value ?? '',
184
- },
185
- };
186
- }
187
- catch (_error) {
188
- if (_error instanceof brightchain_lib_1.QuorumError) {
189
- return (0, errorResponse_1.mapQuorumError)(_error);
190
- }
191
- return (0, errorResponse_1.handleError)(_error);
192
- }
193
- };
194
- /**
195
- * GET /api/quorum/members
196
- * List all active quorum members.
197
- *
198
- * Returns all members that are currently active in the quorum.
199
- * Inactive (removed) members are not included in the response.
200
- *
201
- * @param _req - Request (no parameters required)
202
- * @returns Array of member objects on success
203
- *
204
- * @example
205
- * ```json
206
- * // Request
207
- * GET /api/quorum/members
208
- *
209
- * // Response
210
- * {
211
- * "message": "Members retrieved successfully",
212
- * "members": [
213
- * {
214
- * "id": "abc123...",
215
- * "publicKey": "04...",
216
- * "metadata": { "name": "Alice", "role": "admin" },
217
- * "isActive": true,
218
- * "createdAt": "2025-01-16T10:00:00Z",
219
- * "updatedAt": "2025-01-16T10:00:00Z"
220
- * }
221
- * ]
222
- * }
223
- * ```
224
- */
225
- this.handleListMembers = async (_req) => {
226
- try {
227
- const quorumService = this.quorumServiceWrapper.getService();
228
- const members = await quorumService.listMembers();
229
- return {
230
- statusCode: 200,
231
- response: {
232
- message: 'Members retrieved successfully',
233
- members: members.map(serializeMember),
234
- },
235
- };
236
- }
237
- catch (_error) {
238
- if (_error instanceof brightchain_lib_1.QuorumError) {
239
- return (0, errorResponse_1.mapQuorumError)(_error);
240
- }
241
- return (0, errorResponse_1.handleError)(_error);
242
- }
243
- };
244
- /**
245
- * DELETE /api/quorum/members/:memberId
246
- * Remove a member from the quorum (deactivate).
247
- *
248
- * Marks the member as inactive. The member's access to existing documents
249
- * they are part of is preserved, but they cannot be added to new documents.
250
- *
251
- * @param req - Request containing the member ID parameter
252
- * @returns Success confirmation on success, or 404 if not found
253
- *
254
- * @example
255
- * ```json
256
- * // Request
257
- * DELETE /api/quorum/members/abc123...
258
- *
259
- * // Response
260
- * {
261
- * "message": "Member removed successfully",
262
- * "success": true,
263
- * "memberId": "abc123..."
264
- * }
265
- * ```
266
- */
267
- this.handleRemoveMember = async (req) => {
268
- try {
269
- const { memberId } = req.params;
270
- if (!memberId) {
271
- return (0, errorResponse_1.validationError)('Missing required parameter: memberId');
272
- }
273
- const quorumService = this.quorumServiceWrapper.getService();
274
- await quorumService.removeMember(memberId);
275
- return {
276
- statusCode: 200,
277
- response: {
278
- message: 'Member removed successfully',
279
- success: true,
280
- memberId,
281
- },
282
- };
283
- }
284
- catch (_error) {
285
- if (_error instanceof brightchain_lib_1.QuorumError) {
286
- return (0, errorResponse_1.mapQuorumError)(_error);
287
- }
288
- return (0, errorResponse_1.handleError)(_error);
289
- }
290
- };
291
- // === Document Sealing/Unsealing Handlers ===
292
- /**
293
- * POST /api/quorum/documents/seal
294
- * Seal a document using Shamir's Secret Sharing.
295
- *
296
- * Encrypts the document with a randomly generated symmetric key, then splits
297
- * the key into shares using Shamir's Secret Sharing. Each share is encrypted
298
- * with the corresponding member's public key.
299
- *
300
- * @param req - Request containing document, member IDs, and optional threshold
301
- * @returns Document ID and sealing metadata on success
302
- *
303
- * @example
304
- * ```json
305
- * // Request
306
- * POST /api/quorum/documents/seal
307
- * {
308
- * "document": { "secret": "data", "value": 42 },
309
- * "memberIds": ["member1...", "member2...", "member3..."],
310
- * "sharesRequired": 2
311
- * }
312
- *
313
- * // Response
314
- * {
315
- * "message": "Document sealed successfully",
316
- * "documentId": "doc123...",
317
- * "memberIds": ["member1...", "member2...", "member3..."],
318
- * "sharesRequired": 2,
319
- * "createdAt": "2025-01-16T10:00:00Z"
320
- * }
321
- * ```
322
- */
323
- this.handleSealDocument = async (req) => {
324
- try {
325
- const { document, memberIds, sharesRequired } = req.body;
326
- // Validate required fields
327
- if (document === undefined) {
328
- return (0, errorResponse_1.validationError)('Missing required field: document');
329
- }
330
- if (!memberIds || !Array.isArray(memberIds) || memberIds.length < 2) {
331
- return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_MEMBER_COUNT, 'At least 2 member IDs are required for sealing');
332
- }
333
- // Validate threshold if provided
334
- if (sharesRequired !== undefined) {
335
- if (sharesRequired < 2) {
336
- return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_THRESHOLD, 'sharesRequired must be at least 2');
337
- }
338
- if (sharesRequired > memberIds.length) {
339
- return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_THRESHOLD, 'sharesRequired cannot exceed the number of members');
340
- }
341
- }
342
- // Get the agent (authenticated member) from session
343
- const sessionsController = this.application.getController('sessions');
344
- let agent;
345
- try {
346
- const sessionMember = sessionsController.getMemberFromSession(req.headers.authorization);
347
- // Cast to GuidV4 member type - the session controller returns a generic Member
348
- agent = sessionMember;
349
- }
350
- catch {
351
- return (0, errorResponse_1.unauthorizedError)();
352
- }
353
- if (!agent) {
354
- return (0, errorResponse_1.unauthorizedError)();
355
- }
356
- const quorumService = this.quorumServiceWrapper.getService();
357
- const result = await quorumService.sealDocument(agent, document, memberIds, sharesRequired);
358
- return {
359
- statusCode: 201,
360
- response: {
361
- message: 'Document sealed successfully',
362
- documentId: result.documentId,
363
- memberIds: result.memberIds,
364
- sharesRequired: result.sharesRequired,
365
- createdAt: result.createdAt.toISOString(),
366
- },
367
- };
368
- }
369
- catch (_error) {
370
- if (_error instanceof brightchain_lib_1.QuorumError) {
371
- return (0, errorResponse_1.mapQuorumError)(_error);
372
- }
373
- return (0, errorResponse_1.handleError)(_error);
374
- }
375
- };
376
- /**
377
- * POST /api/quorum/documents/:documentId/unseal
378
- * Unseal a document using member credentials (mnemonics).
379
- *
380
- * Recovers member private keys from provided mnemonics, then uses them
381
- * to decrypt shares and reconstruct the original document.
382
- *
383
- * Note: This endpoint requires the QuorumService to have the document
384
- * loaded in memory. For disk-persisted documents, the full reconstruction
385
- * is not yet implemented.
386
- *
387
- * @param req - Request containing document ID and member credentials
388
- * @returns Original document on success
389
- *
390
- * @example
391
- * ```json
392
- * // Request
393
- * POST /api/quorum/documents/doc123.../unseal
394
- * {
395
- * "memberCredentials": [
396
- * { "memberId": "member1...", "mnemonic": "word1 word2 word3..." },
397
- * { "memberId": "member2...", "mnemonic": "word4 word5 word6..." }
398
- * ]
399
- * }
400
- *
401
- * // Response
402
- * {
403
- * "message": "Document unsealed successfully",
404
- * "document": { "secret": "data", "value": 42 }
405
- * }
406
- * ```
407
- */
408
- this.handleUnsealDocument = async (req) => {
409
- try {
410
- const { documentId } = req.params;
411
- const { memberCredentials } = req
412
- .body;
413
- if (!documentId) {
414
- return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
415
- }
416
- if (!memberCredentials ||
417
- !Array.isArray(memberCredentials) ||
418
- memberCredentials.length === 0) {
419
- return (0, errorResponse_1.validationError)('Missing required field: memberCredentials (array of {memberId, mnemonic})');
420
- }
421
- // Validate each credential has required fields
422
- for (const cred of memberCredentials) {
423
- if (!cred.memberId || !cred.mnemonic) {
424
- return (0, errorResponse_1.validationError)('Each memberCredential must have memberId and mnemonic');
425
- }
426
- }
427
- const quorumService = this.quorumServiceWrapper.getService();
428
- // Check if document exists and if we have enough shares
429
- const docInfo = await quorumService.getDocument(documentId);
430
- if (!docInfo) {
431
- return (0, errorResponse_1.notFoundError)('Document', documentId);
432
- }
433
- // Check if provided members can unlock the document
434
- const memberIds = memberCredentials.map((c) => c.memberId);
435
- const canUnlockResult = await quorumService.canUnlock(documentId, memberIds);
436
- if (!canUnlockResult.canUnlock) {
437
- return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INSUFFICIENT_SHARES, `Insufficient shares: provided ${canUnlockResult.sharesProvided}, required ${canUnlockResult.sharesRequired}`);
438
- }
439
- // Recover members with private keys from mnemonics
440
- const eciesService = brightchain_lib_1.ServiceProvider.getInstance().eciesService;
441
- const membersWithPrivateKey = [];
442
- for (const cred of memberCredentials) {
443
- // Get the stored member info to get their metadata
444
- const storedMember = await quorumService.getMember(cred.memberId);
445
- if (!storedMember) {
446
- return (0, errorResponse_1.notFoundError)('Member', cred.memberId);
447
- }
448
- // Recover wallet from mnemonic - need to wrap string in SecureString
449
- const secureString = new ecies_lib_1.SecureString(cred.mnemonic);
450
- const { wallet } = eciesService.walletAndSeedFromMnemonic(secureString);
451
- const recoveredPublicKey = new Uint8Array(wallet.getPublicKey());
452
- // Verify the recovered public key matches the stored one
453
- if ((0, ecies_lib_1.uint8ArrayToHex)(recoveredPublicKey) !==
454
- (0, ecies_lib_1.uint8ArrayToHex)(storedMember.publicKey)) {
455
- return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.SHARE_DECRYPTION_FAILED, `Mnemonic does not match member ${cred.memberId}`);
456
- }
457
- // Create a member with the recovered private key
458
- const email = storedMember.metadata.email
459
- ? new ecies_lib_1.EmailString(storedMember.metadata.email)
460
- : new ecies_lib_1.EmailString(`${storedMember.metadata.name?.toLowerCase().replace(/\s+/g, '.') ?? 'unknown'}@placeholder.local`);
461
- // Use Member.newMember and then replace the wallet
462
- // This is a workaround since Member constructor may not accept wallet directly
463
- const { member: tempMember } = ecies_lib_1.Member.newMember(eciesService, ecies_lib_1.MemberType.User, storedMember.metadata.name ?? 'Unknown', email);
464
- // Create a member-like object with the recovered wallet's private key
465
- // The unsealDocument method needs members with privateKey access
466
- const recoveredMember = Object.create(tempMember);
467
- Object.defineProperty(recoveredMember, 'privateKey', {
468
- get: () => new Uint8Array(wallet.getPrivateKey()),
469
- configurable: true,
470
- });
471
- Object.defineProperty(recoveredMember, 'publicKey', {
472
- get: () => recoveredPublicKey,
473
- configurable: true,
474
- });
475
- membersWithPrivateKey.push(recoveredMember);
476
- }
477
- // Unseal the document
478
- const unsealedDocument = await quorumService.unsealDocument(documentId, membersWithPrivateKey);
479
- return {
480
- statusCode: 200,
481
- response: {
482
- message: 'Document unsealed successfully',
483
- document: unsealedDocument,
484
- },
485
- };
486
- }
487
- catch (_error) {
488
- if (_error instanceof brightchain_lib_1.QuorumError) {
489
- return (0, errorResponse_1.mapQuorumError)(_error);
490
- }
491
- return (0, errorResponse_1.handleError)(_error);
492
- }
493
- };
494
- /**
495
- * GET /api/quorum/documents/:documentId
496
- * Get metadata for a sealed document.
497
- *
498
- * Returns information about the document including which members have access
499
- * and how many shares are required to unseal it.
500
- *
501
- * @param req - Request containing the document ID parameter
502
- * @returns Document metadata on success, or 404 if not found
503
- *
504
- * @example
505
- * ```json
506
- * // Request
507
- * GET /api/quorum/documents/doc123...
508
- *
509
- * // Response
510
- * {
511
- * "message": "Document retrieved successfully",
512
- * "document": {
513
- * "id": "doc123...",
514
- * "memberIds": ["member1...", "member2...", "member3..."],
515
- * "sharesRequired": 2,
516
- * "createdAt": "2025-01-16T10:00:00Z",
517
- * "creatorId": "creator..."
518
- * }
519
- * }
520
- * ```
521
- */
522
- this.handleGetDocument = async (req) => {
523
- try {
524
- const { documentId } = req.params;
525
- if (!documentId) {
526
- return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
527
- }
528
- const quorumService = this.quorumServiceWrapper.getService();
529
- const document = await quorumService.getDocument(documentId);
530
- if (!document) {
531
- return (0, errorResponse_1.notFoundError)('Document', documentId);
532
- }
533
- return {
534
- statusCode: 200,
535
- response: {
536
- message: 'Document retrieved successfully',
537
- document,
538
- },
539
- };
540
- }
541
- catch (_error) {
542
- if (_error instanceof brightchain_lib_1.QuorumError) {
543
- return (0, errorResponse_1.mapQuorumError)(_error);
544
- }
545
- return (0, errorResponse_1.handleError)(_error);
546
- }
547
- };
548
- /**
549
- * GET /api/quorum/documents/:documentId/can-unlock
550
- * Check if a set of members can unlock a document.
551
- *
552
- * Determines whether the provided members have enough shares to meet
553
- * the threshold required to unseal the document.
554
- *
555
- * @param req - Request containing document ID and member IDs query parameter
556
- * @returns Unlock status and share count information
557
- *
558
- * @example
559
- * ```json
560
- * // Request
561
- * GET /api/quorum/documents/doc123.../can-unlock?memberIds=member1,member2
562
- *
563
- * // Response
564
- * {
565
- * "message": "Can-unlock check completed",
566
- * "canUnlock": true,
567
- * "sharesProvided": 2,
568
- * "sharesRequired": 2,
569
- * "missingMembers": ["member3..."]
570
- * }
571
- * ```
572
- */
573
- this.handleCanUnlock = async (req) => {
574
- try {
575
- const { documentId } = req.params;
576
- const { memberIds: memberIdsStr } = req
577
- .query;
578
- if (!documentId) {
579
- return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
580
- }
581
- if (!memberIdsStr) {
582
- return (0, errorResponse_1.validationError)('Missing required query parameter: memberIds (comma-separated)');
583
- }
584
- const memberIds = memberIdsStr
585
- .split(',')
586
- .map((id) => id.trim());
587
- const quorumService = this.quorumServiceWrapper.getService();
588
- const result = await quorumService.canUnlock(documentId, memberIds);
589
- return {
590
- statusCode: 200,
591
- response: {
592
- message: 'Can-unlock check completed',
593
- ...result,
594
- },
595
- };
596
- }
597
- catch (_error) {
598
- if (_error instanceof brightchain_lib_1.QuorumError) {
599
- return (0, errorResponse_1.mapQuorumError)(_error);
600
- }
601
- return (0, errorResponse_1.handleError)(_error);
602
- }
603
- };
604
121
  this.quorumServiceWrapper = new quorum_1.QuorumServiceWrapper(application);
605
122
  }
606
123
  initRouteDefinitions() {
@@ -653,6 +170,489 @@ class QuorumController extends base_1.BaseController {
653
170
  canUnlock: this.handleCanUnlock.bind(this),
654
171
  };
655
172
  }
173
+ // === Member Management Handlers ===
174
+ /**
175
+ * POST /api/quorum/members
176
+ * Add a new member to the quorum with generated cryptographic keys.
177
+ *
178
+ * Creates a new member with ECIES key pair and adds them to the quorum.
179
+ * The mnemonic phrase is returned for key recovery - it should be stored
180
+ * securely by the user as it cannot be retrieved later.
181
+ *
182
+ * @param req - Request containing member name and optional metadata
183
+ * @returns Member details and mnemonic on success
184
+ *
185
+ * @example
186
+ * ```json
187
+ * // Request
188
+ * POST /api/quorum/members
189
+ * {
190
+ * "name": "Alice",
191
+ * "email": "alice@example.com",
192
+ * "role": "admin"
193
+ * }
194
+ *
195
+ * // Response
196
+ * {
197
+ * "message": "Member added successfully",
198
+ * "member": {
199
+ * "id": "abc123...",
200
+ * "publicKey": "04...",
201
+ * "metadata": { "name": "Alice", "email": "alice@example.com", "role": "admin" },
202
+ * "isActive": true,
203
+ * "createdAt": "2025-01-16T10:00:00Z",
204
+ * "updatedAt": "2025-01-16T10:00:00Z"
205
+ * },
206
+ * "mnemonic": "word1 word2 word3..."
207
+ * }
208
+ * ```
209
+ */
210
+ async handleAddMember(req) {
211
+ try {
212
+ const { name, email, role } = req.body;
213
+ // Validate required fields
214
+ if (!name) {
215
+ return (0, errorResponse_1.validationError)('Missing required field: name');
216
+ }
217
+ // Create a new member with generated keys
218
+ const eciesService = brightchain_lib_1.ServiceProvider.getInstance().eciesService;
219
+ const emailString = email
220
+ ? new ecies_lib_1.EmailString(email)
221
+ : new ecies_lib_1.EmailString(`${name.toLowerCase().replace(/\s+/g, '.')}@placeholder.local`);
222
+ const memberWithMnemonic = ecies_lib_1.Member.newMember(eciesService, ecies_lib_1.MemberType.User, name, emailString);
223
+ const metadata = {
224
+ name,
225
+ email,
226
+ role,
227
+ };
228
+ const quorumService = this.quorumServiceWrapper.getService();
229
+ const quorumMember = await quorumService.addMember(memberWithMnemonic.member, metadata);
230
+ return {
231
+ statusCode: 201,
232
+ response: {
233
+ message: 'Member added successfully',
234
+ member: serializeMember(quorumMember),
235
+ mnemonic: memberWithMnemonic.mnemonic.value ?? '',
236
+ },
237
+ };
238
+ }
239
+ catch (_error) {
240
+ if (_error instanceof brightchain_lib_1.QuorumError) {
241
+ return (0, errorResponse_1.mapQuorumError)(_error);
242
+ }
243
+ return (0, errorResponse_1.handleError)(_error);
244
+ }
245
+ }
246
+ /**
247
+ * GET /api/quorum/members
248
+ * List all active quorum members.
249
+ *
250
+ * Returns all members that are currently active in the quorum.
251
+ * Inactive (removed) members are not included in the response.
252
+ *
253
+ * @param _req - Request (no parameters required)
254
+ * @returns Array of member objects on success
255
+ *
256
+ * @example
257
+ * ```json
258
+ * // Request
259
+ * GET /api/quorum/members
260
+ *
261
+ * // Response
262
+ * {
263
+ * "message": "Members retrieved successfully",
264
+ * "members": [
265
+ * {
266
+ * "id": "abc123...",
267
+ * "publicKey": "04...",
268
+ * "metadata": { "name": "Alice", "role": "admin" },
269
+ * "isActive": true,
270
+ * "createdAt": "2025-01-16T10:00:00Z",
271
+ * "updatedAt": "2025-01-16T10:00:00Z"
272
+ * }
273
+ * ]
274
+ * }
275
+ * ```
276
+ */
277
+ async handleListMembers(_req) {
278
+ try {
279
+ const quorumService = this.quorumServiceWrapper.getService();
280
+ const members = await quorumService.listMembers();
281
+ return {
282
+ statusCode: 200,
283
+ response: {
284
+ message: 'Members retrieved successfully',
285
+ members: members.map(serializeMember),
286
+ },
287
+ };
288
+ }
289
+ catch (_error) {
290
+ if (_error instanceof brightchain_lib_1.QuorumError) {
291
+ return (0, errorResponse_1.mapQuorumError)(_error);
292
+ }
293
+ return (0, errorResponse_1.handleError)(_error);
294
+ }
295
+ }
296
+ /**
297
+ * DELETE /api/quorum/members/:memberId
298
+ * Remove a member from the quorum (deactivate).
299
+ *
300
+ * Marks the member as inactive. The member's access to existing documents
301
+ * they are part of is preserved, but they cannot be added to new documents.
302
+ *
303
+ * @param req - Request containing the member ID parameter
304
+ * @returns Success confirmation on success, or 404 if not found
305
+ *
306
+ * @example
307
+ * ```json
308
+ * // Request
309
+ * DELETE /api/quorum/members/abc123...
310
+ *
311
+ * // Response
312
+ * {
313
+ * "message": "Member removed successfully",
314
+ * "success": true,
315
+ * "memberId": "abc123..."
316
+ * }
317
+ * ```
318
+ */
319
+ async handleRemoveMember(req) {
320
+ try {
321
+ const { memberId } = req.params;
322
+ if (!memberId) {
323
+ return (0, errorResponse_1.validationError)('Missing required parameter: memberId');
324
+ }
325
+ const quorumService = this.quorumServiceWrapper.getService();
326
+ await quorumService.removeMember(memberId);
327
+ return {
328
+ statusCode: 200,
329
+ response: {
330
+ message: 'Member removed successfully',
331
+ success: true,
332
+ memberId,
333
+ },
334
+ };
335
+ }
336
+ catch (_error) {
337
+ if (_error instanceof brightchain_lib_1.QuorumError) {
338
+ return (0, errorResponse_1.mapQuorumError)(_error);
339
+ }
340
+ return (0, errorResponse_1.handleError)(_error);
341
+ }
342
+ }
343
+ // === Document Sealing/Unsealing Handlers ===
344
+ /**
345
+ * POST /api/quorum/documents/seal
346
+ * Seal a document using Shamir's Secret Sharing.
347
+ *
348
+ * Encrypts the document with a randomly generated symmetric key, then splits
349
+ * the key into shares using Shamir's Secret Sharing. Each share is encrypted
350
+ * with the corresponding member's public key.
351
+ *
352
+ * @param req - Request containing document, member IDs, and optional threshold
353
+ * @returns Document ID and sealing metadata on success
354
+ *
355
+ * @example
356
+ * ```json
357
+ * // Request
358
+ * POST /api/quorum/documents/seal
359
+ * {
360
+ * "document": { "secret": "data", "value": 42 },
361
+ * "memberIds": ["member1...", "member2...", "member3..."],
362
+ * "sharesRequired": 2
363
+ * }
364
+ *
365
+ * // Response
366
+ * {
367
+ * "message": "Document sealed successfully",
368
+ * "documentId": "doc123...",
369
+ * "memberIds": ["member1...", "member2...", "member3..."],
370
+ * "sharesRequired": 2,
371
+ * "createdAt": "2025-01-16T10:00:00Z"
372
+ * }
373
+ * ```
374
+ */
375
+ async handleSealDocument(req) {
376
+ try {
377
+ const { document, memberIds, sharesRequired } = req.body;
378
+ // Validate required fields
379
+ if (document === undefined) {
380
+ return (0, errorResponse_1.validationError)('Missing required field: document');
381
+ }
382
+ if (!memberIds || !Array.isArray(memberIds) || memberIds.length < 2) {
383
+ return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_MEMBER_COUNT, 'At least 2 member IDs are required for sealing');
384
+ }
385
+ // Validate threshold if provided
386
+ if (sharesRequired !== undefined) {
387
+ if (sharesRequired < 2) {
388
+ return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_THRESHOLD, 'sharesRequired must be at least 2');
389
+ }
390
+ if (sharesRequired > memberIds.length) {
391
+ return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INVALID_THRESHOLD, 'sharesRequired cannot exceed the number of members');
392
+ }
393
+ }
394
+ // Get the agent (authenticated member) from session
395
+ const sessionsController = this.application.getController('sessions');
396
+ let agent;
397
+ try {
398
+ const sessionMember = sessionsController.getMemberFromSession(req.headers.authorization);
399
+ // Cast to GuidV4 member type - the session controller returns a generic Member
400
+ agent = sessionMember;
401
+ }
402
+ catch {
403
+ return (0, errorResponse_1.unauthorizedError)();
404
+ }
405
+ if (!agent) {
406
+ return (0, errorResponse_1.unauthorizedError)();
407
+ }
408
+ const quorumService = this.quorumServiceWrapper.getService();
409
+ const result = await quorumService.sealDocument(agent, document, memberIds, sharesRequired);
410
+ return {
411
+ statusCode: 201,
412
+ response: {
413
+ message: 'Document sealed successfully',
414
+ documentId: result.documentId,
415
+ memberIds: result.memberIds,
416
+ sharesRequired: result.sharesRequired,
417
+ createdAt: result.createdAt.toISOString(),
418
+ },
419
+ };
420
+ }
421
+ catch (_error) {
422
+ if (_error instanceof brightchain_lib_1.QuorumError) {
423
+ return (0, errorResponse_1.mapQuorumError)(_error);
424
+ }
425
+ return (0, errorResponse_1.handleError)(_error);
426
+ }
427
+ }
428
+ /**
429
+ * POST /api/quorum/documents/:documentId/unseal
430
+ * Unseal a document using member credentials (mnemonics).
431
+ *
432
+ * Recovers member private keys from provided mnemonics, then uses them
433
+ * to decrypt shares and reconstruct the original document.
434
+ *
435
+ * Note: This endpoint requires the QuorumService to have the document
436
+ * loaded in memory. For disk-persisted documents, the full reconstruction
437
+ * is not yet implemented.
438
+ *
439
+ * @param req - Request containing document ID and member credentials
440
+ * @returns Original document on success
441
+ *
442
+ * @example
443
+ * ```json
444
+ * // Request
445
+ * POST /api/quorum/documents/doc123.../unseal
446
+ * {
447
+ * "memberCredentials": [
448
+ * { "memberId": "member1...", "mnemonic": "word1 word2 word3..." },
449
+ * { "memberId": "member2...", "mnemonic": "word4 word5 word6..." }
450
+ * ]
451
+ * }
452
+ *
453
+ * // Response
454
+ * {
455
+ * "message": "Document unsealed successfully",
456
+ * "document": { "secret": "data", "value": 42 }
457
+ * }
458
+ * ```
459
+ */
460
+ async handleUnsealDocument(req) {
461
+ try {
462
+ const { documentId } = req.params;
463
+ const { memberCredentials } = req
464
+ .body;
465
+ if (!documentId) {
466
+ return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
467
+ }
468
+ if (!memberCredentials ||
469
+ !Array.isArray(memberCredentials) ||
470
+ memberCredentials.length === 0) {
471
+ return (0, errorResponse_1.validationError)('Missing required field: memberCredentials (array of {memberId, mnemonic})');
472
+ }
473
+ // Validate each credential has required fields
474
+ for (const cred of memberCredentials) {
475
+ if (!cred.memberId || !cred.mnemonic) {
476
+ return (0, errorResponse_1.validationError)('Each memberCredential must have memberId and mnemonic');
477
+ }
478
+ }
479
+ const quorumService = this.quorumServiceWrapper.getService();
480
+ // Check if document exists and if we have enough shares
481
+ const docInfo = await quorumService.getDocument(documentId);
482
+ if (!docInfo) {
483
+ return (0, errorResponse_1.notFoundError)('Document', documentId);
484
+ }
485
+ // Check if provided members can unlock the document
486
+ const memberIds = memberCredentials.map((c) => c.memberId);
487
+ const canUnlockResult = await quorumService.canUnlock(documentId, memberIds);
488
+ if (!canUnlockResult.canUnlock) {
489
+ return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.INSUFFICIENT_SHARES, `Insufficient shares: provided ${canUnlockResult.sharesProvided}, required ${canUnlockResult.sharesRequired}`);
490
+ }
491
+ // Recover members with private keys from mnemonics
492
+ const eciesService = brightchain_lib_1.ServiceProvider.getInstance().eciesService;
493
+ const membersWithPrivateKey = [];
494
+ for (const cred of memberCredentials) {
495
+ // Get the stored member info to get their metadata
496
+ const storedMember = await quorumService.getMember(cred.memberId);
497
+ if (!storedMember) {
498
+ return (0, errorResponse_1.notFoundError)('Member', cred.memberId);
499
+ }
500
+ // Recover wallet from mnemonic - need to wrap string in SecureString
501
+ const secureString = new ecies_lib_1.SecureString(cred.mnemonic);
502
+ const { wallet } = eciesService.walletAndSeedFromMnemonic(secureString);
503
+ const recoveredPublicKey = new Uint8Array(wallet.getPublicKey());
504
+ // Verify the recovered public key matches the stored one
505
+ if ((0, ecies_lib_1.uint8ArrayToHex)(recoveredPublicKey) !==
506
+ (0, ecies_lib_1.uint8ArrayToHex)(storedMember.publicKey)) {
507
+ return (0, errorResponse_1.createApiErrorResult)(400, errorResponse_1.ErrorCode.SHARE_DECRYPTION_FAILED, `Mnemonic does not match member ${cred.memberId}`);
508
+ }
509
+ // Create a member with the recovered private key
510
+ const email = storedMember.metadata.email
511
+ ? new ecies_lib_1.EmailString(storedMember.metadata.email)
512
+ : new ecies_lib_1.EmailString(`${storedMember.metadata.name?.toLowerCase().replace(/\s+/g, '.') ?? 'unknown'}@placeholder.local`);
513
+ // Use Member.newMember and then replace the wallet
514
+ // This is a workaround since Member constructor may not accept wallet directly
515
+ const { member: tempMember } = ecies_lib_1.Member.newMember(eciesService, ecies_lib_1.MemberType.User, storedMember.metadata.name ?? 'Unknown', email);
516
+ // Create a member-like object with the recovered wallet's private key
517
+ // The unsealDocument method needs members with privateKey access
518
+ const recoveredMember = Object.create(tempMember);
519
+ Object.defineProperty(recoveredMember, 'privateKey', {
520
+ get: () => new Uint8Array(wallet.getPrivateKey()),
521
+ configurable: true,
522
+ });
523
+ Object.defineProperty(recoveredMember, 'publicKey', {
524
+ get: () => recoveredPublicKey,
525
+ configurable: true,
526
+ });
527
+ membersWithPrivateKey.push(recoveredMember);
528
+ }
529
+ // Unseal the document
530
+ const unsealedDocument = await quorumService.unsealDocument(documentId, membersWithPrivateKey);
531
+ return {
532
+ statusCode: 200,
533
+ response: {
534
+ message: 'Document unsealed successfully',
535
+ document: unsealedDocument,
536
+ },
537
+ };
538
+ }
539
+ catch (_error) {
540
+ if (_error instanceof brightchain_lib_1.QuorumError) {
541
+ return (0, errorResponse_1.mapQuorumError)(_error);
542
+ }
543
+ return (0, errorResponse_1.handleError)(_error);
544
+ }
545
+ }
546
+ /**
547
+ * GET /api/quorum/documents/:documentId
548
+ * Get metadata for a sealed document.
549
+ *
550
+ * Returns information about the document including which members have access
551
+ * and how many shares are required to unseal it.
552
+ *
553
+ * @param req - Request containing the document ID parameter
554
+ * @returns Document metadata on success, or 404 if not found
555
+ *
556
+ * @example
557
+ * ```json
558
+ * // Request
559
+ * GET /api/quorum/documents/doc123...
560
+ *
561
+ * // Response
562
+ * {
563
+ * "message": "Document retrieved successfully",
564
+ * "document": {
565
+ * "id": "doc123...",
566
+ * "memberIds": ["member1...", "member2...", "member3..."],
567
+ * "sharesRequired": 2,
568
+ * "createdAt": "2025-01-16T10:00:00Z",
569
+ * "creatorId": "creator..."
570
+ * }
571
+ * }
572
+ * ```
573
+ */
574
+ async handleGetDocument(req) {
575
+ try {
576
+ const { documentId } = req.params;
577
+ if (!documentId) {
578
+ return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
579
+ }
580
+ const quorumService = this.quorumServiceWrapper.getService();
581
+ const document = await quorumService.getDocument(documentId);
582
+ if (!document) {
583
+ return (0, errorResponse_1.notFoundError)('Document', documentId);
584
+ }
585
+ return {
586
+ statusCode: 200,
587
+ response: {
588
+ message: 'Document retrieved successfully',
589
+ document,
590
+ },
591
+ };
592
+ }
593
+ catch (_error) {
594
+ if (_error instanceof brightchain_lib_1.QuorumError) {
595
+ return (0, errorResponse_1.mapQuorumError)(_error);
596
+ }
597
+ return (0, errorResponse_1.handleError)(_error);
598
+ }
599
+ }
600
+ /**
601
+ * GET /api/quorum/documents/:documentId/can-unlock
602
+ * Check if a set of members can unlock a document.
603
+ *
604
+ * Determines whether the provided members have enough shares to meet
605
+ * the threshold required to unseal the document.
606
+ *
607
+ * @param req - Request containing document ID and member IDs query parameter
608
+ * @returns Unlock status and share count information
609
+ *
610
+ * @example
611
+ * ```json
612
+ * // Request
613
+ * GET /api/quorum/documents/doc123.../can-unlock?memberIds=member1,member2
614
+ *
615
+ * // Response
616
+ * {
617
+ * "message": "Can-unlock check completed",
618
+ * "canUnlock": true,
619
+ * "sharesProvided": 2,
620
+ * "sharesRequired": 2,
621
+ * "missingMembers": ["member3..."]
622
+ * }
623
+ * ```
624
+ */
625
+ async handleCanUnlock(req) {
626
+ try {
627
+ const { documentId } = req.params;
628
+ const { memberIds: memberIdsStr } = req
629
+ .query;
630
+ if (!documentId) {
631
+ return (0, errorResponse_1.validationError)('Missing required parameter: documentId');
632
+ }
633
+ if (!memberIdsStr) {
634
+ return (0, errorResponse_1.validationError)('Missing required query parameter: memberIds (comma-separated)');
635
+ }
636
+ const memberIds = memberIdsStr
637
+ .split(',')
638
+ .map((id) => id.trim());
639
+ const quorumService = this.quorumServiceWrapper.getService();
640
+ const result = await quorumService.canUnlock(documentId, memberIds);
641
+ return {
642
+ statusCode: 200,
643
+ response: {
644
+ message: 'Can-unlock check completed',
645
+ ...result,
646
+ },
647
+ };
648
+ }
649
+ catch (_error) {
650
+ if (_error instanceof brightchain_lib_1.QuorumError) {
651
+ return (0, errorResponse_1.mapQuorumError)(_error);
652
+ }
653
+ return (0, errorResponse_1.handleError)(_error);
654
+ }
655
+ }
656
656
  }
657
657
  exports.QuorumController = QuorumController;
658
658
  //# sourceMappingURL=quorum.js.map