@fiado/type-kit 3.415.0 → 3.417.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/loanCredit/dtos/loanDeviceContract.test.ts +2 -2
- package/_test_/unit/mdm/dtos/mdmDeviceContract.test.ts +2 -2
- package/_test_/unit/messagesConnector/sendMessagesBulkContract.test.ts +178 -0
- package/bin/loanCredit/dtos/LoanDeviceNotifyItem.d.ts +8 -2
- package/bin/loanCredit/dtos/LoanDeviceNotifyItem.js +2 -2
- package/bin/mdm/dtos/DeviceNotifyRequest.d.ts +13 -3
- package/bin/mdm/dtos/DeviceNotifyRequest.js +2 -2
- package/bin/messagesConnector/constants/MessagesBulkLimits.d.ts +8 -0
- package/bin/messagesConnector/constants/MessagesBulkLimits.js +11 -0
- package/bin/messagesConnector/dtos/NotificationQueueMessageRequestV2.d.ts +5 -0
- package/bin/messagesConnector/dtos/NotificationQueueMessageRequestV2.js +7 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkItem.d.ts +22 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkItem.js +85 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkRequest.d.ts +14 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkRequest.js +41 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkResponse.d.ts +5 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkResponse.js +7 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkResultItem.d.ts +11 -0
- package/bin/messagesConnector/dtos/SendMessagesBulkResultItem.js +7 -0
- package/bin/messagesConnector/enums/MessageBulkResultCodeEnum.d.ts +16 -0
- package/bin/messagesConnector/enums/MessageBulkResultCodeEnum.js +20 -0
- package/bin/messagesConnector/index.d.ts +6 -0
- package/bin/messagesConnector/index.js +6 -0
- package/package.json +1 -1
- package/src/loanCredit/dtos/LoanDeviceNotifyItem.ts +10 -4
- package/src/mdm/dtos/DeviceNotifyRequest.ts +15 -5
- package/src/messagesConnector/constants/MessagesBulkLimits.ts +9 -0
- package/src/messagesConnector/dtos/NotificationQueueMessageRequestV2.ts +10 -0
- package/src/messagesConnector/dtos/SendMessagesBulkItem.ts +66 -0
- package/src/messagesConnector/dtos/SendMessagesBulkRequest.ts +28 -0
- package/src/messagesConnector/dtos/SendMessagesBulkResponse.ts +6 -0
- package/src/messagesConnector/dtos/SendMessagesBulkResultItem.ts +16 -0
- package/src/messagesConnector/enums/MessageBulkResultCodeEnum.ts +16 -0
- package/src/messagesConnector/index.ts +6 -0
|
@@ -334,8 +334,8 @@ describe('LoanDeviceNotifyRequest', () => {
|
|
|
334
334
|
/** Cota de cada campo de texto libre, para probar el borde exacto y el borde + 1. */
|
|
335
335
|
const NOTIFY_MAX_LENGTHS: ReadonlyArray<readonly [string, number]> = [
|
|
336
336
|
['notificationCode', 64],
|
|
337
|
-
['title',
|
|
338
|
-
['content',
|
|
337
|
+
['title', 50],
|
|
338
|
+
['content', 350],
|
|
339
339
|
];
|
|
340
340
|
|
|
341
341
|
it('valida happy path (0 errores)', async () => {
|
|
@@ -152,8 +152,8 @@ describe('DeviceNotifyRequest — topes de longitud de los tres textos', () => {
|
|
|
152
152
|
/** Mismos números que `LoanDeviceNotifyItem`: las dos puntas del contrato dicen lo mismo. */
|
|
153
153
|
const limits = [
|
|
154
154
|
['notificationCode', 64],
|
|
155
|
-
['title',
|
|
156
|
-
['content',
|
|
155
|
+
['title', 50],
|
|
156
|
+
['content', 350],
|
|
157
157
|
] as const;
|
|
158
158
|
|
|
159
159
|
it.each(limits)('acepta %s en el largo máximo', async (field, max) => {
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate, ValidationError } from 'class-validator';
|
|
4
|
+
import { SendMessagesBulkItem } from '../../../src/messagesConnector/dtos/SendMessagesBulkItem';
|
|
5
|
+
import { SendMessagesBulkRequest } from '../../../src/messagesConnector/dtos/SendMessagesBulkRequest';
|
|
6
|
+
import { NotificationQueueMessageRequestV2 } from '../../../src/messagesConnector/dtos/NotificationQueueMessageRequestV2';
|
|
7
|
+
import * as MessagesConnectorBarrel from '../../../src/messagesConnector/index';
|
|
8
|
+
import { DeliveryChannelExtendedEnum } from '../../../src/messagesConnector/enums/DeliveryChannelExtendedEnum';
|
|
9
|
+
import { NotificationOriginEnum } from '../../../src/messagesConnector/enums/NotificationOriginEnum';
|
|
10
|
+
import { MessageBulkResultCodeEnum } from '../../../src/messagesConnector/enums/MessageBulkResultCodeEnum';
|
|
11
|
+
import {
|
|
12
|
+
MESSAGES_BULK_MAX_BATCH, MESSAGES_BULK_REFERENCE_MAX_LENGTH,
|
|
13
|
+
} from '../../../src/messagesConnector/constants/MessagesBulkLimits';
|
|
14
|
+
|
|
15
|
+
const validItem = {
|
|
16
|
+
reference: 'collections-2026-09-09-MORNING-0001',
|
|
17
|
+
messageType: 'COLLECTION_PRE_DUE_2_DAYS',
|
|
18
|
+
channelType: DeliveryChannelExtendedEnum.SMS,
|
|
19
|
+
directoryId: '01M0B5D7FQA3T06K4REEVPRM33',
|
|
20
|
+
typeOfDirectoryId: 'USER',
|
|
21
|
+
destination: '+525512345678',
|
|
22
|
+
language: 'es',
|
|
23
|
+
country: 'MX',
|
|
24
|
+
variables: { name: 'Ana', amount: '1200.00' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const validRequest = { items: [validItem] };
|
|
28
|
+
|
|
29
|
+
/** True si el error de `property` trae ese constraint puntual (no solo "algo fallo"). */
|
|
30
|
+
const hasConstraint = (errors: ValidationError[], property: string, constraint: string): boolean =>
|
|
31
|
+
errors.some((e) => e.property === property && Boolean(e.constraints?.[constraint]));
|
|
32
|
+
|
|
33
|
+
const validateRequest = async (payload: Record<string, unknown>): Promise<ValidationError[]> =>
|
|
34
|
+
validate(plainToInstance(SendMessagesBulkRequest, { ...validRequest, ...payload }));
|
|
35
|
+
|
|
36
|
+
const validateItem = async (payload: Record<string, unknown>): Promise<ValidationError[]> =>
|
|
37
|
+
validate(plainToInstance(SendMessagesBulkItem, { ...validItem, ...payload }));
|
|
38
|
+
|
|
39
|
+
describe('SendMessagesBulkItem', () => {
|
|
40
|
+
it('valida el item minimo del endpoint', async () => {
|
|
41
|
+
expect(await validateItem({})).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it.each(Object.values(DeliveryChannelExtendedEnum))('valida con channelType %s', async (channelType) => {
|
|
45
|
+
expect(await validateItem({ channelType })).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('falla si channelType esta fuera del enum', async () => {
|
|
49
|
+
expect(hasConstraint(await validateItem({ channelType: 'PIGEON' }), 'channelType', 'isEnum')).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it.each(['reference', 'messageType', 'directoryId', 'typeOfDirectoryId', 'destination', 'language', 'country'] as const)(
|
|
53
|
+
'falla si %s viene vacio', async (field) => {
|
|
54
|
+
expect(hasConstraint(await validateItem({ [field]: '' }), field, 'isNotEmpty')).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('falla si la referencia excede el largo maximo', async () => {
|
|
58
|
+
const reference = 'x'.repeat(MESSAGES_BULK_REFERENCE_MAX_LENGTH + 1);
|
|
59
|
+
expect(hasConstraint(await validateItem({ reference }), 'reference', 'maxLength')).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('falla si una variable no es string: el texto se interpola tal cual', async () => {
|
|
63
|
+
const errors = await validateItem({ variables: { amount: 1200 } });
|
|
64
|
+
expect(errors.some((e) => e.property === 'variables')).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('valida con origin explicito', async () => {
|
|
68
|
+
expect(await validateItem({ origin: NotificationOriginEnum.EVENT })).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('valida sin origin: su ausencia ya significa EVENT', async () => {
|
|
72
|
+
const dto = plainToInstance(SendMessagesBulkItem, validItem);
|
|
73
|
+
expect(await validate(dto)).toEqual([]);
|
|
74
|
+
expect(dto.origin).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('SendMessagesBulkRequest', () => {
|
|
79
|
+
it('valida el sobre minimo', async () => {
|
|
80
|
+
expect(await validateRequest({})).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('valida sin tenantId: messages-business asume FIADO', async () => {
|
|
84
|
+
const dto = plainToInstance(SendMessagesBulkRequest, validRequest);
|
|
85
|
+
expect(await validate(dto)).toEqual([]);
|
|
86
|
+
expect(dto.tenantId).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('falla si items viene vacio', async () => {
|
|
90
|
+
expect(hasConstraint(await validateRequest({ items: [] }), 'items', 'arrayNotEmpty')).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('falla si dos items repiten la misma referencia: el resultado se devuelve por referencia', async () => {
|
|
94
|
+
expect(hasConstraint(await validateRequest({ items: [validItem, validItem] }), 'items', 'arrayUnique')).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('NO declara el tope del lote: lo rechaza el lambda con su propio codigo', async () => {
|
|
98
|
+
const items = Array.from({ length: MESSAGES_BULK_MAX_BATCH + 1 },
|
|
99
|
+
(_, i) => ({ ...validItem, reference: `ref-${i}` }));
|
|
100
|
+
expect(await validateRequest({ items })).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('acepta un lote con los canales mezclados', async () => {
|
|
104
|
+
const items = [
|
|
105
|
+
{ ...validItem, reference: 'a', channelType: DeliveryChannelExtendedEnum.SMS },
|
|
106
|
+
{ ...validItem, reference: 'b', channelType: DeliveryChannelExtendedEnum.MAIL },
|
|
107
|
+
{ ...validItem, reference: 'c', channelType: DeliveryChannelExtendedEnum.PUSH_NOTIFICATION },
|
|
108
|
+
];
|
|
109
|
+
expect(await validateRequest({ items })).toEqual([]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('valida en profundidad cada item', async () => {
|
|
113
|
+
const errors = await validateRequest({ items: [{ ...validItem, channelType: 'PIGEON' }] });
|
|
114
|
+
const children = errors.find((e) => e.property === 'items')?.children ?? [];
|
|
115
|
+
expect(hasConstraint(children[0]?.children ?? [], 'channelType', 'isEnum')).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('materializa los items como SendMessagesBulkItem', () => {
|
|
119
|
+
const dto = plainToInstance(SendMessagesBulkRequest, validRequest);
|
|
120
|
+
expect(dto.items[0]).toBeInstanceOf(SendMessagesBulkItem);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('falla si tenantId viene vacio: ausente cae a FIADO, pero "" no es un tenant', async () => {
|
|
124
|
+
expect(hasConstraint(await validateRequest({ tenantId: '' }), 'tenantId', 'isNotEmpty')).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('NotificationQueueMessageRequestV2', () => {
|
|
129
|
+
const validQueueMessage = {
|
|
130
|
+
templateId: 'COLLECTION_PRE_DUE_2_DAYS',
|
|
131
|
+
channelType: DeliveryChannelExtendedEnum.SMS,
|
|
132
|
+
language: 'es',
|
|
133
|
+
country: 'MX',
|
|
134
|
+
typeOfDirectoryId: 'USER',
|
|
135
|
+
directoryId: '01M0B5D7FQA3T06K4REEVPRM33',
|
|
136
|
+
destination: '+525512345678',
|
|
137
|
+
variables: { name: 'Ana' },
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
it('acepta el messageLogId que reserva el lote', async () => {
|
|
141
|
+
const dto = plainToInstance(NotificationQueueMessageRequestV2,
|
|
142
|
+
{ ...validQueueMessage, messageLogId: 'bulk-1' });
|
|
143
|
+
expect(await validate(dto)).toEqual([]);
|
|
144
|
+
expect(dto.messageLogId).toBe('bulk-1');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('sigue valido sin messageLogId: los productores de siempre no lo mandan', async () => {
|
|
148
|
+
const dto = plainToInstance(NotificationQueueMessageRequestV2, validQueueMessage);
|
|
149
|
+
expect(await validate(dto)).toEqual([]);
|
|
150
|
+
expect(dto.messageLogId).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('falla si messageLogId viene vacio', async () => {
|
|
154
|
+
const dto = plainToInstance(NotificationQueueMessageRequestV2, { ...validQueueMessage, messageLogId: '' });
|
|
155
|
+
expect(hasConstraint(await validate(dto), 'messageLogId', 'isNotEmpty')).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('barrel de messagesConnector', () => {
|
|
160
|
+
it('exporta el par del endpoint de lotes', () => {
|
|
161
|
+
expect(MessagesConnectorBarrel.SendMessagesBulkItem).toBe(SendMessagesBulkItem);
|
|
162
|
+
expect(MessagesConnectorBarrel.SendMessagesBulkRequest).toBe(SendMessagesBulkRequest);
|
|
163
|
+
expect(MessagesConnectorBarrel.SendMessagesBulkResponse).toBeDefined();
|
|
164
|
+
expect(MessagesConnectorBarrel.SendMessagesBulkResultItem).toBeDefined();
|
|
165
|
+
expect(MessagesConnectorBarrel.MESSAGES_BULK_MAX_BATCH).toBe(MESSAGES_BULK_MAX_BATCH);
|
|
166
|
+
expect(MessagesConnectorBarrel.MessageBulkResultCodeEnum).toBe(MessageBulkResultCodeEnum);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('el acuse por item se tipa contra el catalogo de codigos del lote', () => {
|
|
170
|
+
const result = new MessagesConnectorBarrel.SendMessagesBulkResultItem();
|
|
171
|
+
result.reference = validItem.reference;
|
|
172
|
+
result.accepted = true;
|
|
173
|
+
result.code = MessageBulkResultCodeEnum.QUEUED;
|
|
174
|
+
result.queueMessageId = 'sqs-1';
|
|
175
|
+
result.messageLogId = 'log-1';
|
|
176
|
+
expect(result.code).toBe(MessageBulkResultCodeEnum.QUEUED);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
@@ -14,8 +14,14 @@ export declare class LoanDeviceNotifyItem {
|
|
|
14
14
|
noticeType?: MdmNoticeTypeEnum;
|
|
15
15
|
/** Código del catálogo de Datacultr. Camino legacy: solo se lee si no viaja `noticeType`. */
|
|
16
16
|
notificationCode?: string;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Título crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
19
|
+
* El tope es el de Trustonic, que exige de 1 a 50 y responde `INVALID_RANGE` fuera de rango.
|
|
20
|
+
*/
|
|
18
21
|
title?: string;
|
|
19
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Cuerpo crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
24
|
+
* El tope es el de Trustonic, que exige de 1 a 350 y responde `INVALID_RANGE` fuera de rango.
|
|
25
|
+
*/
|
|
20
26
|
content?: string;
|
|
21
27
|
}
|
|
@@ -51,7 +51,7 @@ __decorate([
|
|
|
51
51
|
(0, class_validator_1.IsOptional)(),
|
|
52
52
|
(0, class_validator_1.IsString)(),
|
|
53
53
|
(0, class_validator_1.IsNotEmpty)(),
|
|
54
|
-
(0, class_validator_1.MaxLength)(
|
|
54
|
+
(0, class_validator_1.MaxLength)(50),
|
|
55
55
|
__metadata("design:type", String)
|
|
56
56
|
], LoanDeviceNotifyItem.prototype, "title", void 0);
|
|
57
57
|
__decorate([
|
|
@@ -59,6 +59,6 @@ __decorate([
|
|
|
59
59
|
(0, class_validator_1.IsOptional)(),
|
|
60
60
|
(0, class_validator_1.IsString)(),
|
|
61
61
|
(0, class_validator_1.IsNotEmpty)(),
|
|
62
|
-
(0, class_validator_1.MaxLength)(
|
|
62
|
+
(0, class_validator_1.MaxLength)(350),
|
|
63
63
|
__metadata("design:type", String)
|
|
64
64
|
], LoanDeviceNotifyItem.prototype, "content", void 0);
|
|
@@ -8,11 +8,21 @@ export declare class DeviceNotifyRequest {
|
|
|
8
8
|
* Cuando viaja, manda: los connectors ignoran `notificationCode`, `title` y `content`.
|
|
9
9
|
*/
|
|
10
10
|
noticeType?: MdmNoticeTypeEnum;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Código del catálogo de Datacultr. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
13
|
+
* Es exclusivo de Datacultr: Trustonic no tiene catálogo de códigos y rechaza el ítem
|
|
14
|
+
* que solo trae este campo.
|
|
15
|
+
*/
|
|
12
16
|
notificationCode?: string;
|
|
13
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Título crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
19
|
+
* El tope es el de Trustonic, que exige de 1 a 50 y responde `INVALID_RANGE` fuera de rango.
|
|
20
|
+
*/
|
|
14
21
|
title?: string;
|
|
15
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Cuerpo crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
24
|
+
* El tope es el de Trustonic, que exige de 1 a 350 y responde `INVALID_RANGE` fuera de rango.
|
|
25
|
+
*/
|
|
16
26
|
content?: string;
|
|
17
27
|
operationReference: string;
|
|
18
28
|
}
|
|
@@ -47,7 +47,7 @@ __decorate([
|
|
|
47
47
|
(0, class_validator_1.IsOptional)(),
|
|
48
48
|
(0, class_validator_1.IsString)(),
|
|
49
49
|
(0, class_validator_1.IsNotEmpty)(),
|
|
50
|
-
(0, class_validator_1.MaxLength)(
|
|
50
|
+
(0, class_validator_1.MaxLength)(50),
|
|
51
51
|
__metadata("design:type", String)
|
|
52
52
|
], DeviceNotifyRequest.prototype, "title", void 0);
|
|
53
53
|
__decorate([
|
|
@@ -55,7 +55,7 @@ __decorate([
|
|
|
55
55
|
(0, class_validator_1.IsOptional)(),
|
|
56
56
|
(0, class_validator_1.IsString)(),
|
|
57
57
|
(0, class_validator_1.IsNotEmpty)(),
|
|
58
|
-
(0, class_validator_1.MaxLength)(
|
|
58
|
+
(0, class_validator_1.MaxLength)(350),
|
|
59
59
|
__metadata("design:type", String)
|
|
60
60
|
], DeviceNotifyRequest.prototype, "content", void 0);
|
|
61
61
|
__decorate([
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tope de items por llamada a `POST /private/messages/bulk`. El lambda que lo atiende tiene
|
|
3
|
+
* `Timeout: 25` y cada item cuesta una escritura condicional en DDB mas un envio a SQS, asi
|
|
4
|
+
* que el lote entero tiene que caber con margen en esa ventana.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MESSAGES_BULK_MAX_BATCH = 100;
|
|
7
|
+
/** Largo maximo de la referencia de idempotencia de un item del lote. */
|
|
8
|
+
export declare const MESSAGES_BULK_REFERENCE_MAX_LENGTH = 96;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MESSAGES_BULK_REFERENCE_MAX_LENGTH = exports.MESSAGES_BULK_MAX_BATCH = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Tope de items por llamada a `POST /private/messages/bulk`. El lambda que lo atiende tiene
|
|
6
|
+
* `Timeout: 25` y cada item cuesta una escritura condicional en DDB mas un envio a SQS, asi
|
|
7
|
+
* que el lote entero tiene que caber con margen en esa ventana.
|
|
8
|
+
*/
|
|
9
|
+
exports.MESSAGES_BULK_MAX_BATCH = 100;
|
|
10
|
+
/** Largo maximo de la referencia de idempotencia de un item del lote. */
|
|
11
|
+
exports.MESSAGES_BULK_REFERENCE_MAX_LENGTH = 96;
|
|
@@ -12,6 +12,11 @@ export declare class NotificationQueueMessageRequestV2 {
|
|
|
12
12
|
destination: string;
|
|
13
13
|
variables: Record<string, string>;
|
|
14
14
|
referenceMessageId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Fila de `MessageLogs_GT` que el lote ya reservo para este mensaje. Cuando viaja, el
|
|
17
|
+
* consumidor completa esa fila en vez de crear una nueva.
|
|
18
|
+
*/
|
|
19
|
+
messageLogId?: string;
|
|
15
20
|
data?: unknown;
|
|
16
21
|
/** Quien disparo la notificacion. Sin default: su ausencia ya significa EVENT. */
|
|
17
22
|
origin?: NotificationOriginEnum;
|
|
@@ -77,6 +77,13 @@ __decorate([
|
|
|
77
77
|
(0, class_validator_1.IsString)(),
|
|
78
78
|
__metadata("design:type", String)
|
|
79
79
|
], NotificationQueueMessageRequestV2.prototype, "referenceMessageId", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, class_transformer_1.Expose)(),
|
|
82
|
+
(0, class_validator_1.IsOptional)(),
|
|
83
|
+
(0, class_validator_1.IsString)(),
|
|
84
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
85
|
+
__metadata("design:type", String)
|
|
86
|
+
], NotificationQueueMessageRequestV2.prototype, "messageLogId", void 0);
|
|
80
87
|
__decorate([
|
|
81
88
|
(0, class_transformer_1.Expose)(),
|
|
82
89
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DeliveryChannelExtendedEnum } from '../enums/DeliveryChannelExtendedEnum';
|
|
2
|
+
import { NotificationOriginEnum } from '../enums/NotificationOriginEnum';
|
|
3
|
+
/**
|
|
4
|
+
* Un mensaje del lote: su destinatario, su momento, su canal y sus variables YA RESUELTAS.
|
|
5
|
+
* Mensajeria no calcula variables ni decide a quien le toca; eso lo trae hecho el caller.
|
|
6
|
+
*/
|
|
7
|
+
export declare class SendMessagesBulkItem {
|
|
8
|
+
/** Idempotencia: dos items con la misma referencia se aceptan una sola vez. */
|
|
9
|
+
reference: string;
|
|
10
|
+
/** El momento del catalogo de plantillas con el que se resuelve el texto. */
|
|
11
|
+
messageType: string;
|
|
12
|
+
channelType: DeliveryChannelExtendedEnum;
|
|
13
|
+
directoryId: string;
|
|
14
|
+
typeOfDirectoryId: string;
|
|
15
|
+
/** Telefono o correo del destinatario, segun el canal. */
|
|
16
|
+
destination: string;
|
|
17
|
+
language: string;
|
|
18
|
+
country: string;
|
|
19
|
+
variables: Record<string, string>;
|
|
20
|
+
/** Quien disparo el mensaje. Sin default: su ausencia ya significa EVENT. */
|
|
21
|
+
origin?: NotificationOriginEnum;
|
|
22
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
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.SendMessagesBulkItem = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const DeliveryChannelExtendedEnum_1 = require("../enums/DeliveryChannelExtendedEnum");
|
|
16
|
+
const NotificationOriginEnum_1 = require("../enums/NotificationOriginEnum");
|
|
17
|
+
const IsStringValueRecord_1 = require("../validators/IsStringValueRecord");
|
|
18
|
+
const MessagesBulkLimits_1 = require("../constants/MessagesBulkLimits");
|
|
19
|
+
/**
|
|
20
|
+
* Un mensaje del lote: su destinatario, su momento, su canal y sus variables YA RESUELTAS.
|
|
21
|
+
* Mensajeria no calcula variables ni decide a quien le toca; eso lo trae hecho el caller.
|
|
22
|
+
*/
|
|
23
|
+
class SendMessagesBulkItem {
|
|
24
|
+
}
|
|
25
|
+
exports.SendMessagesBulkItem = SendMessagesBulkItem;
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_transformer_1.Expose)(),
|
|
28
|
+
(0, class_validator_1.IsString)(),
|
|
29
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
30
|
+
(0, class_validator_1.MaxLength)(MessagesBulkLimits_1.MESSAGES_BULK_REFERENCE_MAX_LENGTH),
|
|
31
|
+
__metadata("design:type", String)
|
|
32
|
+
], SendMessagesBulkItem.prototype, "reference", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, class_transformer_1.Expose)(),
|
|
35
|
+
(0, class_validator_1.IsString)(),
|
|
36
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], SendMessagesBulkItem.prototype, "messageType", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, class_transformer_1.Expose)(),
|
|
41
|
+
(0, class_validator_1.IsEnum)(DeliveryChannelExtendedEnum_1.DeliveryChannelExtendedEnum),
|
|
42
|
+
__metadata("design:type", String)
|
|
43
|
+
], SendMessagesBulkItem.prototype, "channelType", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, class_transformer_1.Expose)(),
|
|
46
|
+
(0, class_validator_1.IsString)(),
|
|
47
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
48
|
+
__metadata("design:type", String)
|
|
49
|
+
], SendMessagesBulkItem.prototype, "directoryId", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, class_transformer_1.Expose)(),
|
|
52
|
+
(0, class_validator_1.IsString)(),
|
|
53
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
54
|
+
__metadata("design:type", String)
|
|
55
|
+
], SendMessagesBulkItem.prototype, "typeOfDirectoryId", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
(0, class_transformer_1.Expose)(),
|
|
58
|
+
(0, class_validator_1.IsString)(),
|
|
59
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], SendMessagesBulkItem.prototype, "destination", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
(0, class_transformer_1.Expose)(),
|
|
64
|
+
(0, class_validator_1.IsString)(),
|
|
65
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
66
|
+
__metadata("design:type", String)
|
|
67
|
+
], SendMessagesBulkItem.prototype, "language", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
(0, class_transformer_1.Expose)(),
|
|
70
|
+
(0, class_validator_1.IsString)(),
|
|
71
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
72
|
+
__metadata("design:type", String)
|
|
73
|
+
], SendMessagesBulkItem.prototype, "country", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
(0, class_transformer_1.Expose)(),
|
|
76
|
+
(0, class_validator_1.IsObject)(),
|
|
77
|
+
(0, class_validator_1.Validate)(IsStringValueRecord_1.IsStringValueRecord),
|
|
78
|
+
__metadata("design:type", Object)
|
|
79
|
+
], SendMessagesBulkItem.prototype, "variables", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, class_transformer_1.Expose)(),
|
|
82
|
+
(0, class_validator_1.IsOptional)(),
|
|
83
|
+
(0, class_validator_1.IsEnum)(NotificationOriginEnum_1.NotificationOriginEnum),
|
|
84
|
+
__metadata("design:type", String)
|
|
85
|
+
], SendMessagesBulkItem.prototype, "origin", void 0);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SendMessagesBulkItem } from './SendMessagesBulkItem';
|
|
2
|
+
/**
|
|
3
|
+
* Body de `POST /private/messages/bulk` (messages-business). Es la unica entrada de mensajes
|
|
4
|
+
* a mensajeria y NO exige que el lote sea de un solo canal.
|
|
5
|
+
*
|
|
6
|
+
* El tope de items no se declara aca: lo rechaza el lambda con su propio codigo, en vez de
|
|
7
|
+
* caer al error generico de validacion.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SendMessagesBulkRequest {
|
|
10
|
+
/** Un resultado por referencia, asi que la referencia repetida no tiene resultado que devolver. */
|
|
11
|
+
items: SendMessagesBulkItem[];
|
|
12
|
+
/** Tenant emisor del lote. Si se omite, messages-business asume FIADO. */
|
|
13
|
+
tenantId?: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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.SendMessagesBulkRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const SendMessagesBulkItem_1 = require("./SendMessagesBulkItem");
|
|
16
|
+
/**
|
|
17
|
+
* Body de `POST /private/messages/bulk` (messages-business). Es la unica entrada de mensajes
|
|
18
|
+
* a mensajeria y NO exige que el lote sea de un solo canal.
|
|
19
|
+
*
|
|
20
|
+
* El tope de items no se declara aca: lo rechaza el lambda con su propio codigo, en vez de
|
|
21
|
+
* caer al error generico de validacion.
|
|
22
|
+
*/
|
|
23
|
+
class SendMessagesBulkRequest {
|
|
24
|
+
}
|
|
25
|
+
exports.SendMessagesBulkRequest = SendMessagesBulkRequest;
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_transformer_1.Expose)(),
|
|
28
|
+
(0, class_validator_1.IsArray)(),
|
|
29
|
+
(0, class_validator_1.ArrayNotEmpty)(),
|
|
30
|
+
(0, class_validator_1.ArrayUnique)((item) => item.reference),
|
|
31
|
+
(0, class_validator_1.ValidateNested)({ each: true }),
|
|
32
|
+
(0, class_transformer_1.Type)(() => SendMessagesBulkItem_1.SendMessagesBulkItem),
|
|
33
|
+
__metadata("design:type", Array)
|
|
34
|
+
], SendMessagesBulkRequest.prototype, "items", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
(0, class_transformer_1.Expose)(),
|
|
37
|
+
(0, class_validator_1.IsOptional)(),
|
|
38
|
+
(0, class_validator_1.IsString)(),
|
|
39
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], SendMessagesBulkRequest.prototype, "tenantId", void 0);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SendMessagesBulkResponse = void 0;
|
|
4
|
+
/** Response 202 de `POST /private/messages/bulk`. Un resultado por item enviado. */
|
|
5
|
+
class SendMessagesBulkResponse {
|
|
6
|
+
}
|
|
7
|
+
exports.SendMessagesBulkResponse = SendMessagesBulkResponse;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MessageBulkResultCodeEnum } from '../enums/MessageBulkResultCodeEnum';
|
|
2
|
+
/** Acuse de UN item del lote. Se correlaciona con el pedido por su `reference`. */
|
|
3
|
+
export declare class SendMessagesBulkResultItem {
|
|
4
|
+
reference: string;
|
|
5
|
+
accepted: boolean;
|
|
6
|
+
code: MessageBulkResultCodeEnum;
|
|
7
|
+
/** MessageId que asigno SQS. Solo viaja cuando el item quedo encolado. */
|
|
8
|
+
queueMessageId?: string;
|
|
9
|
+
/** Fila de `MessageLogs_GT` con la que se sigue el mensaje. Solo cuando el item quedo encolado. */
|
|
10
|
+
messageLogId?: string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SendMessagesBulkResultItem = void 0;
|
|
4
|
+
/** Acuse de UN item del lote. Se correlaciona con el pedido por su `reference`. */
|
|
5
|
+
class SendMessagesBulkResultItem {
|
|
6
|
+
}
|
|
7
|
+
exports.SendMessagesBulkResultItem = SendMessagesBulkResultItem;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resultado de UN item del lote de `POST /private/messages/bulk`. Es por item a proposito:
|
|
3
|
+
* un telefono malo no tumba los otros noventa y nueve.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum MessageBulkResultCodeEnum {
|
|
6
|
+
/** Encolado. La entrega sigue por la cola, con sus reintentos y su DLQ. */
|
|
7
|
+
QUEUED = "QUEUED",
|
|
8
|
+
/** Ya se habia aceptado un item con esa misma `reference`: no se encola de nuevo. */
|
|
9
|
+
DUPLICATE_REFERENCE = "DUPLICATE_REFERENCE",
|
|
10
|
+
/** El canal no entra por esta puerta. El aviso MDM sale por `mdm-notify`. */
|
|
11
|
+
CHANNEL_NOT_ACCEPTED = "CHANNEL_NOT_ACCEPTED",
|
|
12
|
+
/** La cola no acepto el mensaje. Es fallo de infraestructura: el item se puede reintentar. */
|
|
13
|
+
QUEUE_UNAVAILABLE = "QUEUE_UNAVAILABLE",
|
|
14
|
+
/** Fallo inesperado al aceptar el item. El resto del lote sigue su curso. */
|
|
15
|
+
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MessageBulkResultCodeEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Resultado de UN item del lote de `POST /private/messages/bulk`. Es por item a proposito:
|
|
6
|
+
* un telefono malo no tumba los otros noventa y nueve.
|
|
7
|
+
*/
|
|
8
|
+
var MessageBulkResultCodeEnum;
|
|
9
|
+
(function (MessageBulkResultCodeEnum) {
|
|
10
|
+
/** Encolado. La entrega sigue por la cola, con sus reintentos y su DLQ. */
|
|
11
|
+
MessageBulkResultCodeEnum["QUEUED"] = "QUEUED";
|
|
12
|
+
/** Ya se habia aceptado un item con esa misma `reference`: no se encola de nuevo. */
|
|
13
|
+
MessageBulkResultCodeEnum["DUPLICATE_REFERENCE"] = "DUPLICATE_REFERENCE";
|
|
14
|
+
/** El canal no entra por esta puerta. El aviso MDM sale por `mdm-notify`. */
|
|
15
|
+
MessageBulkResultCodeEnum["CHANNEL_NOT_ACCEPTED"] = "CHANNEL_NOT_ACCEPTED";
|
|
16
|
+
/** La cola no acepto el mensaje. Es fallo de infraestructura: el item se puede reintentar. */
|
|
17
|
+
MessageBulkResultCodeEnum["QUEUE_UNAVAILABLE"] = "QUEUE_UNAVAILABLE";
|
|
18
|
+
/** Fallo inesperado al aceptar el item. El resto del lote sigue su curso. */
|
|
19
|
+
MessageBulkResultCodeEnum["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
20
|
+
})(MessageBulkResultCodeEnum || (exports.MessageBulkResultCodeEnum = MessageBulkResultCodeEnum = {}));
|
|
@@ -25,3 +25,9 @@ export * from './dtos/MdmNotifyItem';
|
|
|
25
25
|
export * from './dtos/MdmNotifyRequest';
|
|
26
26
|
export * from './dtos/MdmNotifyResponse';
|
|
27
27
|
export * from './dtos/MdmNotifyBatchResponse';
|
|
28
|
+
export * from './enums/MessageBulkResultCodeEnum';
|
|
29
|
+
export * from './constants/MessagesBulkLimits';
|
|
30
|
+
export * from './dtos/SendMessagesBulkItem';
|
|
31
|
+
export * from './dtos/SendMessagesBulkRequest';
|
|
32
|
+
export * from './dtos/SendMessagesBulkResultItem';
|
|
33
|
+
export * from './dtos/SendMessagesBulkResponse';
|
|
@@ -41,3 +41,9 @@ __exportStar(require("./dtos/MdmNotifyItem"), exports);
|
|
|
41
41
|
__exportStar(require("./dtos/MdmNotifyRequest"), exports);
|
|
42
42
|
__exportStar(require("./dtos/MdmNotifyResponse"), exports);
|
|
43
43
|
__exportStar(require("./dtos/MdmNotifyBatchResponse"), exports);
|
|
44
|
+
__exportStar(require("./enums/MessageBulkResultCodeEnum"), exports);
|
|
45
|
+
__exportStar(require("./constants/MessagesBulkLimits"), exports);
|
|
46
|
+
__exportStar(require("./dtos/SendMessagesBulkItem"), exports);
|
|
47
|
+
__exportStar(require("./dtos/SendMessagesBulkRequest"), exports);
|
|
48
|
+
__exportStar(require("./dtos/SendMessagesBulkResultItem"), exports);
|
|
49
|
+
__exportStar(require("./dtos/SendMessagesBulkResponse"), exports);
|
package/package.json
CHANGED
|
@@ -34,19 +34,25 @@ export class LoanDeviceNotifyItem {
|
|
|
34
34
|
@MaxLength(64)
|
|
35
35
|
notificationCode?: string;
|
|
36
36
|
|
|
37
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Título crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
39
|
+
* El tope es el de Trustonic, que exige de 1 a 50 y responde `INVALID_RANGE` fuera de rango.
|
|
40
|
+
*/
|
|
38
41
|
@Expose()
|
|
39
42
|
@IsOptional()
|
|
40
43
|
@IsString()
|
|
41
44
|
@IsNotEmpty()
|
|
42
|
-
@MaxLength(
|
|
45
|
+
@MaxLength(50)
|
|
43
46
|
title?: string;
|
|
44
47
|
|
|
45
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Cuerpo crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
50
|
+
* El tope es el de Trustonic, que exige de 1 a 350 y responde `INVALID_RANGE` fuera de rango.
|
|
51
|
+
*/
|
|
46
52
|
@Expose()
|
|
47
53
|
@IsOptional()
|
|
48
54
|
@IsString()
|
|
49
55
|
@IsNotEmpty()
|
|
50
|
-
@MaxLength(
|
|
56
|
+
@MaxLength(350)
|
|
51
57
|
content?: string;
|
|
52
58
|
}
|
|
@@ -22,7 +22,11 @@ export class DeviceNotifyRequest {
|
|
|
22
22
|
@IsEnum(MdmNoticeTypeEnum)
|
|
23
23
|
noticeType?: MdmNoticeTypeEnum;
|
|
24
24
|
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Código del catálogo de Datacultr. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
27
|
+
* Es exclusivo de Datacultr: Trustonic no tiene catálogo de códigos y rechaza el ítem
|
|
28
|
+
* que solo trae este campo.
|
|
29
|
+
*/
|
|
26
30
|
@Expose()
|
|
27
31
|
@IsOptional()
|
|
28
32
|
@IsString()
|
|
@@ -30,20 +34,26 @@ export class DeviceNotifyRequest {
|
|
|
30
34
|
@MaxLength(64)
|
|
31
35
|
notificationCode?: string;
|
|
32
36
|
|
|
33
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Título crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
39
|
+
* El tope es el de Trustonic, que exige de 1 a 50 y responde `INVALID_RANGE` fuera de rango.
|
|
40
|
+
*/
|
|
34
41
|
@Expose()
|
|
35
42
|
@IsOptional()
|
|
36
43
|
@IsString()
|
|
37
44
|
@IsNotEmpty()
|
|
38
|
-
@MaxLength(
|
|
45
|
+
@MaxLength(50)
|
|
39
46
|
title?: string;
|
|
40
47
|
|
|
41
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Cuerpo crudo para Trustonic. Camino legacy: solo se lee si no viaja `noticeType`.
|
|
50
|
+
* El tope es el de Trustonic, que exige de 1 a 350 y responde `INVALID_RANGE` fuera de rango.
|
|
51
|
+
*/
|
|
42
52
|
@Expose()
|
|
43
53
|
@IsOptional()
|
|
44
54
|
@IsString()
|
|
45
55
|
@IsNotEmpty()
|
|
46
|
-
@MaxLength(
|
|
56
|
+
@MaxLength(350)
|
|
47
57
|
content?: string;
|
|
48
58
|
|
|
49
59
|
@Expose()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tope de items por llamada a `POST /private/messages/bulk`. El lambda que lo atiende tiene
|
|
3
|
+
* `Timeout: 25` y cada item cuesta una escritura condicional en DDB mas un envio a SQS, asi
|
|
4
|
+
* que el lote entero tiene que caber con margen en esa ventana.
|
|
5
|
+
*/
|
|
6
|
+
export const MESSAGES_BULK_MAX_BATCH = 100;
|
|
7
|
+
|
|
8
|
+
/** Largo maximo de la referencia de idempotencia de un item del lote. */
|
|
9
|
+
export const MESSAGES_BULK_REFERENCE_MAX_LENGTH = 96;
|
|
@@ -55,6 +55,16 @@ export class NotificationQueueMessageRequestV2 {
|
|
|
55
55
|
@IsString()
|
|
56
56
|
referenceMessageId?: string;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Fila de `MessageLogs_GT` que el lote ya reservo para este mensaje. Cuando viaja, el
|
|
60
|
+
* consumidor completa esa fila en vez de crear una nueva.
|
|
61
|
+
*/
|
|
62
|
+
@Expose()
|
|
63
|
+
@IsOptional()
|
|
64
|
+
@IsString()
|
|
65
|
+
@IsNotEmpty()
|
|
66
|
+
messageLogId?: string;
|
|
67
|
+
|
|
58
68
|
@Expose()
|
|
59
69
|
@IsOptional()
|
|
60
70
|
data?: unknown;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength, Validate } from 'class-validator';
|
|
3
|
+
import { DeliveryChannelExtendedEnum } from '../enums/DeliveryChannelExtendedEnum';
|
|
4
|
+
import { NotificationOriginEnum } from '../enums/NotificationOriginEnum';
|
|
5
|
+
import { IsStringValueRecord } from '../validators/IsStringValueRecord';
|
|
6
|
+
import { MESSAGES_BULK_REFERENCE_MAX_LENGTH } from '../constants/MessagesBulkLimits';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Un mensaje del lote: su destinatario, su momento, su canal y sus variables YA RESUELTAS.
|
|
10
|
+
* Mensajeria no calcula variables ni decide a quien le toca; eso lo trae hecho el caller.
|
|
11
|
+
*/
|
|
12
|
+
export class SendMessagesBulkItem {
|
|
13
|
+
/** Idempotencia: dos items con la misma referencia se aceptan una sola vez. */
|
|
14
|
+
@Expose()
|
|
15
|
+
@IsString()
|
|
16
|
+
@IsNotEmpty()
|
|
17
|
+
@MaxLength(MESSAGES_BULK_REFERENCE_MAX_LENGTH)
|
|
18
|
+
reference!: string;
|
|
19
|
+
|
|
20
|
+
/** El momento del catalogo de plantillas con el que se resuelve el texto. */
|
|
21
|
+
@Expose()
|
|
22
|
+
@IsString()
|
|
23
|
+
@IsNotEmpty()
|
|
24
|
+
messageType!: string;
|
|
25
|
+
|
|
26
|
+
@Expose()
|
|
27
|
+
@IsEnum(DeliveryChannelExtendedEnum)
|
|
28
|
+
channelType!: DeliveryChannelExtendedEnum;
|
|
29
|
+
|
|
30
|
+
@Expose()
|
|
31
|
+
@IsString()
|
|
32
|
+
@IsNotEmpty()
|
|
33
|
+
directoryId!: string;
|
|
34
|
+
|
|
35
|
+
@Expose()
|
|
36
|
+
@IsString()
|
|
37
|
+
@IsNotEmpty()
|
|
38
|
+
typeOfDirectoryId!: string;
|
|
39
|
+
|
|
40
|
+
/** Telefono o correo del destinatario, segun el canal. */
|
|
41
|
+
@Expose()
|
|
42
|
+
@IsString()
|
|
43
|
+
@IsNotEmpty()
|
|
44
|
+
destination!: string;
|
|
45
|
+
|
|
46
|
+
@Expose()
|
|
47
|
+
@IsString()
|
|
48
|
+
@IsNotEmpty()
|
|
49
|
+
language!: string;
|
|
50
|
+
|
|
51
|
+
@Expose()
|
|
52
|
+
@IsString()
|
|
53
|
+
@IsNotEmpty()
|
|
54
|
+
country!: string;
|
|
55
|
+
|
|
56
|
+
@Expose()
|
|
57
|
+
@IsObject()
|
|
58
|
+
@Validate(IsStringValueRecord)
|
|
59
|
+
variables!: Record<string, string>;
|
|
60
|
+
|
|
61
|
+
/** Quien disparo el mensaje. Sin default: su ausencia ya significa EVENT. */
|
|
62
|
+
@Expose()
|
|
63
|
+
@IsOptional()
|
|
64
|
+
@IsEnum(NotificationOriginEnum)
|
|
65
|
+
origin?: NotificationOriginEnum;
|
|
66
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Expose, Type } from 'class-transformer';
|
|
2
|
+
import { ArrayNotEmpty, ArrayUnique, IsArray, IsNotEmpty, IsOptional, IsString, ValidateNested } from 'class-validator';
|
|
3
|
+
import { SendMessagesBulkItem } from './SendMessagesBulkItem';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Body de `POST /private/messages/bulk` (messages-business). Es la unica entrada de mensajes
|
|
7
|
+
* a mensajeria y NO exige que el lote sea de un solo canal.
|
|
8
|
+
*
|
|
9
|
+
* El tope de items no se declara aca: lo rechaza el lambda con su propio codigo, en vez de
|
|
10
|
+
* caer al error generico de validacion.
|
|
11
|
+
*/
|
|
12
|
+
export class SendMessagesBulkRequest {
|
|
13
|
+
/** Un resultado por referencia, asi que la referencia repetida no tiene resultado que devolver. */
|
|
14
|
+
@Expose()
|
|
15
|
+
@IsArray()
|
|
16
|
+
@ArrayNotEmpty()
|
|
17
|
+
@ArrayUnique((item: SendMessagesBulkItem) => item.reference)
|
|
18
|
+
@ValidateNested({ each: true })
|
|
19
|
+
@Type(() => SendMessagesBulkItem)
|
|
20
|
+
items!: SendMessagesBulkItem[];
|
|
21
|
+
|
|
22
|
+
/** Tenant emisor del lote. Si se omite, messages-business asume FIADO. */
|
|
23
|
+
@Expose()
|
|
24
|
+
@IsOptional()
|
|
25
|
+
@IsString()
|
|
26
|
+
@IsNotEmpty()
|
|
27
|
+
tenantId?: string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MessageBulkResultCodeEnum } from '../enums/MessageBulkResultCodeEnum';
|
|
2
|
+
|
|
3
|
+
/** Acuse de UN item del lote. Se correlaciona con el pedido por su `reference`. */
|
|
4
|
+
export class SendMessagesBulkResultItem {
|
|
5
|
+
reference!: string;
|
|
6
|
+
|
|
7
|
+
accepted!: boolean;
|
|
8
|
+
|
|
9
|
+
code!: MessageBulkResultCodeEnum;
|
|
10
|
+
|
|
11
|
+
/** MessageId que asigno SQS. Solo viaja cuando el item quedo encolado. */
|
|
12
|
+
queueMessageId?: string;
|
|
13
|
+
|
|
14
|
+
/** Fila de `MessageLogs_GT` con la que se sigue el mensaje. Solo cuando el item quedo encolado. */
|
|
15
|
+
messageLogId?: string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resultado de UN item del lote de `POST /private/messages/bulk`. Es por item a proposito:
|
|
3
|
+
* un telefono malo no tumba los otros noventa y nueve.
|
|
4
|
+
*/
|
|
5
|
+
export enum MessageBulkResultCodeEnum {
|
|
6
|
+
/** Encolado. La entrega sigue por la cola, con sus reintentos y su DLQ. */
|
|
7
|
+
QUEUED = 'QUEUED',
|
|
8
|
+
/** Ya se habia aceptado un item con esa misma `reference`: no se encola de nuevo. */
|
|
9
|
+
DUPLICATE_REFERENCE = 'DUPLICATE_REFERENCE',
|
|
10
|
+
/** El canal no entra por esta puerta. El aviso MDM sale por `mdm-notify`. */
|
|
11
|
+
CHANNEL_NOT_ACCEPTED = 'CHANNEL_NOT_ACCEPTED',
|
|
12
|
+
/** La cola no acepto el mensaje. Es fallo de infraestructura: el item se puede reintentar. */
|
|
13
|
+
QUEUE_UNAVAILABLE = 'QUEUE_UNAVAILABLE',
|
|
14
|
+
/** Fallo inesperado al aceptar el item. El resto del lote sigue su curso. */
|
|
15
|
+
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
|
16
|
+
}
|
|
@@ -25,3 +25,9 @@ export * from './dtos/MdmNotifyItem';
|
|
|
25
25
|
export * from './dtos/MdmNotifyRequest';
|
|
26
26
|
export * from './dtos/MdmNotifyResponse';
|
|
27
27
|
export * from './dtos/MdmNotifyBatchResponse';
|
|
28
|
+
export * from './enums/MessageBulkResultCodeEnum';
|
|
29
|
+
export * from './constants/MessagesBulkLimits';
|
|
30
|
+
export * from './dtos/SendMessagesBulkItem';
|
|
31
|
+
export * from './dtos/SendMessagesBulkRequest';
|
|
32
|
+
export * from './dtos/SendMessagesBulkResultItem';
|
|
33
|
+
export * from './dtos/SendMessagesBulkResponse';
|