@fiado/type-kit 3.609.0 → 3.610.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/_test_/unit/biometrics/BiometricEventTypeEnum.test.ts +35 -0
  2. package/_test_/unit/biometrics/BiometricVerificationResponse.test.ts +19 -0
  3. package/_test_/unit/kyc/KycProgressEnums.test.ts +20 -0
  4. package/_test_/unit/kyc/KycProofOfAddressCompletedV1.test.ts +24 -0
  5. package/_test_/unit/kyc/KycStepCompletedV1.test.ts +34 -0
  6. package/_test_/unit/kyc/KycVerificationChangedV1.test.ts +30 -0
  7. package/_test_/unit/kyc/KycVerificationProgressV1.test.ts +144 -0
  8. package/_test_/unit/retailWizard/kycAttemptProgress.test.ts +131 -0
  9. package/bin/biometrics/dtos/responses/BiometricVerificationResponse.d.ts +2 -0
  10. package/bin/biometrics/dtos/responses/BiometricVerificationResponse.js +6 -0
  11. package/bin/biometrics/enums/BiometricEventTypeEnum.d.ts +7 -3
  12. package/bin/biometrics/enums/BiometricEventTypeEnum.js +6 -2
  13. package/bin/kyc/enums/KycFlowEnum.d.ts +5 -0
  14. package/bin/kyc/enums/KycFlowEnum.js +9 -0
  15. package/bin/kyc/enums/KycProgressStageEnum.d.ts +6 -0
  16. package/bin/kyc/enums/KycProgressStageEnum.js +10 -0
  17. package/bin/kyc/events/KycProofOfAddressCompletedV1.d.ts +2 -0
  18. package/bin/kyc/events/KycProofOfAddressCompletedV1.js +7 -0
  19. package/bin/kyc/events/KycStepCompletedV1.d.ts +5 -0
  20. package/bin/kyc/events/KycStepCompletedV1.js +14 -0
  21. package/bin/kyc/events/KycVerificationChangedV1.d.ts +2 -0
  22. package/bin/kyc/events/KycVerificationChangedV1.js +7 -0
  23. package/bin/kyc/events/KycVerificationProgressV1.d.ts +14 -0
  24. package/bin/kyc/events/KycVerificationProgressV1.js +63 -0
  25. package/bin/kyc/index.d.ts +3 -0
  26. package/bin/kyc/index.js +3 -0
  27. package/bin/retailWizard/dtos/KycAttemptProgress.d.ts +14 -0
  28. package/bin/retailWizard/dtos/KycAttemptProgress.js +2 -0
  29. package/bin/retailWizard/dtos/KycStatusProgress.d.ts +7 -0
  30. package/bin/retailWizard/dtos/KycStatusProgress.js +2 -0
  31. package/bin/retailWizard/dtos/responses/KycPrepareResponse.d.ts +4 -0
  32. package/bin/retailWizard/dtos/responses/ProofOfAddressPrepareResponse.d.ts +2 -0
  33. package/bin/retailWizard/enums/KycAttemptStageEnum.d.ts +8 -0
  34. package/bin/retailWizard/enums/KycAttemptStageEnum.js +12 -0
  35. package/bin/retailWizard/index.d.ts +3 -0
  36. package/bin/retailWizard/index.js +3 -0
  37. package/package.json +1 -1
  38. package/src/biometrics/dtos/responses/BiometricVerificationResponse.ts +4 -0
  39. package/src/biometrics/enums/BiometricEventTypeEnum.ts +8 -2
  40. package/src/kyc/enums/KycFlowEnum.ts +5 -0
  41. package/src/kyc/enums/KycProgressStageEnum.ts +6 -0
  42. package/src/kyc/events/KycProofOfAddressCompletedV1.ts +4 -0
  43. package/src/kyc/events/KycStepCompletedV1.ts +9 -0
  44. package/src/kyc/events/KycVerificationChangedV1.ts +4 -0
  45. package/src/kyc/events/KycVerificationProgressV1.ts +33 -0
  46. package/src/kyc/index.ts +3 -0
  47. package/src/retailWizard/dtos/KycAttemptProgress.ts +15 -0
  48. package/src/retailWizard/dtos/KycStatusProgress.ts +8 -0
  49. package/src/retailWizard/dtos/responses/KycPrepareResponse.ts +4 -0
  50. package/src/retailWizard/dtos/responses/ProofOfAddressPrepareResponse.ts +2 -0
  51. package/src/retailWizard/enums/KycAttemptStageEnum.ts +8 -0
  52. package/src/retailWizard/index.ts +3 -0
@@ -0,0 +1,35 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import { BiometricEventTypeEnum, BiometricVerificationChangedV1 } from '../../../src/biometrics/index';
5
+
6
+ const base = {
7
+ eventId: 'evt-1',
8
+ biometricVerificationId: 'bio-1',
9
+ provider: 'METAMAP',
10
+ eventType: 'VERIFICATION_STARTED',
11
+ occurredAt: '2026-10-28T10:05:00.000Z',
12
+ };
13
+
14
+ describe('BiometricEventTypeEnum', () => {
15
+ it('declara los seis eventos que traduce el webhook', () => {
16
+ expect(Object.values(BiometricEventTypeEnum)).toEqual([
17
+ 'VERIFICATION_STARTED',
18
+ 'STEP_COMPLETED',
19
+ 'VERIFICATION_COMPLETED',
20
+ 'VERIFICATION_EXPIRED',
21
+ 'INPUTS_COMPLETED',
22
+ 'UPDATED',
23
+ ]);
24
+ });
25
+
26
+ it.each([BiometricEventTypeEnum.INPUTS_COMPLETED, BiometricEventTypeEnum.UPDATED])(
27
+ 'BiometricVerificationChangedV1 acepta el eventType %s',
28
+ async (eventType) => {
29
+ const dto = plainToInstance(BiometricVerificationChangedV1, { ...base, eventType }, { excludeExtraneousValues: true });
30
+
31
+ expect(await validate(dto as object)).toHaveLength(0);
32
+ expect(dto.eventType).toBe(eventType);
33
+ },
34
+ );
35
+ });
@@ -60,4 +60,23 @@ describe('BiometricVerificationResponse', () => {
60
60
  expect(instancia(base).referenceImageSource).toBe(BiometricReferenceSourceEnum.KYC_SELFIE);
61
61
  });
62
62
  });
63
+
64
+ // Cuándo el cliente terminó de subir su información; lo usa el wizard para INPUTS_COMPLETED.
65
+ describe('inputsCompletedAt', () => {
66
+ it('es opcional', async () => {
67
+ expect(await propiedadesConError(base)).toEqual([]);
68
+ expect(instancia(base).inputsCompletedAt).toBeUndefined();
69
+ });
70
+
71
+ it('acepta ISO-8601 UTC y sobrevive al plainToInstance', async () => {
72
+ const raw = { ...base, inputsCompletedAt: '2026-10-28T10:07:00.000Z' };
73
+
74
+ expect(await propiedadesConError(raw)).toEqual([]);
75
+ expect(instancia(raw).inputsCompletedAt).toBe('2026-10-28T10:07:00.000Z');
76
+ });
77
+
78
+ it('rechaza una fecha que no es ISO-8601', async () => {
79
+ expect(await propiedadesConError({ ...base, inputsCompletedAt: '28/10/2026' })).toContain('inputsCompletedAt');
80
+ });
81
+ });
63
82
  });
@@ -0,0 +1,20 @@
1
+ import 'reflect-metadata';
2
+ import { KycFlowEnum, KycProgressStageEnum } from '../../../src/kyc/index';
3
+ import { KycMetadataStepEnum } from '../../../src/retailWizard/index';
4
+
5
+ describe('KycProgressStageEnum', () => {
6
+ it('declara solo las tres etapas que publica el webhook', () => {
7
+ expect(Object.values(KycProgressStageEnum)).toEqual(['STARTED', 'INPUTS_COMPLETED', 'EXPIRED']);
8
+ });
9
+ });
10
+
11
+ describe('KycFlowEnum', () => {
12
+ it('declara los dos flujos de Metamap que salen del wizard', () => {
13
+ expect(Object.values(KycFlowEnum)).toEqual(['IDENTITY', 'PROOF_OF_ADDRESS']);
14
+ });
15
+
16
+ // El webhook deriva flow de metadata.kycStep: si los valores divergen, el comprobante se rutea como identidad.
17
+ it('PROOF_OF_ADDRESS coincide con el kycStep de la metadata', () => {
18
+ expect(KycFlowEnum.PROOF_OF_ADDRESS).toBe(KycMetadataStepEnum.PROOF_OF_ADDRESS);
19
+ });
20
+ });
@@ -192,4 +192,28 @@ describe('KycProofOfAddressCompletedV1', () => {
192
192
  ].sort(),
193
193
  );
194
194
  });
195
+
196
+ // ── Intento (estados MetaMap/QR) ──────────────────────────────────────────
197
+
198
+ describe('attemptId', () => {
199
+ it('acepta y expone attemptId', async () => {
200
+ const dto = instancia({ ...base, attemptId: 'att-1' });
201
+
202
+ expect(await validate(dto as object)).toHaveLength(0);
203
+ expect(dto.attemptId).toBe('att-1');
204
+ });
205
+
206
+ it('valida sin attemptId (compatibilidad hacia atrás)', async () => {
207
+ const dto = instancia(base);
208
+
209
+ expect(await validate(dto as object)).toHaveLength(0);
210
+ expect(dto.attemptId).toBeUndefined();
211
+ });
212
+
213
+ it('rechaza attemptId vacío', async () => {
214
+ const errors = await validate(instancia({ ...base, attemptId: '' }) as object);
215
+
216
+ expect(errors.map((e) => e.property)).toContain('attemptId');
217
+ });
218
+ });
195
219
  });
@@ -2,6 +2,7 @@ import 'reflect-metadata';
2
2
  import { plainToInstance } from 'class-transformer';
3
3
  import { validate } from 'class-validator';
4
4
  import {
5
+ KycFlowEnum,
5
6
  KycStepCompletedV1,
6
7
  KycVerificationChangedV1,
7
8
  KycSubCheckNameEnum,
@@ -236,4 +237,37 @@ describe('KycStepCompletedV1', () => {
236
237
  );
237
238
  expect(Object.values(KycWatchlistStatusEnum)).toEqual(['CLEAR', 'HIT']);
238
239
  });
240
+
241
+ // ── Intento y flujo (estados MetaMap/QR) ──────────────────────────────────
242
+
243
+ describe('attemptId y flow', () => {
244
+ it('acepta y expone attemptId y flow', async () => {
245
+ const dto = instancia({ ...base, attemptId: 'att-1', flow: 'IDENTITY' });
246
+
247
+ expect(await validate(dto as object)).toHaveLength(0);
248
+ expect(dto.attemptId).toBe('att-1');
249
+ expect(dto.flow).toBe(KycFlowEnum.IDENTITY);
250
+ });
251
+
252
+ // Mensajes en vuelo y sesiones previas al despliegue no los traen.
253
+ it('valida sin attemptId ni flow', async () => {
254
+ const dto = instancia(base);
255
+
256
+ expect(await validate(dto as object)).toHaveLength(0);
257
+ expect(dto.attemptId).toBeUndefined();
258
+ expect(dto.flow).toBeUndefined();
259
+ });
260
+
261
+ it('rechaza attemptId vacío', async () => {
262
+ const errors = await validate(instancia({ ...base, attemptId: '' }) as object);
263
+
264
+ expect(errors.map((e) => e.property)).toContain('attemptId');
265
+ });
266
+
267
+ it.each(['FACEMATCH', 'identity'])('rechaza el flow %s', async (flow) => {
268
+ const errors = await validate(instancia({ ...base, flow }) as object);
269
+
270
+ expect(errors.map((e) => e.property)).toContain('flow');
271
+ });
272
+ });
239
273
  });
@@ -152,4 +152,34 @@ describe('KycVerificationChangedV1', () => {
152
152
 
153
153
  expect(errors.map((e) => e.property)).toContain('updateDate');
154
154
  });
155
+
156
+ // Estados MetaMap/QR: el cierre trae el intento para que el wizard descarte los ajenos.
157
+ describe('attemptId', () => {
158
+ const closing = {
159
+ verificationId: 'ver-1', directoryId: 'dir-1', peopleId: 'ppl-1',
160
+ verificationStatus: 'COMPLETED', verificationResult: 'VERIFIED',
161
+ updateDate: '2026-10-28T10:05:00.000Z',
162
+ };
163
+
164
+ it('acepta y expone attemptId', async () => {
165
+ const dto = plainToInstance(KycVerificationChangedV1, { ...closing, attemptId: 'att-1' }, { excludeExtraneousValues: true });
166
+
167
+ expect(await validate(dto as object)).toHaveLength(0);
168
+ expect(dto.attemptId).toBe('att-1');
169
+ });
170
+
171
+ it('valida sin attemptId (compatibilidad hacia atrás)', async () => {
172
+ const dto = plainToInstance(KycVerificationChangedV1, closing, { excludeExtraneousValues: true });
173
+
174
+ expect(await validate(dto as object)).toHaveLength(0);
175
+ expect(dto.attemptId).toBeUndefined();
176
+ });
177
+
178
+ it('rechaza attemptId vacío', async () => {
179
+ const dto = plainToInstance(KycVerificationChangedV1, { ...closing, attemptId: '' }, { excludeExtraneousValues: true });
180
+ const errors = await validate(dto as object);
181
+
182
+ expect(errors.map((e) => e.property)).toContain('attemptId');
183
+ });
184
+ });
155
185
  });
@@ -0,0 +1,144 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import {
5
+ KycFlowEnum,
6
+ KycProgressStageEnum,
7
+ KycProofOfAddressCompletedV1,
8
+ KycStepCompletedV1,
9
+ KycVerificationChangedV1,
10
+ KycVerificationProgressV1,
11
+ } from '../../../src/kyc/index';
12
+
13
+ /** Base válida; cada caso pisa solo el campo que prueba. */
14
+ const base = {
15
+ eventType: 'KycVerificationProgressV1',
16
+ stage: 'STARTED',
17
+ flow: 'IDENTITY',
18
+ verificationId: 'ver-1',
19
+ directoryId: 'dir-1',
20
+ attemptId: 'att-1',
21
+ occurredAt: '2026-10-28T10:05:00.000Z',
22
+ };
23
+
24
+ const toDto = (raw: Record<string, unknown>): KycVerificationProgressV1 =>
25
+ plainToInstance(KycVerificationProgressV1, raw, { excludeExtraneousValues: true });
26
+
27
+ const errorProps = async (raw: Record<string, unknown>): Promise<string[]> =>
28
+ (await validate(toDto(raw) as object)).map((e) => e.property);
29
+
30
+ describe('KycVerificationProgressV1', () => {
31
+ it('valida el shape que publica el webhook', async () => {
32
+ const dto = toDto(base);
33
+
34
+ expect(await errorProps(base)).toEqual([]);
35
+ expect(dto.stage).toBe(KycProgressStageEnum.STARTED);
36
+ expect(dto.flow).toBe(KycFlowEnum.IDENTITY);
37
+ expect(dto.attemptId).toBe('att-1');
38
+ });
39
+
40
+ it.each(Object.values(KycProgressStageEnum))('acepta la etapa %s', async (stage) => {
41
+ expect(await errorProps({ ...base, stage })).toEqual([]);
42
+ });
43
+
44
+ it.each(Object.values(KycFlowEnum))('acepta el flujo %s', async (flow) => {
45
+ expect(await errorProps({ ...base, flow })).toEqual([]);
46
+ });
47
+
48
+ // Sesiones creadas antes del despliegue: la metadata no trae attemptId.
49
+ it('valida sin attemptId', async () => {
50
+ const { attemptId: _omitted, ...withoutAttempt } = base;
51
+
52
+ expect(await errorProps(withoutAttempt)).toEqual([]);
53
+ expect(toDto(withoutAttempt).attemptId).toBeUndefined();
54
+ });
55
+
56
+ it('rechaza attemptId vacío', async () => {
57
+ expect(await errorProps({ ...base, attemptId: '' })).toContain('attemptId');
58
+ });
59
+
60
+ describe('eventType', () => {
61
+ it('rechaza el evento sin eventType', async () => {
62
+ const { eventType: _omitted, ...withoutType } = base;
63
+
64
+ expect(await errorProps(withoutType)).toContain('eventType');
65
+ });
66
+
67
+ it('rechaza el eventType de otro evento', async () => {
68
+ expect(await errorProps({ ...base, eventType: 'KycStepCompletedV1' })).toContain('eventType');
69
+ });
70
+ });
71
+
72
+ // AWAITING_START y RESULT son etapas del wizard, nunca llegan por evento.
73
+ it.each(['AWAITING_START', 'RESULT', 'COMPLETED'])('rechaza la etapa %s', async (stage) => {
74
+ expect(await errorProps({ ...base, stage })).toContain('stage');
75
+ });
76
+
77
+ // FACEMATCH no pasa por este evento: su avance sale del GET de biometrics.
78
+ it('rechaza el flujo FACEMATCH', async () => {
79
+ expect(await errorProps({ ...base, flow: 'FACEMATCH' })).toContain('flow');
80
+ });
81
+
82
+ it.each(['verificationId', 'directoryId'])('rechaza %s vacío', async (field) => {
83
+ expect(await errorProps({ ...base, [field]: '' })).toContain(field);
84
+ });
85
+
86
+ it.each(['stage', 'flow', 'verificationId', 'directoryId', 'occurredAt'])('rechaza el evento sin %s', async (field) => {
87
+ const raw: Record<string, unknown> = { ...base };
88
+ delete raw[field];
89
+
90
+ expect(await errorProps(raw)).toContain(field);
91
+ });
92
+
93
+ describe('occurredAt', () => {
94
+ it.each([
95
+ ['offset positivo en vez de Z', '2026-10-28T15:05:00+05:00'],
96
+ ['solo fecha, sin hora', '2026-10-28'],
97
+ ['sin zona horaria', '2026-10-28T10:05:00'],
98
+ ['formato local', '28/10/2026'],
99
+ ])('rechaza occurredAt %s', async (_label, value) => {
100
+ expect(await errorProps({ ...base, occurredAt: value })).toContain('occurredAt');
101
+ });
102
+
103
+ it.each([
104
+ ['con milisegundos', '2026-10-28T10:05:00.000Z'],
105
+ ['sin milisegundos', '2026-10-28T10:05:00Z'],
106
+ ])('acepta occurredAt en UTC %s', async (_label, value) => {
107
+ expect(await errorProps({ ...base, occurredAt: value })).toEqual([]);
108
+ });
109
+ });
110
+
111
+ // Comparte RetailKycInboundQueue con otros tres eventos: ninguno se puede hacer pasar por otro.
112
+ describe('convivencia en RetailKycInboundQueue', () => {
113
+ it('un avance NO valida como estación', async () => {
114
+ const errors = await validate(plainToInstance(KycStepCompletedV1, base, { excludeExtraneousValues: true }) as object);
115
+
116
+ expect(errors.map((e) => e.property)).toEqual(expect.arrayContaining(['eventType', 'step', 'status']));
117
+ });
118
+
119
+ it('un avance NO valida como cierre', async () => {
120
+ const errors = await validate(plainToInstance(KycVerificationChangedV1, base, { excludeExtraneousValues: true }) as object);
121
+
122
+ expect(errors.map((e) => e.property)).toEqual(
123
+ expect.arrayContaining(['peopleId', 'verificationStatus', 'verificationResult', 'updateDate']),
124
+ );
125
+ });
126
+
127
+ it('un avance NO valida como comprobante', async () => {
128
+ const errors = await validate(
129
+ plainToInstance(KycProofOfAddressCompletedV1, base, { excludeExtraneousValues: true }) as object,
130
+ );
131
+
132
+ expect(errors.map((e) => e.property)).toEqual(expect.arrayContaining(['eventType', 'status', 'addressPersisted']));
133
+ });
134
+
135
+ it('una estación NO valida como avance', async () => {
136
+ const station = {
137
+ eventType: 'KycStepCompletedV1', verificationId: 'ver-1', directoryId: 'dir-1',
138
+ step: 'facematch', status: 'PASS', occurredAt: '2026-10-28T10:05:00.000Z',
139
+ };
140
+
141
+ expect(await errorProps(station)).toEqual(expect.arrayContaining(['eventType', 'stage', 'flow']));
142
+ });
143
+ });
144
+ });
@@ -0,0 +1,131 @@
1
+ import 'reflect-metadata';
2
+ import { KycProgressStageEnum } from '../../../src/kyc/index';
3
+ import { KycModalityEnum } from '../../../src/retailCustomer/enums/KycModalityEnum';
4
+ import {
5
+ KycAttemptStageEnum,
6
+ KycMetadataSourceEnum,
7
+ KycMetadataStepEnum,
8
+ type KycAttemptProgress,
9
+ type KycPrepareResponse,
10
+ type KycSdkMetadata,
11
+ type KycStatusProgress,
12
+ type ProofOfAddressPrepareResponse,
13
+ } from '../../../src/retailWizard/index';
14
+
15
+ const qrAttempt: KycAttemptProgress = {
16
+ attemptId: 'att-1',
17
+ modality: KycModalityEnum.CUSTOMER_LINK,
18
+ link: 'https://sk.fiado.test/abc',
19
+ stage: KycAttemptStageEnum.STARTED,
20
+ stageAt: '2026-10-28T10:05:00.000Z',
21
+ attemptStartedAt: '2026-10-28T10:00:00.000Z',
22
+ };
23
+
24
+ const tabletAttempt: KycAttemptProgress = {
25
+ attemptId: 'att-2',
26
+ modality: KycModalityEnum.STORE_DEVICE,
27
+ stage: KycAttemptStageEnum.AWAITING_START,
28
+ stageAt: '2026-10-28T10:00:00.000Z',
29
+ attemptStartedAt: '2026-10-28T10:00:00.000Z',
30
+ };
31
+
32
+ describe('KycAttemptStageEnum', () => {
33
+ it('declara las cinco etapas en orden de rango', () => {
34
+ expect(Object.values(KycAttemptStageEnum)).toEqual([
35
+ 'AWAITING_START', 'STARTED', 'INPUTS_COMPLETED', 'EXPIRED', 'RESULT',
36
+ ]);
37
+ });
38
+
39
+ // El wizard copia la etapa del evento al intento por valor.
40
+ it.each(Object.values(KycProgressStageEnum))('incluye la etapa de evento %s', (stage) => {
41
+ expect(Object.values(KycAttemptStageEnum)).toContain(stage);
42
+ });
43
+ });
44
+
45
+ describe('KycAttemptProgress', () => {
46
+ it('lleva link en QR y lo omite en tablet', () => {
47
+ expect(qrAttempt.link).toBe('https://sk.fiado.test/abc');
48
+ expect(tabletAttempt.link).toBeUndefined();
49
+ });
50
+
51
+ it('solo admite las modalidades de prepare', () => {
52
+ const manual: KycAttemptProgress = {
53
+ ...tabletAttempt,
54
+ // @ts-expect-error MANUAL no es una modalidad de prepare
55
+ modality: KycModalityEnum.MANUAL,
56
+ };
57
+
58
+ expect(manual.modality).toBe('MANUAL');
59
+ });
60
+
61
+ // El tope de 25 min del front se mide contra la fecha del prepare, no contra el montaje.
62
+ it('exige attemptStartedAt', () => {
63
+ const { attemptStartedAt: _omitted, ...rest } = qrAttempt;
64
+ // @ts-expect-error attemptStartedAt es obligatorio
65
+ const withoutStart: KycAttemptProgress = rest;
66
+
67
+ expect(qrAttempt.attemptStartedAt).toBe('2026-10-28T10:00:00.000Z');
68
+ expect(withoutStart.attemptStartedAt).toBeUndefined();
69
+ });
70
+ });
71
+
72
+ describe('KycStatusProgress', () => {
73
+ it('trae un intento o null por cada flujo', () => {
74
+ const progress: KycStatusProgress = { identity: qrAttempt, facematch: null, proofOfAddress: tabletAttempt };
75
+
76
+ expect(Object.keys(progress).sort()).toEqual(['facematch', 'identity', 'proofOfAddress']);
77
+ expect(progress.facematch).toBeNull();
78
+ });
79
+ });
80
+
81
+ describe('KycSdkMetadata', () => {
82
+ it('acepta attemptId junto a source y kycStep', () => {
83
+ const metadata: KycSdkMetadata = {
84
+ directoryId: 'dir-1',
85
+ typeOfDirectoryId: 'PHONE',
86
+ peopleId: 'ppl-1',
87
+ countryId: 'MX',
88
+ phoneNumber: '5512345678',
89
+ source: KycMetadataSourceEnum.SUREKEEP_WIZARD,
90
+ kycStep: KycMetadataStepEnum.PROOF_OF_ADDRESS,
91
+ attemptId: 'att-1',
92
+ };
93
+
94
+ expect(metadata.attemptId).toBe('att-1');
95
+ });
96
+ });
97
+
98
+ // El front liga el SDK y los callbacks al attemptId que devuelve el prepare.
99
+ describe('attemptId en las respuestas de prepare', () => {
100
+ // Sin intento creado (alreadyVerified o bypass de dev) no hay attemptId.
101
+ it('KycPrepareResponse lleva attemptId al preparar y lo omite sin intento', () => {
102
+ const prepared: KycPrepareResponse = {
103
+ modality: KycModalityEnum.CUSTOMER_LINK,
104
+ shortUrl: 'https://sk.fiado.test/abc',
105
+ attemptId: 'att-1',
106
+ };
107
+ const alreadyVerified: KycPrepareResponse = {
108
+ modality: KycModalityEnum.CUSTOMER_LINK,
109
+ alreadyVerified: true,
110
+ };
111
+
112
+ expect(prepared.attemptId).toBe('att-1');
113
+ expect(alreadyVerified.attemptId).toBeUndefined();
114
+ });
115
+
116
+ // Con domicilio ya registrado no se crea intento, por eso no hay attemptId.
117
+ it('ProofOfAddressPrepareResponse lleva attemptId al preparar y lo omite con alreadyHasAddress', () => {
118
+ const prepared: ProofOfAddressPrepareResponse = {
119
+ modality: KycModalityEnum.STORE_DEVICE,
120
+ clientId: 'client-1',
121
+ attemptId: 'att-3',
122
+ };
123
+ const alreadyHasAddress: ProofOfAddressPrepareResponse = {
124
+ modality: KycModalityEnum.STORE_DEVICE,
125
+ alreadyHasAddress: true,
126
+ };
127
+
128
+ expect(prepared.attemptId).toBe('att-3');
129
+ expect(alreadyHasAddress.attemptId).toBeUndefined();
130
+ });
131
+ });
@@ -91,6 +91,8 @@ export declare class BiometricVerificationResponse {
91
91
  updatedAt: string;
92
92
  /** Cuándo vence la entrega. Es lo que el `GET` compara para persistir `EXPIRED` (DEC-015). */
93
93
  expiresAt: string;
94
+ /** Cuándo el usuario terminó de subir su información. ISO-8601 UTC con `Z`; ausente si aún no. */
95
+ inputsCompletedAt?: string;
94
96
  /** Cuándo alcanzó un estado terminal. Ausente mientras siga viva. */
95
97
  completedAt?: string;
96
98
  }
@@ -129,6 +129,12 @@ __decorate([
129
129
  (0, class_validator_1.IsISO8601)({ strict: true }),
130
130
  __metadata("design:type", String)
131
131
  ], BiometricVerificationResponse.prototype, "expiresAt", void 0);
132
+ __decorate([
133
+ (0, class_transformer_1.Expose)(),
134
+ (0, class_validator_1.IsOptional)(),
135
+ (0, class_validator_1.IsISO8601)({ strict: true }),
136
+ __metadata("design:type", String)
137
+ ], BiometricVerificationResponse.prototype, "inputsCompletedAt", void 0);
132
138
  __decorate([
133
139
  (0, class_transformer_1.Expose)(),
134
140
  (0, class_validator_1.IsOptional)(),
@@ -3,8 +3,8 @@
3
3
  * lo que el consumer usa para decidir la transición de estado.
4
4
  *
5
5
  * Es el vocabulario NUESTRO, no el de Metamap: `kyc-metamap-webhook` traduce sus `eventName` a
6
- * estos cuatro antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
7
- * el día que entre otro proveedor traduce a los mismos cuatro.
6
+ * estos valores antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
7
+ * el día que entre otro proveedor traduce a los mismos valores.
8
8
  *
9
9
  * `biometrics-business` — Entrega 1.
10
10
  */
@@ -24,5 +24,9 @@ export declare enum BiometricEventTypeEnum {
24
24
  * ⚠️ **No se depende de este evento para expirar.** El `GET` persiste `EXPIRED` comparando
25
25
  * contra `expiresAt` (DEC-015), así que una verificación vence aunque este evento nunca llegue.
26
26
  */
27
- VERIFICATION_EXPIRED = "VERIFICATION_EXPIRED"
27
+ VERIFICATION_EXPIRED = "VERIFICATION_EXPIRED",
28
+ /** El usuario terminó de subir su información. Sigue en `IN_PROGRESS` y graba `inputsCompletedAt`. */
29
+ INPUTS_COMPLETED = "INPUTS_COMPLETED",
30
+ /** El proveedor cambió el veredicto (revisión manual). Se trata igual que `VERIFICATION_COMPLETED`. */
31
+ UPDATED = "UPDATED"
28
32
  }
@@ -6,8 +6,8 @@ exports.BiometricEventTypeEnum = void 0;
6
6
  * lo que el consumer usa para decidir la transición de estado.
7
7
  *
8
8
  * Es el vocabulario NUESTRO, no el de Metamap: `kyc-metamap-webhook` traduce sus `eventName` a
9
- * estos cuatro antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
10
- * el día que entre otro proveedor traduce a los mismos cuatro.
9
+ * estos valores antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
10
+ * el día que entre otro proveedor traduce a los mismos valores.
11
11
  *
12
12
  * `biometrics-business` — Entrega 1.
13
13
  */
@@ -29,4 +29,8 @@ var BiometricEventTypeEnum;
29
29
  * contra `expiresAt` (DEC-015), así que una verificación vence aunque este evento nunca llegue.
30
30
  */
31
31
  BiometricEventTypeEnum["VERIFICATION_EXPIRED"] = "VERIFICATION_EXPIRED";
32
+ /** El usuario terminó de subir su información. Sigue en `IN_PROGRESS` y graba `inputsCompletedAt`. */
33
+ BiometricEventTypeEnum["INPUTS_COMPLETED"] = "INPUTS_COMPLETED";
34
+ /** El proveedor cambió el veredicto (revisión manual). Se trata igual que `VERIFICATION_COMPLETED`. */
35
+ BiometricEventTypeEnum["UPDATED"] = "UPDATED";
32
36
  })(BiometricEventTypeEnum || (exports.BiometricEventTypeEnum = BiometricEventTypeEnum = {}));
@@ -0,0 +1,5 @@
1
+ /** Flujo de Metamap al que pertenece un evento; el webhook lo deriva de `metadata.kycStep`. */
2
+ export declare enum KycFlowEnum {
3
+ IDENTITY = "IDENTITY",
4
+ PROOF_OF_ADDRESS = "PROOF_OF_ADDRESS"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KycFlowEnum = void 0;
4
+ /** Flujo de Metamap al que pertenece un evento; el webhook lo deriva de `metadata.kycStep`. */
5
+ var KycFlowEnum;
6
+ (function (KycFlowEnum) {
7
+ KycFlowEnum["IDENTITY"] = "IDENTITY";
8
+ KycFlowEnum["PROOF_OF_ADDRESS"] = "PROOF_OF_ADDRESS";
9
+ })(KycFlowEnum || (exports.KycFlowEnum = KycFlowEnum = {}));
@@ -0,0 +1,6 @@
1
+ /** Etapa de avance de una verificación de Metamap, tal como la publica `kyc-metamap-webhook`. */
2
+ export declare enum KycProgressStageEnum {
3
+ STARTED = "STARTED",
4
+ INPUTS_COMPLETED = "INPUTS_COMPLETED",
5
+ EXPIRED = "EXPIRED"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KycProgressStageEnum = void 0;
4
+ /** Etapa de avance de una verificación de Metamap, tal como la publica `kyc-metamap-webhook`. */
5
+ var KycProgressStageEnum;
6
+ (function (KycProgressStageEnum) {
7
+ KycProgressStageEnum["STARTED"] = "STARTED";
8
+ KycProgressStageEnum["INPUTS_COMPLETED"] = "INPUTS_COMPLETED";
9
+ KycProgressStageEnum["EXPIRED"] = "EXPIRED";
10
+ })(KycProgressStageEnum || (exports.KycProgressStageEnum = KycProgressStageEnum = {}));
@@ -46,4 +46,6 @@ export declare class KycProofOfAddressCompletedV1 {
46
46
  * truena. Normalizar a UTC es trabajo del webhook; este candado lo manda al DLQ si deja de hacerlo.
47
47
  */
48
48
  occurredAt: string;
49
+ /** Intento del wizard que originó el comprobante; el consumidor descarta los que no son el vigente. */
50
+ attemptId?: string;
49
51
  }
@@ -73,3 +73,10 @@ __decorate([
73
73
  }),
74
74
  __metadata("design:type", String)
75
75
  ], KycProofOfAddressCompletedV1.prototype, "occurredAt", void 0);
76
+ __decorate([
77
+ (0, class_transformer_1.Expose)(),
78
+ (0, class_validator_1.IsOptional)(),
79
+ (0, class_validator_1.IsString)(),
80
+ (0, class_validator_1.IsNotEmpty)(),
81
+ __metadata("design:type", String)
82
+ ], KycProofOfAddressCompletedV1.prototype, "attemptId", void 0);
@@ -1,3 +1,4 @@
1
+ import { KycFlowEnum } from '../enums/KycFlowEnum';
1
2
  import { KycSubCheckNameEnum } from '../enums/KycSubCheckNameEnum';
2
3
  import { KycSubCheckStatusEnum } from '../enums/KycSubCheckStatusEnum';
3
4
  import { KycWatchlistStatusEnum } from '../enums/KycWatchlistStatusEnum';
@@ -82,4 +83,8 @@ export declare class KycStepCompletedV1 {
82
83
  occurredAt: string;
83
84
  /** El flujo de Metamap que corrió. Solo para diagnóstico — nadie ramifica por él. */
84
85
  metamapFlowId?: string;
86
+ /** Intento del wizard que originó la verificación; el consumidor descarta los que no son el vigente. */
87
+ attemptId?: string;
88
+ /** Flujo al que pertenece la estación, derivado de `metadata.kycStep`. */
89
+ flow?: KycFlowEnum;
85
90
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.KycStepCompletedV1 = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const KycFlowEnum_1 = require("../enums/KycFlowEnum");
15
16
  const KycSubCheckNameEnum_1 = require("../enums/KycSubCheckNameEnum");
16
17
  const IsKycStepStatusByStep_1 = require("../validators/IsKycStepStatusByStep");
17
18
  /**
@@ -91,3 +92,16 @@ __decorate([
91
92
  (0, class_validator_1.IsString)(),
92
93
  __metadata("design:type", String)
93
94
  ], KycStepCompletedV1.prototype, "metamapFlowId", void 0);
95
+ __decorate([
96
+ (0, class_transformer_1.Expose)(),
97
+ (0, class_validator_1.IsOptional)(),
98
+ (0, class_validator_1.IsString)(),
99
+ (0, class_validator_1.IsNotEmpty)(),
100
+ __metadata("design:type", String)
101
+ ], KycStepCompletedV1.prototype, "attemptId", void 0);
102
+ __decorate([
103
+ (0, class_transformer_1.Expose)(),
104
+ (0, class_validator_1.IsOptional)(),
105
+ (0, class_validator_1.IsEnum)(KycFlowEnum_1.KycFlowEnum),
106
+ __metadata("design:type", String)
107
+ ], KycStepCompletedV1.prototype, "flow", void 0);
@@ -71,4 +71,6 @@ export declare class KycVerificationChangedV1 {
71
71
  * degradación segura (el consumidor lo pide y lo guarda él).
72
72
  */
73
73
  addressPushedToFiado?: boolean;
74
+ /** Intento del wizard que originó la verificación; el consumidor descarta los que no son el vigente. */
75
+ attemptId?: string;
74
76
  }
@@ -104,3 +104,10 @@ __decorate([
104
104
  (0, class_validator_1.IsBoolean)(),
105
105
  __metadata("design:type", Boolean)
106
106
  ], KycVerificationChangedV1.prototype, "addressPushedToFiado", void 0);
107
+ __decorate([
108
+ (0, class_transformer_1.Expose)(),
109
+ (0, class_validator_1.IsOptional)(),
110
+ (0, class_validator_1.IsString)(),
111
+ (0, class_validator_1.IsNotEmpty)(),
112
+ __metadata("design:type", String)
113
+ ], KycVerificationChangedV1.prototype, "attemptId", void 0);
@@ -0,0 +1,14 @@
1
+ import { KycFlowEnum } from '../enums/KycFlowEnum';
2
+ import { KycProgressStageEnum } from '../enums/KycProgressStageEnum';
3
+ /** Avance de una verificación de Metamap (started, inputs_completed, expired) que publica `kyc-metamap-webhook`. */
4
+ export declare class KycVerificationProgressV1 {
5
+ eventType: 'KycVerificationProgressV1';
6
+ stage: KycProgressStageEnum;
7
+ flow: KycFlowEnum;
8
+ verificationId: string;
9
+ directoryId: string;
10
+ /** Intento del wizard que originó la verificación; ausente en sesiones previas al despliegue. */
11
+ attemptId?: string;
12
+ /** ISO-8601 en UTC con `Z`, igual que los demás eventos de la cola. */
13
+ occurredAt: string;
14
+ }
@@ -0,0 +1,63 @@
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.KycVerificationProgressV1 = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const KycFlowEnum_1 = require("../enums/KycFlowEnum");
16
+ const KycProgressStageEnum_1 = require("../enums/KycProgressStageEnum");
17
+ /** Avance de una verificación de Metamap (started, inputs_completed, expired) que publica `kyc-metamap-webhook`. */
18
+ class KycVerificationProgressV1 {
19
+ }
20
+ exports.KycVerificationProgressV1 = KycVerificationProgressV1;
21
+ __decorate([
22
+ (0, class_transformer_1.Expose)(),
23
+ (0, class_validator_1.IsIn)(['KycVerificationProgressV1']),
24
+ __metadata("design:type", String)
25
+ ], KycVerificationProgressV1.prototype, "eventType", void 0);
26
+ __decorate([
27
+ (0, class_transformer_1.Expose)(),
28
+ (0, class_validator_1.IsEnum)(KycProgressStageEnum_1.KycProgressStageEnum),
29
+ __metadata("design:type", String)
30
+ ], KycVerificationProgressV1.prototype, "stage", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsEnum)(KycFlowEnum_1.KycFlowEnum),
34
+ __metadata("design:type", String)
35
+ ], KycVerificationProgressV1.prototype, "flow", void 0);
36
+ __decorate([
37
+ (0, class_transformer_1.Expose)(),
38
+ (0, class_validator_1.IsString)(),
39
+ (0, class_validator_1.IsNotEmpty)(),
40
+ __metadata("design:type", String)
41
+ ], KycVerificationProgressV1.prototype, "verificationId", void 0);
42
+ __decorate([
43
+ (0, class_transformer_1.Expose)(),
44
+ (0, class_validator_1.IsString)(),
45
+ (0, class_validator_1.IsNotEmpty)(),
46
+ __metadata("design:type", String)
47
+ ], KycVerificationProgressV1.prototype, "directoryId", void 0);
48
+ __decorate([
49
+ (0, class_transformer_1.Expose)(),
50
+ (0, class_validator_1.IsOptional)(),
51
+ (0, class_validator_1.IsString)(),
52
+ (0, class_validator_1.IsNotEmpty)(),
53
+ __metadata("design:type", String)
54
+ ], KycVerificationProgressV1.prototype, "attemptId", void 0);
55
+ __decorate([
56
+ (0, class_transformer_1.Expose)(),
57
+ (0, class_validator_1.IsString)(),
58
+ (0, class_validator_1.IsISO8601)({ strict: true }),
59
+ (0, class_validator_1.Matches)(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/, {
60
+ message: 'occurredAt debe ser ISO-8601 en UTC con Z (ej. 2026-10-28T10:05:00.000Z)',
61
+ }),
62
+ __metadata("design:type", String)
63
+ ], KycVerificationProgressV1.prototype, "occurredAt", void 0);
@@ -3,6 +3,8 @@ export * from './enums/KycSubCheckStatusEnum';
3
3
  export * from './enums/KycWatchlistStatusEnum';
4
4
  export * from './enums/KycSubCheckNameEnum';
5
5
  export * from './enums/ProofAddressStatusEnum';
6
+ export * from './enums/KycProgressStageEnum';
7
+ export * from './enums/KycFlowEnum';
6
8
  export * from './dtos/KycSubChecks';
7
9
  export * from './validators/IsKycStepStatusByStep';
8
10
  export * from './helpers/applyKycStep';
@@ -12,3 +14,4 @@ export * from './dtos/responses/KycByDirectoryResponse';
12
14
  export * from './events/KycVerificationChangedV1';
13
15
  export * from './events/KycStepCompletedV1';
14
16
  export * from './events/KycProofOfAddressCompletedV1';
17
+ export * from './events/KycVerificationProgressV1';
package/bin/kyc/index.js CHANGED
@@ -21,6 +21,8 @@ __exportStar(require("./enums/KycSubCheckStatusEnum"), exports);
21
21
  __exportStar(require("./enums/KycWatchlistStatusEnum"), exports);
22
22
  __exportStar(require("./enums/KycSubCheckNameEnum"), exports);
23
23
  __exportStar(require("./enums/ProofAddressStatusEnum"), exports);
24
+ __exportStar(require("./enums/KycProgressStageEnum"), exports);
25
+ __exportStar(require("./enums/KycFlowEnum"), exports);
24
26
  // Sub-pasos descompuestos (SureKeep F2)
25
27
  __exportStar(require("./dtos/KycSubChecks"), exports);
26
28
  // Validators
@@ -36,3 +38,4 @@ __exportStar(require("./dtos/responses/KycByDirectoryResponse"), exports);
36
38
  __exportStar(require("./events/KycVerificationChangedV1"), exports);
37
39
  __exportStar(require("./events/KycStepCompletedV1"), exports);
38
40
  __exportStar(require("./events/KycProofOfAddressCompletedV1"), exports);
41
+ __exportStar(require("./events/KycVerificationProgressV1"), exports);
@@ -0,0 +1,14 @@
1
+ import { KycModalityEnum } from '../../retailCustomer/enums/KycModalityEnum';
2
+ import { KycAttemptStageEnum } from '../enums/KycAttemptStageEnum';
3
+ /** Avance del intento vigente de un flujo KYC, tal como lo devuelve `GET kyc/status`. */
4
+ export interface KycAttemptProgress {
5
+ attemptId: string;
6
+ modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
7
+ /** `shortUrl` del QR; ausente en `STORE_DEVICE`. */
8
+ link?: string;
9
+ stage: KycAttemptStageEnum;
10
+ /** Cuándo entró a la etapa actual, ISO-8601 UTC. */
11
+ stageAt: string;
12
+ /** Fecha del prepare, ISO-8601 UTC; el front mide contra ella el tope de 25 min. */
13
+ attemptStartedAt: string;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import type { KycAttemptProgress } from './KycAttemptProgress';
2
+ /** Bloque `progress` de `GET kyc/status`: el intento vigente de cada flujo, o `null` si no hay. */
3
+ export interface KycStatusProgress {
4
+ identity: KycAttemptProgress | null;
5
+ facematch: KycAttemptProgress | null;
6
+ proofOfAddress: KycAttemptProgress | null;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -52,6 +52,8 @@ export interface KycSdkMetadata {
52
52
  * domicilio del documento de identidad: `kyc-metamap-webhook` rutea por este campo.
53
53
  */
54
54
  kycStep?: KycMetadataStepEnum;
55
+ /** Intento del wizard que originó la verificación; el webhook lo copia a cada evento. */
56
+ attemptId?: string;
55
57
  }
56
58
  /**
57
59
  * Paso del onboarding que originó una verificación, tal como viaja en `KycSdkMetadata.kycStep`.
@@ -94,6 +96,8 @@ export interface KycPrepareResponse {
94
96
  * (`KycManualRequest`). Por eso el tipo se estrecha a las dos que el SDK puede ejecutar.
95
97
  */
96
98
  modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
99
+ /** Intento que abrió este prepare; ausente cuando no se crea intento: alreadyVerified o bypass de dev. */
100
+ attemptId?: string;
97
101
  /** STORE_DEVICE — clientId de la cuenta Metamap (mismo valor en prod y dev). */
98
102
  clientId?: string;
99
103
  /** STORE_DEVICE — flow de Metamap por país; sale de la configuración del wizard. */
@@ -13,6 +13,8 @@ import { KycModalityEnum } from '../../../retailCustomer/enums/KycModalityEnum';
13
13
  export interface ProofOfAddressPrepareResponse {
14
14
  /** `MANUAL` no es una modalidad de `prepare`: la captura manual es su propio endpoint. */
15
15
  modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
16
+ /** Intento que abrió este prepare; ausente cuando alreadyHasAddress. */
17
+ attemptId?: string;
16
18
  /** STORE_DEVICE — clientId de la cuenta Metamap (mismo valor en prod y dev). */
17
19
  clientId?: string;
18
20
  /** STORE_DEVICE — flow de Metamap del comprobante de domicilio. */
@@ -0,0 +1,8 @@
1
+ /** Etapa del intento vigente de un flujo KYC del wizard; el rango de monotonía vive en el wizard. */
2
+ export declare enum KycAttemptStageEnum {
3
+ AWAITING_START = "AWAITING_START",
4
+ STARTED = "STARTED",
5
+ INPUTS_COMPLETED = "INPUTS_COMPLETED",
6
+ EXPIRED = "EXPIRED",
7
+ RESULT = "RESULT"
8
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KycAttemptStageEnum = void 0;
4
+ /** Etapa del intento vigente de un flujo KYC del wizard; el rango de monotonía vive en el wizard. */
5
+ var KycAttemptStageEnum;
6
+ (function (KycAttemptStageEnum) {
7
+ KycAttemptStageEnum["AWAITING_START"] = "AWAITING_START";
8
+ KycAttemptStageEnum["STARTED"] = "STARTED";
9
+ KycAttemptStageEnum["INPUTS_COMPLETED"] = "INPUTS_COMPLETED";
10
+ KycAttemptStageEnum["EXPIRED"] = "EXPIRED";
11
+ KycAttemptStageEnum["RESULT"] = "RESULT";
12
+ })(KycAttemptStageEnum || (exports.KycAttemptStageEnum = KycAttemptStageEnum = {}));
@@ -33,6 +33,7 @@ export * from './enums/LinePaymentTypeEnum';
33
33
  export * from './enums/WizardLineRoleEnum';
34
34
  export * from './enums/EmailStateEnum';
35
35
  export * from './enums/SaleChannelEnum';
36
+ export * from './enums/KycAttemptStageEnum';
36
37
  export * from './dtos/WizardConsents';
37
38
  export * from './dtos/WizardPayment';
38
39
  export * from './dtos/WizardProduct';
@@ -57,6 +58,8 @@ export * from './dtos/WizardReservedLine';
57
58
  export * from './dtos/WizardGiftLine';
58
59
  export * from './dtos/SaleLine';
59
60
  export * from './dtos/AccessorySaleLine';
61
+ export * from './dtos/KycAttemptProgress';
62
+ export * from './dtos/KycStatusProgress';
60
63
  export * from './dtos/WizardSession';
61
64
  export * from './dtos/OtpVerification';
62
65
  export * from './dtos/Sale';
@@ -52,6 +52,7 @@ __exportStar(require("./enums/LinePaymentTypeEnum"), exports);
52
52
  __exportStar(require("./enums/WizardLineRoleEnum"), exports);
53
53
  __exportStar(require("./enums/EmailStateEnum"), exports);
54
54
  __exportStar(require("./enums/SaleChannelEnum"), exports);
55
+ __exportStar(require("./enums/KycAttemptStageEnum"), exports);
55
56
  // DTOs anidados
56
57
  __exportStar(require("./dtos/WizardConsents"), exports);
57
58
  __exportStar(require("./dtos/WizardPayment"), exports);
@@ -79,6 +80,8 @@ __exportStar(require("./dtos/WizardReservedLine"), exports);
79
80
  __exportStar(require("./dtos/WizardGiftLine"), exports);
80
81
  __exportStar(require("./dtos/SaleLine"), exports);
81
82
  __exportStar(require("./dtos/AccessorySaleLine"), exports);
83
+ __exportStar(require("./dtos/KycAttemptProgress"), exports);
84
+ __exportStar(require("./dtos/KycStatusProgress"), exports);
82
85
  // Entidades principales (shapes de estado/persistencia — planas)
83
86
  __exportStar(require("./dtos/WizardSession"), exports);
84
87
  __exportStar(require("./dtos/OtpVerification"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.609.0",
3
+ "version": "3.610.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -138,6 +138,10 @@ export class BiometricVerificationResponse {
138
138
  @Expose() @IsISO8601({ strict: true })
139
139
  expiresAt!: string;
140
140
 
141
+ /** Cuándo el usuario terminó de subir su información. ISO-8601 UTC con `Z`; ausente si aún no. */
142
+ @Expose() @IsOptional() @IsISO8601({ strict: true })
143
+ inputsCompletedAt?: string;
144
+
141
145
  /** Cuándo alcanzó un estado terminal. Ausente mientras siga viva. */
142
146
  @Expose() @IsOptional() @IsISO8601({ strict: true })
143
147
  completedAt?: string;
@@ -3,8 +3,8 @@
3
3
  * lo que el consumer usa para decidir la transición de estado.
4
4
  *
5
5
  * Es el vocabulario NUESTRO, no el de Metamap: `kyc-metamap-webhook` traduce sus `eventName` a
6
- * estos cuatro antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
7
- * el día que entre otro proveedor traduce a los mismos cuatro.
6
+ * estos valores antes de publicar. Así el consumer no aprende el catálogo de un proveedor externo, y
7
+ * el día que entre otro proveedor traduce a los mismos valores.
8
8
  *
9
9
  * `biometrics-business` — Entrega 1.
10
10
  */
@@ -28,4 +28,10 @@ export enum BiometricEventTypeEnum {
28
28
  * contra `expiresAt` (DEC-015), así que una verificación vence aunque este evento nunca llegue.
29
29
  */
30
30
  VERIFICATION_EXPIRED = 'VERIFICATION_EXPIRED',
31
+
32
+ /** El usuario terminó de subir su información. Sigue en `IN_PROGRESS` y graba `inputsCompletedAt`. */
33
+ INPUTS_COMPLETED = 'INPUTS_COMPLETED',
34
+
35
+ /** El proveedor cambió el veredicto (revisión manual). Se trata igual que `VERIFICATION_COMPLETED`. */
36
+ UPDATED = 'UPDATED',
31
37
  }
@@ -0,0 +1,5 @@
1
+ /** Flujo de Metamap al que pertenece un evento; el webhook lo deriva de `metadata.kycStep`. */
2
+ export enum KycFlowEnum {
3
+ IDENTITY = 'IDENTITY',
4
+ PROOF_OF_ADDRESS = 'PROOF_OF_ADDRESS',
5
+ }
@@ -0,0 +1,6 @@
1
+ /** Etapa de avance de una verificación de Metamap, tal como la publica `kyc-metamap-webhook`. */
2
+ export enum KycProgressStageEnum {
3
+ STARTED = 'STARTED',
4
+ INPUTS_COMPLETED = 'INPUTS_COMPLETED',
5
+ EXPIRED = 'EXPIRED',
6
+ }
@@ -65,4 +65,8 @@ export class KycProofOfAddressCompletedV1 {
65
65
  message: 'occurredAt debe ser ISO-8601 en UTC con Z (ej. 2026-08-11T10:05:00.000Z): un offset rompe el orden léxico',
66
66
  })
67
67
  occurredAt!: string;
68
+
69
+ /** Intento del wizard que originó el comprobante; el consumidor descarta los que no son el vigente. */
70
+ @Expose() @IsOptional() @IsString() @IsNotEmpty()
71
+ attemptId?: string;
68
72
  }
@@ -1,5 +1,6 @@
1
1
  import { Expose } from 'class-transformer';
2
2
  import { IsEnum, IsIn, IsISO8601, IsNotEmpty, IsOptional, IsString, Matches, Validate } from 'class-validator';
3
+ import { KycFlowEnum } from '../enums/KycFlowEnum';
3
4
  import { KycSubCheckNameEnum } from '../enums/KycSubCheckNameEnum';
4
5
  import { KycSubCheckStatusEnum } from '../enums/KycSubCheckStatusEnum';
5
6
  import { KycWatchlistStatusEnum } from '../enums/KycWatchlistStatusEnum';
@@ -102,4 +103,12 @@ export class KycStepCompletedV1 {
102
103
  /** El flujo de Metamap que corrió. Solo para diagnóstico — nadie ramifica por él. */
103
104
  @Expose() @IsOptional() @IsString()
104
105
  metamapFlowId?: string;
106
+
107
+ /** Intento del wizard que originó la verificación; el consumidor descarta los que no son el vigente. */
108
+ @Expose() @IsOptional() @IsString() @IsNotEmpty()
109
+ attemptId?: string;
110
+
111
+ /** Flujo al que pertenece la estación, derivado de `metadata.kycStep`. */
112
+ @Expose() @IsOptional() @IsEnum(KycFlowEnum)
113
+ flow?: KycFlowEnum;
105
114
  }
@@ -95,4 +95,8 @@ export class KycVerificationChangedV1 {
95
95
  */
96
96
  @Expose() @IsOptional() @IsBoolean()
97
97
  addressPushedToFiado?: boolean;
98
+
99
+ /** Intento del wizard que originó la verificación; el consumidor descarta los que no son el vigente. */
100
+ @Expose() @IsOptional() @IsString() @IsNotEmpty()
101
+ attemptId?: string;
98
102
  }
@@ -0,0 +1,33 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsEnum, IsIn, IsISO8601, IsNotEmpty, IsOptional, IsString, Matches } from 'class-validator';
3
+ import { KycFlowEnum } from '../enums/KycFlowEnum';
4
+ import { KycProgressStageEnum } from '../enums/KycProgressStageEnum';
5
+
6
+ /** Avance de una verificación de Metamap (started, inputs_completed, expired) que publica `kyc-metamap-webhook`. */
7
+ export class KycVerificationProgressV1 {
8
+ @Expose() @IsIn(['KycVerificationProgressV1'])
9
+ eventType!: 'KycVerificationProgressV1';
10
+
11
+ @Expose() @IsEnum(KycProgressStageEnum)
12
+ stage!: KycProgressStageEnum;
13
+
14
+ @Expose() @IsEnum(KycFlowEnum)
15
+ flow!: KycFlowEnum;
16
+
17
+ @Expose() @IsString() @IsNotEmpty()
18
+ verificationId!: string;
19
+
20
+ @Expose() @IsString() @IsNotEmpty()
21
+ directoryId!: string;
22
+
23
+ /** Intento del wizard que originó la verificación; ausente en sesiones previas al despliegue. */
24
+ @Expose() @IsOptional() @IsString() @IsNotEmpty()
25
+ attemptId?: string;
26
+
27
+ /** ISO-8601 en UTC con `Z`, igual que los demás eventos de la cola. */
28
+ @Expose() @IsString() @IsISO8601({ strict: true })
29
+ @Matches(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/, {
30
+ message: 'occurredAt debe ser ISO-8601 en UTC con Z (ej. 2026-10-28T10:05:00.000Z)',
31
+ })
32
+ occurredAt!: string;
33
+ }
package/src/kyc/index.ts CHANGED
@@ -5,6 +5,8 @@ export * from './enums/KycSubCheckStatusEnum';
5
5
  export * from './enums/KycWatchlistStatusEnum';
6
6
  export * from './enums/KycSubCheckNameEnum';
7
7
  export * from './enums/ProofAddressStatusEnum';
8
+ export * from './enums/KycProgressStageEnum';
9
+ export * from './enums/KycFlowEnum';
8
10
 
9
11
  // Sub-pasos descompuestos (SureKeep F2)
10
12
  export * from './dtos/KycSubChecks';
@@ -26,3 +28,4 @@ export * from './dtos/responses/KycByDirectoryResponse';
26
28
  export * from './events/KycVerificationChangedV1';
27
29
  export * from './events/KycStepCompletedV1';
28
30
  export * from './events/KycProofOfAddressCompletedV1';
31
+ export * from './events/KycVerificationProgressV1';
@@ -0,0 +1,15 @@
1
+ import { KycModalityEnum } from '../../retailCustomer/enums/KycModalityEnum';
2
+ import { KycAttemptStageEnum } from '../enums/KycAttemptStageEnum';
3
+
4
+ /** Avance del intento vigente de un flujo KYC, tal como lo devuelve `GET kyc/status`. */
5
+ export interface KycAttemptProgress {
6
+ attemptId: string;
7
+ modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
8
+ /** `shortUrl` del QR; ausente en `STORE_DEVICE`. */
9
+ link?: string;
10
+ stage: KycAttemptStageEnum;
11
+ /** Cuándo entró a la etapa actual, ISO-8601 UTC. */
12
+ stageAt: string;
13
+ /** Fecha del prepare, ISO-8601 UTC; el front mide contra ella el tope de 25 min. */
14
+ attemptStartedAt: string;
15
+ }
@@ -0,0 +1,8 @@
1
+ import type { KycAttemptProgress } from './KycAttemptProgress';
2
+
3
+ /** Bloque `progress` de `GET kyc/status`: el intento vigente de cada flujo, o `null` si no hay. */
4
+ export interface KycStatusProgress {
5
+ identity: KycAttemptProgress | null;
6
+ facematch: KycAttemptProgress | null;
7
+ proofOfAddress: KycAttemptProgress | null;
8
+ }
@@ -53,6 +53,8 @@ export interface KycSdkMetadata {
53
53
  * domicilio del documento de identidad: `kyc-metamap-webhook` rutea por este campo.
54
54
  */
55
55
  kycStep?: KycMetadataStepEnum;
56
+ /** Intento del wizard que originó la verificación; el webhook lo copia a cada evento. */
57
+ attemptId?: string;
56
58
  }
57
59
 
58
60
  /**
@@ -98,6 +100,8 @@ export interface KycPrepareResponse {
98
100
  * (`KycManualRequest`). Por eso el tipo se estrecha a las dos que el SDK puede ejecutar.
99
101
  */
100
102
  modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
103
+ /** Intento que abrió este prepare; ausente cuando no se crea intento: alreadyVerified o bypass de dev. */
104
+ attemptId?: string;
101
105
  /** STORE_DEVICE — clientId de la cuenta Metamap (mismo valor en prod y dev). */
102
106
  clientId?: string;
103
107
  /** STORE_DEVICE — flow de Metamap por país; sale de la configuración del wizard. */
@@ -14,6 +14,8 @@ import { KycModalityEnum } from '../../../retailCustomer/enums/KycModalityEnum';
14
14
  export interface ProofOfAddressPrepareResponse {
15
15
  /** `MANUAL` no es una modalidad de `prepare`: la captura manual es su propio endpoint. */
16
16
  modality: KycModalityEnum.CUSTOMER_LINK | KycModalityEnum.STORE_DEVICE;
17
+ /** Intento que abrió este prepare; ausente cuando alreadyHasAddress. */
18
+ attemptId?: string;
17
19
  /** STORE_DEVICE — clientId de la cuenta Metamap (mismo valor en prod y dev). */
18
20
  clientId?: string;
19
21
  /** STORE_DEVICE — flow de Metamap del comprobante de domicilio. */
@@ -0,0 +1,8 @@
1
+ /** Etapa del intento vigente de un flujo KYC del wizard; el rango de monotonía vive en el wizard. */
2
+ export enum KycAttemptStageEnum {
3
+ AWAITING_START = 'AWAITING_START',
4
+ STARTED = 'STARTED',
5
+ INPUTS_COMPLETED = 'INPUTS_COMPLETED',
6
+ EXPIRED = 'EXPIRED',
7
+ RESULT = 'RESULT',
8
+ }
@@ -36,6 +36,7 @@ export * from './enums/LinePaymentTypeEnum';
36
36
  export * from './enums/WizardLineRoleEnum';
37
37
  export * from './enums/EmailStateEnum';
38
38
  export * from './enums/SaleChannelEnum';
39
+ export * from './enums/KycAttemptStageEnum';
39
40
 
40
41
  // DTOs anidados
41
42
  export * from './dtos/WizardConsents';
@@ -62,6 +63,8 @@ export * from './dtos/WizardReservedLine';
62
63
  export * from './dtos/WizardGiftLine';
63
64
  export * from './dtos/SaleLine';
64
65
  export * from './dtos/AccessorySaleLine';
66
+ export * from './dtos/KycAttemptProgress';
67
+ export * from './dtos/KycStatusProgress';
65
68
 
66
69
  // Entidades principales (shapes de estado/persistencia — planas)
67
70
  export * from './dtos/WizardSession';