plenna_utilities 1.6.0 → 1.7.1

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 (32) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +7 -0
  3. package/dist/src/alerts/application/send-alert-impl.service.d.ts +8 -0
  4. package/dist/src/alerts/application/send-alert-impl.service.js +20 -0
  5. package/dist/src/alerts/domain/interfaces/alerts.d.ts +51 -0
  6. package/dist/src/alerts/domain/interfaces/alerts.js +2 -0
  7. package/dist/src/alerts/domain/services/send-alert.service.d.ts +4 -0
  8. package/dist/src/alerts/domain/services/send-alert.service.js +6 -0
  9. package/dist/src/alerts/domain/usecases/send-alert.usecase.d.ts +9 -0
  10. package/dist/src/alerts/domain/usecases/send-alert.usecase.js +49 -0
  11. package/dist/src/alerts/presenter/index.d.ts +2 -0
  12. package/dist/src/alerts/presenter/index.js +11 -0
  13. package/dist/src/common/domain/alerts/alerts.d.ts +4 -0
  14. package/dist/src/common/domain/alerts/alerts.js +6 -0
  15. package/dist/src/common/domain/configurations/configurations.d.ts +3 -0
  16. package/dist/src/common/domain/configurations/configurations.js +6 -0
  17. package/dist/src/common/domain/interfaces/products.interfaces.d.ts +3 -0
  18. package/dist/src/common/domain/interfaces/products.interfaces.js +7 -0
  19. package/dist/src/common/domain/interfaces/usecases.interface.d.ts +3 -0
  20. package/dist/src/common/domain/interfaces/usecases.interface.js +2 -0
  21. package/dist/src/common/domain/shared/date.transformer.d.ts +4 -0
  22. package/dist/src/common/domain/shared/date.transformer.js +43 -0
  23. package/dist/src/common/domain/shared/index.d.ts +2 -0
  24. package/dist/src/common/domain/shared/index.js +18 -0
  25. package/dist/src/common/domain/shared/interpolation.transformer.d.ts +3 -0
  26. package/dist/src/common/domain/shared/interpolation.transformer.js +16 -0
  27. package/dist/src/common/infrastructure/slack/slack.d.ts +7 -0
  28. package/dist/src/common/infrastructure/slack/slack.js +37 -0
  29. package/dist/src/common/infrastructure/yaml-converter/configurations/slack.yaml +32 -0
  30. package/dist/src/common/infrastructure/yaml-converter/yaml-converter.d.ts +4 -0
  31. package/dist/src/common/infrastructure/yaml-converter/yaml-converter.js +28 -0
  32. package/package.json +10 -5
package/dist/index.d.ts CHANGED
@@ -6,3 +6,5 @@ export * from './src/general';
6
6
  export * from './src/customerio';
7
7
  export * from './src/mailer';
8
8
  export * from './src/airTable';
9
+ export * from './src/alerts/presenter';
10
+ export * from './src/common/domain/shared';
package/dist/index.js CHANGED
@@ -13,7 +13,12 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
13
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
16
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
+ const dotenv_1 = __importDefault(require("dotenv"));
21
+ dotenv_1.default.config();
17
22
  __exportStar(require("./src/lambdas"), exports);
18
23
  __exportStar(require("./src/time"), exports);
19
24
  __exportStar(require("./src/s3"), exports);
@@ -22,3 +27,5 @@ __exportStar(require("./src/general"), exports);
22
27
  __exportStar(require("./src/customerio"), exports);
23
28
  __exportStar(require("./src/mailer"), exports);
24
29
  __exportStar(require("./src/airTable"), exports);
30
+ __exportStar(require("./src/alerts/presenter"), exports);
31
+ __exportStar(require("./src/common/domain/shared"), exports);
@@ -0,0 +1,8 @@
1
+ import { type AlertsHandler } from '../../common/domain/alerts/alerts';
2
+ import { type AlertResponse, type IAlert } from '../domain/interfaces/alerts';
3
+ import { AlertService } from '../domain/services/send-alert.service';
4
+ export declare class AlertServiceImpl extends AlertService {
5
+ private readonly alertImpl;
6
+ constructor(alertImpl: AlertsHandler);
7
+ sendAlert(alert: IAlert): Promise<AlertResponse | undefined>;
8
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AlertServiceImpl = void 0;
4
+ const send_alert_service_1 = require("../domain/services/send-alert.service");
5
+ class AlertServiceImpl extends send_alert_service_1.AlertService {
6
+ alertImpl;
7
+ constructor(alertImpl) {
8
+ super();
9
+ this.alertImpl = alertImpl;
10
+ }
11
+ async sendAlert(alert) {
12
+ try {
13
+ return await this.alertImpl.sendAlert(alert);
14
+ }
15
+ catch (error) {
16
+ console.info(error);
17
+ }
18
+ }
19
+ }
20
+ exports.AlertServiceImpl = AlertServiceImpl;
@@ -0,0 +1,51 @@
1
+ export interface TextObject {
2
+ type: 'plain_text' | 'mrkdwn';
3
+ text: string;
4
+ emoji?: boolean;
5
+ }
6
+ export interface FieldObject {
7
+ type: 'mrkdwn';
8
+ text: string;
9
+ }
10
+ export interface HeaderBlock {
11
+ type: 'header';
12
+ text: TextObject;
13
+ }
14
+ export interface SectionBlock {
15
+ type: 'section';
16
+ text: TextObject;
17
+ fields?: FieldObject[];
18
+ }
19
+ export interface DividerBlock {
20
+ type: 'divider';
21
+ }
22
+ export interface ContextBlock {
23
+ type: 'context';
24
+ elements: TextObject[];
25
+ }
26
+ export type Block = HeaderBlock | SectionBlock | DividerBlock | ContextBlock;
27
+ export interface IAlert {
28
+ channel: string;
29
+ text: string;
30
+ blocks?: Block[];
31
+ threadTs?: string;
32
+ }
33
+ export interface ITemplatesConfiguration {
34
+ templates: Record<string, IAlert>;
35
+ }
36
+ export interface AlertTemplateInput {
37
+ template?: string;
38
+ date?: string;
39
+ reportDate?: string;
40
+ text?: string;
41
+ bookingUser?: string;
42
+ channel?: string;
43
+ origin?: string;
44
+ huliId?: string;
45
+ threadTs?: string;
46
+ toDo?: string;
47
+ }
48
+ export interface AlertResponse {
49
+ channel: string;
50
+ ts: string;
51
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ import { type AlertResponse, type IAlert } from '../interfaces/alerts';
2
+ export declare abstract class AlertService {
3
+ abstract sendAlert(alert: IAlert): Promise<AlertResponse | undefined>;
4
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AlertService = void 0;
4
+ class AlertService {
5
+ }
6
+ exports.AlertService = AlertService;
@@ -0,0 +1,9 @@
1
+ import { type Configuration } from '../../../common/domain/configurations/configurations';
2
+ import { type UseCase } from '../../../common/domain/interfaces/usecases.interface';
3
+ import { type AlertService } from '../services/send-alert.service';
4
+ export declare class SendAlertUseCase implements UseCase {
5
+ private readonly configuration;
6
+ private readonly alertService;
7
+ constructor(configuration: Configuration, alertService: AlertService);
8
+ exec(...args: any[]): Promise<any>;
9
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SendAlertUseCase = void 0;
4
+ const products_interfaces_1 = require("../../../common/domain/interfaces/products.interfaces");
5
+ const interpolation_transformer_1 = require("../../../common/domain/shared/interpolation.transformer");
6
+ class SendAlertUseCase {
7
+ configuration;
8
+ alertService;
9
+ constructor(configuration, alertService) {
10
+ this.configuration = configuration;
11
+ this.alertService = alertService;
12
+ }
13
+ async exec(...args) {
14
+ try {
15
+ const [input] = args;
16
+ const alertData = input;
17
+ if ((0, interpolation_transformer_1.isNonEmpty)(alertData?.channel) || !(0, interpolation_transformer_1.isNonEmpty)(alertData?.template)) {
18
+ const alert = {
19
+ channel: alertData?.channel ?? '',
20
+ text: alertData?.text ?? '',
21
+ threadTs: alertData?.threadTs
22
+ };
23
+ return await this.alertService.sendAlert(alert);
24
+ }
25
+ const getConfiguration = await this.configuration.getConfiguration(products_interfaces_1.Products.SLACK);
26
+ if (getConfiguration === undefined)
27
+ throw new Error('configuration not found');
28
+ const templateKey = alertData.template ?? '';
29
+ const templateInfo = getConfiguration.templates[templateKey];
30
+ if (templateInfo === null && templateInfo === undefined)
31
+ throw new Error('template not found');
32
+ templateInfo.channel = (0, interpolation_transformer_1.isNonEmpty)(alertData?.channel)
33
+ ? alertData.channel ?? ''
34
+ : templateInfo.channel;
35
+ if (templateInfo.blocks !== undefined) {
36
+ templateInfo.blocks.forEach((block) => {
37
+ if (block.type === 'section' && block.fields != null) {
38
+ block.fields = (0, interpolation_transformer_1.interpolateFields)(block.fields, alertData);
39
+ }
40
+ });
41
+ }
42
+ return await this.alertService.sendAlert(templateInfo);
43
+ }
44
+ catch (error) {
45
+ console.error(error);
46
+ }
47
+ }
48
+ }
49
+ exports.SendAlertUseCase = SendAlertUseCase;
@@ -0,0 +1,2 @@
1
+ import { SendAlertUseCase } from '../domain/usecases/send-alert.usecase';
2
+ export declare const sendAlert: SendAlertUseCase;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendAlert = void 0;
4
+ const slack_1 = require("../../common/infrastructure/slack/slack");
5
+ const yaml_converter_1 = require("../../common/infrastructure/yaml-converter/yaml-converter");
6
+ const send_alert_impl_service_1 = require("../application/send-alert-impl.service");
7
+ const send_alert_usecase_1 = require("../domain/usecases/send-alert.usecase");
8
+ const alertImpl = new slack_1.SlackImpl(process.env.SLACK_TOKEN ?? '');
9
+ const configuration = new yaml_converter_1.ConfigurationYaml();
10
+ const alertService = new send_alert_impl_service_1.AlertServiceImpl(alertImpl);
11
+ exports.sendAlert = new send_alert_usecase_1.SendAlertUseCase(configuration, alertService);
@@ -0,0 +1,4 @@
1
+ import { type AlertResponse } from '../../../alerts/domain/interfaces/alerts';
2
+ export declare abstract class AlertsHandler {
3
+ abstract sendAlert(...args: any[]): Promise<AlertResponse | undefined>;
4
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AlertsHandler = void 0;
4
+ class AlertsHandler {
5
+ }
6
+ exports.AlertsHandler = AlertsHandler;
@@ -0,0 +1,3 @@
1
+ export declare abstract class Configuration {
2
+ abstract getConfiguration<T>(product: string, customPath?: string): Promise<T | undefined>;
3
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Configuration = void 0;
4
+ class Configuration {
5
+ }
6
+ exports.Configuration = Configuration;
@@ -0,0 +1,3 @@
1
+ export declare enum Products {
2
+ SLACK = "slack"
3
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Products = void 0;
4
+ var Products;
5
+ (function (Products) {
6
+ Products["SLACK"] = "slack";
7
+ })(Products || (exports.Products = Products = {}));
@@ -0,0 +1,3 @@
1
+ export interface UseCase {
2
+ exec: (...args: any[]) => Promise<any>;
3
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ export declare const formatDate: (isoDate: string) => string;
2
+ export declare const formatHour: (time24: string) => string;
3
+ export declare const getDifferenceInMinutes: (startTime: string, endTime: string) => number;
4
+ export declare const formatIsoDateToSpanish: (isoString: string) => string;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatIsoDateToSpanish = exports.getDifferenceInMinutes = exports.formatHour = exports.formatDate = void 0;
4
+ const formatDate = (isoDate) => {
5
+ const date = new Date(isoDate);
6
+ return date.toLocaleDateString('es-ES', {
7
+ day: 'numeric',
8
+ month: 'long',
9
+ year: 'numeric'
10
+ });
11
+ };
12
+ exports.formatDate = formatDate;
13
+ const formatHour = (time24) => {
14
+ const [hours, minutes, seconds] = time24.split(':').map(Number);
15
+ const date = new Date();
16
+ date.setHours(hours, minutes, seconds);
17
+ return date.toLocaleTimeString('es-ES', {
18
+ hour: 'numeric',
19
+ minute: '2-digit',
20
+ hour12: true
21
+ });
22
+ };
23
+ exports.formatHour = formatHour;
24
+ const getDifferenceInMinutes = (startTime, endTime) => {
25
+ const [h1, m1, s1] = startTime.split(':').map(Number);
26
+ const [h2, m2, s2] = endTime.split(':').map(Number);
27
+ const startDate = new Date();
28
+ startDate.setHours(h1, m1, s1, 0);
29
+ const endDate = new Date();
30
+ endDate.setHours(h2, m2, s2, 0);
31
+ const diffMs = endDate.getTime() - startDate.getTime();
32
+ return Math.floor(diffMs / 60000);
33
+ };
34
+ exports.getDifferenceInMinutes = getDifferenceInMinutes;
35
+ const formatIsoDateToSpanish = (isoString) => {
36
+ const date = new Date(isoString);
37
+ return date.toLocaleDateString('es-ES', {
38
+ day: 'numeric',
39
+ month: 'long',
40
+ year: 'numeric'
41
+ });
42
+ };
43
+ exports.formatIsoDateToSpanish = formatIsoDateToSpanish;
@@ -0,0 +1,2 @@
1
+ export * from './date.transformer';
2
+ export * from './interpolation.transformer';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./date.transformer"), exports);
18
+ __exportStar(require("./interpolation.transformer"), exports);
@@ -0,0 +1,3 @@
1
+ import { type AlertTemplateInput, type FieldObject } from '../../../alerts/domain/interfaces/alerts';
2
+ export declare function interpolateFields(fields: FieldObject[], input: AlertTemplateInput): FieldObject[];
3
+ export declare const isNonEmpty: (value?: string) => boolean;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isNonEmpty = void 0;
4
+ exports.interpolateFields = interpolateFields;
5
+ function interpolateFields(fields, input) {
6
+ return fields.map((field) => {
7
+ let text = field.text;
8
+ text = text.replace(/\{(\w+)\}/g, (_, key) => {
9
+ const value = input[key];
10
+ return value ?? `{${key}}`;
11
+ });
12
+ return { ...field, text };
13
+ });
14
+ }
15
+ const isNonEmpty = (value) => { return value !== '' && value !== undefined; };
16
+ exports.isNonEmpty = isNonEmpty;
@@ -0,0 +1,7 @@
1
+ import { type AlertResponse } from '../../../alerts/domain/interfaces/alerts';
2
+ import { AlertsHandler } from '../../domain/alerts/alerts';
3
+ export declare class SlackImpl extends AlertsHandler {
4
+ private readonly client;
5
+ constructor(token: string);
6
+ sendAlert(...args: any[]): Promise<AlertResponse | undefined>;
7
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlackImpl = void 0;
4
+ const alerts_1 = require("../../domain/alerts/alerts");
5
+ const web_api_1 = require("@slack/web-api");
6
+ class SlackImpl extends alerts_1.AlertsHandler {
7
+ client;
8
+ constructor(token) {
9
+ super();
10
+ this.client = new web_api_1.WebClient(token);
11
+ }
12
+ async sendAlert(...args) {
13
+ try {
14
+ const [input] = args;
15
+ const data = input;
16
+ const { channel, text, blocks, threadTs } = data;
17
+ if (typeof channel !== 'string' || channel.trim() === '' ||
18
+ typeof text !== 'string' || text.trim() === '') {
19
+ return;
20
+ }
21
+ const response = await this.client.chat.postMessage({
22
+ channel,
23
+ text,
24
+ blocks,
25
+ thread_ts: threadTs
26
+ });
27
+ return {
28
+ channel: response?.channel ?? '',
29
+ ts: response?.ts ?? ''
30
+ };
31
+ }
32
+ catch (error) {
33
+ console.info(JSON.stringify(error));
34
+ }
35
+ }
36
+ }
37
+ exports.SlackImpl = SlackImpl;
@@ -0,0 +1,32 @@
1
+ templates:
2
+ noInfo:
3
+ channel: 'C08S575SWCF'
4
+ text: '🚨 Error de Agenda'
5
+ blocks:
6
+ - type: header
7
+ text:
8
+ type: plain_text
9
+ text: '🚨 Error de Agenda'
10
+ emoji: true
11
+ - type: section
12
+ text:
13
+ type: mrkdwn
14
+ text: '*Motivo:* Se creó una cita en Huli con información errónea, por lo que esta agenda no es válida.'
15
+ fields:
16
+ - type: mrkdwn
17
+ text: "*ID de cita en Huli:*\n{huliId}"
18
+ - type: mrkdwn
19
+ text: "*Persona que intentó agendar:*\n<{bookingUser}>"
20
+ - type: mrkdwn
21
+ text: "*Fecha y hora de la cita:*\n{date}"
22
+ - type: mrkdwn
23
+ text: "*¿Qué pasó?:*\n{text}"
24
+ - type: mrkdwn
25
+ text: "*¿Qué debes hacer?:*\n{toDo}"
26
+ - type: mrkdwn
27
+ text: "*Fecha de reporte:*\n{reportDate}"
28
+ - type: divider
29
+ - type: context
30
+ elements:
31
+ - type: mrkdwn
32
+ text: 'Generado automáticamente por el sistema de validación de agendas.'
@@ -0,0 +1,4 @@
1
+ import { Configuration } from '../../../common/domain/configurations/configurations';
2
+ export declare class ConfigurationYaml extends Configuration {
3
+ getConfiguration<T>(product: string, customPath?: string): Promise<T | undefined>;
4
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ConfigurationYaml = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const yaml_1 = __importDefault(require("yaml"));
10
+ const configurations_1 = require("../../../common/domain/configurations/configurations");
11
+ class ConfigurationYaml extends configurations_1.Configuration {
12
+ async getConfiguration(product, customPath) {
13
+ try {
14
+ const finalPath = typeof customPath === 'string' && customPath.trim() !== ''
15
+ ? path_1.default.resolve(customPath)
16
+ : path_1.default.resolve(__dirname, 'configurations');
17
+ const yamlFilePath = path_1.default.join(finalPath, `${product.replace(/ /g, '_').toLocaleLowerCase()}.yaml`);
18
+ const yamlContent = fs_1.default.readFileSync(yamlFilePath, 'utf-8');
19
+ const yamlObject = yaml_1.default.parse(yamlContent);
20
+ return yamlObject;
21
+ }
22
+ catch (error) {
23
+ console.error(`Error loading YAML configuration for ${product}:`, error);
24
+ return undefined;
25
+ }
26
+ }
27
+ }
28
+ exports.ConfigurationYaml = ConfigurationYaml;
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "plenna_utilities",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "plenna's utils for backend projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
- "dist/"
8
+ "dist/**/*"
9
9
  ],
10
10
  "scripts": {
11
- "lint": "rm -rf dist && eslint '**/*.{ts,tsx}'",
12
- "build": "npm run lint && tsc"
11
+ "lint": "eslint '**/*.{ts,tsx}' --fix",
12
+ "build": "npm run lint && tsc && npm run copy-assets",
13
+ "copy-assets": "npx copyfiles -u 1 \"src/**/*.yaml\" dist/src/"
13
14
  },
14
15
  "repository": {
15
16
  "type": "git"
@@ -30,6 +31,7 @@
30
31
  "eslint-plugin-import": "^2.29.1",
31
32
  "eslint-plugin-n": "^16.6.2",
32
33
  "eslint-plugin-promise": "^6.1.1",
34
+ "@types/yamljs": "^0.2.34",
33
35
  "typescript": "^5.4.5"
34
36
  },
35
37
  "dependencies": {
@@ -39,6 +41,9 @@
39
41
  "@googleapis/drive": "^8.10.0",
40
42
  "@googleapis/sheets": "^8.0.0",
41
43
  "customerio-node": "^4.1.1",
42
- "google-auth-library": "^9.11.0"
44
+ "google-auth-library": "^9.11.0",
45
+ "yaml": "^2.3.0",
46
+ "@slack/web-api": "^6.9.1",
47
+ "dotenv": "^16.4.5"
43
48
  }
44
49
  }