@mojaloop/ml-schema-transformer-lib
Version:
Shared component for ML schemas translation
1 lines • 159 kB
Source Map (JSON)
{"version":3,"sources":["../src/lib/transformer.ts","../src/lib/utils/index.ts","../src/types/type-guards.ts","../src/types/index.ts","../src/lib/transforms/index.ts","../src/lib/createTransformer.ts","../src/lib/logger.ts","../src/mappings/fspiopiso20022/index.ts","../src/mappings/fspiopiso20022/discovery.ts","../src/mappings/fspiopiso20022/quotes.ts","../src/mappings/fspiopiso20022/fxQuotes.ts","../src/mappings/fspiopiso20022/transfers.ts","../src/mappings/fspiopiso20022/fxTransfers.ts","../src/lib/transforms/pipeline.ts","../src/lib/transforms/extensions.ts","../src/lib/validation/index.ts","../src/lib/validation/validator.ts","../src/facades/fspiop.ts","../src/facades/fspiopiso20022.ts","../src/index.ts"],"sourcesContent":["/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nimport { ITransformer, Source, Target, TransformFunctionOptions } from '../types';\nimport { DataMapper, State } from '../types/map-transform';\nimport { createTransformer } from './createTransformer';\n\nexport const transformFn = async (source: Partial<Source>, options: TransformFunctionOptions): Promise<Partial<Target>> => {\n const { mapping, mapTransformOptions, mapperOptions, logger } = options;\n try {\n const transformer = createTransformer(mapping, { mapTransformOptions });\n return transformer.transform(source, { mapperOptions });\n } catch (error) {\n logger.error('Error transforming payload with supplied mapping', { error, source, mapping });\n throw error;\n }\n};\n\nexport class Transformer implements ITransformer {\n mapper: DataMapper;\n \n constructor(mapper: DataMapper) {\n this.mapper = mapper;\n }\n\n async transform(source: Partial<Source>, { mapperOptions }: { mapperOptions?: State } = {}): Promise<Partial<Target>> {\n return this.mapper(source, mapperOptions) as Promise<Partial<Target>>;\n }\n}\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nconst idGenerator = require('@mojaloop/central-services-shared').Util.id;\nconst { CreateFSPIOPErrorFromErrorCode } = require('@mojaloop/central-services-error-handling')\nimport * as ilpPacket from 'ilp-packet';\nimport { ConfigOptions, GenericObject, ID_GENERATOR_TYPE, Primitive, isContextLogger } from '../../types';\nimport { TransformDefinition } from '../../types/map-transform';\nimport { ContextLogger } from '@mojaloop/central-services-logger/src/contextLogger';\n\n// improve: use enums from cs-shared\n// We only cover the states that are externally visible\nconst fspiopToIsoTransferStateMap: GenericObject = {\n COMMITTED: 'COMM',\n RESERVED: 'RESV',\n RECEIVED: 'RECV',\n ABORTED: 'ABOR'\n}\n\n// Generates a unique ID\nexport const generateID = (idGenType: ID_GENERATOR_TYPE = ID_GENERATOR_TYPE.ulid, config: GenericObject = {}): string => {\n switch (idGenType) {\n case ID_GENERATOR_TYPE.ulid:\n case ID_GENERATOR_TYPE.uuid:\n return idGenerator({ ...config, type: idGenType })();\n default:\n return idGenerator({ ...config, type: ID_GENERATOR_TYPE.ulid })();\n }\n}\n\n// improve: import enums from cs-shared\nexport const isPersonPartyIdType = (partyIdType: string) => partyIdType && !['BUSINESS', 'ALIAS', 'DEVICE'].includes(partyIdType);\n\nexport const isEmptyObject = (data: unknown) => {\n return typeof data === 'object' && data !== null && Object.keys(data as object).length === 0;\n}\n\n// Safely sets nested property in an object\nexport const setProp = (obj: unknown, path: string, value: unknown) => {\n const pathParts = path.split('.');\n let current = obj as GenericObject;\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i] as string;\n if (!current[part]) {\n current[part] = {};\n }\n current = current[part];\n }\n current[pathParts[pathParts.length - 1] as string] = value;\n}\n\n// Safely gets nested property from an object\nexport const getProp = (obj: unknown, path: string): unknown => {\n const pathParts = path.split('.');\n let current = obj;\n for (const part of pathParts) {\n if (typeof current === 'object' && current !== null && part in current) {\n current = (current as GenericObject)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\n// Safely checks if nested property exists in an object\nexport const hasProp = (obj: unknown, path: string): boolean => {\n const pathParts = path.split('.');\n let current = obj;\n for (const part of pathParts) {\n if (typeof current === 'object' && current !== null && part in current) {\n current = (current as GenericObject)[part];\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n// Merges deeply nested objects\n// e.g { a: { b: 1 } } and { a: { c: 2 } } => { a: { b: 1, c: 2 } }\nexport const deepMerge = (target: GenericObject, source: GenericObject): GenericObject => {\n for (const key in source) {\n if (source[key] instanceof Object && key in target) {\n Object.assign(source[key], deepMerge(target[key], source[key]));\n }\n }\n Object.assign(target, source);\n return target;\n}\n\n// Gets the description for an error code\nexport const getDescrForErrCode = (code: string | number): string => {\n try {\n const errorCode = Number.parseInt(code as string);\n const errorCreated = CreateFSPIOPErrorFromErrorCode(errorCode);\n return errorCreated?.apiErrorCode?.type?.description;\n } catch (error) {\n return 'Unknown error';\n }\n}\n\n// Gets the ILP packet condition from an ILP packet\nexport const getIlpPacketCondition = (inputIlpPacket: string): string => {\n const binaryPacket = Buffer.from(inputIlpPacket, 'base64');\n const decoded = ilpPacket.deserializeIlpPrepare(binaryPacket);\n return decoded?.executionCondition?.toString('base64url');\n}\n\n// Converts FSPIOP transfer state to FSPIOP ISO20022 transfer state\nexport const toIsoTransferState = (fspiopState: string): string | undefined => {\n if (!fspiopState) return undefined;\n const isoState = fspiopToIsoTransferStateMap[fspiopState] as string;\n if (!isoState) throw new Error(`toIsoTransferState: Unknown FSPIOP transfer state: ${fspiopState}`);\n return isoState;\n}\n\n// Converts FSPIOP ISO20022 transfer state to FSPIOP transfer state\nexport const toFspiopTransferState = (isoState: string): string | undefined => {\n if (!isoState) return undefined;\n for (const [key, value] of Object.entries(fspiopToIsoTransferStateMap)) {\n if (value === isoState) return key;\n }\n throw new Error(`toFspiopTransferState: Unknown ISO20022 transfer state: ${isoState}`);\n}\n\n// Validates configuration options\nexport const validateConfig = (config: ConfigOptions): void => {\n if (hasProp(config, 'logger') && !isContextLogger(config.logger as ContextLogger)) {\n throw new Error('Invalid logger provided');\n }\n}\n\n// Unrolls extensions array into an object\n// e.g [ { key: 'key1', value: 'value1' }, { key: 'key2', value: 'value2' } ] => { key1: 'value1', key2: 'value2' }\nexport const unrollExtensions = (extensions: Array<{ key: string, value: unknown }>): GenericObject => {\n const unrolled: GenericObject = {};\n for (const { key, value } of extensions) {\n setProp(unrolled, key, value);\n }\n return unrolled;\n}\n\n// Rolls up unmapped properties (i.e properties in source object not found in the mapping values - r.h.s) into extensions array\n// e.g { a: 1, b: 2 } => [ { key: 'a', value: 1 }, { key: 'b', value: 2 } ]\nexport const rollUpUnmappedAsExtensions = (source: GenericObject, mapping: TransformDefinition): Array<{ key: string, value: unknown }> => {\n const extensions = [];\n const mappingObj = mapping = typeof mapping === 'string' ? JSON.parse(mapping) : mapping;\n // we are only interested in body and $context mappings\n const mappingValues = extractValues(mappingObj)\n .map((value) => String(value))\n .filter((value) => value.startsWith('body.') || value.startsWith('$context.'))\n .map((value) => value.replace('body.', ''))\n .map((value) => value.replace(/\\$context\\.[a-zA-Z0-9]+./, ''));\n // for the source, we are only interested in body\n const sourcePaths = getObjectPaths(source.body);\n\n for (const path of sourcePaths) {\n if (!mappingValues.includes(path)) {\n const value = getProp(source.body, path);\n extensions.push({ key: path, value });\n }\n }\n\n return extensions;\n}\n\n// Extracts all leaf values from an object including values nested in arrays and objects\n// e.g { a: { b: 1, c: { d: 2, e: [ 3, 4 ] } } } => [1, 2, 3, 4]\nexport const extractValues = (obj: GenericObject) => {\n const values: Primitive[] = [];\n\n function recurse(current: GenericObject | Primitive | null) {\n if (Array.isArray(current)) {\n current.forEach(item => recurse(item));\n } else if (typeof current === 'object' && current !== null) {\n Object.values(current).forEach(value => recurse(value));\n } else { \n values.push((current as Primitive));\n }\n }\n\n recurse(obj);\n return values;\n}\n\n// Gets all paths to leaf nodes in an object\n// e.g { a: { b: 1, c: { d: 2 } } } => ['a.b', 'a.c.d']\nexport const getObjectPaths = (obj: GenericObject, prefix = '') => {\n let paths: string[] = [];\n\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {\n paths = paths.concat(getObjectPaths(obj[key], path));\n } else {\n paths.push(path);\n }\n }\n }\n\n return paths;\n}\n\n// Removes duplicates from an array of objects based on a unique key\n// e.g [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Alice' } ] => [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ]\nexport const deduplicateObjectsArray = (arr: GenericObject[], uniqueKey: string): GenericObject[] => {\n const seen = new Set();\n return arr.reduce((acc: GenericObject[], obj) => {\n if (!seen.has(obj[uniqueKey])) {\n seen.add(obj[uniqueKey]);\n acc.push(obj);\n }\n return acc;\n }, []);\n}\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nimport { ContextLogger } from '@mojaloop/central-services-logger/src/contextLogger';\nimport { FspiopPutQuotesSource, FspiopSource, IsoSource, FspiopPutPartiesSource, FspiopPutPartiesErrorSource } from '.';\n\nexport const isContextLogger = (logger: ContextLogger): logger is ContextLogger => {\n return (\n 'info' in logger &&\n 'error' in logger &&\n 'warn' in logger &&\n 'verbose' in logger &&\n 'debug' in logger &&\n 'silly' in logger &&\n 'audit' in logger &&\n 'trace' in logger\n );\n};\n\nconst baseFspiopGuards = {\n isSource: (source: FspiopSource): source is FspiopSource => {\n return !!(source.body);\n }\n};\n\nconst baseIsoGuards = {\n isSource: (source: IsoSource): source is IsoSource => {\n return !!(source.body);\n }\n};\n\nconst FSPIOP = {\n parties: {\n put: {\n isSource: (source: FspiopPutPartiesSource): source is FspiopPutPartiesSource => {\n return !!(source.body && (source.headers?.['fspiop-source'] && source.headers['fspiop-destination']) && (source.params.IdPath || (source.params?.Type && source.params.ID)));\n }\n },\n putError: {\n isSource: (source: FspiopPutPartiesErrorSource): source is FspiopPutPartiesErrorSource => {\n return !!(source.body && (source.headers?.['fspiop-source'] && source.headers['fspiop-destination']) && (source.params.IdPath || (source.params?.Type && source.params.ID)));\n }\n }\n },\n quotes: {\n post: baseFspiopGuards,\n put: {\n isSource: (source: FspiopPutQuotesSource): source is FspiopPutQuotesSource => {\n return !!(source.body && source.params?.ID && ((source.$context?.isoPostQuote) || (source.headers?.['fspiop-source'] && source.headers['fspiop-destination'])));\n }\n },\n putError: baseFspiopGuards\n },\n transfers: {\n post: baseFspiopGuards,\n patch: baseFspiopGuards,\n put: baseFspiopGuards,\n putError: baseFspiopGuards\n },\n fxQuotes: {\n post: baseFspiopGuards,\n put: baseFspiopGuards,\n putError: baseFspiopGuards\n },\n fxTransfers: {\n post: baseFspiopGuards,\n patch: baseFspiopGuards,\n put: baseFspiopGuards,\n putError: baseFspiopGuards\n }\n};\n\nconst FSPIOPISO20022 = {\n parties: {\n put: baseIsoGuards,\n putError: baseIsoGuards\n },\n quotes: {\n post: baseIsoGuards,\n put: baseIsoGuards,\n putError: baseIsoGuards\n },\n transfers: {\n post: baseIsoGuards,\n patch: baseIsoGuards,\n put: baseIsoGuards,\n putError: baseIsoGuards\n },\n fxQuotes: {\n post: baseIsoGuards,\n put: baseIsoGuards,\n putError: baseIsoGuards\n },\n fxTransfers: {\n post: baseIsoGuards,\n patch: baseIsoGuards,\n put: baseIsoGuards,\n putError: baseIsoGuards\n }\n};\n\nexport const TypeGuards = { FSPIOP, FSPIOPISO20022 };\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nimport { ContextLogger } from '@mojaloop/central-services-logger/src/contextLogger';\nimport { AsyncTransformer, Options, State, TransformDefinition, Transformer } from './map-transform';\n\nexport enum HTTP_METHOD {\n GET = 'GET',\n PUT = 'PUT',\n POST = 'POST',\n DELETE = 'DELETE',\n PATCH = 'PATCH'\n}\n\nexport enum API_NAME {\n FSPIOP = 'fspiop',\n ISO20022 = 'iso'\n}\n\nexport interface ITransformer {\n transform(source: Partial<Source>, { mapperOptions }: { mapperOptions?: State }): Promise<Partial<Target>>;\n}\n\nexport type FacadeOptions = { overrideMapping?: TransformDefinition, mapTransformOptions?: Options, mapperOptions?: State, validateTarget?: boolean };\n\nexport type FspiopFacadeOptions = FacadeOptions & { unrollExtensions?: boolean };\nexport type FspiopFacadeFunction = (source: Source, options: FacadeOptions) => Promise<IsoTarget>;\nexport type IsoFacadeOptions = FacadeOptions & { rollUpUnmappedAsExtensions?: boolean };\nexport type IsoFacadeFunction = (source: IsoSource, options: FacadeOptions) => Promise<Partial<Target>>;\n\nexport type TransformFunctionOptions = { mapping: TransformDefinition, mapperOptions?: State, mapTransformOptions?: Options, logger: ContextLogger };\nexport type CreateTransformerOptions = { mapTransformOptions?: Options };\n\nexport enum ID_GENERATOR_TYPE {\n ulid = 'ulid',\n uuid = 'uuid'\n}\n\nexport interface ICustomTransforms {\n [key: string | symbol]: Transformer | AsyncTransformer\n}\n\nexport type ConfigOptions = {\n logger?: ContextLogger;\n isTestingMode?: boolean;\n unrollExtensions?: boolean;\n rollUpUnmappedAsExtensions?: boolean;\n validateTarget?: boolean;\n}\n\nexport type Headers = {\n 'fspiop-source': string;\n 'fspiop-destination': string;\n}\n\nexport type Params = {\n Type?: string;\n ID?: string;\n SubId?: string;\n}\n\nexport type PartyIdParamsSource = {\n Type: string;\n ID: string;\n SubId?: string;\n IdPath?: string; // format: IdType/IdValue or IdType/IdValue/SubIdValue\n} | {\n Type?: string;\n ID?: string;\n SubId?: string;\n IdPath: string; // format: IdType/IdValue or IdType/IdValue/SubIdValue\n}\n\nexport type PartyIdParamsTarget = {\n Type: string;\n ID: string;\n SubId?: string;\n}\n\nexport type Source = {\n body: GenericObject;\n headers?: Headers;\n params?: Partial<Params>;\n}\n\nexport type Target = {\n body: GenericObject;\n headers: Headers;\n params: Params;\n};\n\nexport type FspiopSource = Pick<Source, 'body'>;\nexport type FspiopTarget = Pick<Target, 'body'>;\nexport type FspiopPutQuotesSource = { body: GenericObject, params: Pick<Params, 'ID'>, $context?: { isoPostQuote: GenericObject }, headers?: Headers } | {body: GenericObject, params: Pick<Params, 'ID'>, headers: Headers, $context?: { isoPostQuote: GenericObject } };\nexport type FspiopPutQuotesTarget = { body: GenericObject, headers: Headers, params: Pick<Params, 'ID'> };\nexport type FspiopPutPartiesSource = { body: GenericObject, headers: Headers, params: PartyIdParamsSource };\nexport type FspiopPutPartiesTarget = { body: GenericObject, headers: Headers, params: PartyIdParamsTarget };\nexport type FspiopPutPartiesErrorSource = { body: GenericObject, headers: Headers, params: PartyIdParamsSource };\nexport type FspiopPutPartiesErrorTarget = { body: GenericObject, headers: Headers, params: PartyIdParamsTarget };\nexport type FspiopPostTransfersSource = { body: GenericObject, $context?: { isoPostQuoteResponse: GenericObject }, headers?: Headers } | {body: GenericObject, params: Pick<Params, 'ID'>, headers: Headers, $context?: { isoPostQuoteResponse: GenericObject } };\n\nexport type IsoSource = Pick<Source, 'body'>;\nexport type IsoTarget = Pick<Target, 'body'>;\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport type GenericObject = Record<string, any>;\nexport type Primitive = string | number | boolean;\n\n// Pipeline types\nexport type PipelineStep = ({ source, target, options, logger }: { source: GenericObject, target: GenericObject, options: GenericObject, logger: ContextLogger }) => GenericObject;\nexport type PipelineStepsConfig = { [key: string]: GenericObject };\nexport type PipelineOptions = {\n pipelineSteps: PipelineStep[];\n logger: ContextLogger;\n [key: string]: any;\n}\n\n\nexport type Json = string | number | boolean | Json[] | { [key: string]: Json };\nexport type LogContext = Json | string | null;\nexport const logLevelsMap = {\n error: 'error',\n warn: 'warn',\n info: 'info',\n verbose: 'verbose',\n debug: 'debug',\n silly: 'silly',\n audit: 'audit',\n trace: 'trace',\n perf: 'perf',\n} as const;\n\nexport const logLevelValues = Object.values(logLevelsMap);\nexport type LogLevel = (typeof logLevelValues)[number];\nexport * from './type-guards';\n\nexport type Request = {\n path: string;\n method: HTTP_METHOD;\n headers: GenericObject;\n body: GenericObject;\n query: GenericObject;\n}\n\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nimport { ICustomTransforms } from '../../types';\nimport { Options, State } from '../../types/map-transform';\nimport { generateID as genID, getDescrForErrCode, getIlpPacketCondition, isEmptyObject, isPersonPartyIdType, toFspiopTransferState, toIsoTransferState } from '../utils';\n\nexport const CustomTransforms: ICustomTransforms = {\n generateID: (options: Options) => () => (data: unknown, state: State) => {\n return genID();\n },\n\n datetimeNow: (options: Options) => () => (data: unknown, state: State) => {\n return new Date().toISOString(); // Not sure if this is the correct format\n },\n\n isPersonParty: (options: Options) => () => (data: unknown, state: State) => {\n return isPersonPartyIdType(data as string);\n },\n\n isNotPersonParty: (options: Options) => () => (data: unknown, state: State) => {\n return !isPersonPartyIdType(data as string);\n },\n\n isNotEmpty: (options: Options) => () => (data: unknown, state: State) => {\n return data && !isEmptyObject(data);\n },\n\n fspiopErrorDescrForCode: (options: Options) => () => (data: unknown, state: State) => {\n return getDescrForErrCode(data as string);\n },\n\n ilpPacketToCondition: (options: Options) => () => (data: unknown, state: State) => {\n return getIlpPacketCondition(data as string);\n },\n\n toFspiopTransferState: (options: Options) => () => (data: unknown, state: State) => {\n return toFspiopTransferState(data as string);\n },\n\n toIsoTransferState: (options: Options) => () => (data: unknown, state: State) => {\n return toIsoTransferState(data as string);\n },\n\n toIsoErrorDescription: (options: Options) => () => (data: unknown, state: State) => {\n // In ISO20022, error descriptions are limited to 105 characters\n const dataStr = data as string;\n return dataStr.length > 105 ? dataStr.substring(0, 105) : dataStr;\n },\n\n supportedCurrenciesToString: (options: Options) => () => (data: unknown, state: State) => {\n return data && Array.isArray(data) && data.length > 0 ? data[0] : data;\n },\n\n toArray: (options: Options) => () => (data: unknown, state: State) => {\n if (data) {\n return Array.isArray(data) ? data : [data];\n }\n\n return undefined;\n }\n}\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\n/* eslint-disable @typescript-eslint/no-require-imports */\nconst mapTransform = require('map-transform-cjs').default;\nimport { TransformDefinition } from '../types/map-transform';\nimport { CreateTransformerOptions, ITransformer } from '../types';\nimport { Transformer } from './transformer';\nimport { CustomTransforms } from './transforms';\n\nexport const createTransformer = (mapping: TransformDefinition, options: CreateTransformerOptions = {}): ITransformer => {\n const { mapTransformOptions } = options;\n const mergedOptions = { ...mapTransformOptions, transformers: { ...mapTransformOptions?.transformers, ...CustomTransforms } };\n mapping = typeof mapping === 'string' ? JSON.parse(mapping) : mapping;\n return new Transformer(mapTransform(mapping, mergedOptions));\n};\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\nimport { loggerFactory } from '@mojaloop/central-services-logger/src/contextLogger';\nimport { LogContext, LogLevel, logLevelsMap } from '../types';\n\nexport const createLogger = (context: LogContext, logLevel: LogLevel) => {\n const log = loggerFactory(context);\n log.setLevel(logLevel);\n return log;\n};\n\nexport const logger = createLogger('MLST', process.env.MLST_LOG_LEVEL as LogLevel || logLevelsMap.warn);\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\n// FSPIOP ISO 20022 to FSPIOP mappings\n\nexport * from './discovery'\nexport * from './quotes'\nexport * from './fxQuotes'\nexport * from './transfers'\nexport * from './fxTransfers'\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\n// FSPIOP ISO220022 to FSPIOP mappings\n\nexport const discovery = {\n parties: {\n put: `{\n \"$noDefaults\": true,\n \"headers.fspiop-source\": \"body.Assgnmt.Assgnr.Agt.FinInstnId.Othr.Id\",\n \"headers.fspiop-destination\": \"body.Assgnmt.Assgne.Agt.FinInstnId.Othr.Id\",\n \"params.IdPath\": \"body.Rpt.OrgnlId\",\n \"body.party.partyIdInfo.partyIdType\": { \"$alt\": [ \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.OrgId.Othr.SchmeNm.Prtry\", \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.PrvtId.Othr.SchmeNm.Prtry\", \"body.Rpt.UpdtdPtyAndAcctId.Pty.PrvtId.Othr.Id\" ] },\n \"body.party.partyIdInfo.partyIdentifier\": { \"$alt\": [\"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.OrgId.Othr.Id\", \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.PrvtId.Othr.Id\"] },\n \"body.party.partyIdInfo.fspId\": \"body.Rpt.UpdtdPtyAndAcctId.Agt.FinInstnId.Othr.Id\",\n \"body.party.name\": \"body.Rpt.UpdtdPtyAndAcctId.Pty.Nm\",\n \"body.party.supportedCurrencies\": [\"body.Rpt.UpdtdPtyAndAcctId.Acct.Ccy\", { \"$transform\": \"toArray\" }]\n }`,\n putError: `{\n \"$noDefaults\": true,\n \"body.errorInformation.errorDescription\": [\"body.Rpt.Rsn.Cd\", { \"$transform\": \"fspiopErrorDescrForCode\" }],\n \"body.errorInformation.errorCode\": \"body.Rpt.Rsn.Cd\",\n \"headers.fspiop-source\": \"body.Assgnmt.Assgnr.Agt.FinInstnId.Othr.Id\",\n \"headers.fspiop-destination\": \"body.Assgnmt.Assgne.Agt.FinInstnId.Othr.Id\",\n \"params.IdPath\": \"body.Rpt.OrgnlId\"\n }`\n }\n}\n\n// FSPIOP to FSPIOP ISO220022 mappings\n\nexport const discovery_reverse = {\n parties: {\n put: `{\n \"$noDefaults\": true,\n \"body.Assgnmt.MsgId\": { \"$transform\": \"generateID\" },\n \"body.Assgnmt.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.Rpt.Vrfctn\": [{ \"$transform\": \"fixed\", \"value\": true }],\n \"body.Assgnmt.Assgnr.Agt.FinInstnId.Othr.Id\": \"headers.fspiop-source\",\n \"body.Assgnmt.Assgne.Agt.FinInstnId.Othr.Id\": \"headers.fspiop-destination\",\n \"body.Rpt.OrgnlId\": \"params.IdPath\",\n \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.OrgId.Othr.SchmeNm.Prtry\": [\"body.party.partyIdInfo.partyIdType\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.PrvtId.Othr.SchmeNm.Prtry\": [\"body.party.partyIdInfo.partyIdType\", { \"$filter\": \"isPersonParty\" }],\n \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.OrgId.Othr.Id\": [\"body.party.partyIdInfo.partyIdentifier\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.Rpt.UpdtdPtyAndAcctId.Pty.Id.PrvtId.Othr.Id\": [\"body.party.partyIdInfo.partyIdentifier\", { \"$filter\": \"isPersonParty\" }],\n \"body.Rpt.UpdtdPtyAndAcctId.Agt.FinInstnId.Othr.Id\": \"body.party.partyIdInfo.fspId\",\n \"body.Rpt.UpdtdPtyAndAcctId.Pty.Nm\": \"body.party.name\",\n \"body.Rpt.UpdtdPtyAndAcctId.Acct.Ccy\": [\"body.party.supportedCurrencies\", { \"$transform\": \"supportedCurrenciesToString\" }]\n }`,\n putError: `{\n \"$noDefaults\": true,\n \"body.Rpt.Rsn.Cd\": \"body.errorInformation.errorCode\",\n \"body.Assgnmt.MsgId\": { \"$transform\": \"generateID\" },\n \"body.Assgnmt.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.Assgnmt.Assgnr.Agt.FinInstnId.Othr.Id\": \"headers.fspiop-source\",\n \"body.Assgnmt.Assgne.Agt.FinInstnId.Othr.Id\": \"headers.fspiop-destination\",\n \"body.Rpt.OrgnlId\": \"params.IdPath\",\n \"body.Rpt.Vrfctn\": [{ \"$transform\": \"fixed\", \"value\": false }]\n }`\n }\n}\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actually holds the copyright for their contributions (see the\n Mojaloop Foundation for an example). Those individuals should have\n their names indented and be marked with a '-'. Email address can be added\n optionally within square brackets <email>.\n\n * Mojaloop Foundation\n - Name Surname <name.surname@mojaloop.io>\n \n * Steven Oderayi <steven.oderayi@infitx.com>\n --------------\n ******/\n\n// FSPIOP ISO 20022 to FSPIOP mappings\n\nexport const quotes = {\n post: `{\n \"$noDefaults\": \"true\",\n \"body.quoteId\": \"body.CdtTrfTxInf.PmtId.TxId\",\n \"body.expiration\": \"body.GrpHdr.PmtInstrXpryDtTm\",\n \"body.transactionId\": \"body.CdtTrfTxInf.PmtId.EndToEndId\",\n \"body.transactionRequestId\": \"body.CdtTrfTxInf.PmtId.InstrId\",\n \"body.payee.partyIdInfo.partyIdType\": { \"$alt\": [ \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.SchmeNm.Prtry\", \"body.CdtTrfTxInf.Cdtr.Id.PrvtId.Othr.SchmeNm.Prtry\" ] },\n \"body.payee.partyIdInfo.partyIdentifier\": { \"$alt\": [ \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.Id\", \"body.CdtTrfTxInf.Cdtr.Id.PrvtId.Othr.Id\" ] },\n \"body.payee.partyIdInfo.fspId\": \"body.CdtTrfTxInf.CdtrAgt.FinInstnId.Othr.Id\",\n \"body.payee.name\": \"body.CdtTrfTxInf.Cdtr.Name\",\n \"body.payee.supportedCurrencies\": [\"body.CdtTrfTxInf.CdtrAcct.Ccy\", { \"$transform\": \"toArray\" }],\n \"body.payer.partyIdInfo.partyIdType\": { \"$alt\": [ \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.SchmeNm.Prtry\", \"body.CdtTrfTxInf.Dbtr.Id.PrvtId.Othr.SchmeNm.Prtry\" ] },\n \"body.payer.partyIdInfo.partyIdentifier\": { \"$alt\": [ \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.Id\", \"body.CdtTrfTxInf.Dbtr.Id.PrvtId.Othr.Id\" ] },\n \"body.payer.partyIdInfo.fspId\": \"body.CdtTrfTxInf.DbtrAgt.FinInstnId.Othr.Id\",\n \"body.payer.name\": \"body.CdtTrfTxInf.Dbtr.Name\",\n \"body.payer.supportedCurrencies\": [\"body.CdtTrfTxInf.DbtrAcct.Ccy\", { \"$transform\": \"toArray\" }],\n \"body.amount.currency\": \"body.CdtTrfTxInf.IntrBkSttlmAmt.Ccy\",\n \"body.amount.amount\": \"body.CdtTrfTxInf.IntrBkSttlmAmt.ActiveCurrencyAndAmount\",\n \"body.transactionType.scenario\": \"body.CdtTrfTxInf.Purp.Prtry\",\n \"body.transactionType.refundInfo.originalTransactionId\": \"body.CdtTrfTxInf.PmtId.InstrId\"\n }`,\n // TODO: Support payeeFspCommission.currency and payeeFspCommission.amount\n // when CdtTrfTxInf.IntrBkSttlmAmt.ChrgsInf.Tp.Cd is \"COMM\"\n put: `{\n \"$noDefaults\": \"true\",\n \"params.ID\": \"body.CdtTrfTxInf.PmtId.TxId\",\n \"headers.fspiop-destination\": \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.Id\",\n \"headers.fspiop-source\": \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.Id\",\n \"body.expiration\": \"body.GrpHdr.PmtInstrXpryDtTm\",\n \"body.transferAmount.currency\": \"body.CdtTrfTxInf.IntrBkSttlmAmt.Ccy\",\n \"body.transferAmount.amount\": \"body.CdtTrfTxInf.IntrBkSttlmAmt.ActiveCurrencyAndAmount\",\n \"body.payeeReceiveAmount.currency\": \"body.CdtTrfTxInf.InstdAmt.Ccy\",\n \"body.payeeReceiveAmount.amount\": \"body.CdtTrfTxInf.InstdAmt.ActiveOrHistoricCurrencyAndAmount\",\n \"body.payeeFspFee.currency\": \"body.CdtTrfTxInf.ChrgsInf.Amt.Ccy\",\n \"body.payeeFspFee.amount\": \"body.CdtTrfTxInf.ChrgsInf.Amt.ActiveOrHistoricCurrencyAndAmount\",\n \"body.ilpPacket\": \"body.CdtTrfTxInf.VrfctnOfTerms.IlpV4PrepPacket\",\n \"body.condition\": [ \"body.CdtTrfTxInf.VrfctnOfTerms.IlpV4PrepPacket\", { \"$transform\": \"ilpPacketToCondition\" }]\n }`,\n putError: `{\n \"$noDefaults\": \"true\",\n \"body.errorInformation.errorCode\": \"body.TxInfAndSts.StsRsnInf.Rsn.Prtry\",\n \"body.errorInformation.errorDescription\": \"body.TxInfAndSts.StsRsnInf.AddtlInf\"\n }`\n}\n\n// FSPIOP to FSPIOP ISO 20022 mappings\n\nexport const quotes_reverse = {\n post: `{\n \"$noDefaults\": \"true\",\n \"body.GrpHdr.MsgId\": { \"$transform\": \"generateID\" },\n \"body.GrpHdr.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.GrpHdr.NbOfTxs\": { \"$transform\": \"fixed\", \"value\": \"1\" },\n \"body.GrpHdr.PmtInstrXpryDtTm\": \"body.expiration\",\n \"body.GrpHdr.SttlmInf.SttlmMtd\": { \"$transform\": \"fixed\", \"value\": \"CLRG\" },\n \"body.CdtTrfTxInf.PmtId.TxId\": \"body.quoteId\",\n \"body.CdtTrfTxInf.PmtId.EndToEndId\": \"body.transactionId\",\n \"body.CdtTrfTxInf.PmtId.InstrId\": \"body.transactionRequestId\",\n \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.SchmeNm.Prtry\": [\"body.payee.partyIdInfo.partyIdType\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.CdtTrfTxInf.Cdtr.Id.PrvtId.Othr.SchmeNm.Prtry\": [\"body.payee.partyIdInfo.partyIdType\", { \"$filter\": \"isPersonParty\" }],\n \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.Id\": [\"body.payee.partyIdInfo.partyIdentifier\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.CdtTrfTxInf.Cdtr.Id.PrvtId.Othr.Id\": [\"body.payee.partyIdInfo.partyIdentifier\", { \"$filter\": \"isPersonParty\" }],\n \"body.CdtTrfTxInf.CdtrAgt.FinInstnId.Othr.Id\": \"body.payee.partyIdInfo.fspId\",\n \"body.CdtTrfTxInf.Cdtr.Name\": \"body.payee.name\",\n \"body.CdtTrfTxInf.CdtrAcct.Ccy\": [\"body.payee.supportedCurrencies\", { \"$transform\": \"supportedCurrenciesToString\" }],\n \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.SchmeNm.Prtry\": [\"body.payer.partyIdInfo.partyIdType\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.CdtTrfTxInf.Dbtr.Id.PrvtId.Othr.SchmeNm.Prtry\": [\"body.payer.partyIdInfo.partyIdType\", { \"$filter\": \"isPersonParty\" }],\n \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.Id\": [\"body.payer.partyIdInfo.partyIdentifier\", { \"$filter\": \"isNotPersonParty\" }],\n \"body.CdtTrfTxInf.Dbtr.Id.PrvtId.Othr.Id\": [\"body.payer.partyIdInfo.partyIdentifier\", { \"$filter\": \"isPersonParty\" }],\n \"body.CdtTrfTxInf.DbtrAgt.FinInstnId.Othr.Id\": \"body.payer.partyIdInfo.fspId\",\n \"body.CdtTrfTxInf.Dbtr.Name\": \"body.payer.name\",\n \"body.CdtTrfTxInf.DbtrAcct.Ccy\": [\"body.payer.supportedCurrencies\", { \"$transform\": \"supportedCurrenciesToString\" }],\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.Ccy\": \"body.amount.currency\",\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.ActiveCurrencyAndAmount\": \"body.amount.amount\",\n \"body.CdtTrfTxInf.Purp.Prtry\": \"body.transactionType.scenario\",\n \"body.CdtTrfTxInf.PmtId.InstrId\": \"body.transactionType.refundInfo.originalTransactionId\"\n }`,\n // TODO: Support payeeFspCommission.currency and payeeFspCommission.amount\n // when CdtTrfTxInf.IntrBkSttlmAmt.ChrgsInf.Tp.Cd is \"COMM\"\n putTesting: `{\n \"$noDefaults\": \"true\",\n \"body.GrpHdr.MsgId\": { \"$transform\": \"generateID\" },\n \"body.GrpHdr.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.GrpHdr.NbOfTxs\": { \"$transform\": \"fixed\", \"value\": \"1\" },\n \"body.GrpHdr.SttlmInf.SttlmMtd\": { \"$transform\": \"fixed\", \"value\": \"CLRG\" },\n \"body.GrpHdr.PmtInstrXpryDtTm\": \"body.expiration\",\n \"body.CdtTrfTxInf.PmtId.TxId\": \"params.ID\",\n \"body.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.Id\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.Dbtr.Id.OrgId.Othr.Id\", \"headers.fspiop-destination\" ]},\n \"body.CdtTrfTxInf.DbtrAgt.FinInstnId.Othr.Id\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.DbtrAgt.FinInstnId.Othr.Id\", \"headers.fspiop-destination\" ]},\n \"body.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.Id\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.Cdtr.Id.OrgId.Othr.Id\", \"headers.fspiop-source\" ] },\n \"body.CdtTrfTxInf.CdtrAgt.FinInstnId.Othr.Id\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.CdtrAgt.FinInstnId.Othr.Id\", \"headers.fspiop-source\" ]},\n \"body.CdtTrfTxInf.ChrgBr\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.ChrgBr\", { \"$transform\": \"fixed\", \"value\": \"SHAR\" } ] },\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.Ccy\": \"body.transferAmount.currency\",\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.ActiveCurrencyAndAmount\": \"body.transferAmount.amount\",\n \"body.CdtTrfTxInf.InstdAmt.Ccy\": \"body.payeeReceiveAmount.currency\",\n \"body.CdtTrfTxInf.InstdAmt.ActiveOrHistoricCurrencyAndAmount\": \"body.payeeReceiveAmount.amount\",\n \"body.CdtTrfTxInf.ChrgsInf.Amt.Ccy\": \"body.payeeFspFee.currency\",\n \"body.CdtTrfTxInf.ChrgsInf.Amt.ActiveOrHistoricCurrencyAndAmount\": \"body.payeeFspFee.amount\",\n \"body.CdtTrfTxInf.ChrgsInf.Agt.FinInstnId.Othr.Id\": { \"$alt\": [ \"$context.isoPostQuote.CdtTrfTxInf.CdtrAgt.FinInstnId.Othr.Id\", { \"$transform\": \"fixed\", \"value\": \"Testing\" } ] },\n \"body.CdtTrfTxInf.VrfctnOfTerms.IlpV4PrepPacket\": \"body.ilpPacket\"\n }`,\n put: `{\n \"$noDefaults\": \"true\",\n \"body.GrpHdr.MsgId\": { \"$transform\": \"generateID\" },\n \"body.GrpHdr.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.GrpHdr.NbOfTxs\": { \"$transform\": \"fixed\", \"value\": \"1\" },\n \"body.GrpHdr.SttlmInf.SttlmMtd\": { \"$transform\": \"fixed\", \"value\": \"CLRG\" },\n \"body.GrpHdr.PmtInstrXpryDtTm\": \"body.expiration\",\n \"body.CdtTrfTxInf.PmtId.TxId\": \"params.ID\",\n \"body.CdtTrfTxInf.Dbtr\": \"$context.isoPostQuote.CdtTrfTxInf.Dbtr\",\n \"body.CdtTrfTxInf.DbtrAgt\": \"$context.isoPostQuote.CdtTrfTxInf.DbtrAgt\",\n \"body.CdtTrfTxInf.Cdtr\": \"$context.isoPostQuote.CdtTrfTxInf.Cdtr\",\n \"body.CdtTrfTxInf.CdtrAgt\": \"$context.isoPostQuote.CdtTrfTxInf.CdtrAgt\",\n \"body.CdtTrfTxInf.ChrgBr\": \"$context.isoPostQuote.CdtTrfTxInf.ChrgBr\",\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.Ccy\": \"body.transferAmount.currency\",\n \"body.CdtTrfTxInf.IntrBkSttlmAmt.ActiveCurrencyAndAmount\": \"body.transferAmount.amount\",\n \"body.CdtTrfTxInf.InstdAmt.Ccy\": \"body.payeeReceiveAmount.currency\",\n \"body.CdtTrfTxInf.InstdAmt.ActiveOrHistoricCurrencyAndAmount\": \"body.payeeReceiveAmount.amount\",\n \"body.CdtTrfTxInf.ChrgsInf.Amt.Ccy\": \"body.payeeFspFee.currency\",\n \"body.CdtTrfTxInf.ChrgsInf.Amt.ActiveOrHistoricCurrencyAndAmount\": \"body.payeeFspFee.amount\",\n \"body.CdtTrfTxInf.ChrgsInf.Agt\": \"$context.isoPostQuote.CdtTrfTxInf.CdtrAgt\",\n \"body.CdtTrfTxInf.VrfctnOfTerms.IlpV4PrepPacket\": \"body.ilpPacket\"\n }`,\n putError: `{\n \"$noDefaults\": \"true\",\n \"body.GrpHdr.MsgId\": { \"$transform\": \"generateID\" },\n \"body.GrpHdr.CreDtTm\": { \"$transform\": \"datetimeNow\" },\n \"body.TxInfAndSts.StsRsnInf.Rsn.Prtry\": \"body.errorInformation.errorCode\",\n \"body.TxInfAndSts.StsRsnInf.AddtlInf\": [ \"body.errorInformation.errorDescription\", { \"$transform\": \"toIsoErrorDescription\" } ]\n }`\n}\n","/*****\n License\n --------------\n Copyright © 2020-2025 Mojaloop Foundation\n 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\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n 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.\n\n Contributors\n --------------\n This is the official list of the Mojaloop project contributors for this file.\n Names of the original copyright holders (individuals or organizations)\n should be listed with a '*' in the first column. People who have\n contributed from an organization can be listed under the organization\n that actua