@mojaloop/central-ledger 19.14.0 → 20.1.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 (394) hide show
  1. package/.grype.yaml +3 -0
  2. package/.license-scanner.json +16 -0
  3. package/.ncurc.yaml +19 -13
  4. package/.nvmrc +1 -1
  5. package/.nycrc.yml +14 -2
  6. package/CHANGELOG.md +51 -0
  7. package/Dockerfile +13 -10
  8. package/README.md +39 -89
  9. package/audit-ci.jsonc +1 -1
  10. package/config/default.json +60 -3
  11. package/config/deprecated.default-settlement.json +160 -0
  12. package/docker/ml-api-adapter/default.json +28 -0
  13. package/docker-compose.yml +6 -0
  14. package/nodemon.json +6 -0
  15. package/package.json +128 -64
  16. package/{sbom-v19.13.2.csv → sbom-v20.0.0.csv} +886 -736
  17. package/scripts/_wait4_all.js +5 -5
  18. package/scripts/transferSettlementTemp/interchangeFeeCalculation.js +51 -0
  19. package/src/api/index.ts +30 -0
  20. package/src/api/interface/swagger.json +2249 -2054
  21. package/src/api/participants/routes.js +1 -1
  22. package/src/api/root/handler.int.ts +55 -0
  23. package/src/api/routes.js +7 -6
  24. package/src/api/server.ts +27 -0
  25. package/src/api/server.unit.ts +16 -0
  26. package/src/api/settlementModels/routes.js +4 -4
  27. package/src/domain/participant/index.d.ts +47 -0
  28. package/src/domain/participant/index.int.ts +724 -0
  29. package/src/domain/participant/index.js +4 -5
  30. package/src/domain/position/fx-prepare.js +1 -1
  31. package/src/domain/position/fx-timeout-reserved.js +6 -0
  32. package/src/domain/position/prepare.js +1 -1
  33. package/src/handlers/admin/handler.js +1 -1
  34. package/src/handlers/index.js +30 -0
  35. package/src/handlers/positions/handler.js +0 -2
  36. package/src/handlers/positions/handlerBatch.js +5 -5
  37. package/src/handlers/register.js +44 -29
  38. package/src/handlers/timeouts/handler.js +1 -4
  39. package/src/handlers/transfers/fx-abort.int.ts +209 -0
  40. package/src/handlers/transfers/fx-handlers.int.ts +275 -0
  41. package/src/handlers/transfers/fx-timeout.int.ts +284 -0
  42. package/src/handlers/transfers/handler.js +1 -3
  43. package/src/handlers/transfers/handlers.int.ts +538 -0
  44. package/src/handlers/transfers/prepare.int.ts +1283 -0
  45. package/src/handlers/transfers/prepare.js +2 -2
  46. package/src/knexfile.js +19 -0
  47. package/src/lib/cache.js +1 -1
  48. package/src/lib/config/index.ts +60 -0
  49. package/src/lib/config/resolver.ts +231 -0
  50. package/src/lib/config/resolver.unit.ts +72 -0
  51. package/src/lib/config/types.ts +372 -0
  52. package/src/lib/config/util.ts +523 -0
  53. package/src/lib/config/util.unit.ts +825 -0
  54. package/src/lib/migrator.js +3 -3
  55. package/src/lib/proxyCache.js +3 -3
  56. package/{migrations → src/migrations}/100100_event.js +1 -1
  57. package/{migrations → src/migrations}/110100_contactType.js +1 -1
  58. package/{migrations → src/migrations}/110200_currency.js +1 -1
  59. package/{migrations → src/migrations}/110201_currency-scale.js +1 -1
  60. package/{migrations → src/migrations}/110300_endpointType.js +1 -1
  61. package/{migrations → src/migrations}/110400_ledgerEntryType.js +1 -1
  62. package/{migrations → src/migrations}/110450_ledgerAccountType.js +1 -1
  63. package/{migrations → src/migrations}/110500_participantLimitType.js +1 -1
  64. package/{migrations → src/migrations}/110600_transferParticipantRoleType.js +1 -1
  65. package/{migrations → src/migrations}/110700_transferState.js +1 -1
  66. package/{migrations → src/migrations}/110900_settlementState.js +1 -1
  67. package/{migrations → src/migrations}/112000_bulkTransferState.js +1 -1
  68. package/{migrations → src/migrations}/112100_bulkProcessingState.js +1 -1
  69. package/{migrations → src/migrations}/200100_participant.js +1 -1
  70. package/{migrations → src/migrations}/200200_participantContact.js +1 -1
  71. package/{migrations → src/migrations}/200300_participantEndpoint.js +1 -1
  72. package/{migrations → src/migrations}/200400_participantParty.js +1 -1
  73. package/{migrations → src/migrations}/200600_token.js +1 -1
  74. package/{migrations → src/migrations}/200601_token-indexes.js +1 -1
  75. package/{migrations → src/migrations}/300100_transferDuplicateCheck.js +2 -2
  76. package/{migrations → src/migrations}/300150_bulkTransferDuplicateCheck.js +2 -2
  77. package/{migrations → src/migrations}/300200_transfer.js +2 -2
  78. package/{migrations → src/migrations}/300202_transfer-decimal184.js +1 -1
  79. package/{migrations → src/migrations}/300250_bulkTransfer.js +2 -3
  80. package/{migrations → src/migrations}/300275_bulkTransferAssociation.js +2 -3
  81. package/{migrations → src/migrations}/300300_ilpPacket.js +1 -1
  82. package/{migrations → src/migrations}/300400_transferStateChange.js +1 -1
  83. package/{migrations → src/migrations}/300450_bulkTransferStateChange.js +1 -1
  84. package/{migrations → src/migrations}/300500_segment.js +1 -1
  85. package/{migrations → src/migrations}/310100_participantCurrency.js +1 -1
  86. package/{migrations → src/migrations}/310200_transferParticipant.js +1 -1
  87. package/{migrations → src/migrations}/310202_transferParticipant-decimal184.js +1 -1
  88. package/{migrations → src/migrations}/310204_transferParticipant-participantId.js +2 -2
  89. package/{migrations → src/migrations}/310300_participantPosition.js +1 -1
  90. package/{migrations → src/migrations}/310302_participantPosition-decimal184.js +1 -1
  91. package/{migrations → src/migrations}/310400_participantPositionChange.js +1 -1
  92. package/{migrations → src/migrations}/310402_participantPositionChange-decimal184.js +1 -1
  93. package/{migrations → src/migrations}/310403_participantPositionChange-participantCurrencyId.js +2 -2
  94. package/{migrations → src/migrations}/310404_participantPositionChange-change.js +2 -2
  95. package/{migrations → src/migrations}/310500_participantLimit.js +1 -1
  96. package/{migrations → src/migrations}/310502_participantLimit-decimal184.js +1 -1
  97. package/{migrations → src/migrations}/400100_settlementWindow.js +1 -1
  98. package/{migrations → src/migrations}/400200_settlement.js +1 -1
  99. package/{migrations → src/migrations}/400300_settlementSettlementWindow.js +1 -1
  100. package/{migrations → src/migrations}/400301_settlementSettlementWindow-indexes.js +0 -1
  101. package/{migrations → src/migrations}/400400_settlementWindowStateChange.js +1 -1
  102. package/{migrations → src/migrations}/400500_settlementTransferParticipant.js +1 -1
  103. package/{migrations → src/migrations}/400502_settlementTransferParticipant-decimal184.js +1 -1
  104. package/{migrations → src/migrations}/400600_settlementParticipantCurrency.js +1 -1
  105. package/{migrations → src/migrations}/400602_settlementParticipantCurrency-decimal184.js +1 -1
  106. package/{migrations → src/migrations}/400700_settlementParticipantCurrencyStateChange.js +1 -1
  107. package/{migrations → src/migrations}/400800_settlementStateChange.js +1 -1
  108. package/{migrations → src/migrations}/400900_settlementWindowContent.js +1 -1
  109. package/{migrations → src/migrations}/401000_settlementWindowContentStateChange.js +1 -1
  110. package/{migrations → src/migrations}/401001_settlementWindowContentStateChange-indexes.js +6 -6
  111. package/{migrations → src/migrations}/401200_settlementContentAggregation.js +1 -1
  112. package/{migrations → src/migrations}/401300_settlementModel.js +1 -1
  113. package/{migrations → src/migrations}/410100_transferFulfilmentDuplicateCheck.js +1 -1
  114. package/{migrations → src/migrations}/410102_transferFulfilmentDuplicateCheck-dropForeignTransferId.js +1 -1
  115. package/{migrations → src/migrations}/410103_transferFulfilmentDuplicateCheck-hashNullable.js +1 -1
  116. package/{migrations → src/migrations}/410200_transferFulfilment.js +1 -1
  117. package/{migrations → src/migrations}/410202_transferFulfilment-ilpFulfilment.js +1 -1
  118. package/{migrations → src/migrations}/410203_transferFulfilment-foreignTransferFulfilmentId.js +1 -1
  119. package/{migrations → src/migrations}/410240_bulkTransferFulfilmentDuplicateCheck.js +1 -1
  120. package/{migrations → src/migrations}/410250_bulkTransferFulfilment.js +1 -1
  121. package/{migrations → src/migrations}/410300_transferExtension.js +1 -1
  122. package/{migrations → src/migrations}/410302_transferExtension-transferErrorId.js +1 -1
  123. package/{migrations → src/migrations}/410350_bulkTransferExtension.js +1 -1
  124. package/{migrations → src/migrations}/410400_transferTimeout.js +1 -1
  125. package/{migrations → src/migrations}/410450_transferErrorDuplicateCheck.js +1 -1
  126. package/{migrations → src/migrations}/410500_transferError.js +1 -1
  127. package/{migrations → src/migrations}/410502_transferError-foreignTransferErrorDuplicateCheckId.js +1 -1
  128. package/{migrations → src/migrations}/410550_bulkTransferError.js +1 -1
  129. package/{migrations → src/migrations}/410600_expiringTransfer.js +1 -1
  130. package/{migrations → src/migrations}/500401_quote-hotfix-2719.js +8 -8
  131. package/{migrations → src/migrations}/500501_feature-fixSubIdRef.js +12 -12
  132. package/{migrations → src/migrations}/500601_party-2480.js +3 -3
  133. package/{migrations → src/migrations}/501001_quoteExtension-quote-service-174.js +1 -2
  134. package/{migrations → src/migrations}/501002_quoteExtension-2522.js +3 -3
  135. package/{migrations → src/migrations}/600010_fxTransferType.js +1 -1
  136. package/{migrations → src/migrations}/600012_fxParticipantCurrencyType.js +1 -1
  137. package/{migrations → src/migrations}/600100_fxTransferDuplicateCheck.js +2 -2
  138. package/{migrations → src/migrations}/600110_fxTransferErrorDuplicateCheck.js.js +1 -1
  139. package/{migrations → src/migrations}/600200_fxTransfer.js +2 -2
  140. package/{migrations → src/migrations}/600400_fxTransferStateChange.js +1 -1
  141. package/{migrations → src/migrations}/600501_fxWatchList.js +2 -2
  142. package/{migrations → src/migrations}/600600_fxTransferFulfilmentDuplicateCheck.js +1 -1
  143. package/{migrations → src/migrations}/600700_fxTransferFulfilment.js +1 -1
  144. package/{migrations → src/migrations}/600800_fxTransferExtension.js +1 -1
  145. package/{migrations → src/migrations}/601400_fxTransferTimeout.js +1 -1
  146. package/{migrations → src/migrations}/601500_fxTransferError.js +1 -1
  147. package/{migrations → src/migrations}/610200_fxTransferParticipant.js +1 -1
  148. package/{migrations → src/migrations}/610202_fxTransferParticipant-participantId.js +2 -2
  149. package/{migrations → src/migrations}/610403_participantPositionChange-fxTransfer.js +1 -1
  150. package/{migrations → src/migrations}/800100_quotePartyView.js +1 -1
  151. package/{migrations → src/migrations}/800101_feature-fixSubIdRef.js +1 -1
  152. package/{migrations → src/migrations}/800200_quoteView.js +1 -1
  153. package/{migrations → src/migrations}/800300_quoteResponseView.js +1 -1
  154. package/{migrations → src/migrations}/900100_foreign-keys.js +18 -18
  155. package/{migrations → src/migrations}/900101_foreign-keys.js +6 -6
  156. package/{migrations → src/migrations}/910100_feature904DDL.js +7 -7
  157. package/{migrations → src/migrations}/910101_feature904DataMigration.js +1 -1
  158. package/{migrations → src/migrations}/910102_feature949DataMigration.js +1 -1
  159. package/{migrations → src/migrations}/910103_feature1093SettlementByCurrency.js +3 -3
  160. package/{migrations → src/migrations}/940101_quotePartyIdInfoExtension-2522.js +25 -25
  161. package/{migrations → src/migrations}/950101_transferParticipantStateChange.js +2 -2
  162. package/{migrations → src/migrations}/950102_settlementModel-adjustPosition.js +2 -2
  163. package/{migrations → src/migrations}/950103_dropTransferParticipantStateChange.js +3 -3
  164. package/{migrations → src/migrations}/950104_settlementModel-settlementAccountTypeId.js +3 -3
  165. package/src/migrations/950107_settlementWindowContent_foreign_settlementModel.js +63 -0
  166. package/{migrations → src/migrations}/950108_participantProxy.js +1 -2
  167. package/{migrations → src/migrations}/950120_fxQuoteConversionTerms_sourceAmount_nullable.js +1 -1
  168. package/{migrations → src/migrations}/960100_create_externalParticipant.js +2 -2
  169. package/{migrations → src/migrations}/960110_alter_transferParticipant__addFiled_externalParticipantId.js +2 -2
  170. package/{migrations → src/migrations}/961001_transferForwarded.js +1 -1
  171. package/{migrations → src/migrations}/961002_fxTransferForwarded.js +1 -1
  172. package/src/models/participant/externalParticipant.int.ts +85 -0
  173. package/src/models/participant/facade.js +4 -2
  174. package/src/models/participant/participantCurrencyCached.js +1 -1
  175. package/src/models/position/facade.js +8 -2
  176. package/src/models/transfer/facade.int.ts +139 -0
  177. package/src/models/transfer/facade.js +8 -3
  178. package/src/models/transfer/transferDuplicateCheck.js +2 -2
  179. package/src/models/transfer/transferError.int.ts +112 -0
  180. package/src/models/transfer/transferExtension.int.ts +137 -0
  181. package/src/models/transfer/transferStateChange.int.ts +117 -0
  182. package/{seeds → src/seeds}/participant.js +1 -1
  183. package/{seeds → src/seeds}/settlementInterchange.js +1 -0
  184. package/src/settlement/api/handlerRoutes.js +71 -0
  185. package/src/settlement/api/handlers/health.js +10 -0
  186. package/src/settlement/api/handlers/index.js +57 -0
  187. package/src/settlement/api/handlers/settlementWindows/{id}.js +103 -0
  188. package/src/settlement/api/handlers/settlementWindows.js +77 -0
  189. package/src/settlement/api/handlers/settlements/{id}.js +133 -0
  190. package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}/accounts/{aid}.js +127 -0
  191. package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}.js +127 -0
  192. package/src/settlement/api/handlers/settlements.js +114 -0
  193. package/src/settlement/api/openapiRouting.js +87 -0
  194. package/src/settlement/api/routes.js +176 -0
  195. package/src/settlement/domain/rules/index.js +46 -0
  196. package/src/settlement/domain/settlement/index.js +405 -0
  197. package/src/settlement/domain/settlementWindow/index.js +117 -0
  198. package/src/settlement/domain/transactions/index.js +83 -0
  199. package/src/settlement/domain/transferSettlement/index.js +57 -0
  200. package/src/settlement/handlers/deferredSettlement/handler.js +180 -0
  201. package/src/settlement/handlers/grossSettlement/handler.js +180 -0
  202. package/src/settlement/handlers/index.js +101 -0
  203. package/src/settlement/handlers/register.js +92 -0
  204. package/src/settlement/handlers/rules/handler.js +164 -0
  205. package/src/settlement/interface/swagger-handler.json +34 -0
  206. package/src/settlement/interface/swagger.json +1560 -0
  207. package/src/settlement/lib/db.js +32 -0
  208. package/src/settlement/lib/kafka/index.js +41 -0
  209. package/src/settlement/lib/kafka/producer.js +142 -0
  210. package/src/settlement/lib/scriptEngine.js +99 -0
  211. package/src/settlement/lib/scriptsLoader.js +175 -0
  212. package/src/settlement/lib/utility.js +243 -0
  213. package/src/settlement/models/ilpPackets/ilpPacket.js +42 -0
  214. package/src/settlement/models/lib/enums.js +192 -0
  215. package/src/settlement/models/misc/migrationLock.js +53 -0
  216. package/src/settlement/models/settlement/facade.js +1652 -0
  217. package/src/settlement/models/settlement/index.js +55 -0
  218. package/src/settlement/models/settlement/participantCurrency.js +48 -0
  219. package/src/settlement/models/settlement/settlement.js +49 -0
  220. package/src/settlement/models/settlement/settlementModel.js +44 -0
  221. package/src/settlement/models/settlement/settlementParticipantCurrency.js +61 -0
  222. package/src/settlement/models/settlement/settlementStateChange.js +44 -0
  223. package/src/settlement/models/settlement/settlementTransferParticipant.js +46 -0
  224. package/src/settlement/models/settlementWindow/facade.js +345 -0
  225. package/src/settlement/models/settlementWindow/index.js +47 -0
  226. package/src/settlement/models/settlementWindow/settlementWindowStateChange.js +55 -0
  227. package/src/settlement/models/settlementWindowContent/facade.js +79 -0
  228. package/src/settlement/models/settlementWindowContent/index.js +40 -0
  229. package/src/settlement/models/settlementWindowContent/settlementWindowContentStateChange.js +53 -0
  230. package/src/settlement/models/transferSettlement/facade.js +363 -0
  231. package/src/settlement/models/transferSettlement/index.js +42 -0
  232. package/src/settlement/shared/logger/index.js +7 -0
  233. package/src/settlement/shared/plugins.js +88 -0
  234. package/src/settlement/shared/setup.js +224 -0
  235. package/src/settlement/utils/truthyProperty.js +37 -0
  236. package/src/shared/legacyUtilShim.js +20 -0
  237. package/src/shared/plugins.js +3 -3
  238. package/src/shared/results.ts +22 -0
  239. package/src/shared/results.unit.ts +38 -0
  240. package/src/shared/setup.js +14 -1
  241. package/src/testing/api-helpers.ts +1222 -0
  242. package/src/testing/exec-async.ts +67 -0
  243. package/src/testing/harness.snapshot.sql +3895 -0
  244. package/src/testing/harness.test.ts +15 -0
  245. package/src/testing/harness.ts +1160 -0
  246. package/src/testing/kafka.ts +221 -0
  247. package/src/testing/prng.ts +82 -0
  248. package/src/testing/rdkafka.test.ts +263 -0
  249. package/src/testing/run.ts +559 -0
  250. package/src/testing/snapshot.test.ts +92 -0
  251. package/src/testing/snapshot.ts +549 -0
  252. package/src/testing/tap-stream.ts +164 -0
  253. package/src/testing/types.ts +95 -0
  254. package/src/testing/util.ts +333 -0
  255. package/src/types/central-services-error-handling.d.ts +72 -0
  256. package/src/types/central-services-stream.d.ts +148 -0
  257. package/test-integration.Dockerfile +0 -2
  258. package/test.Dockerfile +0 -2
  259. package/tsconfig.json +40 -0
  260. package/config/knexfile.js +0 -19
  261. package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +0 -63
  262. package/src/api/index.js +0 -16
  263. package/src/lib/config.js +0 -81
  264. /package/{migrations → src/migrations}/110101_contactType-indexes.js +0 -0
  265. /package/{migrations → src/migrations}/110301_endpointType-indexes.js +0 -0
  266. /package/{migrations → src/migrations}/110401_ledgerEntryType-indexes.js +0 -0
  267. /package/{migrations → src/migrations}/110451_ledgerAccountType-indexes.js +0 -0
  268. /package/{migrations → src/migrations}/110501_participantLimitType-indexes.js +0 -0
  269. /package/{migrations → src/migrations}/110601_transferParticipantRoleType-indexes.js +0 -0
  270. /package/{migrations → src/migrations}/110800_settlementWindowState.js +0 -0
  271. /package/{migrations → src/migrations}/111000_amountType.js +0 -0
  272. /package/{migrations → src/migrations}/111001_amountType-indexes.js +0 -0
  273. /package/{migrations → src/migrations}/111100_balanceOfPayments.js +0 -0
  274. /package/{migrations → src/migrations}/111101_balanceOfPayments-indexes.js +0 -0
  275. /package/{migrations → src/migrations}/111200_partyIdentifierType.js +0 -0
  276. /package/{migrations → src/migrations}/111201_partyIdentifierType-indexes.js +0 -0
  277. /package/{migrations → src/migrations}/111300_partyType.js +0 -0
  278. /package/{migrations → src/migrations}/111301_partyType-indexes.js +0 -0
  279. /package/{migrations → src/migrations}/111400_quoteDuplicateCheck.js +0 -0
  280. /package/{migrations → src/migrations}/111500_transactionInitiator.js +0 -0
  281. /package/{migrations → src/migrations}/111501_transactionInitiator-indexes.js +0 -0
  282. /package/{migrations → src/migrations}/111600_transactionInitiatorType.js +0 -0
  283. /package/{migrations → src/migrations}/111601_transactionInitiatorType-indexes.js +0 -0
  284. /package/{migrations → src/migrations}/111700_settlementDelay.js +0 -0
  285. /package/{migrations → src/migrations}/111701_settlementDelay-indexes.js +0 -0
  286. /package/{migrations → src/migrations}/111800_settlementInterchange.js +0 -0
  287. /package/{migrations → src/migrations}/111801_settlementInterchange-indexes.js +0 -0
  288. /package/{migrations → src/migrations}/111900_settlementGranularity.js +0 -0
  289. /package/{migrations → src/migrations}/111901_settlementGranularity-indexes.js +0 -0
  290. /package/{migrations → src/migrations}/112101_bulkProcessingState-indexes.js +0 -0
  291. /package/{migrations → src/migrations}/200101_participant-indexes.js +0 -0
  292. /package/{migrations → src/migrations}/200201_participantContact-indexes.js +0 -0
  293. /package/{migrations → src/migrations}/200301_participantEndpoint-indexes.js +0 -0
  294. /package/{migrations → src/migrations}/200401_participantParty-indexes.js +0 -0
  295. /package/{migrations → src/migrations}/300201_transfer-indexes.js +0 -0
  296. /package/{migrations → src/migrations}/300251_bulkTransfer-indexes.js +0 -0
  297. /package/{migrations → src/migrations}/300276_bulkTransferAssociation-indexes.js +0 -0
  298. /package/{migrations → src/migrations}/300401_transferStateChange-indexes.js +0 -0
  299. /package/{migrations → src/migrations}/300451_bulkTransferStateChange-indexes.js +0 -0
  300. /package/{migrations → src/migrations}/300501_segment-indexes.js +0 -0
  301. /package/{migrations → src/migrations}/310101_participantCurrency-indexes.js +0 -0
  302. /package/{migrations → src/migrations}/310201_transferParticipant-indexes.js +0 -0
  303. /package/{migrations → src/migrations}/310203_transferParticipant-indexes.js +0 -0
  304. /package/{migrations → src/migrations}/310301_participantPosition-indexes.js +0 -0
  305. /package/{migrations → src/migrations}/310401_participantPositionChange-indexes.js +0 -0
  306. /package/{migrations → src/migrations}/310405_participantPositionChange-positionChange.js +0 -0
  307. /package/{migrations → src/migrations}/310406_participantPositionChange-positionChange-revert.js +0 -0
  308. /package/{migrations → src/migrations}/310501_participantLimit-indexes.js +0 -0
  309. /package/{migrations → src/migrations}/310503_participantLimit-indexes-composite.js +0 -0
  310. /package/{migrations → src/migrations}/400401_settlmentWindowStateChange-indexes.js +0 -0
  311. /package/{migrations → src/migrations}/400501_settlementTransferParticipant-indexes.js +0 -0
  312. /package/{migrations → src/migrations}/400601_settlementParticipantCurrency-indexes.js +0 -0
  313. /package/{migrations → src/migrations}/400701_settlementParticipantCurrencyStateChange-indexes.js +0 -0
  314. /package/{migrations → src/migrations}/400801_settlementStateChange-indexes.js +0 -0
  315. /package/{migrations → src/migrations}/401002_settlementWindowContent-indexes.js +0 -0
  316. /package/{migrations → src/migrations}/401201_settlementContentAggregation-indexes.js +0 -0
  317. /package/{migrations → src/migrations}/401301_settlementModel-indexes.js +0 -0
  318. /package/{migrations → src/migrations}/410101_transferFulfilmentDuplicateCheck-indexes.js +0 -0
  319. /package/{migrations → src/migrations}/410201_transferFulfilment-indexes.js +0 -0
  320. /package/{migrations → src/migrations}/410301_transferExtension-indexes.js +0 -0
  321. /package/{migrations → src/migrations}/410351_bulkTransferExtension-indexes.js +0 -0
  322. /package/{migrations → src/migrations}/410401_transferTimeout-indexes.js +0 -0
  323. /package/{migrations → src/migrations}/410501_transferError-indexes.js +0 -0
  324. /package/{migrations → src/migrations}/410551_bulkTransferError-indexes.js +0 -0
  325. /package/{migrations → src/migrations}/410601_expiringTransfer-indexes.js +0 -0
  326. /package/{migrations → src/migrations}/500100_transactionReference.js +0 -0
  327. /package/{migrations → src/migrations}/500101_transactionReference-indexes.js +0 -0
  328. /package/{migrations → src/migrations}/500200_transactionScenario.js +0 -0
  329. /package/{migrations → src/migrations}/500201_transactionScenario-indexes.js +0 -0
  330. /package/{migrations → src/migrations}/500300_transactionSubScenario.js +0 -0
  331. /package/{migrations → src/migrations}/500400_quote.js +0 -0
  332. /package/{migrations → src/migrations}/500500_quoteParty.js +0 -0
  333. /package/{migrations → src/migrations}/500600_party.js +0 -0
  334. /package/{migrations → src/migrations}/500700_quoteResponse.js +0 -0
  335. /package/{migrations → src/migrations}/500800_quoteResponseIlpPacket.js +0 -0
  336. /package/{migrations → src/migrations}/500900_geoCode.js +0 -0
  337. /package/{migrations → src/migrations}/501000_quoteExtension.js +0 -0
  338. /package/{migrations → src/migrations}/501100_quoteResponseDuplicateCheck.js +0 -0
  339. /package/{migrations → src/migrations}/501200_quoteError.js +0 -0
  340. /package/{migrations → src/migrations}/501300_transferRules.js +0 -0
  341. /package/{migrations → src/migrations}/600011_fxTransferType-indexes.js +0 -0
  342. /package/{migrations → src/migrations}/600013_fxParticipantCurrencyType-indexes.js +0 -0
  343. /package/{migrations → src/migrations}/600201_fxTransfer-indexes.js +0 -0
  344. /package/{migrations → src/migrations}/600401_fxTransferStateChange-indexes.js +0 -0
  345. /package/{migrations → src/migrations}/600502_fxWatchList-indexes.js +0 -0
  346. /package/{migrations → src/migrations}/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +0 -0
  347. /package/{migrations → src/migrations}/600701_fxTransferFulfilment-indexes.js +0 -0
  348. /package/{migrations → src/migrations}/601401_fxTransferTimeout-indexes.js +0 -0
  349. /package/{migrations → src/migrations}/601501_fxTransferError-indexes.js +0 -0
  350. /package/{migrations → src/migrations}/610201_fxTransferParticipant-indexes.js +0 -0
  351. /package/{migrations → src/migrations}/910102_hotfix954.js +0 -0
  352. /package/{migrations → src/migrations}/940100_quotePartyIdInfoExtension.js +0 -0
  353. /package/{migrations → src/migrations}/950100_settlementContentAggregation-decimal184.js +0 -0
  354. /package/{migrations → src/migrations}/950106_unique_settlement_model_ledger_account_currency.js +0 -0
  355. /package/{migrations → src/migrations}/950109_fxQuote.js +0 -0
  356. /package/{migrations → src/migrations}/950110_fxQuoteResponse.js +0 -0
  357. /package/{migrations → src/migrations}/950111_fxQuoteError.js +0 -0
  358. /package/{migrations → src/migrations}/950113_fxQuoteDuplicateCheck.js +0 -0
  359. /package/{migrations → src/migrations}/950114_fxQuoteResponseDuplicateCheck.js +0 -0
  360. /package/{migrations → src/migrations}/950115_fxQuoteConversionTerms.js +0 -0
  361. /package/{migrations → src/migrations}/950116_fxQuoteConversionTermsExtension.js +0 -0
  362. /package/{migrations → src/migrations}/950117_fxQuoteResponseConversionTerms.js +0 -0
  363. /package/{migrations → src/migrations}/950118_fxQuoteResponseConversionTermsExtension.js +0 -0
  364. /package/{migrations → src/migrations}/950119_fxCharge.js +0 -0
  365. /package/{migrations → src/migrations}/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +0 -0
  366. /package/{migrations → src/migrations}/960112_fxTransfer-indexes2.js +0 -0
  367. /package/{migrations → src/migrations}/960113_fxTransferExtension-indexes.js +0 -0
  368. /package/{migrations → src/migrations}/960114_fxTransferTimeout-indexes2.js +0 -0
  369. /package/{migrations → src/migrations}/961000_participantEndpoint_unique.js +0 -0
  370. /package/{migrations → src/migrations}/migration.template +0 -0
  371. /package/{seeds → src/seeds}/amountType.js +0 -0
  372. /package/{seeds → src/seeds}/balanceOfPayments.js +0 -0
  373. /package/{seeds → src/seeds}/bulkProcessingState.js +0 -0
  374. /package/{seeds → src/seeds}/bulkTransferState.js +0 -0
  375. /package/{seeds → src/seeds}/currency.js +0 -0
  376. /package/{seeds → src/seeds}/endpointType.js +0 -0
  377. /package/{seeds → src/seeds}/fxParticipantCurrencyType.js +0 -0
  378. /package/{seeds → src/seeds}/fxTransferType.js +0 -0
  379. /package/{seeds → src/seeds}/ledgerAccountType.js +0 -0
  380. /package/{seeds → src/seeds}/ledgerEntryType.js +0 -0
  381. /package/{seeds → src/seeds}/participantLimitType.js +0 -0
  382. /package/{seeds → src/seeds}/partyIdentifierType.js +0 -0
  383. /package/{seeds → src/seeds}/partyType.js +0 -0
  384. /package/{seeds → src/seeds}/settlementDelay.js +0 -0
  385. /package/{seeds → src/seeds}/settlementGranularity.js +0 -0
  386. /package/{seeds → src/seeds}/settlementState.js +0 -0
  387. /package/{seeds → src/seeds}/settlementWindow1State.js +0 -0
  388. /package/{seeds → src/seeds}/settlementWindow2Open.js +0 -0
  389. /package/{seeds → src/seeds}/transactionInitiator.js +0 -0
  390. /package/{seeds → src/seeds}/transactionInitiatorType.js +0 -0
  391. /package/{seeds → src/seeds}/transactionScenario.js +0 -0
  392. /package/{seeds → src/seeds}/transferParticipantRoleType.js +0 -0
  393. /package/{seeds → src/seeds}/transferState.js +0 -0
  394. /package/{seeds → src/seeds}/z1000_settlementModel-deprecated.js- +0 -0
@@ -0,0 +1,523 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2026 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * TigerBeetle
23
+ - Lewis Daly <lewis@tigerbeetle.com>
24
+ --------------
25
+
26
+ ******/
27
+
28
+ import assert from 'node:assert'
29
+ import { ApplicationConfig, DatabaseConfig, DistLockConfig, InstrumentationConfig, InstrumentationMetricsLabels, KafkaConfig, KafkaConsumerConfig, KafkaProducerConfig, RecursivePartial } from './types'
30
+ import { logger } from '../../shared/logger'
31
+ import { MySqlProxyCacheConfig, RedisClusterProxyCacheConfig, RedisProxyCacheConfig } from '@mojaloop/inter-scheme-proxy-cache-lib'
32
+
33
+ class ConfigValidationError extends Error {
34
+ constructor(message: string) {
35
+ super(message)
36
+ this.name = 'ConfigValidationError'
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @function assertString
42
+ * @description Assert that the input is a string.
43
+ */
44
+ export function assertString(input: unknown): void {
45
+ if (typeof input !== 'string') {
46
+ throw new ConfigValidationError(`assertString() expected 'string', instead found ${typeof input}`)
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @function assertNumber
52
+ * @description Assert that the input is a number.
53
+ */
54
+ export function assertNumber(input: unknown): void {
55
+ if (typeof input !== 'number') {
56
+ throw new ConfigValidationError(`assertNumber() expected 'number', instead found ${typeof input}`)
57
+ }
58
+
59
+ if (Number.isNaN(input)) {
60
+ throw new ConfigValidationError(`assertNumber() expected 'number', instead found NaN`)
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @function assertBoolean
66
+ * @description Assert that the input is a boolean.
67
+ */
68
+ export function assertBoolean(input: unknown): void {
69
+ if (typeof input !== 'boolean') {
70
+ throw new ConfigValidationError(`assertNumber() expected 'boolean', instead found ${typeof input}`)
71
+ }
72
+ }
73
+
74
+ /**
75
+ * @function assertStringOrNull
76
+ * @description Assert that the input is a string or null.
77
+ */
78
+ export function assertStringOrNull(input: unknown): void {
79
+ if (input === null) {
80
+ return
81
+ }
82
+
83
+ return assertString(input)
84
+ }
85
+
86
+ /**
87
+ * @function assertStringIfDefined
88
+ * @description Assert that the input is a string if it is defined.
89
+ */
90
+ export function assertStringIfDefined(input: unknown): void {
91
+ if (input === undefined) {
92
+ return
93
+ }
94
+ assertString(input)
95
+ }
96
+
97
+ /**
98
+ * @function assertNumberIfDefined
99
+ * @description Assert that the input is a number if it is defined.
100
+ */
101
+ export function assertNumberIfDefined(input: unknown): void {
102
+ if (input === undefined) {
103
+ return
104
+ }
105
+ assertNumber(input)
106
+ }
107
+
108
+ /**
109
+ * @function assertBooleanIfDefined
110
+ * @description Assert that the input is a boolean if it is defined.
111
+ */
112
+ export function assertBooleanIfDefined(input: unknown): void {
113
+ if (input === undefined) {
114
+ return
115
+ }
116
+ assertBoolean(input)
117
+ }
118
+
119
+ /**
120
+ * @function assertProxyCacheConfig
121
+ * @description Assert that the proxy cache config is defined.
122
+ */
123
+ export function assertProxyCacheConfig(input: unknown): void {
124
+ assert(input)
125
+ if ((input as RedisClusterProxyCacheConfig).cluster) {
126
+ const unsafeConfigCluster = input as RedisClusterProxyCacheConfig
127
+ assert(Array.isArray(unsafeConfigCluster.cluster), 'Expected `cluster` to be an array.')
128
+ assert(unsafeConfigCluster.cluster.length > 0, 'Expected .cluster to contain at least 1 item.')
129
+ for (const node of unsafeConfigCluster.cluster) {
130
+ assertString(node.host)
131
+ assertNumber(node.port)
132
+ }
133
+ assertStringIfDefined(unsafeConfigCluster.username)
134
+ assertStringIfDefined(unsafeConfigCluster.password)
135
+ assertBooleanIfDefined(unsafeConfigCluster.lazyConnect)
136
+ assertNumberIfDefined(unsafeConfigCluster.db)
137
+ return
138
+ }
139
+ const unsafeEither = input as RedisProxyCacheConfig | MySqlProxyCacheConfig
140
+ const unsafeRedis = input as RedisProxyCacheConfig
141
+ const unsafeMySQL = input as MySqlProxyCacheConfig
142
+
143
+ assertString(unsafeEither.host)
144
+ assertNumber(unsafeEither.port)
145
+
146
+ // Optional RedisOptions fields.
147
+ assertStringIfDefined(unsafeRedis.username)
148
+ assertStringIfDefined(unsafeRedis.password)
149
+ assertBooleanIfDefined(unsafeRedis.lazyConnect)
150
+ assertNumberIfDefined(unsafeRedis.db)
151
+
152
+ // Optional MySqlProxyCacheConfig fields.
153
+ assertStringIfDefined(unsafeMySQL.database)
154
+ assertStringIfDefined(unsafeMySQL.user)
155
+ }
156
+
157
+ /**
158
+ * @function assertKafkaConsumerConfig
159
+ * @description Assert that a Kafka consumer config is valid.
160
+ */
161
+ export function assertKafkaConsumerConfig(input: unknown): void {
162
+ const unsafeConsumerConfig = input as KafkaConsumerConfig
163
+ assert(unsafeConsumerConfig)
164
+ assert(unsafeConsumerConfig.config)
165
+ assert(unsafeConsumerConfig.config.options)
166
+ assert(unsafeConsumerConfig.config.rdkafkaConf)
167
+ assert(unsafeConsumerConfig.config.topicConf)
168
+ }
169
+
170
+ /**
171
+ * @function assertKafkaProducerConfig
172
+ * @description Assert that a Kafka producer config is valid.
173
+ */
174
+ export function assertKafkaProducerConfig(input: unknown): void {
175
+ const unsafeProducerConfig = input as KafkaProducerConfig
176
+ assert(unsafeProducerConfig)
177
+ assert(unsafeProducerConfig.config)
178
+ assert(unsafeProducerConfig.config.options)
179
+ assert(unsafeProducerConfig.config.rdkafkaConf)
180
+ assert(unsafeProducerConfig.config.topicConf)
181
+ }
182
+
183
+ /**
184
+ * @function assertKafkaConfig
185
+ * @description Assert that the Kafka config is valid.
186
+ */
187
+ export function assertKafkaConfig(input: unknown): void {
188
+ const unsafeConfig = input as KafkaConfig
189
+ assertNestedFields(unsafeConfig, 'EVENT_TYPE_ACTION_TOPIC_MAP.POSITION')
190
+
191
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.PREPARE)
192
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.FX_PREPARE)
193
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.BULK_PREPARE)
194
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.COMMIT)
195
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.BULK_COMMIT)
196
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.RESERVE)
197
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.FX_RESERVE)
198
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.TIMEOUT_RESERVED)
199
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.FX_TIMEOUT_RESERVED)
200
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.ABORT)
201
+ assertStringOrNull(unsafeConfig.EVENT_TYPE_ACTION_TOPIC_MAP.POSITION.FX_ABORT)
202
+
203
+ assertNestedFields(unsafeConfig, 'TOPIC_TEMPLATES.PARTICIPANT_TOPIC_TEMPLATE.TEMPLATE')
204
+ assertNestedFields(unsafeConfig, 'TOPIC_TEMPLATES.PARTICIPANT_TOPIC_TEMPLATE.REGEX')
205
+ assertNestedFields(unsafeConfig, 'TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE')
206
+ assertNestedFields(unsafeConfig, 'TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.REGEX')
207
+
208
+ // Check the Consumer Configs. We can just check the leaf nodes.
209
+ assertNestedFields(unsafeConfig, 'CONSUMER.BULK.PREPARE')
210
+ assertNestedFields(unsafeConfig, 'CONSUMER.BULK.PROCESSING')
211
+ assertNestedFields(unsafeConfig, 'CONSUMER.BULK.FULFIL')
212
+ assertNestedFields(unsafeConfig, 'CONSUMER.BULK.GET')
213
+ assertNestedFields(unsafeConfig, 'CONSUMER.TRANSFER.PREPARE')
214
+ assertNestedFields(unsafeConfig, 'CONSUMER.TRANSFER.GET')
215
+ assertNestedFields(unsafeConfig, 'CONSUMER.TRANSFER.FULFIL')
216
+ assertNestedFields(unsafeConfig, 'CONSUMER.TRANSFER.POSITION')
217
+ assertNestedFields(unsafeConfig, 'CONSUMER.TRANSFER.POSITION_BATCH')
218
+ assertNestedFields(unsafeConfig, 'CONSUMER.ADMIN.TRANSFER')
219
+ assertNestedFields(unsafeConfig, 'CONSUMER.NOTIFICATION.EVENT')
220
+ assertNestedFields(unsafeConfig, 'CONSUMER.DEFERREDSETTLEMENT.CLOSE')
221
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.BULK.PREPARE)
222
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.BULK.PROCESSING)
223
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.BULK.FULFIL)
224
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.BULK.GET)
225
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.TRANSFER.PREPARE)
226
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.TRANSFER.GET)
227
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.TRANSFER.FULFIL)
228
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.TRANSFER.POSITION)
229
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.TRANSFER.POSITION_BATCH)
230
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.ADMIN.TRANSFER)
231
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.NOTIFICATION.EVENT)
232
+ assertKafkaConsumerConfig(unsafeConfig.CONSUMER.DEFERREDSETTLEMENT.CLOSE)
233
+
234
+ // Check the Producer Configs.
235
+ assert(unsafeConfig.PRODUCER)
236
+ assert(unsafeConfig.PRODUCER.BULK)
237
+ assert(unsafeConfig.PRODUCER.BULK.PROCESSING)
238
+ assert(unsafeConfig.PRODUCER.TRANSFER)
239
+ assert(unsafeConfig.PRODUCER.TRANSFER.PREPARE)
240
+ assert(unsafeConfig.PRODUCER.TRANSFER.FULFIL)
241
+ assert(unsafeConfig.PRODUCER.TRANSFER.POSITION)
242
+ assert(unsafeConfig.PRODUCER.NOTIFICATION)
243
+ assert(unsafeConfig.PRODUCER.NOTIFICATION.EVENT)
244
+ assert(unsafeConfig.PRODUCER.ADMIN)
245
+ assert(unsafeConfig.PRODUCER.ADMIN.TRANSFER)
246
+
247
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.BULK.PROCESSING)
248
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.TRANSFER.PREPARE)
249
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.TRANSFER.FULFIL)
250
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.TRANSFER.POSITION)
251
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.NOTIFICATION.EVENT)
252
+ assertKafkaProducerConfig(unsafeConfig.PRODUCER.ADMIN.TRANSFER)
253
+ }
254
+
255
+ /**
256
+ * @function assertDatabaseConfig
257
+ * @description Assert that the Database config is valid.
258
+ */
259
+ export function assertDatabaseConfig(input: unknown): void {
260
+ const unsafeConfig = input as DatabaseConfig
261
+ assertString(unsafeConfig.client)
262
+ assert(unsafeConfig.connection, 'Expected `.connection` to be defined.')
263
+ assertString(unsafeConfig.connection.host)
264
+ assertNumber(unsafeConfig.connection.port)
265
+ assertString(unsafeConfig.connection.user)
266
+ assertString(unsafeConfig.connection.password)
267
+ assertString(unsafeConfig.connection.database)
268
+ assert(unsafeConfig.pool, 'Expected `.pool` to be defined.')
269
+ assertNumber(unsafeConfig.pool.min)
270
+ assertNumber(unsafeConfig.pool.max)
271
+ assertNumber(unsafeConfig.pool.acquireTimeoutMillis)
272
+ assertNumber(unsafeConfig.pool.createTimeoutMillis)
273
+ assertNumber(unsafeConfig.pool.destroyTimeoutMillis)
274
+ assertNumber(unsafeConfig.pool.idleTimeoutMillis)
275
+ assertNumber(unsafeConfig.pool.reapIntervalMillis)
276
+ assertNumber(unsafeConfig.pool.createRetryIntervalMillis)
277
+ assertBoolean(unsafeConfig.debug)
278
+ }
279
+
280
+ /**
281
+ * @function assertInstrumentationMetricsLabels
282
+ * @description Assert that the instrumentation metrics labels config is valid.
283
+ */
284
+ export function assertInstrumentationMetricsLabels(input: unknown): void {
285
+ assert(input, 'Expected instrumentation metrics labels to be defined')
286
+ const unsafeConfig = input as InstrumentationMetricsLabels
287
+ assertString(unsafeConfig.fspId)
288
+ }
289
+
290
+ /**
291
+ * @function assertInstrumentationConfig
292
+ * @description Assert that the instrumentation config is valid.
293
+ */
294
+ export function assertInstrumentationConfig(input: unknown): void {
295
+ assert(input, 'Expected instrumentation config to be defined')
296
+ const unsafeConfig = input as InstrumentationConfig
297
+ assertNumber(unsafeConfig.timeout)
298
+ assertString(unsafeConfig.prefix)
299
+ assert(unsafeConfig.defaultLabels, 'Expected `.defaultLabels` to be defined')
300
+ assertString(unsafeConfig.defaultLabels.serviceName)
301
+ }
302
+
303
+ /**
304
+ * @function assertDistLockConfig
305
+ * @description Assert that the distributed lock config is valid.
306
+ */
307
+ export function assertDistLockConfig(input: unknown): void {
308
+ assert(input, 'Expected dist lock config to be defined')
309
+ const unsafeConfig = input as DistLockConfig
310
+ assertBoolean(unsafeConfig.enabled)
311
+ assertNumber(unsafeConfig.lockTimeout)
312
+ assertNumber(unsafeConfig.acquireTimeout)
313
+ assertNumber(unsafeConfig.driftFactor)
314
+ assertNumber(unsafeConfig.retryCount)
315
+ assertNumber(unsafeConfig.retryDelay)
316
+ assertNumber(unsafeConfig.retryJitter)
317
+ assert(Array.isArray(unsafeConfig.redisConfigs), 'Expected `.redisConfigs` to be an array')
318
+ for (const redisConfig of unsafeConfig.redisConfigs) {
319
+ assertString(redisConfig.type)
320
+ assert(Array.isArray(redisConfig.cluster), 'Expected `.cluster` to be an array')
321
+ for (const node of redisConfig.cluster) {
322
+ assertString(node.host)
323
+ assertNumber(node.port)
324
+ }
325
+ }
326
+ }
327
+
328
+ /**
329
+ * @function assertProvisioning
330
+ * @description Assert that the provisioning config is valid.
331
+ */
332
+ export function assertProvisioning(input: unknown): void {
333
+ assert(input, 'Expected provisioning config to be defined.')
334
+ const unsafeConfig = input as ApplicationConfig['EXPERIMENTAL']['PROVISIONING']
335
+
336
+ assertBoolean(unsafeConfig.enabled)
337
+ if (unsafeConfig.enabled === false) {
338
+ return
339
+ }
340
+
341
+ assert(Array.isArray(unsafeConfig.currencies) && unsafeConfig.currencies.length > 0,
342
+ 'expected .currencies to be an array with at least one element'
343
+ )
344
+ unsafeConfig.currencies.forEach(currency => assertString(currency))
345
+ assertStringIfDefined(unsafeConfig.hubAlertEmailAddress)
346
+ }
347
+
348
+ /**
349
+ * @function defaultTo
350
+ * @description Return the input if defined, otherwise return the default value.
351
+ */
352
+ export function defaultTo<T>(input: unknown, defaultValue: T): T {
353
+ if (input === undefined) {
354
+ return defaultValue
355
+ }
356
+
357
+ assert.equal(typeof input, typeof defaultValue)
358
+ return input as T
359
+ }
360
+
361
+ /**
362
+ * @function stringToBoolean
363
+ * @description Convert a string 'true' or 'false' to a boolean.
364
+ */
365
+ export function stringToBoolean(input: string): boolean {
366
+ assert(input !== undefined)
367
+ assert(typeof input === 'string')
368
+
369
+ switch (input.toLowerCase()) {
370
+ case 'true': return true
371
+ case 'false': return false
372
+ default: {
373
+ throw new Error(`stringToBoolean, unknown input: ${input}`)
374
+ }
375
+ }
376
+ }
377
+
378
+ /**
379
+ * @function defaultEnvString
380
+ * @description Get an environment variable or return a default value.
381
+ */
382
+ export function defaultEnvString(env: NodeJS.ProcessEnv, name: string, defaultValue: string): string {
383
+ assert(env, 'Expected env to be defined.')
384
+ assert(typeof name === 'string', 'Expected `name` to be a string.')
385
+ assert(defaultValue, 'Expected a default value.')
386
+ assert(typeof defaultValue === 'string', 'Expected default value to be a string')
387
+
388
+ let processEnvValue = env[name]
389
+ if (Array.isArray(processEnvValue)) {
390
+ processEnvValue = processEnvValue[0]
391
+ }
392
+ // Need to protect for cases where the value may intentionally false!
393
+ if (processEnvValue === undefined) {
394
+ logger.info(`defaultEnvString - ${name} not set - defaulting to: ${defaultValue}`)
395
+ return defaultValue
396
+ }
397
+
398
+ logger.info(`defaultEnvString - ${name} is set - resolved to: ${processEnvValue}`)
399
+ return processEnvValue
400
+ }
401
+
402
+ /**
403
+ * @function kafkaWithBrokerDefaults
404
+ * @description Configure the metadata.broker.list without needing to touch each individual config.
405
+ * If config.rdkafkaConf['metadata.broker.list'] is already set, then this doesn't modify it.
406
+ */
407
+ export function kafkaWithBrokerDefaults(input: KafkaConfig, defaultBroker: string): KafkaConfig {
408
+ assert(defaultBroker)
409
+ assert(input.CONSUMER)
410
+ assert(input.PRODUCER)
411
+
412
+ const applyBrokerDefaults = (
413
+ group: Record<string, Record<string, KafkaConsumerConfig | KafkaProducerConfig>>,
414
+ groupName: string
415
+ ) => {
416
+ Object.keys(group).forEach(key => {
417
+ const topic = group[key]
418
+ Object.keys(topic).forEach(topicKey => {
419
+ const leafConfig = topic[topicKey] as KafkaConsumerConfig | KafkaProducerConfig
420
+ const path = `input.${groupName}.${key}.${topicKey}`
421
+ if (leafConfig?.config?.rdkafkaConf
422
+ && !leafConfig.config.rdkafkaConf['metadata.broker.list']
423
+ ) {
424
+ logger.debug(`Config kafkaWithBrokerDefaults() defaulting: ${path}.config.rdkafkaConf['metadata.broker.list'] with: ${defaultBroker}`)
425
+ leafConfig.config.rdkafkaConf['metadata.broker.list'] = defaultBroker
426
+ }
427
+ })
428
+ })
429
+ }
430
+
431
+ applyBrokerDefaults(input.CONSUMER as Record<string, Record<string, KafkaConsumerConfig>>, 'CONSUMER')
432
+ applyBrokerDefaults(input.PRODUCER as Record<string, Record<string, KafkaProducerConfig>>, 'PRODUCER')
433
+
434
+ return input
435
+ }
436
+
437
+ /**
438
+ * @function convertBigIntToNumber
439
+ * @description Converts a bigint to a number, throwing an error if the bigint is outside of the
440
+ * range (MIN_SAFE_INTEGER, MAX_SAFE_INTEGER).
441
+ */
442
+ export function convertBigIntToNumber(input: bigint): number {
443
+ if (input > BigInt(Number.MAX_SAFE_INTEGER) ||
444
+ input < BigInt(Number.MIN_SAFE_INTEGER)
445
+ ) {
446
+ throw new Error(`convertBigIntToNumber failed: input is outside of safe range.`)
447
+ }
448
+
449
+ return Number(input)
450
+ }
451
+
452
+ /**
453
+ * @function safeStringToNumber
454
+ * @description Safetly convert from a string representation of a number to a number.
455
+ */
456
+ export function safeStringToNumber(input: string) {
457
+ assert(typeof input === 'string')
458
+ const trimmed = input.trim()
459
+
460
+ // Check if it's a valid number string.
461
+ if (trimmed === '' || Number.isNaN(Number(trimmed))) {
462
+ throw new TypeError(`Invalid number string: "${input}".`)
463
+ }
464
+
465
+ const num = Number(trimmed)
466
+ if (!Number.isFinite(num)) {
467
+ throw new TypeError(`Number out of range: "${input}".`)
468
+ }
469
+
470
+ return num
471
+ }
472
+
473
+ /**
474
+ * @function assertRange
475
+ * @description Assert that an input number is within a specified range.
476
+ */
477
+ export function assertRange(input: any, minInclusive: number, maxInclusive: number): void {
478
+ assert(maxInclusive > minInclusive, `assertRange invalid args - expected maxInclusive > minInclusive.`)
479
+ assert(typeof input === 'number')
480
+ assert(input >= minInclusive && input <= maxInclusive, `assertRange valid range: [${minInclusive}, ${maxInclusive}].`)
481
+ }
482
+
483
+ /**
484
+ * @function assertNestedFields
485
+ * @description Assert that a nested field is defined in the raw config.
486
+ */
487
+ export function assertNestedFields(rawConfig: any, path: string): void {
488
+ const parts = path.split('.')
489
+ let current = rawConfig
490
+ let traversed = ''
491
+
492
+ for (const part of parts) {
493
+ traversed = traversed ? `${traversed}.${part}` : part
494
+ assert(current[part] !== undefined, `expected \`${traversed}\` to be defined`)
495
+ current = current[part]
496
+ }
497
+ }
498
+
499
+ /**
500
+ * @function deepMerge
501
+ * @description Deep merge source into target, mutating target in place.
502
+ * Arrays are replaced, not merged. Only plain objects are recursively merged.
503
+ */
504
+ export function deepMerge<T extends Record<string, any>>(target: T, source: RecursivePartial<T>): T {
505
+ for (const key of Object.keys(source) as Array<keyof T>) {
506
+ const valSource = source[key]
507
+ const valTarget = target[key]
508
+
509
+ if (
510
+ valSource !== null &&
511
+ typeof valSource === 'object' &&
512
+ !Array.isArray(valSource) &&
513
+ valTarget !== null &&
514
+ typeof valTarget === 'object' &&
515
+ !Array.isArray(valTarget)
516
+ ) {
517
+ deepMerge(valTarget, valSource as any)
518
+ } else {
519
+ target[key] = valSource as T[keyof T]
520
+ }
521
+ }
522
+ return target
523
+ }