@fiado/api-invoker 4.67.0 → 4.70.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 (33) hide show
  1. package/bin/container.config.js +2 -0
  2. package/bin/index.d.ts +3 -0
  3. package/bin/index.js +3 -0
  4. package/bin/loanCollectorAssignment/api/LoanCollectorAssignmentBusinessApi.d.ts +24 -0
  5. package/bin/loanCollectorAssignment/api/LoanCollectorAssignmentBusinessApi.js +51 -0
  6. package/bin/loanCollectorAssignment/api/interfaces/ILoanCollectorAssignmentBusinessApi.d.ts +63 -0
  7. package/bin/loanCollectorAssignment/api/interfaces/ILoanCollectorAssignmentBusinessApi.js +1 -0
  8. package/bin/loanCollectorAssignment/index.d.ts +2 -0
  9. package/bin/loanCollectorAssignment/index.js +2 -0
  10. package/bin/places-business/api/PlacesBusinessApi.d.ts +12 -0
  11. package/bin/places-business/api/PlacesBusinessApi.js +32 -0
  12. package/bin/places-business/api/interfaces/IPlacesBusinessApi.d.ts +9 -0
  13. package/bin/places-business/api/interfaces/IPlacesBusinessApi.js +1 -0
  14. package/bin/places-business/index.d.ts +2 -0
  15. package/bin/places-business/index.js +2 -0
  16. package/bin/retailCustomer/api/RetailCustomerBusinessApi.d.ts +27 -0
  17. package/bin/retailCustomer/api/RetailCustomerBusinessApi.js +56 -0
  18. package/bin/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.d.ts +76 -0
  19. package/bin/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.js +1 -0
  20. package/bin/retailCustomer/index.d.ts +2 -0
  21. package/bin/retailCustomer/index.js +2 -0
  22. package/package.json +2 -2
  23. package/src/container.config.ts +3 -0
  24. package/src/index.ts +3 -0
  25. package/src/loanCollectorAssignment/api/LoanCollectorAssignmentBusinessApi.ts +52 -0
  26. package/src/loanCollectorAssignment/api/interfaces/ILoanCollectorAssignmentBusinessApi.ts +78 -0
  27. package/src/loanCollectorAssignment/index.ts +2 -0
  28. package/src/places-business/api/PlacesBusinessApi.ts +22 -0
  29. package/src/places-business/api/interfaces/IPlacesBusinessApi.ts +9 -0
  30. package/src/places-business/index.ts +2 -0
  31. package/src/retailCustomer/api/RetailCustomerBusinessApi.ts +63 -0
  32. package/src/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.ts +97 -0
  33. package/src/retailCustomer/index.ts +2 -0
@@ -68,6 +68,7 @@ import { EventHistoryApi } from "./event-history-business/index.js";
68
68
  import ReportProcessorBusinessApi from "./report-processor-business/api/ReportProcessorBusinessApi.js";
69
69
  import NotificationWSMessagePublisher from "./notificationWebsockets/queue/NotificationWSMessagePublisher.js";
70
70
  import PeopleBusinessApi from "./people-business/api/PeopleBusinessApi.js";
71
+ import PlacesBusinessApi from "./places-business/api/PlacesBusinessApi.js";
71
72
  import STPBusinessApi from "./stp-business/api/STPBusinessApi.js";
72
73
  import MulticommServicePaymentApi from "./multicommServicePayment/api/MulticommServicePaymentApi.js";
73
74
  import ProductPaymentApi from "./product-payment/api/ProductPaymentApi.js";
@@ -191,6 +192,7 @@ export const apiInvokerBindings = new ContainerModule(({ bind }) => {
191
192
  bind("IEventHistoryApi").to(EventHistoryApi);
192
193
  bind("IReportProcessorBusinessApi").to(ReportProcessorBusinessApi);
193
194
  bind("IPeopleBusinessApi").to(PeopleBusinessApi);
195
+ bind("IPlacesBusinessApi").to(PlacesBusinessApi);
194
196
  bind("ISTPBusinessApi").to(STPBusinessApi);
195
197
  bind("IProductPaymentApi").to(ProductPaymentApi);
196
198
  bind("ICommissionBusinessApi").to(CommissionBusinessApi);
package/bin/index.d.ts CHANGED
@@ -61,6 +61,7 @@ export * from "./event-history-business/index.js";
61
61
  export * from "./report-processor-business/index.js";
62
62
  export * from "./notificationWebsockets/index.js";
63
63
  export * from "./people-business/index.js";
64
+ export * from "./places-business/index.js";
64
65
  export * from "./stp-business/index.js";
65
66
  export * from "./multicommServicePayment/index.js";
66
67
  export * from "./product-payment/index.js";
@@ -77,8 +78,10 @@ export * from "./milestone-business/index.js";
77
78
  export * from "./cognitoBackofficeConnector/index.js";
78
79
  export * from "./platformRbac/index.js";
79
80
  export * from "./retailOrg/index.js";
81
+ export * from "./retailCustomer/index.js";
80
82
  export * from "./loanConfig/index.js";
81
83
  export * from "./loanOfferings/index.js";
84
+ export * from "./loanCollectorAssignment/index.js";
82
85
  export * from "./messages-business/index.js";
83
86
  export * from "./totp-security/index.js";
84
87
  export * from "./equality-connector/index.js";
package/bin/index.js CHANGED
@@ -61,6 +61,7 @@ export * from "./event-history-business/index.js";
61
61
  export * from "./report-processor-business/index.js";
62
62
  export * from "./notificationWebsockets/index.js";
63
63
  export * from "./people-business/index.js";
64
+ export * from "./places-business/index.js";
64
65
  export * from "./stp-business/index.js";
65
66
  export * from "./multicommServicePayment/index.js";
66
67
  export * from "./product-payment/index.js";
@@ -77,8 +78,10 @@ export * from "./milestone-business/index.js";
77
78
  export * from "./cognitoBackofficeConnector/index.js";
78
79
  export * from "./platformRbac/index.js";
79
80
  export * from "./retailOrg/index.js";
81
+ export * from "./retailCustomer/index.js";
80
82
  export * from "./loanConfig/index.js";
81
83
  export * from "./loanOfferings/index.js";
84
+ export * from "./loanCollectorAssignment/index.js";
82
85
  export * from "./messages-business/index.js";
83
86
  export * from "./totp-security/index.js";
84
87
  export * from "./equality-connector/index.js";
@@ -0,0 +1,24 @@
1
+ import type { IHttpRequest } from "@fiado/http-client";
2
+ import { StandardResponse } from "@fiado/gateway-adapter";
3
+ import { AutoAssignRequest, CollectorAssignmentResponse } from "@fiado/type-kit/bin/loanCollectorAssignment/index.js";
4
+ import { ILoanCollectorAssignmentBusinessApi } from "./interfaces/ILoanCollectorAssignmentBusinessApi.js";
5
+ /**
6
+ * Publisher HTTP del lambda `loan-collector-assignment-business` (componente 08 SureKeep Fase 1) para
7
+ * sus 3 endpoints privados de asignación de cartera. Contrato y semántica completos →
8
+ * `ILoanCollectorAssignmentBusinessApi` (tenantId obligatorio, `StandardResponse` → leer `result.data`).
9
+ *
10
+ * Env var requerida en el consumer: `LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL`.
11
+ * El template.yml del consumer la setea con:
12
+ *
13
+ * LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL: '{{resolve:ssm:loan-collector-assignment-business}}'
14
+ *
15
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
16
+ */
17
+ export default class LoanCollectorAssignmentBusinessApi implements ILoanCollectorAssignmentBusinessApi {
18
+ private httpRequest;
19
+ private readonly baseUrl;
20
+ constructor(httpRequest: IHttpRequest);
21
+ autoAssign(input: AutoAssignRequest, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
22
+ release(creditId: string, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
23
+ getAssignmentByCredit(creditId: string, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
24
+ }
@@ -0,0 +1,51 @@
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
+ /**
15
+ * Publisher HTTP del lambda `loan-collector-assignment-business` (componente 08 SureKeep Fase 1) para
16
+ * sus 3 endpoints privados de asignación de cartera. Contrato y semántica completos →
17
+ * `ILoanCollectorAssignmentBusinessApi` (tenantId obligatorio, `StandardResponse` → leer `result.data`).
18
+ *
19
+ * Env var requerida en el consumer: `LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL`.
20
+ * El template.yml del consumer la setea con:
21
+ *
22
+ * LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL: '{{resolve:ssm:loan-collector-assignment-business}}'
23
+ *
24
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
25
+ */
26
+ let LoanCollectorAssignmentBusinessApi = class LoanCollectorAssignmentBusinessApi {
27
+ httpRequest;
28
+ // El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//private".
29
+ baseUrl = (process.env.LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL || "").replace(/\/+$/, "");
30
+ constructor(httpRequest) {
31
+ this.httpRequest = httpRequest;
32
+ }
33
+ async autoAssign(input, tenantId) {
34
+ const url = `${this.baseUrl}/private/collector-assignments/auto-assign?tenantId=${encodeURIComponent(tenantId)}`;
35
+ return await this.httpRequest.post(url, input);
36
+ }
37
+ async release(creditId, tenantId) {
38
+ const url = `${this.baseUrl}/private/collector-assignments/${encodeURIComponent(creditId)}/release?tenantId=${encodeURIComponent(tenantId)}`;
39
+ return await this.httpRequest.put(url);
40
+ }
41
+ async getAssignmentByCredit(creditId, tenantId) {
42
+ const url = `${this.baseUrl}/private/collector-assignments/by-credit/${encodeURIComponent(creditId)}?tenantId=${encodeURIComponent(tenantId)}`;
43
+ return await this.httpRequest.get(url);
44
+ }
45
+ };
46
+ LoanCollectorAssignmentBusinessApi = __decorate([
47
+ injectable(),
48
+ __param(0, inject("IHttpRequest")),
49
+ __metadata("design:paramtypes", [Object])
50
+ ], LoanCollectorAssignmentBusinessApi);
51
+ export default LoanCollectorAssignmentBusinessApi;
@@ -0,0 +1,63 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import { AutoAssignRequest, CollectorAssignmentResponse } from "@fiado/type-kit/bin/loanCollectorAssignment/index.js";
3
+ /**
4
+ * Contrato del publisher HTTP del lambda `loan-collector-assignment-business` (componente 08 SureKeep
5
+ * Fase 1) para sus 3 endpoints privados de asignación de cartera de cobranza (service-to-service,
6
+ * VPC-only). Este lambda decide qué cobrador gestiona qué crédito.
7
+ *
8
+ * Consumidor previsto:
9
+ * - motor de crédito (F3) → auto-asigna cobrador al crearse el crédito · libera al liquidarlo ·
10
+ * consulta quién gestiona un crédito.
11
+ *
12
+ * ─────────────────────────────────────────────────────────────────────────────
13
+ * `tenantId` es OBLIGATORIO en los 3 métodos — no es un detalle de firma.
14
+ * ─────────────────────────────────────────────────────────────────────────────
15
+ * Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
16
+ * el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
17
+ * tenant explícito por query y `@fiado/tenant-context` asume el rol de ESE silo. Sin `tenantId` →
18
+ * `400 UNKNOWN_TENANT` (fail-closed). Nunca hay default: caer a un tenant por default sería fail-OPEN
19
+ * y podría tocar el silo de otra SOFOM (auto-assign y release ESCRIBEN).
20
+ *
21
+ * ─────────────────────────────────────────────────────────────────────────────
22
+ * ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
23
+ * ─────────────────────────────────────────────────────────────────────────────
24
+ *
25
+ * Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
26
+ * Cada consumer mapea a su propio error de dominio (ver `fiado-api-invoker § 6`):
27
+ * `412 NO_ACTIVE_RULE` (el retailer no tiene regla de asignación activa)
28
+ * `503 NO_COLLECTORS_AVAILABLE` (no hay cobradores elegibles para asignar)
29
+ * `404 ASSIGNMENT_NOT_FOUND` (el crédito no tiene asignación — release / consulta)
30
+ * `400 UNKNOWN_TENANT` (tenantId ausente o desconocido)
31
+ *
32
+ * Env var requerida en el consumer: `LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL`.
33
+ * El template.yml del consumer la setea con:
34
+ *
35
+ * LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL: '{{resolve:ssm:loan-collector-assignment-business}}'
36
+ *
37
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
38
+ */
39
+ export interface ILoanCollectorAssignmentBusinessApi {
40
+ /**
41
+ * POST /private/collector-assignments/auto-assign — asigna un cobrador al crédito recién creado
42
+ * (regla activa → cobradores elegibles → ranking) y devuelve la asignación ACTIVE. Idempotente:
43
+ * si el crédito ya tiene cobrador activo devuelve el existente.
44
+ *
45
+ * @throws `412 NO_ACTIVE_RULE` si el retailer no tiene regla activa; `503 NO_COLLECTORS_AVAILABLE`
46
+ * si no hay cobradores elegibles.
47
+ */
48
+ autoAssign(input: AutoAssignRequest, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
49
+ /**
50
+ * PUT /private/collector-assignments/{creditId}/release — libera la asignación al liquidarse el
51
+ * crédito (la marca INACTIVE). Idempotente: sobre una asignación ya liberada devuelve sin re-emitir.
52
+ *
53
+ * @throws `404 ASSIGNMENT_NOT_FOUND` si el crédito no tiene asignación.
54
+ */
55
+ release(creditId: string, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
56
+ /**
57
+ * GET /private/collector-assignments/by-credit/{creditId} — devuelve la asignación (cobrador
58
+ * actual + estado) de un crédito.
59
+ *
60
+ * @throws `404 ASSIGNMENT_NOT_FOUND` si el crédito no tiene asignación.
61
+ */
62
+ getAssignmentByCredit(creditId: string, tenantId: string): Promise<StandardResponse<CollectorAssignmentResponse>>;
63
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ILoanCollectorAssignmentBusinessApi.js";
2
+ export { default as LoanCollectorAssignmentBusinessApi } from "./api/LoanCollectorAssignmentBusinessApi.js";
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ILoanCollectorAssignmentBusinessApi.js";
2
+ export { default as LoanCollectorAssignmentBusinessApi } from "./api/LoanCollectorAssignmentBusinessApi.js";
@@ -0,0 +1,12 @@
1
+ import { IHttpRequest } from "@fiado/http-client";
2
+ import { SearchAddressRequest, SearchAddressResponse, ReverseGeocodeRequest, ReverseGeocodeResponse } from "@fiado/type-kit/bin/places/index.js";
3
+ import { IPlacesBusinessApi } from "./interfaces/IPlacesBusinessApi.js";
4
+ type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
5
+ export default class PlacesBusinessApi implements IPlacesBusinessApi {
6
+ private httpRequest;
7
+ private readonly baseUrl;
8
+ constructor(httpRequest: IHttpRequest);
9
+ searchAddress(request: SearchAddressRequest): Promise<FiadoApiResponse<SearchAddressResponse>>;
10
+ reverseGeocode(request: ReverseGeocodeRequest): Promise<FiadoApiResponse<ReverseGeocodeResponse>>;
11
+ }
12
+ export {};
@@ -0,0 +1,32 @@
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
+ let PlacesBusinessApi = class PlacesBusinessApi {
15
+ httpRequest;
16
+ baseUrl = process.env.PLACES_BUSINESS_LAMBDA_URL || "";
17
+ constructor(httpRequest) {
18
+ this.httpRequest = httpRequest;
19
+ }
20
+ async searchAddress(request) {
21
+ return await this.httpRequest.post(`${this.baseUrl}private/search-address`, request, { operationName: "privateSearchAddress" });
22
+ }
23
+ async reverseGeocode(request) {
24
+ return await this.httpRequest.post(`${this.baseUrl}private/reverse-geocode`, request, { operationName: "privateReverseGeocode" });
25
+ }
26
+ };
27
+ PlacesBusinessApi = __decorate([
28
+ injectable(),
29
+ __param(0, inject("IHttpRequest")),
30
+ __metadata("design:paramtypes", [Object])
31
+ ], PlacesBusinessApi);
32
+ export default PlacesBusinessApi;
@@ -0,0 +1,9 @@
1
+ import { SearchAddressRequest, SearchAddressResponse, ReverseGeocodeRequest, ReverseGeocodeResponse } from "@fiado/type-kit/bin/places/index.js";
2
+ type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
3
+ export interface IPlacesBusinessApi {
4
+ /** Geocoding por texto (POST /private/search-address, operationId privateSearchAddress). */
5
+ searchAddress(request: SearchAddressRequest): Promise<FiadoApiResponse<SearchAddressResponse>>;
6
+ /** Reverse geocoding (POST /private/reverse-geocode, operationId privateReverseGeocode). */
7
+ reverseGeocode(request: ReverseGeocodeRequest): Promise<FiadoApiResponse<ReverseGeocodeResponse>>;
8
+ }
9
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './api/PlacesBusinessApi.js';
2
+ export * from './api/interfaces/IPlacesBusinessApi.js';
@@ -0,0 +1,2 @@
1
+ export * from './api/PlacesBusinessApi.js';
2
+ export * from './api/interfaces/IPlacesBusinessApi.js';
@@ -0,0 +1,27 @@
1
+ import type { IHttpRequest } from "@fiado/http-client";
2
+ import { StandardResponse } from "@fiado/gateway-adapter";
3
+ import { UpsertCustomerFromKycRequest, AccountResultRequest, CustomerResponse } from "@fiado/type-kit/bin/retailCustomer/index.js";
4
+ import { IRetailCustomerBusinessApi } from "./interfaces/IRetailCustomerBusinessApi.js";
5
+ /**
6
+ * Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 4
7
+ * endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
8
+ *
9
+ * Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
10
+ * `retail-org-business`: el silo se resuelve por el `tenantId` canónico que manda el caller).
11
+ *
12
+ * Env var requerida en el consumer: `RETAIL_CUSTOMER_BUSINESS_URL`.
13
+ * El template.yml del consumer la setea con:
14
+ *
15
+ * RETAIL_CUSTOMER_BUSINESS_URL: '{{resolve:ssm:retail-customer-business}}'
16
+ *
17
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
18
+ */
19
+ export default class RetailCustomerBusinessApi implements IRetailCustomerBusinessApi {
20
+ private httpRequest;
21
+ private readonly baseUrl;
22
+ constructor(httpRequest: IHttpRequest);
23
+ upsertCustomerFromKyc(payload: UpsertCustomerFromKycRequest, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
24
+ setAccountResult(customerId: string, payload: AccountResultRequest, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
25
+ getCustomerByPhone(phone: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
26
+ getCustomer(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
27
+ }
@@ -0,0 +1,56 @@
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
+ /**
15
+ * Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 4
16
+ * endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
17
+ *
18
+ * Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
19
+ * `retail-org-business`: el silo se resuelve por el `tenantId` canónico que manda el caller).
20
+ *
21
+ * Env var requerida en el consumer: `RETAIL_CUSTOMER_BUSINESS_URL`.
22
+ * El template.yml del consumer la setea con:
23
+ *
24
+ * RETAIL_CUSTOMER_BUSINESS_URL: '{{resolve:ssm:retail-customer-business}}'
25
+ *
26
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
27
+ */
28
+ let RetailCustomerBusinessApi = class RetailCustomerBusinessApi {
29
+ httpRequest;
30
+ baseUrl = process.env.RETAIL_CUSTOMER_BUSINESS_URL || "";
31
+ constructor(httpRequest) {
32
+ this.httpRequest = httpRequest;
33
+ }
34
+ async upsertCustomerFromKyc(payload, tenantId) {
35
+ const url = `${this.baseUrl}/private/customers/upsert-from-kyc?tenantId=${encodeURIComponent(tenantId)}`;
36
+ return await this.httpRequest.post(url, payload);
37
+ }
38
+ async setAccountResult(customerId, payload, tenantId) {
39
+ const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}/account-result?tenantId=${encodeURIComponent(tenantId)}`;
40
+ return await this.httpRequest.put(url, payload);
41
+ }
42
+ async getCustomerByPhone(phone, tenantId) {
43
+ const url = `${this.baseUrl}/private/customers/by-phone/${encodeURIComponent(phone)}?tenantId=${encodeURIComponent(tenantId)}`;
44
+ return await this.httpRequest.get(url);
45
+ }
46
+ async getCustomer(customerId, tenantId) {
47
+ const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}?tenantId=${encodeURIComponent(tenantId)}`;
48
+ return await this.httpRequest.get(url);
49
+ }
50
+ };
51
+ RetailCustomerBusinessApi = __decorate([
52
+ injectable(),
53
+ __param(0, inject("IHttpRequest")),
54
+ __metadata("design:paramtypes", [Object])
55
+ ], RetailCustomerBusinessApi);
56
+ export default RetailCustomerBusinessApi;
@@ -0,0 +1,76 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import { UpsertCustomerFromKycRequest, AccountResultRequest, CustomerResponse } from "@fiado/type-kit/bin/retailCustomer/index.js";
3
+ /**
4
+ * Contrato del publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail)
5
+ * para sus 4 endpoints privados de cliente (service-to-service, VPC-only).
6
+ *
7
+ * Consumidor previsto:
8
+ * - `retail-wizard-business` → upsert del cliente post-KYC, aterrizaje del resultado de apertura
9
+ * de cuenta (D35), y lecturas del cliente por teléfono / id durante la saga de venta.
10
+ *
11
+ * ─────────────────────────────────────────────────────────────────────────────
12
+ * `tenantId` es OBLIGATORIO en los 4 métodos — no es un detalle de firma.
13
+ * ─────────────────────────────────────────────────────────────────────────────
14
+ * Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
15
+ * el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
16
+ * tenant explícito por query (`?tenantId=`) y `@fiado/tenant-context` (`withContextByTenantId`) asume
17
+ * el rol de ESE silo. Sin `tenantId` → `400 UNKNOWN_TENANT` (fail-closed). Nunca hay default: caer a un
18
+ * tenant por default sería fail-OPEN y podría devolver datos de otra SOFOM.
19
+ *
20
+ * ⚠️ `tenantId` = el tenant CANÓNICO (p.ej. `'surekeep'`), NO el issuer Cognito ni la URL del pool.
21
+ * Es el mismo valor que consume `retail-org-business` en sus privados (`withContextByTenantId`).
22
+ *
23
+ * ─────────────────────────────────────────────────────────────────────────────
24
+ * ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
25
+ * ─────────────────────────────────────────────────────────────────────────────
26
+ * `@fiado/http-client` entrega el BODY PELADO (hace `return response.data` en `AxiosHttpRequest`), así
27
+ * que `.statusCode`/`.body` no existen en runtime. El envelope real del lambda destino es
28
+ * `{ code, date, data, msg, description }` = `StandardResponse<T>` (ya exportado por
29
+ * `@fiado/gateway-adapter`). El consumer lee el shape del cliente en `result.data`.
30
+ *
31
+ * Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
32
+ * Cada consumer mapea a su propio error de dominio (ver `fiado-api-invoker § 6`):
33
+ * `404 CUSTOMER_NOT_FOUND` (por id / por teléfono inexistente)
34
+ * `400 UNKNOWN_TENANT` (tenantId ausente o desconocido)
35
+ *
36
+ * Env var requerida en el consumer: `RETAIL_CUSTOMER_BUSINESS_URL`.
37
+ * El template.yml del consumer la setea con:
38
+ *
39
+ * RETAIL_CUSTOMER_BUSINESS_URL: '{{resolve:ssm:retail-customer-business}}'
40
+ *
41
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
42
+ */
43
+ export interface IRetailCustomerBusinessApi {
44
+ /**
45
+ * POST /private/customers/upsert-from-kyc?tenantId= — upsert idempotente del cliente tras el KYC
46
+ * (paso 02f). El lambda resuelve UNIQ#PHONE + UNIQ#CURP en la misma TX y setea
47
+ * `accountStatus=OPENING` server-side (la apertura corre en background, D35). Responde `201`.
48
+ *
49
+ * NOTA (TD-014 del customer): el `address` del type-kit tipa el `AddressBase` canónico (pesado);
50
+ * el lambda valida con un DTO local ligero. El domicilio OCR-parcial se salda con `RetailAddress`
51
+ * aditivo al type-kit (backlog) — no acá.
52
+ */
53
+ upsertCustomerFromKyc(payload: UpsertCustomerFromKycRequest, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
54
+ /**
55
+ * PUT /private/customers/{customerId}/account-result?tenantId= — aterriza el resultado terminal de
56
+ * la apertura de cuenta async (D35). Solo acepta OPEN/FAILED (nunca el intermedio OPENING). OPEN
57
+ * llega con `pcfClabe`/`pcfAccountLevel`; FAILED con `failReason`.
58
+ *
59
+ * @throws si el cliente no existe (`404 CUSTOMER_NOT_FOUND`).
60
+ */
61
+ setAccountResult(customerId: string, payload: AccountResultRequest, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
62
+ /**
63
+ * GET /private/customers/by-phone/{phone}?tenantId= — resuelve el cliente por su teléfono MX (10
64
+ * dígitos, ya normalizado sin separadores). Usado por el wizard para saber si el teléfono ya es
65
+ * cliente del silo.
66
+ *
67
+ * @throws si no hay cliente con ese teléfono (`404 CUSTOMER_NOT_FOUND`).
68
+ */
69
+ getCustomerByPhone(phone: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
70
+ /**
71
+ * GET /private/customers/{customerId}?tenantId= — resuelve el cliente por su id.
72
+ *
73
+ * @throws si el cliente no existe (`404 CUSTOMER_NOT_FOUND`).
74
+ */
75
+ getCustomer(customerId: string, tenantId: string): Promise<StandardResponse<CustomerResponse>>;
76
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/IRetailCustomerBusinessApi.js";
2
+ export { default as RetailCustomerBusinessApi } from "./api/RetailCustomerBusinessApi.js";
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/IRetailCustomerBusinessApi.js";
2
+ export { default as RetailCustomerBusinessApi } from "./api/RetailCustomerBusinessApi.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/api-invoker",
3
- "version": "4.67.0",
3
+ "version": "4.70.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",
@@ -34,7 +34,7 @@
34
34
  "@fiado/gateway-adapter": "^3.9.0",
35
35
  "@fiado/http-client": "^2.0.1",
36
36
  "@fiado/logger": "^1.1.3",
37
- "@fiado/type-kit": "^3.193.0",
37
+ "@fiado/type-kit": "^3.196.0",
38
38
  "dotenv": "^16.4.7"
39
39
  },
40
40
  "peerDependencies": {
@@ -99,6 +99,8 @@ import { INotificationWSMessagesPublisher } from "./notificationWebsockets/index
99
99
  import NotificationWSMessagePublisher from "./notificationWebsockets/queue/NotificationWSMessagePublisher.js";
100
100
  import PeopleBusinessApi from "./people-business/api/PeopleBusinessApi.js";
101
101
  import { IPeopleBusinessApi } from "./people-business/index.js";
102
+ import PlacesBusinessApi from "./places-business/api/PlacesBusinessApi.js";
103
+ import { IPlacesBusinessApi } from "./places-business/index.js";
102
104
  import STPBusinessApi from "./stp-business/api/STPBusinessApi.js";
103
105
  import { ISTPBusinessApi } from "./stp-business/index.js";
104
106
  import { IMulticommServicePaymentApi } from "./multicommServicePayment/index.js";
@@ -252,6 +254,7 @@ export const apiInvokerBindings = new ContainerModule(({ bind }) => {
252
254
  bind<IEventHistoryApi>("IEventHistoryApi").to(EventHistoryApi);
253
255
  bind<IReportProcessorBusinessApi>("IReportProcessorBusinessApi").to(ReportProcessorBusinessApi);
254
256
  bind<IPeopleBusinessApi>("IPeopleBusinessApi").to(PeopleBusinessApi);
257
+ bind<IPlacesBusinessApi>("IPlacesBusinessApi").to(PlacesBusinessApi);
255
258
  bind<ISTPBusinessApi>("ISTPBusinessApi").to(STPBusinessApi);
256
259
  bind<IProductPaymentApi>("IProductPaymentApi").to(ProductPaymentApi);
257
260
  bind<ICommissionBusinessApi>("ICommissionBusinessApi").to(CommissionBusinessApi);
package/src/index.ts CHANGED
@@ -61,6 +61,7 @@ export * from "./event-history-business/index.js";
61
61
  export * from "./report-processor-business/index.js";
62
62
  export * from "./notificationWebsockets/index.js";
63
63
  export * from "./people-business/index.js";
64
+ export * from "./places-business/index.js";
64
65
  export * from "./stp-business/index.js";
65
66
  export * from "./multicommServicePayment/index.js";
66
67
  export * from "./product-payment/index.js";
@@ -77,8 +78,10 @@ export * from "./milestone-business/index.js";
77
78
  export * from "./cognitoBackofficeConnector/index.js";
78
79
  export * from "./platformRbac/index.js";
79
80
  export * from "./retailOrg/index.js";
81
+ export * from "./retailCustomer/index.js";
80
82
  export * from "./loanConfig/index.js";
81
83
  export * from "./loanOfferings/index.js";
84
+ export * from "./loanCollectorAssignment/index.js";
82
85
  export * from "./messages-business/index.js";
83
86
  export * from "./totp-security/index.js";
84
87
  export * from "./equality-connector/index.js";
@@ -0,0 +1,52 @@
1
+ import { inject, injectable } from "inversify";
2
+ import type { IHttpRequest } from "@fiado/http-client";
3
+ import { StandardResponse } from "@fiado/gateway-adapter";
4
+ import {
5
+ AutoAssignRequest,
6
+ CollectorAssignmentResponse,
7
+ } from "@fiado/type-kit/bin/loanCollectorAssignment/index.js";
8
+ import { ILoanCollectorAssignmentBusinessApi } from "./interfaces/ILoanCollectorAssignmentBusinessApi.js";
9
+
10
+ /**
11
+ * Publisher HTTP del lambda `loan-collector-assignment-business` (componente 08 SureKeep Fase 1) para
12
+ * sus 3 endpoints privados de asignación de cartera. Contrato y semántica completos →
13
+ * `ILoanCollectorAssignmentBusinessApi` (tenantId obligatorio, `StandardResponse` → leer `result.data`).
14
+ *
15
+ * Env var requerida en el consumer: `LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL`.
16
+ * El template.yml del consumer la setea con:
17
+ *
18
+ * LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL: '{{resolve:ssm:loan-collector-assignment-business}}'
19
+ *
20
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
21
+ */
22
+ @injectable()
23
+ export default class LoanCollectorAssignmentBusinessApi implements ILoanCollectorAssignmentBusinessApi {
24
+ // El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//private".
25
+ private readonly baseUrl = (process.env.LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL || "").replace(/\/+$/, "");
26
+
27
+ constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {}
28
+
29
+ async autoAssign(
30
+ input: AutoAssignRequest,
31
+ tenantId: string,
32
+ ): Promise<StandardResponse<CollectorAssignmentResponse>> {
33
+ const url = `${this.baseUrl}/private/collector-assignments/auto-assign?tenantId=${encodeURIComponent(tenantId)}`;
34
+ return await this.httpRequest.post(url, input);
35
+ }
36
+
37
+ async release(
38
+ creditId: string,
39
+ tenantId: string,
40
+ ): Promise<StandardResponse<CollectorAssignmentResponse>> {
41
+ const url = `${this.baseUrl}/private/collector-assignments/${encodeURIComponent(creditId)}/release?tenantId=${encodeURIComponent(tenantId)}`;
42
+ return await this.httpRequest.put(url);
43
+ }
44
+
45
+ async getAssignmentByCredit(
46
+ creditId: string,
47
+ tenantId: string,
48
+ ): Promise<StandardResponse<CollectorAssignmentResponse>> {
49
+ const url = `${this.baseUrl}/private/collector-assignments/by-credit/${encodeURIComponent(creditId)}?tenantId=${encodeURIComponent(tenantId)}`;
50
+ return await this.httpRequest.get(url);
51
+ }
52
+ }
@@ -0,0 +1,78 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import {
3
+ AutoAssignRequest,
4
+ CollectorAssignmentResponse,
5
+ } from "@fiado/type-kit/bin/loanCollectorAssignment/index.js";
6
+
7
+ /**
8
+ * Contrato del publisher HTTP del lambda `loan-collector-assignment-business` (componente 08 SureKeep
9
+ * Fase 1) para sus 3 endpoints privados de asignación de cartera de cobranza (service-to-service,
10
+ * VPC-only). Este lambda decide qué cobrador gestiona qué crédito.
11
+ *
12
+ * Consumidor previsto:
13
+ * - motor de crédito (F3) → auto-asigna cobrador al crearse el crédito · libera al liquidarlo ·
14
+ * consulta quién gestiona un crédito.
15
+ *
16
+ * ─────────────────────────────────────────────────────────────────────────────
17
+ * `tenantId` es OBLIGATORIO en los 3 métodos — no es un detalle de firma.
18
+ * ─────────────────────────────────────────────────────────────────────────────
19
+ * Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
20
+ * el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
21
+ * tenant explícito por query y `@fiado/tenant-context` asume el rol de ESE silo. Sin `tenantId` →
22
+ * `400 UNKNOWN_TENANT` (fail-closed). Nunca hay default: caer a un tenant por default sería fail-OPEN
23
+ * y podría tocar el silo de otra SOFOM (auto-assign y release ESCRIBEN).
24
+ *
25
+ * ─────────────────────────────────────────────────────────────────────────────
26
+ * ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
27
+ * ─────────────────────────────────────────────────────────────────────────────
28
+ *
29
+ * Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
30
+ * Cada consumer mapea a su propio error de dominio (ver `fiado-api-invoker § 6`):
31
+ * `412 NO_ACTIVE_RULE` (el retailer no tiene regla de asignación activa)
32
+ * `503 NO_COLLECTORS_AVAILABLE` (no hay cobradores elegibles para asignar)
33
+ * `404 ASSIGNMENT_NOT_FOUND` (el crédito no tiene asignación — release / consulta)
34
+ * `400 UNKNOWN_TENANT` (tenantId ausente o desconocido)
35
+ *
36
+ * Env var requerida en el consumer: `LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL`.
37
+ * El template.yml del consumer la setea con:
38
+ *
39
+ * LOAN_COLLECTOR_ASSIGNMENT_BUSINESS_URL: '{{resolve:ssm:loan-collector-assignment-business}}'
40
+ *
41
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
42
+ */
43
+ export interface ILoanCollectorAssignmentBusinessApi {
44
+ /**
45
+ * POST /private/collector-assignments/auto-assign — asigna un cobrador al crédito recién creado
46
+ * (regla activa → cobradores elegibles → ranking) y devuelve la asignación ACTIVE. Idempotente:
47
+ * si el crédito ya tiene cobrador activo devuelve el existente.
48
+ *
49
+ * @throws `412 NO_ACTIVE_RULE` si el retailer no tiene regla activa; `503 NO_COLLECTORS_AVAILABLE`
50
+ * si no hay cobradores elegibles.
51
+ */
52
+ autoAssign(
53
+ input: AutoAssignRequest,
54
+ tenantId: string,
55
+ ): Promise<StandardResponse<CollectorAssignmentResponse>>;
56
+
57
+ /**
58
+ * PUT /private/collector-assignments/{creditId}/release — libera la asignación al liquidarse el
59
+ * crédito (la marca INACTIVE). Idempotente: sobre una asignación ya liberada devuelve sin re-emitir.
60
+ *
61
+ * @throws `404 ASSIGNMENT_NOT_FOUND` si el crédito no tiene asignación.
62
+ */
63
+ release(
64
+ creditId: string,
65
+ tenantId: string,
66
+ ): Promise<StandardResponse<CollectorAssignmentResponse>>;
67
+
68
+ /**
69
+ * GET /private/collector-assignments/by-credit/{creditId} — devuelve la asignación (cobrador
70
+ * actual + estado) de un crédito.
71
+ *
72
+ * @throws `404 ASSIGNMENT_NOT_FOUND` si el crédito no tiene asignación.
73
+ */
74
+ getAssignmentByCredit(
75
+ creditId: string,
76
+ tenantId: string,
77
+ ): Promise<StandardResponse<CollectorAssignmentResponse>>;
78
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ILoanCollectorAssignmentBusinessApi.js";
2
+ export { default as LoanCollectorAssignmentBusinessApi } from "./api/LoanCollectorAssignmentBusinessApi.js";
@@ -0,0 +1,22 @@
1
+ import { inject, injectable } from "inversify";
2
+ import { IHttpRequest } from "@fiado/http-client";
3
+ import { SearchAddressRequest, SearchAddressResponse, ReverseGeocodeRequest, ReverseGeocodeResponse } from "@fiado/type-kit/bin/places/index.js";
4
+ import { IPlacesBusinessApi } from "./interfaces/IPlacesBusinessApi.js";
5
+ type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
6
+
7
+ @injectable()
8
+ export default class PlacesBusinessApi implements IPlacesBusinessApi {
9
+
10
+ private readonly baseUrl = process.env.PLACES_BUSINESS_LAMBDA_URL || "";
11
+
12
+ constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {
13
+ }
14
+
15
+ async searchAddress(request: SearchAddressRequest): Promise<FiadoApiResponse<SearchAddressResponse>> {
16
+ return await this.httpRequest.post(`${this.baseUrl}private/search-address`, request, { operationName: "privateSearchAddress" });
17
+ }
18
+
19
+ async reverseGeocode(request: ReverseGeocodeRequest): Promise<FiadoApiResponse<ReverseGeocodeResponse>> {
20
+ return await this.httpRequest.post(`${this.baseUrl}private/reverse-geocode`, request, { operationName: "privateReverseGeocode" });
21
+ }
22
+ }
@@ -0,0 +1,9 @@
1
+ import { SearchAddressRequest, SearchAddressResponse, ReverseGeocodeRequest, ReverseGeocodeResponse } from "@fiado/type-kit/bin/places/index.js";
2
+ type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
3
+
4
+ export interface IPlacesBusinessApi {
5
+ /** Geocoding por texto (POST /private/search-address, operationId privateSearchAddress). */
6
+ searchAddress(request: SearchAddressRequest): Promise<FiadoApiResponse<SearchAddressResponse>>;
7
+ /** Reverse geocoding (POST /private/reverse-geocode, operationId privateReverseGeocode). */
8
+ reverseGeocode(request: ReverseGeocodeRequest): Promise<FiadoApiResponse<ReverseGeocodeResponse>>;
9
+ }
@@ -0,0 +1,2 @@
1
+ export * from './api/PlacesBusinessApi.js';
2
+ export * from './api/interfaces/IPlacesBusinessApi.js';
@@ -0,0 +1,63 @@
1
+ import { inject, injectable } from "inversify";
2
+ import type { IHttpRequest } from "@fiado/http-client";
3
+ import { StandardResponse } from "@fiado/gateway-adapter";
4
+ import {
5
+ UpsertCustomerFromKycRequest,
6
+ AccountResultRequest,
7
+ CustomerResponse,
8
+ } from "@fiado/type-kit/bin/retailCustomer/index.js";
9
+ import { IRetailCustomerBusinessApi } from "./interfaces/IRetailCustomerBusinessApi.js";
10
+
11
+ /**
12
+ * Publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail) para sus 4
13
+ * endpoints privados de cliente. Contrato y semántica completos → `IRetailCustomerBusinessApi`.
14
+ *
15
+ * Los paths y el `?tenantId=` matchean `openapi/private.yaml` del lambda destino (mismo patrón que
16
+ * `retail-org-business`: el silo se resuelve por el `tenantId` canónico que manda el caller).
17
+ *
18
+ * Env var requerida en el consumer: `RETAIL_CUSTOMER_BUSINESS_URL`.
19
+ * El template.yml del consumer la setea con:
20
+ *
21
+ * RETAIL_CUSTOMER_BUSINESS_URL: '{{resolve:ssm:retail-customer-business}}'
22
+ *
23
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
24
+ */
25
+ @injectable()
26
+ export default class RetailCustomerBusinessApi implements IRetailCustomerBusinessApi {
27
+ private readonly baseUrl = process.env.RETAIL_CUSTOMER_BUSINESS_URL || "";
28
+
29
+ constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {}
30
+
31
+ async upsertCustomerFromKyc(
32
+ payload: UpsertCustomerFromKycRequest,
33
+ tenantId: string,
34
+ ): Promise<StandardResponse<CustomerResponse>> {
35
+ const url = `${this.baseUrl}/private/customers/upsert-from-kyc?tenantId=${encodeURIComponent(tenantId)}`;
36
+ return await this.httpRequest.post(url, payload);
37
+ }
38
+
39
+ async setAccountResult(
40
+ customerId: string,
41
+ payload: AccountResultRequest,
42
+ tenantId: string,
43
+ ): Promise<StandardResponse<CustomerResponse>> {
44
+ const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}/account-result?tenantId=${encodeURIComponent(tenantId)}`;
45
+ return await this.httpRequest.put(url, payload);
46
+ }
47
+
48
+ async getCustomerByPhone(
49
+ phone: string,
50
+ tenantId: string,
51
+ ): Promise<StandardResponse<CustomerResponse>> {
52
+ const url = `${this.baseUrl}/private/customers/by-phone/${encodeURIComponent(phone)}?tenantId=${encodeURIComponent(tenantId)}`;
53
+ return await this.httpRequest.get(url);
54
+ }
55
+
56
+ async getCustomer(
57
+ customerId: string,
58
+ tenantId: string,
59
+ ): Promise<StandardResponse<CustomerResponse>> {
60
+ const url = `${this.baseUrl}/private/customers/${encodeURIComponent(customerId)}?tenantId=${encodeURIComponent(tenantId)}`;
61
+ return await this.httpRequest.get(url);
62
+ }
63
+ }
@@ -0,0 +1,97 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import {
3
+ UpsertCustomerFromKycRequest,
4
+ AccountResultRequest,
5
+ CustomerResponse,
6
+ } from "@fiado/type-kit/bin/retailCustomer/index.js";
7
+
8
+ /**
9
+ * Contrato del publisher HTTP del lambda `retail-customer-business` (SureKeep Fase 2, pista Retail)
10
+ * para sus 4 endpoints privados de cliente (service-to-service, VPC-only).
11
+ *
12
+ * Consumidor previsto:
13
+ * - `retail-wizard-business` → upsert del cliente post-KYC, aterrizaje del resultado de apertura
14
+ * de cuenta (D35), y lecturas del cliente por teléfono / id durante la saga de venta.
15
+ *
16
+ * ─────────────────────────────────────────────────────────────────────────────
17
+ * `tenantId` es OBLIGATORIO en los 4 métodos — no es un detalle de firma.
18
+ * ─────────────────────────────────────────────────────────────────────────────
19
+ * Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC), así que
20
+ * el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller declara el
21
+ * tenant explícito por query (`?tenantId=`) y `@fiado/tenant-context` (`withContextByTenantId`) asume
22
+ * el rol de ESE silo. Sin `tenantId` → `400 UNKNOWN_TENANT` (fail-closed). Nunca hay default: caer a un
23
+ * tenant por default sería fail-OPEN y podría devolver datos de otra SOFOM.
24
+ *
25
+ * ⚠️ `tenantId` = el tenant CANÓNICO (p.ej. `'surekeep'`), NO el issuer Cognito ni la URL del pool.
26
+ * Es el mismo valor que consume `retail-org-business` en sus privados (`withContextByTenantId`).
27
+ *
28
+ * ─────────────────────────────────────────────────────────────────────────────
29
+ * ⚠️ Patrón de retorno: `StandardResponse<T>` — el consumer accede `result.data`, NO `result.body`.
30
+ * ─────────────────────────────────────────────────────────────────────────────
31
+ * `@fiado/http-client` entrega el BODY PELADO (hace `return response.data` en `AxiosHttpRequest`), así
32
+ * que `.statusCode`/`.body` no existen en runtime. El envelope real del lambda destino es
33
+ * `{ code, date, data, msg, description }` = `StandardResponse<T>` (ya exportado por
34
+ * `@fiado/gateway-adapter`). El consumer lee el shape del cliente en `result.data`.
35
+ *
36
+ * Errores: el lambda destino lanza `DomainError` tipado → el publisher RECHAZA (no devuelve null).
37
+ * Cada consumer mapea a su propio error de dominio (ver `fiado-api-invoker § 6`):
38
+ * `404 CUSTOMER_NOT_FOUND` (por id / por teléfono inexistente)
39
+ * `400 UNKNOWN_TENANT` (tenantId ausente o desconocido)
40
+ *
41
+ * Env var requerida en el consumer: `RETAIL_CUSTOMER_BUSINESS_URL`.
42
+ * El template.yml del consumer la setea con:
43
+ *
44
+ * RETAIL_CUSTOMER_BUSINESS_URL: '{{resolve:ssm:retail-customer-business}}'
45
+ *
46
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
47
+ */
48
+ export interface IRetailCustomerBusinessApi {
49
+ /**
50
+ * POST /private/customers/upsert-from-kyc?tenantId= — upsert idempotente del cliente tras el KYC
51
+ * (paso 02f). El lambda resuelve UNIQ#PHONE + UNIQ#CURP en la misma TX y setea
52
+ * `accountStatus=OPENING` server-side (la apertura corre en background, D35). Responde `201`.
53
+ *
54
+ * NOTA (TD-014 del customer): el `address` del type-kit tipa el `AddressBase` canónico (pesado);
55
+ * el lambda valida con un DTO local ligero. El domicilio OCR-parcial se salda con `RetailAddress`
56
+ * aditivo al type-kit (backlog) — no acá.
57
+ */
58
+ upsertCustomerFromKyc(
59
+ payload: UpsertCustomerFromKycRequest,
60
+ tenantId: string,
61
+ ): Promise<StandardResponse<CustomerResponse>>;
62
+
63
+ /**
64
+ * PUT /private/customers/{customerId}/account-result?tenantId= — aterriza el resultado terminal de
65
+ * la apertura de cuenta async (D35). Solo acepta OPEN/FAILED (nunca el intermedio OPENING). OPEN
66
+ * llega con `pcfClabe`/`pcfAccountLevel`; FAILED con `failReason`.
67
+ *
68
+ * @throws si el cliente no existe (`404 CUSTOMER_NOT_FOUND`).
69
+ */
70
+ setAccountResult(
71
+ customerId: string,
72
+ payload: AccountResultRequest,
73
+ tenantId: string,
74
+ ): Promise<StandardResponse<CustomerResponse>>;
75
+
76
+ /**
77
+ * GET /private/customers/by-phone/{phone}?tenantId= — resuelve el cliente por su teléfono MX (10
78
+ * dígitos, ya normalizado sin separadores). Usado por el wizard para saber si el teléfono ya es
79
+ * cliente del silo.
80
+ *
81
+ * @throws si no hay cliente con ese teléfono (`404 CUSTOMER_NOT_FOUND`).
82
+ */
83
+ getCustomerByPhone(
84
+ phone: string,
85
+ tenantId: string,
86
+ ): Promise<StandardResponse<CustomerResponse>>;
87
+
88
+ /**
89
+ * GET /private/customers/{customerId}?tenantId= — resuelve el cliente por su id.
90
+ *
91
+ * @throws si el cliente no existe (`404 CUSTOMER_NOT_FOUND`).
92
+ */
93
+ getCustomer(
94
+ customerId: string,
95
+ tenantId: string,
96
+ ): Promise<StandardResponse<CustomerResponse>>;
97
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/IRetailCustomerBusinessApi.js";
2
+ export { default as RetailCustomerBusinessApi } from "./api/RetailCustomerBusinessApi.js";