@mojaloop/central-services-shared 18.35.3 → 18.36.0-snapshot.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -7
- package/package.json +7 -5
- package/src/config.js +7 -0
- package/src/index.d.ts +35 -187
- package/src/util/endpoints.js +0 -3
- package/src/util/otelDto.js +53 -0
- package/src/util/request.js +81 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
### [18.35.3](https://github.com/mojaloop/central-services-shared/compare/v18.35.2...v18.35.3) (2026-02-06)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
### Chore
|
|
9
|
-
|
|
10
|
-
* extend type definitions ([#503](https://github.com/mojaloop/central-services-shared/issues/503)) ([82b9820](https://github.com/mojaloop/central-services-shared/commit/82b9820f8df7221397e8cd3cff53ea0df9cf0042))
|
|
11
|
-
|
|
12
5
|
### [18.35.2](https://github.com/mojaloop/central-services-shared/compare/v18.35.1...v18.35.2) (2026-01-28)
|
|
13
6
|
|
|
14
7
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mojaloop/central-services-shared",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.36.0-snapshot.0",
|
|
4
4
|
"description": "Shared code for mojaloop central services",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "ModusBox",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"test:endpoints": "npx tape 'test/unit/util/endpoints.test.js'",
|
|
49
49
|
"test:mysql": "npx tape 'test/unit/mysql/**/*.test.js'",
|
|
50
50
|
"test:participants": "npx tape 'test/unit/util/participants.test.js'",
|
|
51
|
+
"test:request": "npx tape 'test/unit/util/request.test.js'",
|
|
51
52
|
"test:trans": "npx tape 'test/unit/util/headers/transformer.test.js'",
|
|
52
53
|
"test:unit": "npx tape 'test/unit/**/*.test.js' | tap-spec",
|
|
53
54
|
"test:xunit": "npx tape 'test/unit/**/**.test.js' | tap-xunit > ./test/results/xunit.xml",
|
|
@@ -71,12 +72,13 @@
|
|
|
71
72
|
"@hapi/joi-date": "2.0.1",
|
|
72
73
|
"@mojaloop/inter-scheme-proxy-cache-lib": "2.9.0",
|
|
73
74
|
"@opentelemetry/api": "1.9.0",
|
|
75
|
+
"@opentelemetry/semantic-conventions": "1.39.0",
|
|
74
76
|
"async-exit-hook": "2.0.1",
|
|
75
77
|
"async-retry": "1.3.3",
|
|
76
78
|
"axios": "1.13.4",
|
|
77
79
|
"clone": "2.1.2",
|
|
78
80
|
"convict": "^6.2.4",
|
|
79
|
-
"dotenv": "17.2.
|
|
81
|
+
"dotenv": "17.2.4",
|
|
80
82
|
"env-var": "7.5.0",
|
|
81
83
|
"event-stream": "4.0.1",
|
|
82
84
|
"fast-safe-stringify": "2.1.1",
|
|
@@ -100,7 +102,7 @@
|
|
|
100
102
|
"@mojaloop/central-services-logger": "11.10.3",
|
|
101
103
|
"@mojaloop/central-services-metrics": "12.8.3",
|
|
102
104
|
"@mojaloop/event-sdk": "14.8.2",
|
|
103
|
-
"@mojaloop/sdk-standard-components": "19.18.
|
|
105
|
+
"@mojaloop/sdk-standard-components": "19.18.7",
|
|
104
106
|
"@opentelemetry/auto-instrumentations-node": "^0.69.0",
|
|
105
107
|
"@types/hapi__joi": "17.1.15",
|
|
106
108
|
"ajv": "^8.17.1",
|
|
@@ -145,7 +147,6 @@
|
|
|
145
147
|
"swagger2openapi": "7.0.8"
|
|
146
148
|
},
|
|
147
149
|
"markdown-it": "12.3.2",
|
|
148
|
-
"fast-xml-parser": "5.3.4",
|
|
149
150
|
"trim": "0.0.3",
|
|
150
151
|
"cross-spawn": "7.0.6",
|
|
151
152
|
"yargs-parser": "21.1.1",
|
|
@@ -153,7 +154,8 @@
|
|
|
153
154
|
"validator": "13.15.22",
|
|
154
155
|
"lodash": "4.17.23",
|
|
155
156
|
"lodash-es": "4.17.23",
|
|
156
|
-
"undici": "7.18.2"
|
|
157
|
+
"undici": "7.18.2",
|
|
158
|
+
"fast-xml-parser": "5.3.4"
|
|
157
159
|
},
|
|
158
160
|
"peerDependencies": {
|
|
159
161
|
"@mojaloop/central-services-error-handling": "13.x.x",
|
package/src/config.js
CHANGED
|
@@ -9,6 +9,13 @@ const config = convict({
|
|
|
9
9
|
env: 'SHARED_CACHE_LOG_LEVEL'
|
|
10
10
|
},
|
|
11
11
|
|
|
12
|
+
httpLogLevel: {
|
|
13
|
+
doc: 'Log level for HTTP wrapper.',
|
|
14
|
+
format: logLevelValues,
|
|
15
|
+
default: logLevelsMap.warn,
|
|
16
|
+
env: 'LOG_LEVEL_HTTP'
|
|
17
|
+
},
|
|
18
|
+
|
|
12
19
|
defaultTtlSec: {
|
|
13
20
|
doc: 'Default cache TTL.',
|
|
14
21
|
format: Number,
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Utils as HapiUtil, Server } from '@hapi/hapi'
|
|
2
2
|
import { ILogger } from '@mojaloop/central-services-logger/src/contextLogger'
|
|
3
3
|
import { Knex } from 'knex';
|
|
4
|
+
import { AxiosRequestConfig, AxiosResponse, ResponseType as AxiosResponseType } from 'axios'
|
|
4
5
|
import IORedis from 'ioredis';
|
|
5
6
|
|
|
6
7
|
declare namespace CentralServicesShared {
|
|
@@ -366,7 +367,7 @@ declare namespace CentralServicesShared {
|
|
|
366
367
|
|
|
367
368
|
enum TransferInternalStateEnum {
|
|
368
369
|
ABORTED_ERROR = 'ABORTED_ERROR',
|
|
369
|
-
ABORTED_REJECTED
|
|
370
|
+
ABORTED_REJECTED= 'ABORTED_REJECTED',
|
|
370
371
|
COMMITTED = 'COMMITTED',
|
|
371
372
|
EXPIRED_PREPARED = 'EXPIRED_PREPARED',
|
|
372
373
|
EXPIRED_RESERVED = 'EXPIRED_RESERVED',
|
|
@@ -443,56 +444,6 @@ declare namespace CentralServicesShared {
|
|
|
443
444
|
LIMIT_ADJUSTMENT = 'limit-adjustment'
|
|
444
445
|
}
|
|
445
446
|
|
|
446
|
-
enum LedgerAccountTypeEnum {
|
|
447
|
-
POSITION = 1,
|
|
448
|
-
SETTLEMENT = 2,
|
|
449
|
-
HUB_RECONCILIATION = 3,
|
|
450
|
-
HUB_MULTILATERAL_SETTLEMENT = 4,
|
|
451
|
-
HUB_FEE = 5,
|
|
452
|
-
POSITION_REMITTANCE = 7,
|
|
453
|
-
SETTLEMENT_REMITTANCE = 8
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
enum LedgerEntryTypeEnum {
|
|
457
|
-
PRINCIPLE_VALUE = 1,
|
|
458
|
-
INTERCHANGE_FEE = 2,
|
|
459
|
-
HUB_FEE = 3,
|
|
460
|
-
POSITION_DEPOSIT = 4,
|
|
461
|
-
POSITION_WITHDRAWAL = 5,
|
|
462
|
-
SETTLEMENT_NET_RECIPIENT = 6,
|
|
463
|
-
SETTLEMENT_NET_SENDER = 7,
|
|
464
|
-
SETTLEMENT_NET_ZERO = 8,
|
|
465
|
-
SETTLEMENT_ACCOUNT_DEPOSIT = 9,
|
|
466
|
-
SETTLEMENT_ACCOUNT_WITHDRAWAL = 10
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
enum ParticipantLimitTypeEnum {
|
|
470
|
-
NET_DEBIT_CAP = 1
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
enum TransferParticipantRoleTypeEnum {
|
|
474
|
-
PAYER_DFSP = 1,
|
|
475
|
-
PAYEE_DFSP = 2,
|
|
476
|
-
HUB = 3,
|
|
477
|
-
DFSP_SETTLEMENT = 4,
|
|
478
|
-
DFSP_POSITION = 5,
|
|
479
|
-
INITIATING_FSP = 6,
|
|
480
|
-
COUNTER_PARTY_FSP = 7
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
enum PartyTypeEnum {
|
|
484
|
-
MSISDN = 'MSISDN',
|
|
485
|
-
EMAIL = 'EMAIL',
|
|
486
|
-
PERSONAL_ID = 'PERSONAL_ID',
|
|
487
|
-
BUSINESS = 'BUSINESS',
|
|
488
|
-
DEVICE = 'DEVICE',
|
|
489
|
-
ACCOUNT_ID = 'ACCOUNT_ID',
|
|
490
|
-
IBAN = 'IBAN',
|
|
491
|
-
ALIAS = 'ALIAS',
|
|
492
|
-
CONSENT = 'CONSENT',
|
|
493
|
-
THIRD_PARTY_LINK = 'THIRD_PARTY_LINK'
|
|
494
|
-
}
|
|
495
|
-
|
|
496
447
|
interface Enum {
|
|
497
448
|
Http: HttpEnum;
|
|
498
449
|
EndPoints: EndPointsEnum;
|
|
@@ -501,18 +452,8 @@ declare namespace CentralServicesShared {
|
|
|
501
452
|
CONSUMER: string,
|
|
502
453
|
PRODUCER: string,
|
|
503
454
|
}
|
|
504
|
-
Topics: {
|
|
505
|
-
NOTIFICATION: string;
|
|
506
|
-
POSITION: string;
|
|
507
|
-
TRANSFER: string;
|
|
508
|
-
[key: string]: string;
|
|
509
|
-
}
|
|
510
455
|
}
|
|
511
456
|
Events: {
|
|
512
|
-
EventStatus: {
|
|
513
|
-
FAILURE: { status: string };
|
|
514
|
-
SUCCESS: { status: string };
|
|
515
|
-
};
|
|
516
457
|
Event: {
|
|
517
458
|
Action: {
|
|
518
459
|
ABORT: EventActionEnum.ABORT;
|
|
@@ -688,53 +629,6 @@ declare namespace CentralServicesShared {
|
|
|
688
629
|
LIMIT_ADJUSTMENT: AdminNotificationActionsEnum.LIMIT_ADJUSTMENT;
|
|
689
630
|
};
|
|
690
631
|
};
|
|
691
|
-
Accounts: {
|
|
692
|
-
LedgerAccountType: {
|
|
693
|
-
POSITION: LedgerAccountTypeEnum.POSITION;
|
|
694
|
-
SETTLEMENT: LedgerAccountTypeEnum.SETTLEMENT;
|
|
695
|
-
HUB_RECONCILIATION: LedgerAccountTypeEnum.HUB_RECONCILIATION;
|
|
696
|
-
HUB_MULTILATERAL_SETTLEMENT: LedgerAccountTypeEnum.HUB_MULTILATERAL_SETTLEMENT;
|
|
697
|
-
HUB_FEE: LedgerAccountTypeEnum.HUB_FEE;
|
|
698
|
-
POSITION_REMITTANCE: LedgerAccountTypeEnum.POSITION_REMITTANCE;
|
|
699
|
-
SETTLEMENT_REMITTANCE: LedgerAccountTypeEnum.SETTLEMENT_REMITTANCE;
|
|
700
|
-
};
|
|
701
|
-
LedgerEntryType: {
|
|
702
|
-
PRINCIPLE_VALUE: LedgerEntryTypeEnum.PRINCIPLE_VALUE;
|
|
703
|
-
INTERCHANGE_FEE: LedgerEntryTypeEnum.INTERCHANGE_FEE;
|
|
704
|
-
HUB_FEE: LedgerEntryTypeEnum.HUB_FEE;
|
|
705
|
-
POSITION_DEPOSIT: LedgerEntryTypeEnum.POSITION_DEPOSIT;
|
|
706
|
-
POSITION_WITHDRAWAL: LedgerEntryTypeEnum.POSITION_WITHDRAWAL;
|
|
707
|
-
SETTLEMENT_NET_RECIPIENT: LedgerEntryTypeEnum.SETTLEMENT_NET_RECIPIENT;
|
|
708
|
-
SETTLEMENT_NET_SENDER: LedgerEntryTypeEnum.SETTLEMENT_NET_SENDER;
|
|
709
|
-
SETTLEMENT_NET_ZERO: LedgerEntryTypeEnum.SETTLEMENT_NET_ZERO;
|
|
710
|
-
SETTLEMENT_ACCOUNT_DEPOSIT: LedgerEntryTypeEnum.SETTLEMENT_ACCOUNT_DEPOSIT;
|
|
711
|
-
SETTLEMENT_ACCOUNT_WITHDRAWAL: LedgerEntryTypeEnum.SETTLEMENT_ACCOUNT_WITHDRAWAL;
|
|
712
|
-
};
|
|
713
|
-
ParticipantLimitType: {
|
|
714
|
-
NET_DEBIT_CAP: ParticipantLimitTypeEnum.NET_DEBIT_CAP;
|
|
715
|
-
};
|
|
716
|
-
TransferParticipantRoleType: {
|
|
717
|
-
PAYER_DFSP: TransferParticipantRoleTypeEnum.PAYER_DFSP;
|
|
718
|
-
PAYEE_DFSP: TransferParticipantRoleTypeEnum.PAYEE_DFSP;
|
|
719
|
-
HUB: TransferParticipantRoleTypeEnum.HUB;
|
|
720
|
-
DFSP_SETTLEMENT: TransferParticipantRoleTypeEnum.DFSP_SETTLEMENT;
|
|
721
|
-
DFSP_POSITION: TransferParticipantRoleTypeEnum.DFSP_POSITION;
|
|
722
|
-
INITIATING_FSP: TransferParticipantRoleTypeEnum.INITIATING_FSP;
|
|
723
|
-
COUNTER_PARTY_FSP: TransferParticipantRoleTypeEnum.COUNTER_PARTY_FSP;
|
|
724
|
-
};
|
|
725
|
-
PartyTypes: {
|
|
726
|
-
MSISDN: PartyTypeEnum.MSISDN;
|
|
727
|
-
EMAIL: PartyTypeEnum.EMAIL;
|
|
728
|
-
PERSONAL_ID: PartyTypeEnum.PERSONAL_ID;
|
|
729
|
-
BUSINESS: PartyTypeEnum.BUSINESS;
|
|
730
|
-
DEVICE: PartyTypeEnum.DEVICE;
|
|
731
|
-
ACCOUNT_ID: PartyTypeEnum.ACCOUNT_ID;
|
|
732
|
-
IBAN: PartyTypeEnum.IBAN;
|
|
733
|
-
ALIAS: PartyTypeEnum.ALIAS;
|
|
734
|
-
CONSENT: PartyTypeEnum.CONSENT;
|
|
735
|
-
THIRD_PARTY_LINK: PartyTypeEnum.THIRD_PARTY_LINK;
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
632
|
}
|
|
739
633
|
|
|
740
634
|
interface Cacheable {
|
|
@@ -763,24 +657,37 @@ declare namespace CentralServicesShared {
|
|
|
763
657
|
accept: string
|
|
764
658
|
}
|
|
765
659
|
|
|
766
|
-
type RequestParams = {
|
|
767
|
-
|
|
768
|
-
|
|
660
|
+
type RequestParams = {
|
|
661
|
+
url: string,
|
|
662
|
+
headers: HapiUtil.Dictionary<string>,
|
|
663
|
+
source: string,
|
|
664
|
+
destination?: string,
|
|
665
|
+
hubNameRegex: RegExp,
|
|
666
|
+
method?: RestMethodsEnum,
|
|
667
|
+
payload?: any,
|
|
668
|
+
params?: AxiosRequestConfig['params'],
|
|
669
|
+
responseType?: AxiosResponseType,
|
|
670
|
+
span?: any,
|
|
671
|
+
jwsSigner?: any,
|
|
672
|
+
protocolVersions?: ProtocolVersionsType,
|
|
673
|
+
apiType?: ApiTypeValues,
|
|
674
|
+
axiosRequestOptionsOverride?: Partial<AxiosRequestConfig>,
|
|
675
|
+
logger?: ILogger,
|
|
676
|
+
peerService?: string
|
|
677
|
+
}
|
|
678
|
+
export interface Request {
|
|
679
|
+
sendRequest(params: RequestParams): Promise<AxiosResponse>
|
|
680
|
+
sendBaseRequest(params?: AxiosRequestConfig & { logger?: ILogger, peerService?: string }): Promise<AxiosResponse>
|
|
769
681
|
}
|
|
770
682
|
|
|
771
683
|
interface Kafka {
|
|
772
|
-
createGeneralTopicConf(template: string, functionality: string, action: string, key?: string, partition?: number, opaqueKey?: any, topicNameOverride?: string): {
|
|
773
|
-
transformGeneralTopicName(template: string, functionality: string, action: string): string
|
|
774
|
-
getKafkaConfig(kafkaConfig: object, flow: string, functionality: string, action: string): object
|
|
684
|
+
createGeneralTopicConf(template: string, functionality: string, action: string, key?: string, partition?: number, opaqueKey?: any, topicNameOverride?: string): {topicName: string, key: string | null, partition: number | null, opaqueKey: any }
|
|
775
685
|
}
|
|
776
686
|
|
|
777
687
|
type MimeTypes = 'text/plain' | 'application/json' | 'application/vnd.interoperability.'
|
|
778
688
|
interface StreamingProtocol {
|
|
779
689
|
decodePayload(input: string, options: Object): Object
|
|
780
690
|
encodePayload(input: string | Buffer, mimeType: MimeTypes): string
|
|
781
|
-
createEventState(status: string, errorCode: string, errorDescription: string): any
|
|
782
|
-
createMetadataWithCorrelatedEvent(transferId: string, topic: string, action: string, state: any): any
|
|
783
|
-
createMessage(id: string, destination: string, source: string, metadata: any, headers: any, payload: any, uriParams: any, contentType: string): any
|
|
784
691
|
}
|
|
785
692
|
|
|
786
693
|
interface HeaderValidation {
|
|
@@ -798,8 +705,8 @@ declare namespace CentralServicesShared {
|
|
|
798
705
|
type ProtocolVersions = (string | symbol)[]
|
|
799
706
|
type ApiTypeValues = 'fspiop' | 'iso20022'
|
|
800
707
|
type APIDocumentationPluginOptions =
|
|
801
|
-
|
|
802
|
-
|
|
708
|
+
| { documentPath: string; document?: never }
|
|
709
|
+
| { document?: string; documentPath?: never }
|
|
803
710
|
|
|
804
711
|
type LoggingPluginOptions = {
|
|
805
712
|
log?: ILogger,
|
|
@@ -871,7 +778,7 @@ declare namespace CentralServicesShared {
|
|
|
871
778
|
|
|
872
779
|
interface PubSub {
|
|
873
780
|
(config: object, publisherClient?: IORedis, subscriberClient?: IORedis): PubSub;
|
|
874
|
-
new(config: object, publisherClient?: IORedis, subscriberClient?: IORedis): PubSub;
|
|
781
|
+
new (config: object, publisherClient?: IORedis, subscriberClient?: IORedis): PubSub;
|
|
875
782
|
connect(): Promise<void>;
|
|
876
783
|
disconnect(): Promise<boolean>;
|
|
877
784
|
healthCheck(): Promise<boolean>;
|
|
@@ -884,7 +791,7 @@ declare namespace CentralServicesShared {
|
|
|
884
791
|
|
|
885
792
|
interface RedisCache {
|
|
886
793
|
(config: object, client?: IORedis): RedisCache;
|
|
887
|
-
new(config: object, client?: IORedis): RedisCache;
|
|
794
|
+
new (config: object, client?: IORedis): RedisCache;
|
|
888
795
|
connect(): Promise<boolean>;
|
|
889
796
|
disconnect(): Promise<boolean>;
|
|
890
797
|
healthCheck(): Promise<boolean>;
|
|
@@ -902,14 +809,14 @@ declare namespace CentralServicesShared {
|
|
|
902
809
|
|
|
903
810
|
type RedisInstanceConfig =
|
|
904
811
|
| {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
812
|
+
type: 'redis';
|
|
813
|
+
host: string;
|
|
814
|
+
port: number;
|
|
815
|
+
}
|
|
909
816
|
| {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
817
|
+
type: 'redis-cluster';
|
|
818
|
+
cluster: Array<{ host: string; port: number }>;
|
|
819
|
+
};
|
|
913
820
|
|
|
914
821
|
interface DistributedLockConfig {
|
|
915
822
|
redisConfigs: RedisInstanceConfig[];
|
|
@@ -936,59 +843,6 @@ declare namespace CentralServicesShared {
|
|
|
936
843
|
createLock(config: DistributedLockConfig, logger?: ILogger): DistributedLock;
|
|
937
844
|
}
|
|
938
845
|
|
|
939
|
-
interface RethrowOptions {
|
|
940
|
-
operation?: string;
|
|
941
|
-
step?: string;
|
|
942
|
-
loggerOverride?: ILogger;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
interface RethrowModule {
|
|
946
|
-
rethrowAndCountFspiopError(error: Error, options?: RethrowOptions, context?: string): never;
|
|
947
|
-
rethrowDatabaseError(error: Error, options?: RethrowOptions): never;
|
|
948
|
-
rethrowCachedDatabaseError(error: Error, options?: RethrowOptions): never;
|
|
949
|
-
rethrowRedisError(error: Error, options?: RethrowOptions): never;
|
|
950
|
-
rethrowKafkaError(error: Error, options?: RethrowOptions): never;
|
|
951
|
-
rethrowCacheError(error: Error, options?: RethrowOptions): never;
|
|
952
|
-
constructSystemExtensionError(error: Error, system: string): Error;
|
|
953
|
-
countFspiopError(error: Error, options?: RethrowOptions, context?: string): Error;
|
|
954
|
-
with(context: string): RethrowModule;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
interface SpanTags {
|
|
958
|
-
transactionType: string;
|
|
959
|
-
transactionAction: string;
|
|
960
|
-
transactionId: string | undefined;
|
|
961
|
-
source: string | undefined;
|
|
962
|
-
destination: string | undefined;
|
|
963
|
-
payerFsp?: string;
|
|
964
|
-
payeeFsp?: string;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
interface QueryTags {
|
|
968
|
-
serviceName: string;
|
|
969
|
-
auditType: string;
|
|
970
|
-
contentType: string;
|
|
971
|
-
operation: string;
|
|
972
|
-
[key: string]: any;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
interface TransferSpanInput {
|
|
976
|
-
payload?: any;
|
|
977
|
-
headers?: Record<string, string>;
|
|
978
|
-
params?: { id?: string };
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
interface EventFramework {
|
|
982
|
-
getTransferSpanTags(input: TransferSpanInput, transactionType: string, transactionAction: string): SpanTags;
|
|
983
|
-
getSpanTags(transactionType: string, transactionAction: string, transactionId: string, source: string, destination: string): SpanTags;
|
|
984
|
-
getQueryTags(serviceName: string, auditType: string, contentType: string, operation: string, additionalTags?: Record<string, any>): QueryTags;
|
|
985
|
-
Tags: {
|
|
986
|
-
getTransferSpanTags: (input: TransferSpanInput, transactionType: string, transactionAction: string) => SpanTags;
|
|
987
|
-
getSpanTags: (transactionType: string, transactionAction: string, transactionId: string, source: string, destination: string) => SpanTags;
|
|
988
|
-
getQueryTags: (serviceName: string, auditType: string, contentType: string, operation: string, additionalTags?: Record<string, any>) => QueryTags;
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
|
|
992
846
|
interface Util {
|
|
993
847
|
Endpoints: Endpoints;
|
|
994
848
|
Participants: Participants;
|
|
@@ -1001,12 +855,6 @@ declare namespace CentralServicesShared {
|
|
|
1001
855
|
HeaderValidation: HeaderValidation;
|
|
1002
856
|
Redis: Redis;
|
|
1003
857
|
distLock: DistLock;
|
|
1004
|
-
rethrow: RethrowModule;
|
|
1005
|
-
EventFramework: EventFramework;
|
|
1006
|
-
resourceVersions: Record<string, { contentVersion: string }>;
|
|
1007
|
-
Http: {
|
|
1008
|
-
SwitchDefaultHeaders: (destination: string, resource: string, hubName: string, contentVersion: string) => Record<string, any>;
|
|
1009
|
-
};
|
|
1010
858
|
}
|
|
1011
859
|
|
|
1012
860
|
const Enum: Enum
|
package/src/util/endpoints.js
CHANGED
|
@@ -197,9 +197,6 @@ exports.getEndpoint = async (switchUrl, fsp, endpointType, options = {}, renderO
|
|
|
197
197
|
hit = endpoints.cached !== null
|
|
198
198
|
endpoints = endpoints.value
|
|
199
199
|
}
|
|
200
|
-
if (!hit) {
|
|
201
|
-
log.warn(`getEndpoint cache miss for fsp=${fsp}, endpointType=${endpointType}`)
|
|
202
|
-
}
|
|
203
200
|
|
|
204
201
|
const result = renderEndpoint(endpoints)
|
|
205
202
|
histTimer({ success: true, hit })
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2020-2025 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
|
+
* Mojaloop Foundation
|
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
|
24
|
+
|
|
25
|
+
--------------
|
|
26
|
+
******/
|
|
27
|
+
/* istanbul ignore file */
|
|
28
|
+
|
|
29
|
+
const otel = require('@opentelemetry/semantic-conventions')
|
|
30
|
+
|
|
31
|
+
const ATTR_SERVICE_PEER_NAME = 'service.peer.name' // using string literal because ATTR_SERVICE_PEER_NAME is only available in @opentelemetry/semantic-conventions/incubating as of now
|
|
32
|
+
|
|
33
|
+
const outgoingRequestDto = ({
|
|
34
|
+
method, url, durationSec, statusCode, errorType, peerService
|
|
35
|
+
}) => ({
|
|
36
|
+
attributes: {
|
|
37
|
+
[otel.ATTR_HTTP_REQUEST_METHOD]: method,
|
|
38
|
+
[otel.ATTR_URL_FULL]: url,
|
|
39
|
+
[otel.METRIC_HTTP_CLIENT_REQUEST_DURATION]: durationSec, // 'duration.ms' is a custom attribute
|
|
40
|
+
...(statusCode && { [otel.ATTR_HTTP_RESPONSE_STATUS_CODE]: statusCode }),
|
|
41
|
+
...(errorType && { [otel.ATTR_ERROR_TYPE]: errorType }),
|
|
42
|
+
...(peerService && { [ATTR_SERVICE_PEER_NAME]: peerService })
|
|
43
|
+
// peerService - logical service name, must be explicitly provided by caller (not derived from URL hostname)
|
|
44
|
+
// think if we should extract it for internal http://... calls from url hostname
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const incomingRequestDto = () => ({ attributes: {} }) // todo: add impl.
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
outgoingRequestDto,
|
|
52
|
+
incomingRequestDto
|
|
53
|
+
}
|
package/src/util/request.js
CHANGED
|
@@ -30,29 +30,31 @@
|
|
|
30
30
|
'use strict'
|
|
31
31
|
|
|
32
32
|
const http = require('node:http')
|
|
33
|
-
const
|
|
33
|
+
const axios = require('axios')
|
|
34
34
|
const stringify = require('fast-safe-stringify')
|
|
35
35
|
const EventSdk = require('@mojaloop/event-sdk')
|
|
36
36
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
37
37
|
const Metrics = require('@mojaloop/central-services-metrics')
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const { logger } = require('../logger')
|
|
38
|
+
|
|
39
|
+
const { logger: globalLogger } = require('../logger')
|
|
41
40
|
const { API_TYPES } = require('../constants')
|
|
42
41
|
const config = require('../config')
|
|
42
|
+
const enums = require('../enums')
|
|
43
|
+
const Headers = require('./headers/transformer')
|
|
44
|
+
const { outgoingRequestDto } = require('./otelDto')
|
|
43
45
|
|
|
44
46
|
const MISSING_FUNCTION_PARAMETERS = 'Missing parameters for function'
|
|
45
47
|
|
|
46
48
|
// Delete the default headers that the `axios` module inserts as they can brake our conventions.
|
|
47
49
|
// By default it would insert `"Accept":"application/json, text/plain, */*"`.
|
|
48
|
-
delete
|
|
50
|
+
delete axios.defaults.headers.common.Accept
|
|
49
51
|
|
|
50
52
|
const keepAlive = (process.env.HTTP_AGENT_KEEP_ALIVE ?? 'true') === 'true'
|
|
51
|
-
|
|
53
|
+
globalLogger.verbose('http keepAlive:', { keepAlive })
|
|
52
54
|
|
|
53
55
|
// Enable keepalive for http
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
axios.defaults.httpAgent = new http.Agent({ keepAlive })
|
|
57
|
+
axios.defaults.httpAgent.toJSON = () => ({})
|
|
56
58
|
|
|
57
59
|
/**
|
|
58
60
|
* @function sendRequest
|
|
@@ -77,11 +79,12 @@ request.defaults.httpAgent.toJSON = () => ({})
|
|
|
77
79
|
* @param {SendRequestProtocolVersions | undefined} protocolVersions the config for Protocol versions to be used
|
|
78
80
|
* @param {'fspiop' | 'iso20022'} apiType the API type of the request being sent
|
|
79
81
|
* @param {object} axiosRequestOptionsOverride axios request options to override https://axios-http.com/docs/req_config
|
|
82
|
+
* @param {ILogger} [logger] ContextLogger instance with specific context
|
|
83
|
+
* @param {string} [peerService] Logical service name to call (for OTel)
|
|
80
84
|
* @param {regex} hubNameRegex hubName Regex
|
|
81
85
|
*
|
|
82
86
|
*@return {Promise<any>} The response for the request being sent or error object with response included
|
|
83
87
|
*/
|
|
84
|
-
|
|
85
88
|
const sendRequest = async ({
|
|
86
89
|
url,
|
|
87
90
|
headers,
|
|
@@ -96,6 +99,8 @@ const sendRequest = async ({
|
|
|
96
99
|
protocolVersions = undefined,
|
|
97
100
|
apiType = API_TYPES.fspiop,
|
|
98
101
|
axiosRequestOptionsOverride = {},
|
|
102
|
+
logger = createHttpLogger(),
|
|
103
|
+
peerService = '',
|
|
99
104
|
hubNameRegex
|
|
100
105
|
}) => {
|
|
101
106
|
const histTimerEnd = Metrics.getHistogram(
|
|
@@ -113,6 +118,9 @@ const sendRequest = async ({
|
|
|
113
118
|
// think, if we can just avoid checking "destination"
|
|
114
119
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(MISSING_FUNCTION_PARAMETERS)
|
|
115
120
|
}
|
|
121
|
+
|
|
122
|
+
const log = logger.child({ component: 'httpRequest' })
|
|
123
|
+
|
|
116
124
|
try {
|
|
117
125
|
const transformedHeaders = Headers.transformHeaders(headers, {
|
|
118
126
|
httpMethod: method,
|
|
@@ -126,9 +134,10 @@ const sendRequest = async ({
|
|
|
126
134
|
url,
|
|
127
135
|
method,
|
|
128
136
|
headers: transformedHeaders,
|
|
129
|
-
data: payload,
|
|
137
|
+
data: payload,
|
|
130
138
|
params,
|
|
131
139
|
responseType,
|
|
140
|
+
peerService,
|
|
132
141
|
timeout: config.get('httpRequestTimeoutMs'),
|
|
133
142
|
...axiosRequestOptionsOverride
|
|
134
143
|
}
|
|
@@ -149,14 +158,18 @@ const sendRequest = async ({
|
|
|
149
158
|
}
|
|
150
159
|
span.audit({ ...rest, payload }, EventSdk.AuditEventAction.egress)
|
|
151
160
|
}
|
|
152
|
-
|
|
153
|
-
const response = await
|
|
161
|
+
|
|
162
|
+
const response = await sendBaseRequest({
|
|
163
|
+
...requestOptions,
|
|
164
|
+
logger: log,
|
|
165
|
+
peerService
|
|
166
|
+
})
|
|
154
167
|
|
|
155
168
|
!!sendRequestSpan && await sendRequestSpan.finish()
|
|
156
169
|
histTimerEnd({ success: true, source, destination, method })
|
|
157
170
|
return response
|
|
158
171
|
} catch (error) {
|
|
159
|
-
|
|
172
|
+
log.error('error in request.sendRequest:', {
|
|
160
173
|
code: error.code,
|
|
161
174
|
message: error.message,
|
|
162
175
|
stack: error.stack,
|
|
@@ -247,6 +260,60 @@ const sendRequest = async ({
|
|
|
247
260
|
}
|
|
248
261
|
}
|
|
249
262
|
|
|
263
|
+
// todo: think better name
|
|
264
|
+
// it's for http calls without params validation and transformHeaders
|
|
265
|
+
const sendBaseRequest = async ({
|
|
266
|
+
logger = createHttpLogger(),
|
|
267
|
+
peerService = '',
|
|
268
|
+
...reqOptions
|
|
269
|
+
} = {}) => {
|
|
270
|
+
const log = logger.child({ component: 'sendBaseRequest' })
|
|
271
|
+
const { method, url } = reqOptions
|
|
272
|
+
const methodUrl = `${method?.toUpperCase()} ${url}`
|
|
273
|
+
const startTime = Date.now()
|
|
274
|
+
let statusCode
|
|
275
|
+
let errorType
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
log.debug(`[-->] options for ${methodUrl}: `, { reqOptions })
|
|
279
|
+
|
|
280
|
+
const response = await axios(reqOptions)
|
|
281
|
+
|
|
282
|
+
statusCode = response?.status
|
|
283
|
+
log.verbose(`[<--] details of ${methodUrl}: `, {
|
|
284
|
+
data: response?.data,
|
|
285
|
+
headers: response?.headers, // todo: extract only needed headers
|
|
286
|
+
statusCode,
|
|
287
|
+
reqOptions
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
return response
|
|
291
|
+
} catch (error) {
|
|
292
|
+
statusCode = error.response?.status
|
|
293
|
+
errorType = error.code
|
|
294
|
+
throw error // todo: think, if we need to rethrow our custom error here
|
|
295
|
+
} finally {
|
|
296
|
+
const severity = typeof statusCode === 'number'
|
|
297
|
+
? (statusCode >= 200 && statusCode < 300 ? 'info' : 'warn')
|
|
298
|
+
: 'error'
|
|
299
|
+
log[severity](`[<--] ${methodUrl} [${statusCode || errorType}]: `, outgoingRequestDto({
|
|
300
|
+
method,
|
|
301
|
+
url,
|
|
302
|
+
statusCode,
|
|
303
|
+
durationSec: (Date.now() - startTime) / 1000,
|
|
304
|
+
errorType,
|
|
305
|
+
peerService
|
|
306
|
+
}))
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const createHttpLogger = () => {
|
|
311
|
+
const logger = globalLogger.child()
|
|
312
|
+
logger.setLevel(config.get('httpLogLevel'))
|
|
313
|
+
return logger
|
|
314
|
+
}
|
|
315
|
+
|
|
250
316
|
module.exports = {
|
|
251
|
-
sendRequest
|
|
317
|
+
sendRequest,
|
|
318
|
+
sendBaseRequest
|
|
252
319
|
}
|