@fiado/type-kit 3.417.0 → 3.419.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 (30) hide show
  1. package/_test_/unit/messagesConnector/NotificationQueueMessageRequestV2.test.ts +48 -0
  2. package/bin/messagesConnector/constants/MessageIdempotencyLimits.d.ts +5 -0
  3. package/bin/messagesConnector/constants/MessageIdempotencyLimits.js +8 -0
  4. package/bin/messagesConnector/dtos/NotificationQueueMessageRequestV2.d.ts +10 -3
  5. package/bin/messagesConnector/dtos/NotificationQueueMessageRequestV2.js +4 -1
  6. package/bin/messagesConnector/index.d.ts +1 -6
  7. package/bin/messagesConnector/index.js +1 -6
  8. package/package.json +1 -1
  9. package/src/messagesConnector/constants/MessageIdempotencyLimits.ts +5 -0
  10. package/src/messagesConnector/dtos/NotificationQueueMessageRequestV2.ts +14 -4
  11. package/src/messagesConnector/index.ts +1 -6
  12. package/_test_/unit/messagesConnector/sendMessagesBulkContract.test.ts +0 -178
  13. package/bin/messagesConnector/constants/MessagesBulkLimits.d.ts +0 -8
  14. package/bin/messagesConnector/constants/MessagesBulkLimits.js +0 -11
  15. package/bin/messagesConnector/dtos/SendMessagesBulkItem.d.ts +0 -22
  16. package/bin/messagesConnector/dtos/SendMessagesBulkItem.js +0 -85
  17. package/bin/messagesConnector/dtos/SendMessagesBulkRequest.d.ts +0 -14
  18. package/bin/messagesConnector/dtos/SendMessagesBulkRequest.js +0 -41
  19. package/bin/messagesConnector/dtos/SendMessagesBulkResponse.d.ts +0 -5
  20. package/bin/messagesConnector/dtos/SendMessagesBulkResponse.js +0 -7
  21. package/bin/messagesConnector/dtos/SendMessagesBulkResultItem.d.ts +0 -11
  22. package/bin/messagesConnector/dtos/SendMessagesBulkResultItem.js +0 -7
  23. package/bin/messagesConnector/enums/MessageBulkResultCodeEnum.d.ts +0 -16
  24. package/bin/messagesConnector/enums/MessageBulkResultCodeEnum.js +0 -20
  25. package/src/messagesConnector/constants/MessagesBulkLimits.ts +0 -9
  26. package/src/messagesConnector/dtos/SendMessagesBulkItem.ts +0 -66
  27. package/src/messagesConnector/dtos/SendMessagesBulkRequest.ts +0 -28
  28. package/src/messagesConnector/dtos/SendMessagesBulkResponse.ts +0 -6
  29. package/src/messagesConnector/dtos/SendMessagesBulkResultItem.ts +0 -16
  30. package/src/messagesConnector/enums/MessageBulkResultCodeEnum.ts +0 -16
@@ -4,6 +4,7 @@ import { validate } from 'class-validator';
4
4
  import { NotificationQueueMessageRequestV2 } from '../../../src/messagesConnector/dtos/NotificationQueueMessageRequestV2';
5
5
  import { NotificationOriginEnum } from '../../../src/messagesConnector/enums/NotificationOriginEnum';
6
6
  import { DeliveryChannelExtendedEnum } from '../../../src/messagesConnector/enums/DeliveryChannelExtendedEnum';
7
+ import { MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH } from '../../../src/messagesConnector/constants/MessageIdempotencyLimits';
7
8
 
8
9
  const base = {
9
10
  templateId: 'OTP_CODE',
@@ -47,3 +48,50 @@ describe('NotificationQueueMessageRequestV2.origin', () => {
47
48
  expect(await errorsOn({ origin: 'CRON' }, 'origin')).not.toHaveLength(0);
48
49
  });
49
50
  });
51
+
52
+ describe('idempotencyKey — la llave de deduplicacion, aparte de la correlacion', () => {
53
+ const validQueueMessage = {
54
+ templateId: 'COLLECTION_PRE_DUE_2_DAYS',
55
+ channelType: DeliveryChannelExtendedEnum.SMS,
56
+ language: 'es',
57
+ country: 'MX',
58
+ typeOfDirectoryId: 'USER',
59
+ directoryId: '01M0B5D7FQA3T06K4REEVPRM33',
60
+ destination: '+525512345678',
61
+ variables: { name: 'Ana' },
62
+ };
63
+ const build = (over: Record<string, unknown> = {}) =>
64
+ plainToInstance(NotificationQueueMessageRequestV2, { ...validQueueMessage, ...over });
65
+
66
+ it('acepta una llave de negocio que no es UUID', async () => {
67
+ expect(await validate(build({ idempotencyKey: 'run-42:credit-7:PRE_DUE_2_DAYS' }))).toEqual([]);
68
+ });
69
+
70
+ // Sin llave no hay deduplicacion: es el comportamiento de todos los productores de hoy.
71
+ it('sigue valido sin llave', async () => {
72
+ const dto = build();
73
+ expect(await validate(dto)).toEqual([]);
74
+ expect(dto.idempotencyKey).toBeUndefined();
75
+ });
76
+
77
+ // El `#` separa los tramos de la llave de MessageLogs_GT: adentro la haria ambigua.
78
+ it('rechaza una llave con "#"', async () => {
79
+ const errors = await validate(build({ idempotencyKey: 'run-42#credit-7' }));
80
+ expect(errors.some((e) => e.property === 'idempotencyKey' && e.constraints?.matches)).toBe(true);
81
+ });
82
+
83
+ it('rechaza una llave sin techo', async () => {
84
+ const errors = await validate(build({ idempotencyKey: 'x'.repeat(MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH + 1) }));
85
+ expect(errors.some((e) => e.property === 'idempotencyKey' && e.constraints?.maxLength)).toBe(true);
86
+ });
87
+
88
+ // referenceMessageId trae el id de la CORRIDA, no del mensaje: deduplicar con el aplastaria
89
+ // en uno todos los avisos de un mismo barrido.
90
+ it('referenceMessageId es correlacion y NO tiene las restricciones de la llave', async () => {
91
+ expect(await validate(build({ referenceMessageId: 'run-42#lo-que-sea' }))).toEqual([]);
92
+ });
93
+
94
+ it('ya no acepta messageLogId: era plomeria del lote retirado', () => {
95
+ expect(Object.keys(new NotificationQueueMessageRequestV2())).not.toContain('messageLogId');
96
+ });
97
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Largo maximo de la llave de idempotencia de un mensaje de la cola. Entra en la llave de
3
+ * `MessageLogs_GT`, asi que acotarla es lo que evita una llave sin techo.
4
+ */
5
+ export declare const MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH = 128;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH = void 0;
4
+ /**
5
+ * Largo maximo de la llave de idempotencia de un mensaje de la cola. Entra en la llave de
6
+ * `MessageLogs_GT`, asi que acotarla es lo que evita una llave sin techo.
7
+ */
8
+ exports.MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH = 128;
@@ -11,12 +11,19 @@ export declare class NotificationQueueMessageRequestV2 {
11
11
  directoryId: string;
12
12
  destination: string;
13
13
  variables: Record<string, string>;
14
+ /** Referencia de correlacion del productor. NO deduplica: para eso esta `idempotencyKey`. */
14
15
  referenceMessageId?: string;
15
16
  /**
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.
17
+ * Llave de idempotencia, opcional y explicita. Cuando viaja, messages-business entrega UNA
18
+ * sola vez el trio (tenantId, idempotencyKey, channelType).
19
+ *
20
+ * Va aparte de `referenceMessageId` a proposito: esa referencia identifica la CORRIDA que
21
+ * produjo el mensaje, no al mensaje, asi que usarla para deduplicar aplastaria en uno todos
22
+ * los avisos de un mismo barrido. La llave tiene que distinguir al destinatario.
23
+ *
24
+ * Un `#` en el valor hace ambigua la llave: no se admite.
18
25
  */
19
- messageLogId?: string;
26
+ idempotencyKey?: string;
20
27
  data?: unknown;
21
28
  /** Quien disparo la notificacion. Sin default: su ausencia ya significa EVENT. */
22
29
  origin?: NotificationOriginEnum;
@@ -15,6 +15,7 @@ const class_transformer_1 = require("class-transformer");
15
15
  const DeliveryChannelExtendedEnum_1 = require("../enums/DeliveryChannelExtendedEnum");
16
16
  const NotificationOriginEnum_1 = require("../enums/NotificationOriginEnum");
17
17
  const IsStringValueRecord_1 = require("../validators/IsStringValueRecord");
18
+ const MessageIdempotencyLimits_1 = require("../constants/MessageIdempotencyLimits");
18
19
  class NotificationQueueMessageRequestV2 {
19
20
  }
20
21
  exports.NotificationQueueMessageRequestV2 = NotificationQueueMessageRequestV2;
@@ -82,8 +83,10 @@ __decorate([
82
83
  (0, class_validator_1.IsOptional)(),
83
84
  (0, class_validator_1.IsString)(),
84
85
  (0, class_validator_1.IsNotEmpty)(),
86
+ (0, class_validator_1.MaxLength)(MessageIdempotencyLimits_1.MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH),
87
+ (0, class_validator_1.Matches)(/^[^#]+$/, { message: 'idempotencyKey no puede contener "#"' }),
85
88
  __metadata("design:type", String)
86
- ], NotificationQueueMessageRequestV2.prototype, "messageLogId", void 0);
89
+ ], NotificationQueueMessageRequestV2.prototype, "idempotencyKey", void 0);
87
90
  __decorate([
88
91
  (0, class_transformer_1.Expose)(),
89
92
  (0, class_validator_1.IsOptional)(),
@@ -25,9 +25,4 @@ 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';
28
+ export * from './constants/MessageIdempotencyLimits';
@@ -41,9 +41,4 @@ __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);
44
+ __exportStar(require("./constants/MessageIdempotencyLimits"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.417.0",
3
+ "version": "3.419.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Largo maximo de la llave de idempotencia de un mensaje de la cola. Entra en la llave de
3
+ * `MessageLogs_GT`, asi que acotarla es lo que evita una llave sin techo.
4
+ */
5
+ export const MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH = 128;
@@ -1,8 +1,9 @@
1
- import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, Validate } from 'class-validator';
1
+ import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, Matches, MaxLength, Validate } from 'class-validator';
2
2
  import { Expose } from 'class-transformer';
3
3
  import { DeliveryChannelExtendedEnum } from '../enums/DeliveryChannelExtendedEnum';
4
4
  import { NotificationOriginEnum } from '../enums/NotificationOriginEnum';
5
5
  import { IsStringValueRecord } from '../validators/IsStringValueRecord';
6
+ import { MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH } from '../constants/MessageIdempotencyLimits';
6
7
 
7
8
  export class NotificationQueueMessageRequestV2 {
8
9
  /** Tenant emisor del mensaje. Si se omite, messages-business asume FIADO. */
@@ -50,20 +51,29 @@ export class NotificationQueueMessageRequestV2 {
50
51
  @Validate(IsStringValueRecord)
51
52
  variables!: Record<string, string>;
52
53
 
54
+ /** Referencia de correlacion del productor. NO deduplica: para eso esta `idempotencyKey`. */
53
55
  @Expose()
54
56
  @IsOptional()
55
57
  @IsString()
56
58
  referenceMessageId?: string;
57
59
 
58
60
  /**
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
+ * Llave de idempotencia, opcional y explicita. Cuando viaja, messages-business entrega UNA
62
+ * sola vez el trio (tenantId, idempotencyKey, channelType).
63
+ *
64
+ * Va aparte de `referenceMessageId` a proposito: esa referencia identifica la CORRIDA que
65
+ * produjo el mensaje, no al mensaje, asi que usarla para deduplicar aplastaria en uno todos
66
+ * los avisos de un mismo barrido. La llave tiene que distinguir al destinatario.
67
+ *
68
+ * Un `#` en el valor hace ambigua la llave: no se admite.
61
69
  */
62
70
  @Expose()
63
71
  @IsOptional()
64
72
  @IsString()
65
73
  @IsNotEmpty()
66
- messageLogId?: string;
74
+ @MaxLength(MESSAGE_IDEMPOTENCY_KEY_MAX_LENGTH)
75
+ @Matches(/^[^#]+$/, { message: 'idempotencyKey no puede contener "#"' })
76
+ idempotencyKey?: string;
67
77
 
68
78
  @Expose()
69
79
  @IsOptional()
@@ -25,9 +25,4 @@ 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';
28
+ export * from './constants/MessageIdempotencyLimits';
@@ -1,178 +0,0 @@
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
- });
@@ -1,8 +0,0 @@
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;
@@ -1,11 +0,0 @@
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;
@@ -1,22 +0,0 @@
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
- }
@@ -1,85 +0,0 @@
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);
@@ -1,14 +0,0 @@
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
- }
@@ -1,41 +0,0 @@
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);
@@ -1,5 +0,0 @@
1
- import { SendMessagesBulkResultItem } from './SendMessagesBulkResultItem';
2
- /** Response 202 de `POST /private/messages/bulk`. Un resultado por item enviado. */
3
- export declare class SendMessagesBulkResponse {
4
- results: SendMessagesBulkResultItem[];
5
- }
@@ -1,7 +0,0 @@
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;
@@ -1,11 +0,0 @@
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
- }
@@ -1,7 +0,0 @@
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;
@@ -1,16 +0,0 @@
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
- }
@@ -1,20 +0,0 @@
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 = {}));
@@ -1,9 +0,0 @@
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;
@@ -1,66 +0,0 @@
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
- }
@@ -1,28 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
1
- import { SendMessagesBulkResultItem } from './SendMessagesBulkResultItem';
2
-
3
- /** Response 202 de `POST /private/messages/bulk`. Un resultado por item enviado. */
4
- export class SendMessagesBulkResponse {
5
- results!: SendMessagesBulkResultItem[];
6
- }
@@ -1,16 +0,0 @@
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
- }
@@ -1,16 +0,0 @@
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
- }