@fiado/api-invoker 5.149.0 → 5.150.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 (25) hide show
  1. package/bin/container.config.js +2 -0
  2. package/bin/index.d.ts +1 -0
  3. package/bin/index.js +1 -0
  4. package/bin/meeting-connector/api/MeetingConnectorApi.d.ts +14 -0
  5. package/bin/meeting-connector/api/MeetingConnectorApi.js +55 -0
  6. package/bin/meeting-connector/api/interfaces/IMeetingConnectorApi.d.ts +83 -0
  7. package/bin/meeting-connector/api/interfaces/IMeetingConnectorApi.js +5 -0
  8. package/bin/meeting-connector/index.d.ts +2 -0
  9. package/bin/meeting-connector/index.js +2 -0
  10. package/bin/onboarding-business/api/OnboardingBusinessApi.d.ts +6 -8
  11. package/bin/onboarding-business/api/OnboardingBusinessApi.js +16 -6
  12. package/bin/onboarding-business/api/interfaces/IOnboardingBusinessApi.d.ts +25 -9
  13. package/bin/usmarketgrowth-business/UsMarketGrowthBusinessApi.d.ts +2 -1
  14. package/bin/usmarketgrowth-business/UsMarketGrowthBusinessApi.js +4 -0
  15. package/bin/usmarketgrowth-business/interfaces/IUsMarketGrowthBusinessApi.d.ts +6 -1
  16. package/package.json +1 -1
  17. package/src/container.config.ts +3 -0
  18. package/src/index.ts +1 -0
  19. package/src/meeting-connector/api/MeetingConnectorApi.ts +51 -0
  20. package/src/meeting-connector/api/interfaces/IMeetingConnectorApi.ts +52 -0
  21. package/src/meeting-connector/index.ts +2 -0
  22. package/src/onboarding-business/api/OnboardingBusinessApi.ts +19 -8
  23. package/src/onboarding-business/api/interfaces/IOnboardingBusinessApi.ts +27 -6
  24. package/src/usmarketgrowth-business/UsMarketGrowthBusinessApi.ts +6 -1
  25. package/src/usmarketgrowth-business/interfaces/IUsMarketGrowthBusinessApi.ts +7 -1
@@ -79,6 +79,7 @@ import ReportProcessorBusinessApi from "./report-processor-business/api/ReportPr
79
79
  import NotificationWSMessagePublisher from "./notificationWebsockets/queue/NotificationWSMessagePublisher.js";
80
80
  import PeopleBusinessApi from "./people-business/api/PeopleBusinessApi.js";
81
81
  import DatalakeReportsApi from "./datalake-reports-business/api/DatalakeReportsApi.js";
82
+ import MeetingConnectorApi from "./meeting-connector/api/MeetingConnectorApi.js";
82
83
  import PlacesBusinessApi from "./places-business/api/PlacesBusinessApi.js";
83
84
  import STPBusinessApi from "./stp-business/api/STPBusinessApi.js";
84
85
  import MulticommServicePaymentApi from "./multicommServicePayment/api/MulticommServicePaymentApi.js";
@@ -237,6 +238,7 @@ export const apiInvokerBindings = new ContainerModule(({ bind }) => {
237
238
  bind("IReportProcessorBusinessApi").to(ReportProcessorBusinessApi);
238
239
  bind("IPeopleBusinessApi").to(PeopleBusinessApi);
239
240
  bind("IDatalakeReportsApi").to(DatalakeReportsApi);
241
+ bind("IMeetingConnectorApi").to(MeetingConnectorApi);
240
242
  bind("IPlacesBusinessApi").to(PlacesBusinessApi);
241
243
  bind("ISTPBusinessApi").to(STPBusinessApi);
242
244
  bind("IProductPaymentApi").to(ProductPaymentApi);
package/bin/index.d.ts CHANGED
@@ -69,6 +69,7 @@ export * from "./report-processor-business/index.js";
69
69
  export * from "./notificationWebsockets/index.js";
70
70
  export * from "./people-business/index.js";
71
71
  export * from "./datalake-reports-business/index.js";
72
+ export * from "./meeting-connector/index.js";
72
73
  export * from "./places-business/index.js";
73
74
  export * from "./stp-business/index.js";
74
75
  export * from "./multicommServicePayment/index.js";
package/bin/index.js CHANGED
@@ -69,6 +69,7 @@ export * from "./report-processor-business/index.js";
69
69
  export * from "./notificationWebsockets/index.js";
70
70
  export * from "./people-business/index.js";
71
71
  export * from "./datalake-reports-business/index.js";
72
+ export * from "./meeting-connector/index.js";
72
73
  export * from "./places-business/index.js";
73
74
  export * from "./stp-business/index.js";
74
75
  export * from "./multicommServicePayment/index.js";
@@ -0,0 +1,14 @@
1
+ import type { IHttpRequest } from "@fiado/http-client";
2
+ import type { IMeetingConnectorApi, MeetingConnectorCreated, MeetingConnectorCreateRequest, MeetingConnectorHost, MeetingConnectorParticipant, MeetingConnectorPollAnswer, MeetingConnectorRegistrant } from "./interfaces/IMeetingConnectorApi.js";
3
+ export default class MeetingConnectorApi implements IMeetingConnectorApi {
4
+ private httpRequest;
5
+ private readonly baseUrl;
6
+ constructor(httpRequest: IHttpRequest);
7
+ getHosts(): Promise<MeetingConnectorHost[]>;
8
+ createMeeting(request: MeetingConnectorCreateRequest): Promise<MeetingConnectorCreated>;
9
+ getStartUrl(externalMeetingId: string): Promise<string>;
10
+ getRegistrant(externalMeetingId: string, registrantId: string): Promise<MeetingConnectorRegistrant | undefined>;
11
+ /** El uuid de una sesión puede traer '/' o '=': va codificado (el connector lo decodifica una vez). */
12
+ getSessionParticipants(sessionId: string): Promise<MeetingConnectorParticipant[]>;
13
+ getSessionPolls(sessionId: string): Promise<MeetingConnectorPollAnswer[] | undefined>;
14
+ }
@@ -0,0 +1,55 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from "inversify";
14
+ const datoDe = (sobre) => (sobre && typeof sobre === "object" && "data" in sobre ? sobre.data : sobre);
15
+ let MeetingConnectorApi = class MeetingConnectorApi {
16
+ httpRequest;
17
+ baseUrl = process.env.MEETING_CONNECTOR_LAMBDA_URL || "";
18
+ constructor(httpRequest) {
19
+ this.httpRequest = httpRequest;
20
+ }
21
+ async getHosts() {
22
+ const r = await this.httpRequest.get(`${this.baseUrl}hosts`);
23
+ return datoDe(r)?.items ?? [];
24
+ }
25
+ async createMeeting(request) {
26
+ const r = await this.httpRequest.post(`${this.baseUrl}meetings`, request);
27
+ return datoDe(r);
28
+ }
29
+ async getStartUrl(externalMeetingId) {
30
+ const r = await this.httpRequest.get(`${this.baseUrl}meetings/${encodeURIComponent(externalMeetingId)}/start-url`);
31
+ return datoDe(r)?.startUrl ?? "";
32
+ }
33
+ async getRegistrant(externalMeetingId, registrantId) {
34
+ const r = await this.httpRequest.get(`${this.baseUrl}meetings/${encodeURIComponent(externalMeetingId)}/registrants/${encodeURIComponent(registrantId)}`);
35
+ return datoDe(r) ?? undefined;
36
+ }
37
+ /** El uuid de una sesión puede traer '/' o '=': va codificado (el connector lo decodifica una vez). */
38
+ async getSessionParticipants(sessionId) {
39
+ const r = await this.httpRequest.get(`${this.baseUrl}sessions/${encodeURIComponent(encodeURIComponent(sessionId))}/participants`);
40
+ return datoDe(r)?.items ?? [];
41
+ }
42
+ async getSessionPolls(sessionId) {
43
+ const r = await this.httpRequest.get(`${this.baseUrl}sessions/${encodeURIComponent(encodeURIComponent(sessionId))}/polls`);
44
+ const datos = datoDe(r);
45
+ if (!datos || datos.ready === false)
46
+ return undefined;
47
+ return datos.items ?? [];
48
+ }
49
+ };
50
+ MeetingConnectorApi = __decorate([
51
+ injectable(),
52
+ __param(0, inject("IHttpRequest")),
53
+ __metadata("design:paramtypes", [Object])
54
+ ], MeetingConnectorApi);
55
+ export default MeetingConnectorApi;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * El contrato agnóstico de meeting-connector (la envoltura del proveedor de reuniones; hoy Zoom,
3
+ * Teams después): nada acá nombra al proveedor. Lo consume meetings-business.
4
+ */
5
+ export type MeetingConnectorHost = {
6
+ email: string;
7
+ name?: string;
8
+ licensed: boolean;
9
+ };
10
+ export type MeetingConnectorCreateRequest = {
11
+ hostEmail: string;
12
+ title: string;
13
+ agenda?: string;
14
+ startsAt: string;
15
+ durationMinutes: number;
16
+ timezone: string;
17
+ registrationRequired: boolean;
18
+ phoneRequired: boolean;
19
+ registrationQuestions?: Array<{
20
+ ref: string;
21
+ text: string;
22
+ required?: boolean;
23
+ dataType?: string;
24
+ }>;
25
+ polls?: Array<{
26
+ title: string;
27
+ questions: Array<{
28
+ ref: string;
29
+ text: string;
30
+ type: string;
31
+ options?: string[];
32
+ }>;
33
+ }>;
34
+ };
35
+ export type MeetingConnectorCreated = {
36
+ externalMeetingId: string;
37
+ registrationUrl?: string;
38
+ joinUrl?: string;
39
+ polls?: Array<{
40
+ title: string;
41
+ externalPollId: string;
42
+ }>;
43
+ };
44
+ export type MeetingConnectorParticipant = {
45
+ participantId: string;
46
+ registrantId?: string;
47
+ name?: string;
48
+ email?: string;
49
+ joinedAt: string;
50
+ leftAt?: string;
51
+ durationSeconds?: number;
52
+ };
53
+ export type MeetingConnectorPollAnswer = {
54
+ name?: string;
55
+ email?: string;
56
+ answers: Array<{
57
+ question: string;
58
+ answer: string;
59
+ externalPollId?: string;
60
+ respondedAt?: string;
61
+ }>;
62
+ };
63
+ export type MeetingConnectorRegistrant = {
64
+ registrantId: string;
65
+ name?: string;
66
+ email?: string;
67
+ phoneNumber?: string;
68
+ answers?: Array<{
69
+ question: string;
70
+ answer: string;
71
+ }>;
72
+ };
73
+ export interface IMeetingConnectorApi {
74
+ getHosts(): Promise<MeetingConnectorHost[]>;
75
+ /** Si algo falla en la plataforma, el connector borra y no queda nada a medias. */
76
+ createMeeting(request: MeetingConnectorCreateRequest): Promise<MeetingConnectorCreated>;
77
+ /** El link del anfitrión vence a las 2 horas: se pide uno nuevo cada vez. */
78
+ getStartUrl(externalMeetingId: string): Promise<string>;
79
+ getRegistrant(externalMeetingId: string, registrantId: string): Promise<MeetingConnectorRegistrant | undefined>;
80
+ getSessionParticipants(sessionId: string): Promise<MeetingConnectorParticipant[]>;
81
+ /** undefined = la plataforma todavía no los tiene listos: reintentar después. */
82
+ getSessionPolls(sessionId: string): Promise<MeetingConnectorPollAnswer[] | undefined>;
83
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * El contrato agnóstico de meeting-connector (la envoltura del proveedor de reuniones; hoy Zoom,
3
+ * Teams después): nada acá nombra al proveedor. Lo consume meetings-business.
4
+ */
5
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './api/interfaces/IMeetingConnectorApi.js';
2
+ export { default as MeetingConnectorApi } from './api/MeetingConnectorApi.js';
@@ -0,0 +1,2 @@
1
+ export * from './api/interfaces/IMeetingConnectorApi.js';
2
+ export { default as MeetingConnectorApi } from './api/MeetingConnectorApi.js';
@@ -1,5 +1,5 @@
1
1
  import type { IHttpRequest } from "@fiado/http-client";
2
- import type { IOnboardingBusinessApi } from "./interfaces/IOnboardingBusinessApi.js";
2
+ import type { IOnboardingBusinessApi, OnboardingAssignTagParams, OnboardingTagSubject } from "./interfaces/IOnboardingBusinessApi.js";
3
3
  export default class OnboardingBusinessApi implements IOnboardingBusinessApi {
4
4
  private httpRequest;
5
5
  private readonly baseUrl;
@@ -25,13 +25,11 @@ export default class OnboardingBusinessApi implements IOnboardingBusinessApi {
25
25
  pageSize?: string;
26
26
  }): Promise<any>;
27
27
  getBatchByIds(ids: string[]): Promise<any>;
28
- tagsSummary(): Promise<any>;
29
- tagsByDirectories(directoryIds: string[]): Promise<any>;
30
- getUsersByTag(tag: string, pageSize?: number, index?: string): Promise<any>;
31
- assignTag(params: {
32
- directoryId: string;
33
- tag: string;
34
- }): Promise<any>;
28
+ tagsSummary(subject?: OnboardingTagSubject): Promise<any>;
29
+ tagsByDirectories(directoryIds: string[], subject?: OnboardingTagSubject): Promise<any>;
30
+ getUsersByTag(tag: string, pageSize?: number, index?: string, subject?: OnboardingTagSubject): Promise<any>;
31
+ removeTag(id: string, subject?: OnboardingTagSubject): Promise<any>;
32
+ assignTag(params: OnboardingAssignTagParams): Promise<any>;
35
33
  issuanceReadiness(params: {
36
34
  directoryId: string;
37
35
  side: string;
@@ -93,25 +93,35 @@ let OnboardingBusinessApi = class OnboardingBusinessApi {
93
93
  const url = `${this.baseUrl}private/getBatchByIds`;
94
94
  return await this.httpRequest.get(`${url}`, { ids });
95
95
  }
96
- async tagsSummary() {
97
- const url = `${this.baseUrl}private/tags/summary`;
96
+ async tagsSummary(subject) {
97
+ const url = `${this.baseUrl}private/tags/summary${subject ? `?subject=${subject}` : ''}`;
98
98
  return await this.httpRequest.get(`${url}`);
99
99
  }
100
- async tagsByDirectories(directoryIds) {
100
+ async tagsByDirectories(directoryIds, subject) {
101
101
  const url = `${this.baseUrl}private/tags/by-directories`;
102
- return await this.httpRequest.post(`${url}`, { directoryIds });
102
+ const body = subject === 'lead' ? { subject, leadIds: directoryIds } : { directoryIds };
103
+ return await this.httpRequest.post(`${url}`, body);
103
104
  }
104
- async getUsersByTag(tag, pageSize = 200, index) {
105
+ async getUsersByTag(tag, pageSize = 200, index, subject) {
105
106
  const queryParams = [`pageSize=${pageSize}`];
106
107
  if (index) {
107
108
  queryParams.push(`index=${encodeURIComponent(index)}`);
108
109
  }
110
+ if (subject) {
111
+ queryParams.push(`subject=${subject}`);
112
+ }
109
113
  const url = `${this.baseUrl}private/tags/${encodeURIComponent(tag)}/users?${queryParams.join('&')}`;
110
114
  return await this.httpRequest.get(`${url}`);
111
115
  }
116
+ async removeTag(id, subject) {
117
+ const url = `${this.baseUrl}private/tags/${encodeURIComponent(id)}${subject ? `?subject=${subject}` : ''}`;
118
+ return await this.httpRequest.delete(`${url}`);
119
+ }
112
120
  async assignTag(params) {
113
121
  const url = `${this.baseUrl}private/tags`;
114
- return await this.httpRequest.post(`${url}`, { directoryId: params.directoryId, tag: params.tag });
122
+ // Sólo viajan los campos presentes: sin subject el cuerpo es el de siempre, { directoryId, tag }.
123
+ const body = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== undefined));
124
+ return await this.httpRequest.post(`${url}`, body);
115
125
  }
116
126
  //**
117
127
  // Function: issuanceReadiness
@@ -1,3 +1,19 @@
1
+ /**
2
+ * A quién se le pone la etiqueta: `user` (UserTags_GT, por directoryId) es el default de siempre;
3
+ * `lead` (LeadTags_GT, por leadId) es de los leads de meetings-business.
4
+ */
5
+ export type OnboardingTagSubject = "user" | "lead";
6
+ /** Con `subject` lead van `leadId`, `phoneNumber` y quién la puso; sin subject, `directoryId` como siempre. */
7
+ export interface OnboardingAssignTagParams {
8
+ subject?: OnboardingTagSubject;
9
+ directoryId?: string;
10
+ leadId?: string;
11
+ tag: string;
12
+ phoneNumber?: string;
13
+ source?: "RULE" | "MANUAL";
14
+ meetingId?: string;
15
+ addedBy?: string;
16
+ }
1
17
  export interface IOnboardingBusinessApi {
2
18
  getById(id: string): Promise<any>;
3
19
  getByPhoneNumber(phoneNumber: string): Promise<any>;
@@ -20,8 +36,8 @@ export interface IOnboardingBusinessApi {
20
36
  pageSize?: string;
21
37
  }): Promise<any>;
22
38
  getBatchByIds(ids: string[]): Promise<any>;
23
- /** Dashboard Ops Segmentos — tags distintos + count c/u (TagsSummaryResponse en data). */
24
- tagsSummary(): Promise<any>;
39
+ /** Dashboard Ops Segmentos — tags distintos + count c/u (TagsSummaryResponse en data). Con `lead`, los de los leads. */
40
+ tagsSummary(subject?: OnboardingTagSubject): Promise<any>;
25
41
  /** Dashboard Ops Segmentos — tags por usuario para un batch de directoryIds (TagsByDirectoriesResponse en data). */
26
42
  /**
27
43
  * Directorios que tienen un tag, paginado.
@@ -32,13 +48,13 @@ export interface IOnboardingBusinessApi {
32
48
  * Es el inverso de `tagsByDirectories` (ese da los tags DE unos directorios; éste da
33
49
  * los directorios CON un tag). Consumido por `direct-deposit-export-business`.
34
50
  */
35
- getUsersByTag(tag: string, pageSize?: number, index?: string): Promise<any>;
36
- tagsByDirectories(directoryIds: string[]): Promise<any>;
37
- /** Asigna un tag a un directoryId. Idempotente: si ya estaba responde 200 con alreadyAssigned true. */
38
- assignTag(params: {
39
- directoryId: string;
40
- tag: string;
41
- }): Promise<any>;
51
+ getUsersByTag(tag: string, pageSize?: number, index?: string, subject?: OnboardingTagSubject): Promise<any>;
52
+ /** Con `lead`, `directoryIds` son leadIds y viajan como `leadIds`. */
53
+ tagsByDirectories(directoryIds: string[], subject?: OnboardingTagSubject): Promise<any>;
54
+ /** Asigna un tag a un directoryId (o a un lead con `subject` lead). Idempotente: si ya estaba responde 200 con alreadyAssigned true. */
55
+ assignTag(params: OnboardingAssignTagParams): Promise<any>;
56
+ /** Quita un tag por su id compuesto (`${directoryId}-${tag}`, o `${leadId}-${tag}` con `subject` lead). Idempotente. */
57
+ removeTag(id: string, subject?: OnboardingTagSubject): Promise<any>;
42
58
  /**
43
59
  * ¿Este expediente cumple los requisitos para emitir el lado indicado?
44
60
  *
@@ -1,5 +1,5 @@
1
1
  import type { IHttpRequest } from "@fiado/http-client";
2
- import type { PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
2
+ import type { CreatePromoterFromLeadRequest, PostPromoterFromLeadResponse, PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
3
3
  import { IUsMarketGrowthBusinessApi } from "./interfaces/IUsMarketGrowthBusinessApi.js";
4
4
  type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
5
5
  export declare class UsMarketGrowthBusinessApi implements IUsMarketGrowthBusinessApi {
@@ -7,5 +7,6 @@ export declare class UsMarketGrowthBusinessApi implements IUsMarketGrowthBusines
7
7
  private readonly baseUrl;
8
8
  constructor(httpRequest: IHttpRequest);
9
9
  getPromoterByDirectoryId(directoryId: string): Promise<FiadoApiResponse<PromoterByDirectoryIdResponse>>;
10
+ createPromoterFromLead(request: CreatePromoterFromLeadRequest): Promise<FiadoApiResponse<PostPromoterFromLeadResponse>>;
10
11
  }
11
12
  export {};
@@ -24,6 +24,10 @@ let UsMarketGrowthBusinessApi = class UsMarketGrowthBusinessApi {
24
24
  const url = joinUrl(this.baseUrl, `private/promoters/directoryId/${encodeURIComponent(directoryId)}`);
25
25
  return await this.httpRequest.get(url);
26
26
  }
27
+ async createPromoterFromLead(request) {
28
+ const url = joinUrl(this.baseUrl, "private/promoters/from-lead");
29
+ return await this.httpRequest.post(url, request);
30
+ }
27
31
  };
28
32
  UsMarketGrowthBusinessApi = __decorate([
29
33
  injectable(),
@@ -1,5 +1,5 @@
1
1
  type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
2
- import type { PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
2
+ import type { CreatePromoterFromLeadRequest, PostPromoterFromLeadResponse, PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
3
3
  /**
4
4
  * Cliente de `usmarketgrowth-business` (promotores de US Market Growth).
5
5
  *
@@ -13,5 +13,10 @@ export interface IUsMarketGrowthBusinessApi {
13
13
  * @param directoryId ID del directorio.
14
14
  */
15
15
  getPromoterByDirectoryId(directoryId: string): Promise<FiadoApiResponse<PromoterByDirectoryIdResponse>>;
16
+ /**
17
+ * 4.5 del plan de reuniones: promotor a partir de un lead, idempotente por teléfono o correo
18
+ * (dos llamadas con el mismo contacto devuelven el mismo promoterId; EXISTING no toca nada).
19
+ */
20
+ createPromoterFromLead(request: CreatePromoterFromLeadRequest): Promise<FiadoApiResponse<PostPromoterFromLeadResponse>>;
16
21
  }
17
22
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/api-invoker",
3
- "version": "5.149.0",
3
+ "version": "5.150.0",
4
4
  "description": "Sirve como un puente entre diferentes funciones lambda, facilitando la comunicación entre ellas a través de invocaciones http",
5
5
  "type": "module",
6
6
  "main": "bin/index.js",
@@ -113,6 +113,8 @@ import { INotificationWSMessagesPublisher } from "./notificationWebsockets/index
113
113
  import NotificationWSMessagePublisher from "./notificationWebsockets/queue/NotificationWSMessagePublisher.js";
114
114
  import PeopleBusinessApi from "./people-business/api/PeopleBusinessApi.js";
115
115
  import DatalakeReportsApi from "./datalake-reports-business/api/DatalakeReportsApi.js";
116
+ import MeetingConnectorApi from "./meeting-connector/api/MeetingConnectorApi.js";
117
+ import { IMeetingConnectorApi } from "./meeting-connector/index.js";
116
118
  import { IDatalakeReportsApi } from "./datalake-reports-business/index.js";
117
119
  import { IPeopleBusinessApi } from "./people-business/index.js";
118
120
  import PlacesBusinessApi from "./places-business/api/PlacesBusinessApi.js";
@@ -311,6 +313,7 @@ export const apiInvokerBindings = new ContainerModule(({ bind }) => {
311
313
  bind<IReportProcessorBusinessApi>("IReportProcessorBusinessApi").to(ReportProcessorBusinessApi);
312
314
  bind<IPeopleBusinessApi>("IPeopleBusinessApi").to(PeopleBusinessApi);
313
315
  bind<IDatalakeReportsApi>("IDatalakeReportsApi").to(DatalakeReportsApi);
316
+ bind<IMeetingConnectorApi>("IMeetingConnectorApi").to(MeetingConnectorApi);
314
317
  bind<IPlacesBusinessApi>("IPlacesBusinessApi").to(PlacesBusinessApi);
315
318
  bind<ISTPBusinessApi>("ISTPBusinessApi").to(STPBusinessApi);
316
319
  bind<IProductPaymentApi>("IProductPaymentApi").to(ProductPaymentApi);
package/src/index.ts CHANGED
@@ -69,6 +69,7 @@ export * from "./report-processor-business/index.js";
69
69
  export * from "./notificationWebsockets/index.js";
70
70
  export * from "./people-business/index.js";
71
71
  export * from "./datalake-reports-business/index.js";
72
+ export * from "./meeting-connector/index.js";
72
73
  export * from "./places-business/index.js";
73
74
  export * from "./stp-business/index.js";
74
75
  export * from "./multicommServicePayment/index.js";
@@ -0,0 +1,51 @@
1
+ import { inject, injectable } from "inversify";
2
+ import type { IHttpRequest } from "@fiado/http-client";
3
+ import type {
4
+ IMeetingConnectorApi, MeetingConnectorCreated, MeetingConnectorCreateRequest, MeetingConnectorHost,
5
+ MeetingConnectorParticipant, MeetingConnectorPollAnswer, MeetingConnectorRegistrant,
6
+ } from "./interfaces/IMeetingConnectorApi.js";
7
+
8
+ type Sobre<T> = { data: T } | T;
9
+ const datoDe = <T>(sobre: Sobre<T>): T => (sobre && typeof sobre === "object" && "data" in (sobre as object) ? (sobre as { data: T }).data : (sobre as T));
10
+
11
+ @injectable()
12
+ export default class MeetingConnectorApi implements IMeetingConnectorApi {
13
+
14
+ private readonly baseUrl = process.env.MEETING_CONNECTOR_LAMBDA_URL || "";
15
+
16
+ constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {
17
+ }
18
+
19
+ async getHosts(): Promise<MeetingConnectorHost[]> {
20
+ const r = await this.httpRequest.get(`${this.baseUrl}hosts`);
21
+ return datoDe<{ items: MeetingConnectorHost[] }>(r as never)?.items ?? [];
22
+ }
23
+
24
+ async createMeeting(request: MeetingConnectorCreateRequest): Promise<MeetingConnectorCreated> {
25
+ const r = await this.httpRequest.post(`${this.baseUrl}meetings`, request);
26
+ return datoDe<MeetingConnectorCreated>(r as never);
27
+ }
28
+
29
+ async getStartUrl(externalMeetingId: string): Promise<string> {
30
+ const r = await this.httpRequest.get(`${this.baseUrl}meetings/${encodeURIComponent(externalMeetingId)}/start-url`);
31
+ return datoDe<{ startUrl: string }>(r as never)?.startUrl ?? "";
32
+ }
33
+
34
+ async getRegistrant(externalMeetingId: string, registrantId: string): Promise<MeetingConnectorRegistrant | undefined> {
35
+ const r = await this.httpRequest.get(`${this.baseUrl}meetings/${encodeURIComponent(externalMeetingId)}/registrants/${encodeURIComponent(registrantId)}`);
36
+ return datoDe<MeetingConnectorRegistrant | undefined>(r as never) ?? undefined;
37
+ }
38
+
39
+ /** El uuid de una sesión puede traer '/' o '=': va codificado (el connector lo decodifica una vez). */
40
+ async getSessionParticipants(sessionId: string): Promise<MeetingConnectorParticipant[]> {
41
+ const r = await this.httpRequest.get(`${this.baseUrl}sessions/${encodeURIComponent(encodeURIComponent(sessionId))}/participants`);
42
+ return datoDe<{ items: MeetingConnectorParticipant[] }>(r as never)?.items ?? [];
43
+ }
44
+
45
+ async getSessionPolls(sessionId: string): Promise<MeetingConnectorPollAnswer[] | undefined> {
46
+ const r = await this.httpRequest.get(`${this.baseUrl}sessions/${encodeURIComponent(encodeURIComponent(sessionId))}/polls`);
47
+ const datos = datoDe<{ ready?: boolean; items?: MeetingConnectorPollAnswer[] }>(r as never);
48
+ if (!datos || datos.ready === false) return undefined;
49
+ return datos.items ?? [];
50
+ }
51
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * El contrato agnóstico de meeting-connector (la envoltura del proveedor de reuniones; hoy Zoom,
3
+ * Teams después): nada acá nombra al proveedor. Lo consume meetings-business.
4
+ */
5
+
6
+ export type MeetingConnectorHost = { email: string; name?: string; licensed: boolean };
7
+
8
+ export type MeetingConnectorCreateRequest = {
9
+ hostEmail: string;
10
+ title: string;
11
+ agenda?: string;
12
+ startsAt: string;
13
+ durationMinutes: number;
14
+ timezone: string;
15
+ registrationRequired: boolean;
16
+ phoneRequired: boolean;
17
+ registrationQuestions?: Array<{ ref: string; text: string; required?: boolean; dataType?: string }>;
18
+ polls?: Array<{ title: string; questions: Array<{ ref: string; text: string; type: string; options?: string[] }> }>;
19
+ };
20
+
21
+ export type MeetingConnectorCreated = {
22
+ externalMeetingId: string;
23
+ registrationUrl?: string;
24
+ joinUrl?: string;
25
+ polls?: Array<{ title: string; externalPollId: string }>;
26
+ };
27
+
28
+ export type MeetingConnectorParticipant = {
29
+ participantId: string;
30
+ registrantId?: string;
31
+ name?: string;
32
+ email?: string;
33
+ joinedAt: string;
34
+ leftAt?: string;
35
+ durationSeconds?: number;
36
+ };
37
+
38
+ export type MeetingConnectorPollAnswer = { name?: string; email?: string; answers: Array<{ question: string; answer: string; externalPollId?: string; respondedAt?: string }> };
39
+
40
+ export type MeetingConnectorRegistrant = { registrantId: string; name?: string; email?: string; phoneNumber?: string; answers?: Array<{ question: string; answer: string }> };
41
+
42
+ export interface IMeetingConnectorApi {
43
+ getHosts(): Promise<MeetingConnectorHost[]>;
44
+ /** Si algo falla en la plataforma, el connector borra y no queda nada a medias. */
45
+ createMeeting(request: MeetingConnectorCreateRequest): Promise<MeetingConnectorCreated>;
46
+ /** El link del anfitrión vence a las 2 horas: se pide uno nuevo cada vez. */
47
+ getStartUrl(externalMeetingId: string): Promise<string>;
48
+ getRegistrant(externalMeetingId: string, registrantId: string): Promise<MeetingConnectorRegistrant | undefined>;
49
+ getSessionParticipants(sessionId: string): Promise<MeetingConnectorParticipant[]>;
50
+ /** undefined = la plataforma todavía no los tiene listos: reintentar después. */
51
+ getSessionPolls(sessionId: string): Promise<MeetingConnectorPollAnswer[] | undefined>;
52
+ }
@@ -0,0 +1,2 @@
1
+ export * from './api/interfaces/IMeetingConnectorApi.js';
2
+ export { default as MeetingConnectorApi } from './api/MeetingConnectorApi.js';
@@ -1,6 +1,6 @@
1
1
  import { inject, injectable } from "inversify";
2
2
  import type { IHttpRequest } from "@fiado/http-client";
3
- import type { IOnboardingBusinessApi } from "./interfaces/IOnboardingBusinessApi.js";
3
+ import type { IOnboardingBusinessApi, OnboardingAssignTagParams, OnboardingTagSubject } from "./interfaces/IOnboardingBusinessApi.js";
4
4
 
5
5
 
6
6
  @injectable()
@@ -91,30 +91,41 @@ export default class OnboardingBusinessApi implements IOnboardingBusinessApi {
91
91
  return await this.httpRequest.get(`${url}`, { ids });
92
92
  }
93
93
 
94
- async tagsSummary(): Promise<any> {
95
- const url = `${this.baseUrl}private/tags/summary`;
94
+ async tagsSummary(subject?: OnboardingTagSubject): Promise<any> {
95
+ const url = `${this.baseUrl}private/tags/summary${subject ? `?subject=${subject}` : ''}`;
96
96
  return await this.httpRequest.get(`${url}`);
97
97
  }
98
98
 
99
- async tagsByDirectories(directoryIds: string[]): Promise<any> {
99
+ async tagsByDirectories(directoryIds: string[], subject?: OnboardingTagSubject): Promise<any> {
100
100
  const url = `${this.baseUrl}private/tags/by-directories`;
101
- return await this.httpRequest.post(`${url}`, { directoryIds });
101
+ const body = subject === 'lead' ? { subject, leadIds: directoryIds } : { directoryIds };
102
+ return await this.httpRequest.post(`${url}`, body);
102
103
  }
103
104
 
104
- async getUsersByTag(tag: string, pageSize = 200, index?: string): Promise<any> {
105
+ async getUsersByTag(tag: string, pageSize = 200, index?: string, subject?: OnboardingTagSubject): Promise<any> {
105
106
  const queryParams = [`pageSize=${pageSize}`];
106
107
 
107
108
  if (index) {
108
109
  queryParams.push(`index=${encodeURIComponent(index)}`);
109
110
  }
111
+ if (subject) {
112
+ queryParams.push(`subject=${subject}`);
113
+ }
110
114
 
111
115
  const url = `${this.baseUrl}private/tags/${encodeURIComponent(tag)}/users?${queryParams.join('&')}`;
112
116
  return await this.httpRequest.get(`${url}`);
113
117
  }
114
118
 
115
- async assignTag(params: { directoryId: string; tag: string }): Promise<any> {
119
+ async removeTag(id: string, subject?: OnboardingTagSubject): Promise<any> {
120
+ const url = `${this.baseUrl}private/tags/${encodeURIComponent(id)}${subject ? `?subject=${subject}` : ''}`;
121
+ return await this.httpRequest.delete(`${url}`);
122
+ }
123
+
124
+ async assignTag(params: OnboardingAssignTagParams): Promise<any> {
116
125
  const url = `${this.baseUrl}private/tags`;
117
- return await this.httpRequest.post(`${url}`, { directoryId: params.directoryId, tag: params.tag });
126
+ // Sólo viajan los campos presentes: sin subject el cuerpo es el de siempre, { directoryId, tag }.
127
+ const body = Object.fromEntries(Object.entries(params).filter(([, value]) => value !== undefined));
128
+ return await this.httpRequest.post(`${url}`, body);
118
129
  }
119
130
 
120
131
  //**
@@ -1,3 +1,21 @@
1
+ /**
2
+ * A quién se le pone la etiqueta: `user` (UserTags_GT, por directoryId) es el default de siempre;
3
+ * `lead` (LeadTags_GT, por leadId) es de los leads de meetings-business.
4
+ */
5
+ export type OnboardingTagSubject = "user" | "lead";
6
+
7
+ /** Con `subject` lead van `leadId`, `phoneNumber` y quién la puso; sin subject, `directoryId` como siempre. */
8
+ export interface OnboardingAssignTagParams {
9
+ subject?: OnboardingTagSubject;
10
+ directoryId?: string;
11
+ leadId?: string;
12
+ tag: string;
13
+ phoneNumber?: string;
14
+ source?: "RULE" | "MANUAL";
15
+ meetingId?: string;
16
+ addedBy?: string;
17
+ }
18
+
1
19
  export interface IOnboardingBusinessApi {
2
20
  getById(id: string): Promise<any>
3
21
  getByPhoneNumber(phoneNumber: string): Promise<any>
@@ -8,8 +26,8 @@ export interface IOnboardingBusinessApi {
8
26
 
9
27
  getBatchByIds(ids: string[]): Promise<any>
10
28
 
11
- /** Dashboard Ops Segmentos — tags distintos + count c/u (TagsSummaryResponse en data). */
12
- tagsSummary(): Promise<any>
29
+ /** Dashboard Ops Segmentos — tags distintos + count c/u (TagsSummaryResponse en data). Con `lead`, los de los leads. */
30
+ tagsSummary(subject?: OnboardingTagSubject): Promise<any>
13
31
  /** Dashboard Ops Segmentos — tags por usuario para un batch de directoryIds (TagsByDirectoriesResponse en data). */
14
32
  /**
15
33
  * Directorios que tienen un tag, paginado.
@@ -20,11 +38,14 @@ export interface IOnboardingBusinessApi {
20
38
  * Es el inverso de `tagsByDirectories` (ese da los tags DE unos directorios; éste da
21
39
  * los directorios CON un tag). Consumido por `direct-deposit-export-business`.
22
40
  */
23
- getUsersByTag(tag: string, pageSize?: number, index?: string): Promise<any>;
41
+ getUsersByTag(tag: string, pageSize?: number, index?: string, subject?: OnboardingTagSubject): Promise<any>;
24
42
 
25
- tagsByDirectories(directoryIds: string[]): Promise<any>
26
- /** Asigna un tag a un directoryId. Idempotente: si ya estaba responde 200 con alreadyAssigned true. */
27
- assignTag(params: { directoryId: string; tag: string }): Promise<any>
43
+ /** Con `lead`, `directoryIds` son leadIds y viajan como `leadIds`. */
44
+ tagsByDirectories(directoryIds: string[], subject?: OnboardingTagSubject): Promise<any>
45
+ /** Asigna un tag a un directoryId (o a un lead con `subject` lead). Idempotente: si ya estaba responde 200 con alreadyAssigned true. */
46
+ assignTag(params: OnboardingAssignTagParams): Promise<any>
47
+ /** Quita un tag por su id compuesto (`${directoryId}-${tag}`, o `${leadId}-${tag}` con `subject` lead). Idempotente. */
48
+ removeTag(id: string, subject?: OnboardingTagSubject): Promise<any>
28
49
 
29
50
  /**
30
51
  * ¿Este expediente cumple los requisitos para emitir el lado indicado?
@@ -1,7 +1,7 @@
1
1
  import { inject, injectable } from "inversify";
2
2
  import type { IHttpRequest } from "@fiado/http-client";
3
3
  import dotenv from 'dotenv';
4
- import type { PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
4
+ import type { CreatePromoterFromLeadRequest, PostPromoterFromLeadResponse, PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
5
5
  import { IUsMarketGrowthBusinessApi } from "./interfaces/IUsMarketGrowthBusinessApi.js";
6
6
  import { joinUrl } from "../utils/joinUrl.js";
7
7
  type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
@@ -19,4 +19,9 @@ export class UsMarketGrowthBusinessApi implements IUsMarketGrowthBusinessApi {
19
19
  const url = joinUrl(this.baseUrl, `private/promoters/directoryId/${encodeURIComponent(directoryId)}`);
20
20
  return await this.httpRequest.get(url);
21
21
  }
22
+
23
+ async createPromoterFromLead(request: CreatePromoterFromLeadRequest): Promise<FiadoApiResponse<PostPromoterFromLeadResponse>> {
24
+ const url = joinUrl(this.baseUrl, "private/promoters/from-lead");
25
+ return await this.httpRequest.post(url, request);
26
+ }
22
27
  }
@@ -1,5 +1,5 @@
1
1
  type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
2
- import type { PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
2
+ import type { CreatePromoterFromLeadRequest, PostPromoterFromLeadResponse, PromoterByDirectoryIdResponse } from "@fiado/type-kit/bin/usmarketgrowth-business/index.js";
3
3
 
4
4
  /**
5
5
  * Cliente de `usmarketgrowth-business` (promotores de US Market Growth).
@@ -14,4 +14,10 @@ export interface IUsMarketGrowthBusinessApi {
14
14
  * @param directoryId ID del directorio.
15
15
  */
16
16
  getPromoterByDirectoryId(directoryId: string): Promise<FiadoApiResponse<PromoterByDirectoryIdResponse>>;
17
+
18
+ /**
19
+ * 4.5 del plan de reuniones: promotor a partir de un lead, idempotente por teléfono o correo
20
+ * (dos llamadas con el mismo contacto devuelven el mismo promoterId; EXISTING no toca nada).
21
+ */
22
+ createPromoterFromLead(request: CreatePromoterFromLeadRequest): Promise<FiadoApiResponse<PostPromoterFromLeadResponse>>;
17
23
  }