@fiado/type-kit 3.405.0 → 3.407.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/_test_/unit/biometrics/BiometricReferenceSourceEnum.test.ts +18 -0
- package/_test_/unit/biometrics/BiometricVerificationResponse.test.ts +63 -0
- package/_test_/unit/biometrics/CreateBiometricVerificationRequest.test.ts +57 -0
- package/_test_/unit/identity/PeopleIdPhotoResponse.test.ts +33 -0
- package/bin/biometrics/dtos/requests/CreateBiometricVerificationRequest.d.ts +13 -0
- package/bin/biometrics/dtos/requests/CreateBiometricVerificationRequest.js +7 -0
- package/bin/biometrics/dtos/responses/BiometricVerificationResponse.d.ts +9 -0
- package/bin/biometrics/dtos/responses/BiometricVerificationResponse.js +6 -0
- package/bin/biometrics/enums/BiometricReferenceSourceEnum.d.ts +14 -0
- package/bin/biometrics/enums/BiometricReferenceSourceEnum.js +18 -0
- package/bin/biometrics/events/BiometricVerificationChangedV1.d.ts +12 -20
- package/bin/biometrics/events/BiometricVerificationChangedV1.js +7 -12
- package/bin/biometrics/index.d.ts +1 -0
- package/bin/biometrics/index.js +1 -0
- package/bin/identity/dtos/PeopleIdPhotoResponse.d.ts +17 -0
- package/bin/identity/dtos/PeopleIdPhotoResponse.js +49 -0
- package/bin/identity/index.d.ts +1 -0
- package/bin/identity/index.js +1 -0
- package/bin/remittance/dtos/RemittancePayerConfig.d.ts +38 -0
- package/bin/remittance/dtos/RemittancePayerConfig.js +45 -0
- package/bin/remittance/dtos/index.d.ts +1 -0
- package/bin/remittance/dtos/index.js +1 -0
- package/bin/remittance/enums/AuditEntityType.d.ts +1 -0
- package/bin/remittance/enums/AuditEntityType.js +1 -0
- package/package.json +1 -1
- package/src/biometrics/dtos/requests/CreateBiometricVerificationRequest.ts +20 -0
- package/src/biometrics/dtos/responses/BiometricVerificationResponse.ts +11 -0
- package/src/biometrics/enums/BiometricReferenceSourceEnum.ts +16 -0
- package/src/biometrics/events/BiometricVerificationChangedV1.ts +12 -20
- package/src/biometrics/index.ts +1 -0
- package/src/identity/dtos/PeopleIdPhotoResponse.ts +27 -0
- package/src/identity/index.ts +1 -0
- package/src/remittance/dtos/RemittancePayerConfig.ts +50 -0
- package/src/remittance/dtos/index.ts +1 -0
- package/src/remittance/enums/AuditEntityType.ts +1 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { BiometricReferenceSourceEnum } from '../../../src/biometrics/index';
|
|
3
|
+
|
|
4
|
+
describe('BiometricReferenceSourceEnum', () => {
|
|
5
|
+
it('tiene exactamente los tres valores del contrato', () => {
|
|
6
|
+
expect(Object.values(BiometricReferenceSourceEnum).sort()).toEqual([
|
|
7
|
+
'CALLER_PROVIDED',
|
|
8
|
+
'ID_DOCUMENT',
|
|
9
|
+
'KYC_SELFIE',
|
|
10
|
+
]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('cada clave es igual a su valor', () => {
|
|
14
|
+
for (const [clave, valor] of Object.entries(BiometricReferenceSourceEnum)) {
|
|
15
|
+
expect(clave).toBe(valor);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
BiometricVerificationResponse,
|
|
6
|
+
BiometricReferenceSourceEnum,
|
|
7
|
+
} from '../../../src/biometrics/index';
|
|
8
|
+
|
|
9
|
+
/** La respuesta mínima válida: todos los campos obligatorios del contrato. */
|
|
10
|
+
const base = {
|
|
11
|
+
biometricVerificationId: 'bio-1',
|
|
12
|
+
type: 'FACEMATCH',
|
|
13
|
+
provider: 'METAMAP',
|
|
14
|
+
directoryId: 'dir-1',
|
|
15
|
+
status: 'IN_PROGRESS',
|
|
16
|
+
result: 'UNKNOWN',
|
|
17
|
+
deliveryMode: 'REDIRECT',
|
|
18
|
+
delivery: { link: 'https://sk.fiado.test/abc', expiresAt: '2026-09-04T17:00:00.000Z' },
|
|
19
|
+
referenceImageSource: 'KYC_SELFIE',
|
|
20
|
+
createdAt: '2026-09-04T16:00:00.000Z',
|
|
21
|
+
updatedAt: '2026-09-04T16:00:00.000Z',
|
|
22
|
+
expiresAt: '2026-09-04T17:00:00.000Z',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const instancia = (raw: Record<string, unknown>): BiometricVerificationResponse =>
|
|
26
|
+
plainToInstance(BiometricVerificationResponse, raw, { excludeExtraneousValues: true });
|
|
27
|
+
|
|
28
|
+
const propiedadesConError = async (raw: Record<string, unknown>): Promise<string[]> =>
|
|
29
|
+
(await validate(instancia(raw) as object)).map((e) => e.property);
|
|
30
|
+
|
|
31
|
+
describe('BiometricVerificationResponse', () => {
|
|
32
|
+
it('valida la respuesta mínima', async () => {
|
|
33
|
+
expect(await propiedadesConError(base)).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* El eco de contra qué foto se comparó. Acá sí entran los TRES valores: `CALLER_PROVIDED` es de
|
|
38
|
+
* salida y decir `KYC_SELFIE` cuando la foto la puso el caller sería mentir sobre la comparación.
|
|
39
|
+
*/
|
|
40
|
+
describe('referenceImageSource', () => {
|
|
41
|
+
it.each(['KYC_SELFIE', 'ID_DOCUMENT', 'CALLER_PROVIDED'])('acepta %s', async (fuente) => {
|
|
42
|
+
const dto = instancia({ ...base, referenceImageSource: fuente });
|
|
43
|
+
|
|
44
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
45
|
+
expect(dto.referenceImageSource).toBe(fuente);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('rechaza la respuesta sin referenceImageSource: siempre viene poblado', async () => {
|
|
49
|
+
const { referenceImageSource: _omitido, ...sinFuente } = base;
|
|
50
|
+
|
|
51
|
+
expect(await propiedadesConError(sinFuente)).toContain('referenceImageSource');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('rechaza un valor fuera del enum', async () => {
|
|
55
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'PROFILE_PICTURE' }))
|
|
56
|
+
.toContain('referenceImageSource');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('sobrevive al plainToInstance con excludeExtraneousValues (lleva @Expose)', () => {
|
|
60
|
+
expect(instancia(base).referenceImageSource).toBe(BiometricReferenceSourceEnum.KYC_SELFIE);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CreateBiometricVerificationRequest,
|
|
6
6
|
BiometricProviderEnum,
|
|
7
7
|
BiometricTypeEnum,
|
|
8
|
+
BiometricReferenceSourceEnum,
|
|
8
9
|
} from '../../../src/biometrics/index';
|
|
9
10
|
|
|
10
11
|
/** El request mínimo válido: los 4 campos obligatorios. */
|
|
@@ -133,4 +134,60 @@ describe('CreateBiometricVerificationRequest', () => {
|
|
|
133
134
|
expect(instancia({ ...base, deliveryMode: 'EMBEDDED_SDK' }).deliveryMode).toBe('EMBEDDED_SDK');
|
|
134
135
|
});
|
|
135
136
|
});
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* `referenceImageSource` elige contra QUÉ foto se compara. Solo dos de los tres valores del enum
|
|
140
|
+
* son legales de entrada: `CALLER_PROVIDED` lo emite la respuesta, no lo pide el caller.
|
|
141
|
+
*/
|
|
142
|
+
describe('referenceImageSource', () => {
|
|
143
|
+
it('acepta ID_DOCUMENT', async () => {
|
|
144
|
+
const dto = instancia({ ...base, referenceImageSource: 'ID_DOCUMENT' });
|
|
145
|
+
|
|
146
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
147
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.ID_DOCUMENT);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('acepta KYC_SELFIE', async () => {
|
|
151
|
+
const dto = instancia({ ...base, referenceImageSource: 'KYC_SELFIE' });
|
|
152
|
+
|
|
153
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
154
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.KYC_SELFIE);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Llega ausente, no con el default puesto: el default lo aplica el manager. Poblarlo acá haría
|
|
159
|
+
* indistinguible el request que mandó la fuente del que solo mandó `referenceImageUrl`.
|
|
160
|
+
*/
|
|
161
|
+
it('es opcional y NO se autopobla con el default', async () => {
|
|
162
|
+
const dto = instancia(base);
|
|
163
|
+
|
|
164
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
165
|
+
expect(dto.referenceImageSource).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('RECHAZA CALLER_PROVIDED, que es solo de salida', async () => {
|
|
169
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'CALLER_PROVIDED' }))
|
|
170
|
+
.toContain('referenceImageSource');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('rechaza un valor que no está en el enum', async () => {
|
|
174
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'PROFILE_PICTURE' }))
|
|
175
|
+
.toContain('referenceImageSource');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// El par tiene que pasar el DTO LIMPIO: quien rechaza el choque es el manager, con
|
|
180
|
+
// `422 CONFLICTING_REFERENCE_IMAGE`. Un validador cross-field acá le daria al caller un
|
|
181
|
+
// `400 VALIDATION_ERROR` generico en vez del codigo tipado que el front espera.
|
|
182
|
+
it('acepta referenceImageUrl y referenceImageSource juntos: el choque lo resuelve el manager', async () => {
|
|
183
|
+
const dto = instancia({
|
|
184
|
+
...base,
|
|
185
|
+
referenceImageUrl: 'https://cdn.tufiado.com/foto.jpg',
|
|
186
|
+
referenceImageSource: BiometricReferenceSourceEnum.ID_DOCUMENT,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(await validate(dto)).toHaveLength(0);
|
|
190
|
+
expect(dto.referenceImageUrl).toBe('https://cdn.tufiado.com/foto.jpg');
|
|
191
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.ID_DOCUMENT);
|
|
192
|
+
});
|
|
136
193
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { PeopleIdPhotoResponse } from '../../../src/identity/index';
|
|
5
|
+
|
|
6
|
+
const base = {
|
|
7
|
+
directoryId: '4cdc2e82-4bdc-4421-8c3a-c77dadea23b7',
|
|
8
|
+
url: 'https://s3.amazonaws.com/bucket/USER/dir/x_PASSPORT_FRONT.jpeg?X-Amz-Expires=900',
|
|
9
|
+
key: 'x_PASSPORT_FRONT.jpeg',
|
|
10
|
+
expiresInSeconds: 900,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const instancia = (raw: Record<string, unknown>): PeopleIdPhotoResponse =>
|
|
14
|
+
plainToInstance(PeopleIdPhotoResponse, raw, { excludeExtraneousValues: true });
|
|
15
|
+
|
|
16
|
+
describe('PeopleIdPhotoResponse', () => {
|
|
17
|
+
it('acepta la respuesta completa', async () => {
|
|
18
|
+
const dto = instancia(base);
|
|
19
|
+
expect(await validate(dto)).toHaveLength(0);
|
|
20
|
+
expect(dto.key).toBe('x_PASSPORT_FRONT.jpeg');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it.each(['directoryId', 'url', 'key', 'expiresInSeconds'])('exige %s', async (campo) => {
|
|
24
|
+
const { [campo]: _, ...sinCampo } = base as Record<string, unknown>;
|
|
25
|
+
const errores = await validate(instancia(sinCampo));
|
|
26
|
+
expect(errores.map((e) => e.property)).toContain(campo);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('rechaza una vigencia no positiva', async () => {
|
|
30
|
+
const errores = await validate(instancia({ ...base, expiresInSeconds: 0 }));
|
|
31
|
+
expect(errores.map((e) => e.property)).toContain('expiresInSeconds');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
2
2
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
3
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
3
4
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
4
5
|
import { BiometricSubject } from '../BiometricSubject';
|
|
5
6
|
/**
|
|
@@ -56,6 +57,18 @@ export declare class CreateBiometricVerificationRequest {
|
|
|
56
57
|
* Úsalo solo si ya tienes la foto correcta a mano y quieres ahorrarte el round-trip.
|
|
57
58
|
*/
|
|
58
59
|
referenceImageUrl?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Contra QUÉ foto se compara. Default `KYC_SELFIE`, que aplica el servicio: acá viaja ausente
|
|
62
|
+
* cuando no lo mandas, para que se pueda distinguir de haberlo pedido explícitamente.
|
|
63
|
+
*
|
|
64
|
+
* **Sin fallback:** si la fuente pedida no tiene foto, responde `REFERENCE_PHOTO_UNAVAILABLE`;
|
|
65
|
+
* no se busca la otra. Quien pide contra el documento y recibe un match sabe que fue contra el
|
|
66
|
+
* documento.
|
|
67
|
+
*
|
|
68
|
+
* 🔴 `CALLER_PROVIDED` NO es válido acá — solo lo emite la respuesta. Y mandar esto junto con
|
|
69
|
+
* `referenceImageUrl` responde `422 CONFLICTING_REFERENCE_IMAGE`: son contradictorios.
|
|
70
|
+
*/
|
|
71
|
+
referenceImageSource?: BiometricReferenceSourceEnum.KYC_SELFIE | BiometricReferenceSourceEnum.ID_DOCUMENT;
|
|
59
72
|
/**
|
|
60
73
|
* Vigencia de la entrega, en segundos. Default 3600.
|
|
61
74
|
*
|
|
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
|
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const BiometricDeliveryModeEnum_1 = require("../../enums/BiometricDeliveryModeEnum");
|
|
16
16
|
const BiometricProviderEnum_1 = require("../../enums/BiometricProviderEnum");
|
|
17
|
+
const BiometricReferenceSourceEnum_1 = require("../../enums/BiometricReferenceSourceEnum");
|
|
17
18
|
const BiometricTypeEnum_1 = require("../../enums/BiometricTypeEnum");
|
|
18
19
|
const BiometricSubject_1 = require("../BiometricSubject");
|
|
19
20
|
/**
|
|
@@ -65,6 +66,12 @@ __decorate([
|
|
|
65
66
|
(0, class_validator_1.IsNotEmpty)(),
|
|
66
67
|
__metadata("design:type", String)
|
|
67
68
|
], CreateBiometricVerificationRequest.prototype, "referenceImageUrl", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
(0, class_transformer_1.Expose)(),
|
|
71
|
+
(0, class_validator_1.IsOptional)(),
|
|
72
|
+
(0, class_validator_1.IsIn)([BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum.KYC_SELFIE, BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum.ID_DOCUMENT]),
|
|
73
|
+
__metadata("design:type", String)
|
|
74
|
+
], CreateBiometricVerificationRequest.prototype, "referenceImageSource", void 0);
|
|
68
75
|
__decorate([
|
|
69
76
|
(0, class_transformer_1.Expose)(),
|
|
70
77
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
2
2
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
3
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
3
4
|
import { BiometricResultEnum } from '../../enums/BiometricResultEnum';
|
|
4
5
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
5
6
|
import { BiometricVerificationStatusEnum } from '../../enums/BiometricVerificationStatusEnum';
|
|
@@ -48,6 +49,14 @@ export declare class BiometricVerificationResponse {
|
|
|
48
49
|
* seguridad. El contrato lo garantiza el productor, que es un solo lambda.
|
|
49
50
|
*/
|
|
50
51
|
delivery: BiometricDelivery;
|
|
52
|
+
/**
|
|
53
|
+
* Contra qué foto se comparó. **Siempre poblado.**
|
|
54
|
+
*
|
|
55
|
+
* `CALLER_PROVIDED` significa que la foto la mandaste tú en `referenceImageUrl`. Es un valor
|
|
56
|
+
* distinto y no el default, porque decir `KYC_SELFIE` cuando la foto la pusiste tú sería mentir
|
|
57
|
+
* sobre contra qué se comparó — y eso es exactamente lo que este campo existe para evitar.
|
|
58
|
+
*/
|
|
59
|
+
referenceImageSource: BiometricReferenceSourceEnum;
|
|
51
60
|
/**
|
|
52
61
|
* Similitud reportada por el proveedor, 0–100, cuando la expone. Rekognition da score; Metamap
|
|
53
62
|
* responde pass/fail y esto viene ausente.
|
|
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
|
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const BiometricDeliveryModeEnum_1 = require("../../enums/BiometricDeliveryModeEnum");
|
|
16
16
|
const BiometricProviderEnum_1 = require("../../enums/BiometricProviderEnum");
|
|
17
|
+
const BiometricReferenceSourceEnum_1 = require("../../enums/BiometricReferenceSourceEnum");
|
|
17
18
|
const BiometricResultEnum_1 = require("../../enums/BiometricResultEnum");
|
|
18
19
|
const BiometricTypeEnum_1 = require("../../enums/BiometricTypeEnum");
|
|
19
20
|
const BiometricVerificationStatusEnum_1 = require("../../enums/BiometricVerificationStatusEnum");
|
|
@@ -72,6 +73,11 @@ __decorate([
|
|
|
72
73
|
(0, class_transformer_1.Expose)(),
|
|
73
74
|
__metadata("design:type", Object)
|
|
74
75
|
], BiometricVerificationResponse.prototype, "delivery", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, class_transformer_1.Expose)(),
|
|
78
|
+
(0, class_validator_1.IsEnum)(BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum),
|
|
79
|
+
__metadata("design:type", String)
|
|
80
|
+
], BiometricVerificationResponse.prototype, "referenceImageSource", void 0);
|
|
75
81
|
__decorate([
|
|
76
82
|
(0, class_transformer_1.Expose)(),
|
|
77
83
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contra QUÉ foto compara el biométrico.
|
|
3
|
+
*
|
|
4
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
5
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
6
|
+
*/
|
|
7
|
+
export declare enum BiometricReferenceSourceEnum {
|
|
8
|
+
/** La selfie del KYC. El default. */
|
|
9
|
+
KYC_SELFIE = "KYC_SELFIE",
|
|
10
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
11
|
+
ID_DOCUMENT = "ID_DOCUMENT",
|
|
12
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
13
|
+
CALLER_PROVIDED = "CALLER_PROVIDED"
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BiometricReferenceSourceEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Contra QUÉ foto compara el biométrico.
|
|
6
|
+
*
|
|
7
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
8
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
9
|
+
*/
|
|
10
|
+
var BiometricReferenceSourceEnum;
|
|
11
|
+
(function (BiometricReferenceSourceEnum) {
|
|
12
|
+
/** La selfie del KYC. El default. */
|
|
13
|
+
BiometricReferenceSourceEnum["KYC_SELFIE"] = "KYC_SELFIE";
|
|
14
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
15
|
+
BiometricReferenceSourceEnum["ID_DOCUMENT"] = "ID_DOCUMENT";
|
|
16
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
17
|
+
BiometricReferenceSourceEnum["CALLER_PROVIDED"] = "CALLER_PROVIDED";
|
|
18
|
+
})(BiometricReferenceSourceEnum || (exports.BiometricReferenceSourceEnum = BiometricReferenceSourceEnum = {}));
|
|
@@ -4,20 +4,15 @@ import { BiometricResultEnum } from '../enums/BiometricResultEnum';
|
|
|
4
4
|
/**
|
|
5
5
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
6
6
|
*
|
|
7
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
8
|
-
*
|
|
7
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
8
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
9
9
|
*
|
|
10
|
-
* **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
14
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
10
|
+
* 🔴 **No se loguea entero:**
|
|
11
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
12
|
+
* veredicto.
|
|
15
13
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
19
|
-
*
|
|
20
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
14
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
15
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
21
16
|
*
|
|
22
17
|
* `biometrics-business` — Entrega 1.
|
|
23
18
|
*/
|
|
@@ -30,15 +25,12 @@ export declare class BiometricVerificationChangedV1 {
|
|
|
30
25
|
/**
|
|
31
26
|
* 🔴 **Identificador ÚNICO de este evento. La clave de deduplicación.**
|
|
32
27
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
28
|
+
* La entrega es *at-least-once*: Metamap reintenta el webhook completo, así que los duplicados
|
|
29
|
+
* son la norma, no la excepción. Y **el candado temporal por `occurredAt` NO alcanza para
|
|
30
|
+
* esto**: dos entregas del mismo evento traen exactamente el mismo `occurredAt`, así que una
|
|
31
|
+
* regla "descartar si es más viejo" las deja pasar a las dos.
|
|
36
32
|
*
|
|
37
33
|
* El consumer guarda los `eventId` ya aplicados y descarta los repetidos.
|
|
38
|
-
*
|
|
39
|
-
* ⚠️ **No deduplicar por el `MessageId` de SQS**: cambia en cada reintento de entrega, así que
|
|
40
|
-
* no deduplica nada. Es el error clásico y por eso queda escrito acá y no en la cabeza de cada
|
|
41
|
-
* consumidor.
|
|
42
34
|
*/
|
|
43
35
|
eventId: string;
|
|
44
36
|
/**
|
|
@@ -73,7 +65,7 @@ export declare class BiometricVerificationChangedV1 {
|
|
|
73
65
|
* el evento real, y la transición no se aplicaría nunca — sin un solo error.
|
|
74
66
|
*
|
|
75
67
|
* Normalizar a UTC es trabajo del traductor del proveedor (`kyc-metamap-webhook`). Este candado
|
|
76
|
-
* existe para que si algún día deja de hacerlo, el
|
|
68
|
+
* existe para que si algún día deja de hacerlo, el evento se rechace en el boundary en vez de
|
|
77
69
|
* corromper el orden en silencio.
|
|
78
70
|
*/
|
|
79
71
|
occurredAt: string;
|
|
@@ -18,20 +18,15 @@ const BiometricResultEnum_1 = require("../enums/BiometricResultEnum");
|
|
|
18
18
|
/**
|
|
19
19
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
20
20
|
*
|
|
21
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
22
|
-
*
|
|
21
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
22
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
28
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
24
|
+
* 🔴 **No se loguea entero:**
|
|
25
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
26
|
+
* veredicto.
|
|
29
27
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
33
|
-
*
|
|
34
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
28
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
29
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
35
30
|
*
|
|
36
31
|
* `biometrics-business` — Entrega 1.
|
|
37
32
|
*/
|
|
@@ -4,6 +4,7 @@ export * from './enums/BiometricDeliveryModeEnum';
|
|
|
4
4
|
export * from './enums/BiometricVerificationStatusEnum';
|
|
5
5
|
export * from './enums/BiometricResultEnum';
|
|
6
6
|
export * from './enums/BiometricEventTypeEnum';
|
|
7
|
+
export * from './enums/BiometricReferenceSourceEnum';
|
|
7
8
|
export * from './dtos/BiometricSubject';
|
|
8
9
|
export * from './dtos/BiometricDelivery';
|
|
9
10
|
export * from './dtos/requests/CreateBiometricVerificationRequest';
|
package/bin/biometrics/index.js
CHANGED
|
@@ -24,6 +24,7 @@ __exportStar(require("./enums/BiometricDeliveryModeEnum"), exports);
|
|
|
24
24
|
__exportStar(require("./enums/BiometricVerificationStatusEnum"), exports);
|
|
25
25
|
__exportStar(require("./enums/BiometricResultEnum"), exports);
|
|
26
26
|
__exportStar(require("./enums/BiometricEventTypeEnum"), exports);
|
|
27
|
+
__exportStar(require("./enums/BiometricReferenceSourceEnum"), exports);
|
|
27
28
|
// DTOs compartidos
|
|
28
29
|
__exportStar(require("./dtos/BiometricSubject"), exports);
|
|
29
30
|
__exportStar(require("./dtos/BiometricDelivery"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
3
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
4
|
+
*
|
|
5
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
6
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
7
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PeopleIdPhotoResponse {
|
|
10
|
+
directoryId: string;
|
|
11
|
+
/** URL presignado de S3 del frente del documento. */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Nombre del archivo en S3, sin el prefijo `USER/{directoryId}/`. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** Vigencia del presigned URL en segundos. */
|
|
16
|
+
expiresInSeconds: number;
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PeopleIdPhotoResponse = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/**
|
|
16
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
17
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
18
|
+
*
|
|
19
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
20
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
21
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
22
|
+
*/
|
|
23
|
+
class PeopleIdPhotoResponse {
|
|
24
|
+
}
|
|
25
|
+
exports.PeopleIdPhotoResponse = PeopleIdPhotoResponse;
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_transformer_1.Expose)(),
|
|
28
|
+
(0, class_validator_1.IsString)(),
|
|
29
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], PeopleIdPhotoResponse.prototype, "directoryId", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, class_transformer_1.Expose)(),
|
|
34
|
+
(0, class_validator_1.IsString)(),
|
|
35
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], PeopleIdPhotoResponse.prototype, "url", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, class_transformer_1.Expose)(),
|
|
40
|
+
(0, class_validator_1.IsString)(),
|
|
41
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
42
|
+
__metadata("design:type", String)
|
|
43
|
+
], PeopleIdPhotoResponse.prototype, "key", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, class_transformer_1.Expose)(),
|
|
46
|
+
(0, class_validator_1.IsInt)(),
|
|
47
|
+
(0, class_validator_1.IsPositive)(),
|
|
48
|
+
__metadata("design:type", Number)
|
|
49
|
+
], PeopleIdPhotoResponse.prototype, "expiresInSeconds", void 0);
|
package/bin/identity/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './dtos/PeopleSelfVerifiedRequest';
|
|
|
12
12
|
export * from './dtos/AgentDocumentKeyResponse';
|
|
13
13
|
export * from './dtos/DocumentUploadResponse';
|
|
14
14
|
export * from './dtos/PeopleSelfieResponse';
|
|
15
|
+
export * from './dtos/PeopleIdPhotoResponse';
|
|
15
16
|
export * from './enums/IdentificationDocumentStatus';
|
|
16
17
|
export * from './enums/SexDocument';
|
|
17
18
|
export * from './enums/InfoSelfVerifiedStatus';
|
package/bin/identity/index.js
CHANGED
|
@@ -29,6 +29,7 @@ __exportStar(require("./dtos/PeopleSelfVerifiedRequest"), exports);
|
|
|
29
29
|
__exportStar(require("./dtos/AgentDocumentKeyResponse"), exports);
|
|
30
30
|
__exportStar(require("./dtos/DocumentUploadResponse"), exports);
|
|
31
31
|
__exportStar(require("./dtos/PeopleSelfieResponse"), exports);
|
|
32
|
+
__exportStar(require("./dtos/PeopleIdPhotoResponse"), exports);
|
|
32
33
|
//enums
|
|
33
34
|
__exportStar(require("./enums/IdentificationDocumentStatus"), exports);
|
|
34
35
|
__exportStar(require("./enums/SexDocument"), exports);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ReceptionMethod } from "../enums/ReceptionMethod";
|
|
2
|
+
/**
|
|
3
|
+
* DTOs de la administración de payers desde el backoffice (v1: enabled + override de nombre).
|
|
4
|
+
* La lista de payers la dicta el catálogo UniTeller; la config es un overlay por payerCode.
|
|
5
|
+
* Dueño de la tabla RemittancePayerConfig_GT: remittance-business.
|
|
6
|
+
*/
|
|
7
|
+
/** Item de la vista de backoffice (Ops): TODOS los payers del catálogo, también deshabilitados. */
|
|
8
|
+
export declare class RemittancePayerConfigItem {
|
|
9
|
+
payerCode: string;
|
|
10
|
+
countryISO: string;
|
|
11
|
+
/** Nombre efectivo: override de Ops si existe, si no el de UniTeller. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Nombre original de UniTeller (para mostrar/quitar el override). */
|
|
14
|
+
unirName: string;
|
|
15
|
+
receptionMethods: ReceptionMethod[];
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
/** true si ya existe fila de config para ese payer (false = solo del catálogo). */
|
|
18
|
+
configured: boolean;
|
|
19
|
+
/** Logo de UniTeller, solo lectura (identificación visual en la lista). */
|
|
20
|
+
logoUrl?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Response de GET /backoffice/config/payers (config chica, sin paginación). */
|
|
23
|
+
export declare class RemittancePayerConfigListResponse {
|
|
24
|
+
items: RemittancePayerConfigItem[];
|
|
25
|
+
}
|
|
26
|
+
/** Body de PUT /backoffice/config/payers/{payerCode}. Ambos opcionales (merge con lo existente); name=null quita el override. */
|
|
27
|
+
export declare class RemittancePayerConfigUpdateRequest {
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
name?: string | null;
|
|
30
|
+
}
|
|
31
|
+
/** Fila cruda de config (endpoint privado → connector, que la mergea al servir el catálogo). */
|
|
32
|
+
export declare class RemittancePayerConfigEntry {
|
|
33
|
+
payerCode: string;
|
|
34
|
+
countryISO: string;
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
name?: string;
|
|
37
|
+
updatedAt: string;
|
|
38
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RemittancePayerConfigEntry = exports.RemittancePayerConfigUpdateRequest = exports.RemittancePayerConfigListResponse = exports.RemittancePayerConfigItem = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
/**
|
|
15
|
+
* DTOs de la administración de payers desde el backoffice (v1: enabled + override de nombre).
|
|
16
|
+
* La lista de payers la dicta el catálogo UniTeller; la config es un overlay por payerCode.
|
|
17
|
+
* Dueño de la tabla RemittancePayerConfig_GT: remittance-business.
|
|
18
|
+
*/
|
|
19
|
+
/** Item de la vista de backoffice (Ops): TODOS los payers del catálogo, también deshabilitados. */
|
|
20
|
+
class RemittancePayerConfigItem {
|
|
21
|
+
}
|
|
22
|
+
exports.RemittancePayerConfigItem = RemittancePayerConfigItem;
|
|
23
|
+
/** Response de GET /backoffice/config/payers (config chica, sin paginación). */
|
|
24
|
+
class RemittancePayerConfigListResponse {
|
|
25
|
+
}
|
|
26
|
+
exports.RemittancePayerConfigListResponse = RemittancePayerConfigListResponse;
|
|
27
|
+
/** Body de PUT /backoffice/config/payers/{payerCode}. Ambos opcionales (merge con lo existente); name=null quita el override. */
|
|
28
|
+
class RemittancePayerConfigUpdateRequest {
|
|
29
|
+
}
|
|
30
|
+
exports.RemittancePayerConfigUpdateRequest = RemittancePayerConfigUpdateRequest;
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_validator_1.IsOptional)(),
|
|
33
|
+
(0, class_validator_1.IsBoolean)(),
|
|
34
|
+
__metadata("design:type", Boolean)
|
|
35
|
+
], RemittancePayerConfigUpdateRequest.prototype, "enabled", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, class_validator_1.IsOptional)(),
|
|
38
|
+
(0, class_validator_1.IsString)(),
|
|
39
|
+
(0, class_validator_1.Length)(1, 60),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], RemittancePayerConfigUpdateRequest.prototype, "name", void 0);
|
|
42
|
+
/** Fila cruda de config (endpoint privado → connector, que la mergea al servir el catálogo). */
|
|
43
|
+
class RemittancePayerConfigEntry {
|
|
44
|
+
}
|
|
45
|
+
exports.RemittancePayerConfigEntry = RemittancePayerConfigEntry;
|
|
@@ -46,5 +46,6 @@ export * from "./RemittanceRule";
|
|
|
46
46
|
export * from "./RemittancePricingTable";
|
|
47
47
|
export * from "./RemittanceExceptionCatalog";
|
|
48
48
|
export * from "./RemittanceCountryConfig";
|
|
49
|
+
export * from "./RemittancePayerConfig";
|
|
49
50
|
export * from "./RemittanceFavoriteItem";
|
|
50
51
|
export * from "./RemittanceFavoriteListResponse";
|
|
@@ -62,5 +62,6 @@ __exportStar(require("./RemittanceRule"), exports);
|
|
|
62
62
|
__exportStar(require("./RemittancePricingTable"), exports);
|
|
63
63
|
__exportStar(require("./RemittanceExceptionCatalog"), exports);
|
|
64
64
|
__exportStar(require("./RemittanceCountryConfig"), exports);
|
|
65
|
+
__exportStar(require("./RemittancePayerConfig"), exports);
|
|
65
66
|
__exportStar(require("./RemittanceFavoriteItem"), exports);
|
|
66
67
|
__exportStar(require("./RemittanceFavoriteListResponse"), exports);
|
|
@@ -9,6 +9,7 @@ var AuditEntityType;
|
|
|
9
9
|
AuditEntityType["COHORT"] = "COHORT";
|
|
10
10
|
AuditEntityType["COMMITTEE"] = "COMMITTEE";
|
|
11
11
|
AuditEntityType["COUNTRY_CONFIG"] = "COUNTRY_CONFIG";
|
|
12
|
+
AuditEntityType["PAYER_CONFIG"] = "PAYER_CONFIG";
|
|
12
13
|
AuditEntityType["SEGMENT"] = "SEGMENT";
|
|
13
14
|
AuditEntityType["PRICING"] = "PRICING";
|
|
14
15
|
AuditEntityType["PROMOTION"] = "PROMOTION";
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Expose, Type } from 'class-transformer';
|
|
2
2
|
import {
|
|
3
3
|
IsEnum,
|
|
4
|
+
IsIn,
|
|
4
5
|
IsInt,
|
|
5
6
|
IsNotEmpty,
|
|
6
7
|
IsOptional,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
} from 'class-validator';
|
|
13
14
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
14
15
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
16
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
15
17
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
16
18
|
import { BiometricSubject } from '../BiometricSubject';
|
|
17
19
|
|
|
@@ -81,6 +83,24 @@ export class CreateBiometricVerificationRequest {
|
|
|
81
83
|
@Expose() @IsOptional() @IsString() @IsNotEmpty()
|
|
82
84
|
referenceImageUrl?: string;
|
|
83
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Contra QUÉ foto se compara. Default `KYC_SELFIE`, que aplica el servicio: acá viaja ausente
|
|
88
|
+
* cuando no lo mandas, para que se pueda distinguir de haberlo pedido explícitamente.
|
|
89
|
+
*
|
|
90
|
+
* **Sin fallback:** si la fuente pedida no tiene foto, responde `REFERENCE_PHOTO_UNAVAILABLE`;
|
|
91
|
+
* no se busca la otra. Quien pide contra el documento y recibe un match sabe que fue contra el
|
|
92
|
+
* documento.
|
|
93
|
+
*
|
|
94
|
+
* 🔴 `CALLER_PROVIDED` NO es válido acá — solo lo emite la respuesta. Y mandar esto junto con
|
|
95
|
+
* `referenceImageUrl` responde `422 CONFLICTING_REFERENCE_IMAGE`: son contradictorios.
|
|
96
|
+
*/
|
|
97
|
+
@Expose()
|
|
98
|
+
@IsOptional()
|
|
99
|
+
@IsIn([BiometricReferenceSourceEnum.KYC_SELFIE, BiometricReferenceSourceEnum.ID_DOCUMENT])
|
|
100
|
+
referenceImageSource?:
|
|
101
|
+
| BiometricReferenceSourceEnum.KYC_SELFIE
|
|
102
|
+
| BiometricReferenceSourceEnum.ID_DOCUMENT;
|
|
103
|
+
|
|
84
104
|
/**
|
|
85
105
|
* Vigencia de la entrega, en segundos. Default 3600.
|
|
86
106
|
*
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from 'class-validator';
|
|
13
13
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
14
14
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
15
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
15
16
|
import { BiometricResultEnum } from '../../enums/BiometricResultEnum';
|
|
16
17
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
17
18
|
import { BiometricVerificationStatusEnum } from '../../enums/BiometricVerificationStatusEnum';
|
|
@@ -77,6 +78,16 @@ export class BiometricVerificationResponse {
|
|
|
77
78
|
@Expose()
|
|
78
79
|
delivery!: BiometricDelivery;
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Contra qué foto se comparó. **Siempre poblado.**
|
|
83
|
+
*
|
|
84
|
+
* `CALLER_PROVIDED` significa que la foto la mandaste tú en `referenceImageUrl`. Es un valor
|
|
85
|
+
* distinto y no el default, porque decir `KYC_SELFIE` cuando la foto la pusiste tú sería mentir
|
|
86
|
+
* sobre contra qué se comparó — y eso es exactamente lo que este campo existe para evitar.
|
|
87
|
+
*/
|
|
88
|
+
@Expose() @IsEnum(BiometricReferenceSourceEnum)
|
|
89
|
+
referenceImageSource!: BiometricReferenceSourceEnum;
|
|
90
|
+
|
|
80
91
|
/**
|
|
81
92
|
* Similitud reportada por el proveedor, 0–100, cuando la expone. Rekognition da score; Metamap
|
|
82
93
|
* responde pass/fail y esto viene ausente.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contra QUÉ foto compara el biométrico.
|
|
3
|
+
*
|
|
4
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
5
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
6
|
+
*/
|
|
7
|
+
export enum BiometricReferenceSourceEnum {
|
|
8
|
+
/** La selfie del KYC. El default. */
|
|
9
|
+
KYC_SELFIE = 'KYC_SELFIE',
|
|
10
|
+
|
|
11
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
12
|
+
ID_DOCUMENT = 'ID_DOCUMENT',
|
|
13
|
+
|
|
14
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
15
|
+
CALLER_PROVIDED = 'CALLER_PROVIDED',
|
|
16
|
+
}
|
|
@@ -18,20 +18,15 @@ import { BiometricResultEnum } from '../enums/BiometricResultEnum';
|
|
|
18
18
|
/**
|
|
19
19
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
20
20
|
*
|
|
21
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
22
|
-
*
|
|
21
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
22
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
28
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
24
|
+
* 🔴 **No se loguea entero:**
|
|
25
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
26
|
+
* veredicto.
|
|
29
27
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
33
|
-
*
|
|
34
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
28
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
29
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
35
30
|
*
|
|
36
31
|
* `biometrics-business` — Entrega 1.
|
|
37
32
|
*/
|
|
@@ -46,15 +41,12 @@ export class BiometricVerificationChangedV1 {
|
|
|
46
41
|
/**
|
|
47
42
|
* 🔴 **Identificador ÚNICO de este evento. La clave de deduplicación.**
|
|
48
43
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
44
|
+
* La entrega es *at-least-once*: Metamap reintenta el webhook completo, así que los duplicados
|
|
45
|
+
* son la norma, no la excepción. Y **el candado temporal por `occurredAt` NO alcanza para
|
|
46
|
+
* esto**: dos entregas del mismo evento traen exactamente el mismo `occurredAt`, así que una
|
|
47
|
+
* regla "descartar si es más viejo" las deja pasar a las dos.
|
|
52
48
|
*
|
|
53
49
|
* El consumer guarda los `eventId` ya aplicados y descarta los repetidos.
|
|
54
|
-
*
|
|
55
|
-
* ⚠️ **No deduplicar por el `MessageId` de SQS**: cambia en cada reintento de entrega, así que
|
|
56
|
-
* no deduplica nada. Es el error clásico y por eso queda escrito acá y no en la cabeza de cada
|
|
57
|
-
* consumidor.
|
|
58
50
|
*/
|
|
59
51
|
@Expose() @IsString() @IsNotEmpty()
|
|
60
52
|
eventId!: string;
|
|
@@ -103,7 +95,7 @@ export class BiometricVerificationChangedV1 {
|
|
|
103
95
|
* el evento real, y la transición no se aplicaría nunca — sin un solo error.
|
|
104
96
|
*
|
|
105
97
|
* Normalizar a UTC es trabajo del traductor del proveedor (`kyc-metamap-webhook`). Este candado
|
|
106
|
-
* existe para que si algún día deja de hacerlo, el
|
|
98
|
+
* existe para que si algún día deja de hacerlo, el evento se rechace en el boundary en vez de
|
|
107
99
|
* corromper el orden en silencio.
|
|
108
100
|
*/
|
|
109
101
|
@Expose() @IsString() @IsISO8601({ strict: true })
|
package/src/biometrics/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './enums/BiometricDeliveryModeEnum';
|
|
|
9
9
|
export * from './enums/BiometricVerificationStatusEnum';
|
|
10
10
|
export * from './enums/BiometricResultEnum';
|
|
11
11
|
export * from './enums/BiometricEventTypeEnum';
|
|
12
|
+
export * from './enums/BiometricReferenceSourceEnum';
|
|
12
13
|
|
|
13
14
|
// DTOs compartidos
|
|
14
15
|
export * from './dtos/BiometricSubject';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
6
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
7
|
+
*
|
|
8
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
9
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
10
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
11
|
+
*/
|
|
12
|
+
export class PeopleIdPhotoResponse {
|
|
13
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
14
|
+
directoryId!: string;
|
|
15
|
+
|
|
16
|
+
/** URL presignado de S3 del frente del documento. */
|
|
17
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
18
|
+
url!: string;
|
|
19
|
+
|
|
20
|
+
/** Nombre del archivo en S3, sin el prefijo `USER/{directoryId}/`. */
|
|
21
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
22
|
+
key!: string;
|
|
23
|
+
|
|
24
|
+
/** Vigencia del presigned URL en segundos. */
|
|
25
|
+
@Expose() @IsInt() @IsPositive()
|
|
26
|
+
expiresInSeconds!: number;
|
|
27
|
+
}
|
package/src/identity/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './dtos/PeopleSelfVerifiedRequest';
|
|
|
14
14
|
export * from './dtos/AgentDocumentKeyResponse';
|
|
15
15
|
export * from './dtos/DocumentUploadResponse';
|
|
16
16
|
export * from './dtos/PeopleSelfieResponse';
|
|
17
|
+
export * from './dtos/PeopleIdPhotoResponse';
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
//enums
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { IsBoolean, IsOptional, IsString, Length } from "class-validator";
|
|
2
|
+
import { ReceptionMethod } from "../enums/ReceptionMethod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DTOs de la administración de payers desde el backoffice (v1: enabled + override de nombre).
|
|
6
|
+
* La lista de payers la dicta el catálogo UniTeller; la config es un overlay por payerCode.
|
|
7
|
+
* Dueño de la tabla RemittancePayerConfig_GT: remittance-business.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Item de la vista de backoffice (Ops): TODOS los payers del catálogo, también deshabilitados. */
|
|
11
|
+
export class RemittancePayerConfigItem {
|
|
12
|
+
payerCode!: string;
|
|
13
|
+
countryISO!: string;
|
|
14
|
+
/** Nombre efectivo: override de Ops si existe, si no el de UniTeller. */
|
|
15
|
+
name!: string;
|
|
16
|
+
/** Nombre original de UniTeller (para mostrar/quitar el override). */
|
|
17
|
+
unirName!: string;
|
|
18
|
+
receptionMethods!: ReceptionMethod[];
|
|
19
|
+
enabled!: boolean;
|
|
20
|
+
/** true si ya existe fila de config para ese payer (false = solo del catálogo). */
|
|
21
|
+
configured!: boolean;
|
|
22
|
+
/** Logo de UniTeller, solo lectura (identificación visual en la lista). */
|
|
23
|
+
logoUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Response de GET /backoffice/config/payers (config chica, sin paginación). */
|
|
27
|
+
export class RemittancePayerConfigListResponse {
|
|
28
|
+
items!: RemittancePayerConfigItem[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Body de PUT /backoffice/config/payers/{payerCode}. Ambos opcionales (merge con lo existente); name=null quita el override. */
|
|
32
|
+
export class RemittancePayerConfigUpdateRequest {
|
|
33
|
+
@IsOptional()
|
|
34
|
+
@IsBoolean()
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
|
|
37
|
+
@IsOptional()
|
|
38
|
+
@IsString()
|
|
39
|
+
@Length(1, 60)
|
|
40
|
+
name?: string | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Fila cruda de config (endpoint privado → connector, que la mergea al servir el catálogo). */
|
|
44
|
+
export class RemittancePayerConfigEntry {
|
|
45
|
+
payerCode!: string;
|
|
46
|
+
countryISO!: string;
|
|
47
|
+
enabled!: boolean;
|
|
48
|
+
name?: string;
|
|
49
|
+
updatedAt!: string;
|
|
50
|
+
}
|
|
@@ -46,5 +46,6 @@ export * from "./RemittanceRule";
|
|
|
46
46
|
export * from "./RemittancePricingTable";
|
|
47
47
|
export * from "./RemittanceExceptionCatalog";
|
|
48
48
|
export * from "./RemittanceCountryConfig";
|
|
49
|
+
export * from "./RemittancePayerConfig";
|
|
49
50
|
export * from "./RemittanceFavoriteItem";
|
|
50
51
|
export * from "./RemittanceFavoriteListResponse";
|