@fiado/api-invoker 5.66.0 → 5.67.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.
@@ -1,5 +1,6 @@
1
1
  import { StandardResponse } from "@fiado/gateway-adapter";
2
2
  import { DeviceAutoLockScheduleRequest, DeviceAutoLockScheduleResponse, DeviceEnrollInitiateResponse, DeviceEnrollRequest, DeviceEnrollStatusRequest, DeviceEnrollStatusResponse, DeviceLastSeenRequest, DeviceLastSeenResponse, DeviceLockRequest, DeviceLockResponse, DeviceNotifyRequest, DeviceNotifyResponse, DevicePinUnlockRequest, DevicePinUnlockResponse, DeviceReleaseInitiateResponse, DeviceReleaseRequest, DeviceReleaseStatusRequest, DeviceReleaseStatusResponse, DeviceStatusRequest, DeviceStatusResponse, DeviceUnlockRequest, DeviceUnlockResponse } from "@fiado/type-kit/bin/mdm/index.js";
3
+ import { DeviceBatchRequest, DeviceBatchResult, DeviceSingleResult } from "../../../utils/MdmEnvelopes.js";
3
4
  /**
4
5
  * Contrato del publisher HTTP del lambda `datacultr-connector` — el provider MDM que traduce el
5
6
  * contrato agnóstico de dispositivo (`@fiado/type-kit/bin/mdm`) a la API de Datacultr. Su consumidor
@@ -46,22 +47,7 @@ import { DeviceAutoLockScheduleRequest, DeviceAutoLockScheduleResponse, DeviceEn
46
47
  *
47
48
  * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
48
49
  */
49
- /**
50
- * Sobre de entrada de los endpoints batch del connector. No vive en `@fiado/type-kit/bin/mdm`
51
- * porque los DTOs publicados son de UN imei; el sobre es dominio del líder (gap E8), migrar a
52
- * type-kit cuando lo publique.
53
- */
54
- export interface DeviceBatchRequest<TItem> {
55
- items: TItem[];
56
- }
57
- /** Sobre de salida de los endpoints batch: viaja dentro de `StandardResponse.data`. Mismo gap E8. */
58
- export interface DeviceBatchResult<TItem> {
59
- results: TItem[];
60
- }
61
- /** Sobre de salida de los endpoints de UN solo IMEI. Hoy solo `pinUnlock` no es batch. */
62
- export interface DeviceSingleResult<TItem> {
63
- result: TItem;
64
- }
50
+ export * from "../../../utils/MdmEnvelopes.js";
65
51
  export interface IDatacultrConnectorApi {
66
52
  /**
67
53
  * POST `/devices/enroll` — pre-registra la expectativa de enrolamiento de cada IMEI.
@@ -1 +1,49 @@
1
- export {};
1
+ /**
2
+ * Contrato del publisher HTTP del lambda `datacultr-connector` — el provider MDM que traduce el
3
+ * contrato agnóstico de dispositivo (`@fiado/type-kit/bin/mdm`) a la API de Datacultr. Su consumidor
4
+ * es el módulo `device/` de `loan-credit-business` (`MdmConnectorClient`), que NUNCA le pega por
5
+ * `http-client` directo: entre lambdas Fiado se habla siempre por `@fiado/api-invoker`.
6
+ *
7
+ * ─────────────────────────────────────────────────────────────────────────────
8
+ * PATHS — `/devices/...`, SIN prefijo `/private`.
9
+ * ─────────────────────────────────────────────────────────────────────────────
10
+ * A diferencia de la mayoría de los privados Fiado (`/private/...`), el `PrivateController` de este
11
+ * connector declara los paths como `/devices/enroll`, `/devices/status`, etc. El aislamiento no lo da
12
+ * el prefijo sino la red: la API privada es `EndpointConfiguration: PRIVATE` con ResourcePolicy que
13
+ * deniega todo lo que no venga de los VPC Endpoints de Fiado.
14
+ *
15
+ * ─────────────────────────────────────────────────────────────────────────────
16
+ * SIN TENANT — hoy el connector es efectivamente single-tenant.
17
+ * ─────────────────────────────────────────────────────────────────────────────
18
+ * Ningún método lleva `tenantId` porque el destino NO lo resuelve: su `PrivateController` no lee
19
+ * `X-Tenant-Id` ni `x-tenant-issuer` (cero referencias en el repo). Las credenciales de Datacultr
20
+ * salen de un único secret del lambda. DEUDA a levantar cuando el connector implemente M6
21
+ * (multi-tenant del MDM): ahí este contrato suma el tenant y pasa a ser un cambio MAJOR.
22
+ *
23
+ * ─────────────────────────────────────────────────────────────────────────────
24
+ * AUTORIZACIÓN — `Feature.ANONIMUS`.
25
+ * ─────────────────────────────────────────────────────────────────────────────
26
+ * Los privados del connector son `Feature.ANONIMUS`: sin RBAC y sin claims. La única protección es
27
+ * la VPC, así que el caller no manda `Authorization` ni headers de identidad.
28
+ *
29
+ * ⚠️ Retorno `StandardResponse<T>` — el consumer lee `result.data`, NO `result.body`.
30
+ * Errores de transporte (falla el lambda entero, no un ítem): el publisher RECHAZA con el
31
+ * `DomainError` tipado del destino. Nunca fallback: el caller jamás recibe un batch vacío
32
+ * disfrazado de éxito.
33
+ *
34
+ * Granularidad POR ÍTEM — el batch NUNCA falla entero:
35
+ * - Cada `results[i]` trae su propio `status` (`SUCCESS` | `PENDING` | `ERROR`) y un `error` opcional.
36
+ * Un 200 puede traer ítems en `ERROR`: el caller TIENE que recorrer `results` y decidir por ítem.
37
+ * - El `error.code` del ítem es un `MdmErrorCodeEnum` (`PROVIDER_NOT_SUPPORTED`, `DEVICE_NOT_FOUND`,
38
+ * `PROVIDER_TIMEOUT`, …). El `status` no lleva el motivo: el motivo vive solo en `error`.
39
+ *
40
+ * Env var requerida en el consumer: `DATACULTR_CONNECTOR_URL`.
41
+ * El template.yml del consumer la setea con:
42
+ *
43
+ * DATACULTR_CONNECTOR_URL: '{{resolve:ssm:datacultr-connector}}'
44
+ *
45
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
46
+ */
47
+ // Los sobres viven en `utils/MdmEnvelopes` porque los comparten todos los connectors MDM.
48
+ // Se re-exportan acá para no cambiar la superficie pública de `@fiado/api-invoker`.
49
+ export * from "../../../utils/MdmEnvelopes.js";
package/bin/index.d.ts CHANGED
@@ -114,3 +114,4 @@ export * from "./collection-engine/index.js";
114
114
  export * from "./domain-callback/index.js";
115
115
  export * from "./datacultrConnector/index.js";
116
116
  export * from "./webhook-business/index.js";
117
+ export * from "./trustonicConnector/index.js";
package/bin/index.js CHANGED
@@ -114,3 +114,4 @@ export * from "./collection-engine/index.js";
114
114
  export * from "./domain-callback/index.js";
115
115
  export * from "./datacultrConnector/index.js";
116
116
  export * from "./webhook-business/index.js";
117
+ export * from "./trustonicConnector/index.js";
@@ -0,0 +1,34 @@
1
+ import type { IHttpRequest } from "@fiado/http-client";
2
+ import { StandardResponse } from "@fiado/gateway-adapter";
3
+ import { DeviceAutoLockScheduleRequest, DeviceAutoLockScheduleResponse, DeviceEnrollInitiateResponse, DeviceEnrollRequest, DeviceEnrollStatusRequest, DeviceEnrollStatusResponse, DeviceLastSeenRequest, DeviceLastSeenResponse, DeviceLockRequest, DeviceLockResponse, DeviceNotifyRequest, DeviceNotifyResponse, DevicePinUnlockRequest, DevicePinUnlockResponse, DeviceReleaseInitiateResponse, DeviceReleaseRequest, DeviceReleaseStatusRequest, DeviceReleaseStatusResponse, DeviceStatusRequest, DeviceStatusResponse, DeviceUnlockRequest, DeviceUnlockResponse } from "@fiado/type-kit/bin/mdm/index.js";
4
+ import { DeviceBatchRequest, DeviceBatchResult } from "../../utils/MdmEnvelopes.js";
5
+ import { DeviceInitiateBatchResult, DevicePollingBatchRequest, ITrustonicConnectorApi } from "./interfaces/ITrustonicConnectorApi.js";
6
+ /**
7
+ * Publisher HTTP del lambda `trustonic-connector` (segundo provider MDM de SureKeep). Contrato y
8
+ * semántica completos → `ITrustonicConnectorApi` (paths sin prefijo `/private`, sin tenant,
9
+ * `StandardResponse` → leer `result.data`, granularidad por ítem, y las cinco diferencias reales
10
+ * contra el connector de Datacultr).
11
+ *
12
+ * Env var requerida en el consumer: `TRUSTONIC_CONNECTOR_URL`.
13
+ * El template.yml del consumer la setea con:
14
+ *
15
+ * TRUSTONIC_CONNECTOR_URL: '{{resolve:ssm:trustonic-connector}}'
16
+ *
17
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
18
+ */
19
+ export default class TrustonicConnectorApi implements ITrustonicConnectorApi {
20
+ private httpRequest;
21
+ private readonly baseUrl;
22
+ constructor(httpRequest: IHttpRequest);
23
+ enrollDevices(input: DeviceBatchRequest<DeviceEnrollRequest>): Promise<StandardResponse<DeviceInitiateBatchResult<DeviceEnrollInitiateResponse>>>;
24
+ enrollStatus(input: DevicePollingBatchRequest<DeviceEnrollStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceEnrollStatusResponse>>>;
25
+ getStatus(input: DeviceBatchRequest<DeviceStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceStatusResponse>>>;
26
+ getLastSeen(input: DeviceBatchRequest<DeviceLastSeenRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceLastSeenResponse>>>;
27
+ lockDevices(input: DeviceBatchRequest<DeviceLockRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceLockResponse>>>;
28
+ unlockDevices(input: DeviceBatchRequest<DeviceUnlockRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceUnlockResponse>>>;
29
+ autoLockSchedule(input: DeviceBatchRequest<DeviceAutoLockScheduleRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceAutoLockScheduleResponse>>>;
30
+ pinUnlock(input: DevicePinUnlockRequest): Promise<StandardResponse<DevicePinUnlockResponse>>;
31
+ notifyDevices(input: DeviceBatchRequest<DeviceNotifyRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceNotifyResponse>>>;
32
+ releaseDevices(input: DeviceBatchRequest<DeviceReleaseRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseInitiateResponse>>>;
33
+ releaseStatus(input: DevicePollingBatchRequest<DeviceReleaseStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseStatusResponse>>>;
34
+ }
@@ -0,0 +1,73 @@
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 `trustonic-connector` (segundo provider MDM de SureKeep). Contrato y
16
+ * semántica completos → `ITrustonicConnectorApi` (paths sin prefijo `/private`, sin tenant,
17
+ * `StandardResponse` → leer `result.data`, granularidad por ítem, y las cinco diferencias reales
18
+ * contra el connector de Datacultr).
19
+ *
20
+ * Env var requerida en el consumer: `TRUSTONIC_CONNECTOR_URL`.
21
+ * El template.yml del consumer la setea con:
22
+ *
23
+ * TRUSTONIC_CONNECTOR_URL: '{{resolve:ssm:trustonic-connector}}'
24
+ *
25
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
26
+ */
27
+ let TrustonicConnectorApi = class TrustonicConnectorApi {
28
+ httpRequest;
29
+ // El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//devices".
30
+ baseUrl = (process.env.TRUSTONIC_CONNECTOR_URL || "").replace(/\/+$/, "");
31
+ constructor(httpRequest) {
32
+ this.httpRequest = httpRequest;
33
+ }
34
+ async enrollDevices(input) {
35
+ return await this.httpRequest.post(`${this.baseUrl}/devices/enroll`, input);
36
+ }
37
+ async enrollStatus(input) {
38
+ return await this.httpRequest.post(`${this.baseUrl}/devices/enroll/status`, input);
39
+ }
40
+ async getStatus(input) {
41
+ return await this.httpRequest.post(`${this.baseUrl}/devices/status`, input);
42
+ }
43
+ async getLastSeen(input) {
44
+ return await this.httpRequest.post(`${this.baseUrl}/devices/last-seen`, input);
45
+ }
46
+ async lockDevices(input) {
47
+ return await this.httpRequest.post(`${this.baseUrl}/devices/lock`, input);
48
+ }
49
+ async unlockDevices(input) {
50
+ return await this.httpRequest.post(`${this.baseUrl}/devices/unlock`, input);
51
+ }
52
+ async autoLockSchedule(input) {
53
+ return await this.httpRequest.post(`${this.baseUrl}/devices/auto-lock-schedule`, input);
54
+ }
55
+ async pinUnlock(input) {
56
+ return await this.httpRequest.post(`${this.baseUrl}/devices/pin-unlock`, input);
57
+ }
58
+ async notifyDevices(input) {
59
+ return await this.httpRequest.post(`${this.baseUrl}/devices/notify`, input);
60
+ }
61
+ async releaseDevices(input) {
62
+ return await this.httpRequest.post(`${this.baseUrl}/devices/release`, input);
63
+ }
64
+ async releaseStatus(input) {
65
+ return await this.httpRequest.post(`${this.baseUrl}/devices/release/status`, input);
66
+ }
67
+ };
68
+ TrustonicConnectorApi = __decorate([
69
+ injectable(),
70
+ __param(0, inject("IHttpRequest")),
71
+ __metadata("design:paramtypes", [Object])
72
+ ], TrustonicConnectorApi);
73
+ export default TrustonicConnectorApi;
@@ -0,0 +1,158 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import { DeviceAutoLockScheduleRequest, DeviceAutoLockScheduleResponse, DeviceEnrollInitiateResponse, DeviceEnrollRequest, DeviceEnrollStatusRequest, DeviceEnrollStatusResponse, DeviceLastSeenRequest, DeviceLastSeenResponse, DeviceLockRequest, DeviceLockResponse, DeviceNotifyRequest, DeviceNotifyResponse, DevicePinUnlockRequest, DevicePinUnlockResponse, DeviceReleaseInitiateResponse, DeviceReleaseRequest, DeviceReleaseStatusRequest, DeviceReleaseStatusResponse, DeviceStatusRequest, DeviceStatusResponse, DeviceUnlockRequest, DeviceUnlockResponse, MdmProviderEnum } from "@fiado/type-kit/bin/mdm/index.js";
3
+ import { DeviceBatchRequest, DeviceBatchResult } from "../../../utils/MdmEnvelopes.js";
4
+ /**
5
+ * Contrato del publisher HTTP del lambda `trustonic-connector` — el segundo provider MDM de
6
+ * SureKeep, que traduce el contrato agnóstico de dispositivo (`@fiado/type-kit/bin/mdm`) a la API
7
+ * de Trustonic. Su consumidor es el módulo `device/` de `loan-credit-business`, que NUNCA le pega
8
+ * por `http-client` directo: entre lambdas Fiado se habla siempre por `@fiado/api-invoker`.
9
+ *
10
+ * ─────────────────────────────────────────────────────────────────────────────
11
+ * SUPERFICIE — 11 operaciones, las mismas que `IDatacultrConnectorApi`.
12
+ * ─────────────────────────────────────────────────────────────────────────────
13
+ * El connector expone 16 endpoints. Quedan afuera `restrictApps`, `archive`, `deactivate`,
14
+ * `deactivateStatus` y `deviceLog`: `IMdmProviderAdapter` de `loan-credit-business` no los pide y
15
+ * el adapter tiene un solo contrato para los dos providers. Sumar operaciones que solo soporta
16
+ * Trustonic es un cambio aparte, con su propia decisión.
17
+ *
18
+ * ─────────────────────────────────────────────────────────────────────────────
19
+ * PATHS — `/devices/...`, SIN prefijo `/private`. Igual que Datacultr.
20
+ * ─────────────────────────────────────────────────────────────────────────────
21
+ * El aislamiento no lo da el prefijo sino la red: la API privada es `EndpointConfiguration:
22
+ * PRIVATE` con ResourcePolicy que deniega todo lo que no venga de los VPC Endpoints de Fiado.
23
+ *
24
+ * ─────────────────────────────────────────────────────────────────────────────
25
+ * SIN TENANT y `Feature.ANONIMUS`.
26
+ * ─────────────────────────────────────────────────────────────────────────────
27
+ * Ningún método lleva `tenantId`: el `PrivateController` del destino no lee `X-Tenant-Id` ni
28
+ * `x-tenant-issuer`, y las credenciales de Trustonic salen de un único secret del lambda. Los
29
+ * privados son `Feature.ANONIMUS` — sin RBAC y sin claims, así que el caller no manda
30
+ * `Authorization`. Misma deuda que Datacultr: cuando el MDM sea multi-tenant, este contrato suma
31
+ * el tenant y pasa a ser un cambio MAJOR.
32
+ *
33
+ * ⚠️ Retorno `StandardResponse<T>` — el consumer lee `result.data`, NO `result.body`.
34
+ * Errores de transporte (falla el lambda entero, no un ítem): el publisher RECHAZA con el
35
+ * `DomainError` tipado del destino. Nunca fallback: el caller jamás recibe un batch vacío
36
+ * disfrazado de éxito.
37
+ *
38
+ * Granularidad POR ÍTEM — el batch NUNCA falla entero:
39
+ * - Cada `results[i]` trae su propio `status` (`SUCCESS` | `PENDING` | `ERROR`) y un `error`
40
+ * opcional. Un 200 puede traer ítems en `ERROR`: el caller TIENE que recorrer `results`.
41
+ * - El `error.code` del ítem es un `MdmErrorCodeEnum`. El `status` no lleva el motivo.
42
+ *
43
+ * ─────────────────────────────────────────────────────────────────────────────
44
+ * DIFERENCIAS DE CONTRATO CONTRA DATACULTR — no son intercambiables.
45
+ * ─────────────────────────────────────────────────────────────────────────────
46
+ * 1. `enrollDevices` devuelve `pollingHandle` + `provider` además de `results`; en Datacultr solo
47
+ * devuelve `results`. Acá el enroll es async de verdad y el handle es obligatorio para polear.
48
+ * 2. `enrollStatus` y `releaseStatus` EXIGEN `pollingHandle` en el body. En Datacultr el sobre de
49
+ * entrada es solo `{ items }`.
50
+ * 3. `lockDevices` soporta `TEMPORARY` de verdad; Datacultr lo degrada por ítem.
51
+ * 4. `autoLockSchedule` está degradado en Trustonic; en Datacultr es la vía real del bloqueo.
52
+ * 5. `notifyDevices` usa `title` + `content` (texto crudo) e ignora `notificationCode`; en
53
+ * Datacultr es al revés.
54
+ *
55
+ * Env var requerida en el consumer: `TRUSTONIC_CONNECTOR_URL`.
56
+ * El template.yml del consumer la setea con:
57
+ *
58
+ * TRUSTONIC_CONNECTOR_URL: '{{resolve:ssm:trustonic-connector}}'
59
+ *
60
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
61
+ */
62
+ /**
63
+ * Sobre de entrada de los endpoints `/status` de Trustonic: además de los ítems exige el
64
+ * `pollingHandle` que devolvió el initiate. Es un string opaco — no lo inspecciones.
65
+ */
66
+ export interface DevicePollingBatchRequest<TItem> {
67
+ pollingHandle: string;
68
+ items: TItem[];
69
+ }
70
+ /**
71
+ * Sobre de salida de un initiate async de Trustonic. `pollingHandle` es lo que el caller manda
72
+ * después a `/status`; `provider` identifica qué MDM atendió la operación.
73
+ */
74
+ export interface DeviceInitiateBatchResult<TItem> {
75
+ pollingHandle: string;
76
+ provider: MdmProviderEnum;
77
+ results: TItem[];
78
+ }
79
+ export interface ITrustonicConnectorApi {
80
+ /**
81
+ * POST `/devices/enroll` — inicia el enrolamiento de cada IMEI en Trustonic (upload de
82
+ * inventario + activación del servicio `DeviceFinancing` en una call atómica).
83
+ *
84
+ * ASYNC de verdad, a diferencia de Datacultr: el destino devuelve `pollingHandle` y el caller
85
+ * DEBE polear `enrollStatus` con ese handle hasta que todos los ítems sean terminales. El caso
86
+ * típico es que todos vuelvan en `PENDING`.
87
+ *
88
+ * `DeviceEnrollRequest.lockMode` (`ONDEMAND` pospago / `SCHEDULED` prepago) es opcional; si se
89
+ * omite el destino asume `ONDEMAND`.
90
+ */
91
+ enrollDevices(input: DeviceBatchRequest<DeviceEnrollRequest>): Promise<StandardResponse<DeviceInitiateBatchResult<DeviceEnrollInitiateResponse>>>;
92
+ /**
93
+ * POST `/devices/enroll/status` — estado del enrolamiento iniciado con `enrollDevices`.
94
+ *
95
+ * ⚠️ EXIGE `pollingHandle`: sin él el destino responde 400 `MISSING_POLLING_HANDLE`.
96
+ *
97
+ * Los campos `enrolledAt`, `enrollmentMode`, `enrollmentId`, `brand` y `model` siempre vienen
98
+ * `undefined` — el endpoint de Trustonic no los expone; existen para Datacultr.
99
+ */
100
+ enrollStatus(input: DevicePollingBatchRequest<DeviceEnrollStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceEnrollStatusResponse>>>;
101
+ /** POST `/devices/status` — estado actual de cada IMEI, con `brand`, `model` y `lastSeenAt`. */
102
+ getStatus(input: DeviceBatchRequest<DeviceStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceStatusResponse>>>;
103
+ /** POST `/devices/last-seen` — último contacto reportado por cada IMEI (heartbeat). */
104
+ getLastSeen(input: DeviceBatchRequest<DeviceLastSeenRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceLastSeenResponse>>>;
105
+ /**
106
+ * POST `/devices/lock` — bloquea cada IMEI, con mensaje opcional en pantalla.
107
+ * Acepta `mode: TEMPORARY` de verdad (con `durationSeconds`), que Datacultr degrada por ítem.
108
+ */
109
+ lockDevices(input: DeviceBatchRequest<DeviceLockRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceLockResponse>>>;
110
+ /**
111
+ * POST `/devices/unlock` — desbloquea cada IMEI.
112
+ * `unlockUntil` (ISO-8601) acota hasta cuándo vale el desbloqueo y solo aplica en modo
113
+ * `SCHEDULED`; si el modo lo exige y falta, el ítem vuelve en `ERROR` con
114
+ * `MdmErrorCodeEnum.UNLOCK_UNTIL_REQUIRED`.
115
+ */
116
+ unlockDevices(input: DeviceBatchRequest<DeviceUnlockRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceUnlockResponse>>>;
117
+ /**
118
+ * POST `/devices/auto-lock-schedule` — programa el bloqueo de cada IMEI en una fecha futura.
119
+ *
120
+ * ⚠️ DEGRADADO en Trustonic: el destino no llama al proveedor y devuelve cada ítem en `ERROR`
121
+ * con `PROVIDER_NOT_SUPPORTED`. Es el espejo exacto de Datacultr, donde ésta es la vía real del
122
+ * bloqueo. El caller no debe asumir la misma semántica entre providers.
123
+ */
124
+ autoLockSchedule(input: DeviceBatchRequest<DeviceAutoLockScheduleRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceAutoLockScheduleResponse>>>;
125
+ /**
126
+ * POST `/devices/pin-unlock` — pide a Trustonic el PIN offline de un equipo sin conectividad.
127
+ *
128
+ * ⚠️ NO ES BATCH y NO LLEVA SOBRE, a diferencia del resto del contrato: el body es el
129
+ * `DevicePinUnlockRequest` pelado y la respuesta es el `DevicePinUnlockResponse` directo en
130
+ * `data`, sin `{ result }` — ahí difiere del `pinUnlock` de Datacultr.
131
+ *
132
+ * Operación sensible: `pin`, `validitySeconds` y `generatedAt` solo vienen con `status`
133
+ * `SUCCESS`. El PIN viaja únicamente en esta respuesta — nunca loggearlo.
134
+ */
135
+ pinUnlock(input: DevicePinUnlockRequest): Promise<StandardResponse<DevicePinUnlockResponse>>;
136
+ /**
137
+ * POST `/devices/notify` — manda una notificación (`BANNER` o `FULLSCREEN`) a cada IMEI.
138
+ * Trustonic usa `title` y `content` como texto crudo e ignora `notificationCode`, al revés que
139
+ * Datacultr, que resuelve el texto por catálogo.
140
+ */
141
+ notifyDevices(input: DeviceBatchRequest<DeviceNotifyRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceNotifyResponse>>>;
142
+ /**
143
+ * POST `/devices/release` — libera definitivamente cada IMEI del MDM (fin de tenure).
144
+ *
145
+ * ⚠️ IRREVERSIBLE: un equipo liberado no se puede re-enrolar en Trustonic.
146
+ * Es sync y terminal — cada ítem vuelve `SUCCESS` o `ERROR`, nunca `PENDING`, y la respuesta NO
147
+ * trae `pollingHandle` (asimetría con `enrollDevices`).
148
+ */
149
+ releaseDevices(input: DeviceBatchRequest<DeviceReleaseRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseInitiateResponse>>>;
150
+ /**
151
+ * POST `/devices/release/status` — consulta el estado de una liberación.
152
+ *
153
+ * ⚠️ EXIGE `pollingHandle` aunque `releaseDevices` no devuelva ninguno: el caller tiene que
154
+ * inventar o reusar un identificador de tracing. Existe solo por simetría con Datacultr, donde
155
+ * el release sí es async; contra Trustonic normalmente no hace falta llamarlo.
156
+ */
157
+ releaseStatus(input: DevicePollingBatchRequest<DeviceReleaseStatusRequest>): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseStatusResponse>>>;
158
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ITrustonicConnectorApi.js";
2
+ export { default as TrustonicConnectorApi } from "./api/TrustonicConnectorApi.js";
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ITrustonicConnectorApi.js";
2
+ export { default as TrustonicConnectorApi } from "./api/TrustonicConnectorApi.js";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Sobres de request/response compartidos por los connectors MDM (`datacultr-connector`,
3
+ * `trustonic-connector`). No viven en `@fiado/type-kit/bin/mdm` porque los DTOs publicados
4
+ * son de UN imei; el sobre es dominio del líder (gap E8), migrar a type-kit cuando lo publique.
5
+ */
6
+ /** Sobre de entrada de los endpoints batch de un connector MDM. */
7
+ export interface DeviceBatchRequest<TItem> {
8
+ items: TItem[];
9
+ }
10
+ /** Sobre de salida de los endpoints batch: viaja dentro de `StandardResponse.data`. */
11
+ export interface DeviceBatchResult<TItem> {
12
+ results: TItem[];
13
+ }
14
+ /** Sobre de salida de los endpoints de UN solo IMEI. Hoy solo `pinUnlock` no es batch. */
15
+ export interface DeviceSingleResult<TItem> {
16
+ result: TItem;
17
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Sobres de request/response compartidos por los connectors MDM (`datacultr-connector`,
3
+ * `trustonic-connector`). No viven en `@fiado/type-kit/bin/mdm` porque los DTOs publicados
4
+ * son de UN imei; el sobre es dominio del líder (gap E8), migrar a type-kit cuando lo publique.
5
+ */
6
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/api-invoker",
3
- "version": "5.66.0",
3
+ "version": "5.67.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.390.0",
37
+ "@fiado/type-kit": "^3.400.0",
38
38
  "dotenv": "^16.4.7"
39
39
  },
40
40
  "peerDependencies": {
@@ -23,6 +23,7 @@ import {
23
23
  DeviceUnlockRequest,
24
24
  DeviceUnlockResponse,
25
25
  } from "@fiado/type-kit/bin/mdm/index.js";
26
+ import { DeviceBatchRequest, DeviceBatchResult, DeviceSingleResult } from "../../../utils/MdmEnvelopes.js";
26
27
 
27
28
  /**
28
29
  * Contrato del publisher HTTP del lambda `datacultr-connector` — el provider MDM que traduce el
@@ -71,24 +72,9 @@ import {
71
72
  * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
72
73
  */
73
74
 
74
- /**
75
- * Sobre de entrada de los endpoints batch del connector. No vive en `@fiado/type-kit/bin/mdm`
76
- * porque los DTOs publicados son de UN imei; el sobre es dominio del líder (gap E8), migrar a
77
- * type-kit cuando lo publique.
78
- */
79
- export interface DeviceBatchRequest<TItem> {
80
- items: TItem[];
81
- }
82
-
83
- /** Sobre de salida de los endpoints batch: viaja dentro de `StandardResponse.data`. Mismo gap E8. */
84
- export interface DeviceBatchResult<TItem> {
85
- results: TItem[];
86
- }
87
-
88
- /** Sobre de salida de los endpoints de UN solo IMEI. Hoy solo `pinUnlock` no es batch. */
89
- export interface DeviceSingleResult<TItem> {
90
- result: TItem;
91
- }
75
+ // Los sobres viven en `utils/MdmEnvelopes` porque los comparten todos los connectors MDM.
76
+ // Se re-exportan acá para no cambiar la superficie pública de `@fiado/api-invoker`.
77
+ export * from "../../../utils/MdmEnvelopes.js";
92
78
 
93
79
  export interface IDatacultrConnectorApi {
94
80
  /**
package/src/index.ts CHANGED
@@ -114,3 +114,4 @@ export * from "./collection-engine/index.js";
114
114
  export * from "./domain-callback/index.js";
115
115
  export * from "./datacultrConnector/index.js";
116
116
  export * from "./webhook-business/index.js";
117
+ export * from "./trustonicConnector/index.js";
@@ -0,0 +1,118 @@
1
+ import { inject, injectable } from "inversify";
2
+ import type { IHttpRequest } from "@fiado/http-client";
3
+ import { StandardResponse } from "@fiado/gateway-adapter";
4
+ import {
5
+ DeviceAutoLockScheduleRequest,
6
+ DeviceAutoLockScheduleResponse,
7
+ DeviceEnrollInitiateResponse,
8
+ DeviceEnrollRequest,
9
+ DeviceEnrollStatusRequest,
10
+ DeviceEnrollStatusResponse,
11
+ DeviceLastSeenRequest,
12
+ DeviceLastSeenResponse,
13
+ DeviceLockRequest,
14
+ DeviceLockResponse,
15
+ DeviceNotifyRequest,
16
+ DeviceNotifyResponse,
17
+ DevicePinUnlockRequest,
18
+ DevicePinUnlockResponse,
19
+ DeviceReleaseInitiateResponse,
20
+ DeviceReleaseRequest,
21
+ DeviceReleaseStatusRequest,
22
+ DeviceReleaseStatusResponse,
23
+ DeviceStatusRequest,
24
+ DeviceStatusResponse,
25
+ DeviceUnlockRequest,
26
+ DeviceUnlockResponse,
27
+ } from "@fiado/type-kit/bin/mdm/index.js";
28
+ import { DeviceBatchRequest, DeviceBatchResult } from "../../utils/MdmEnvelopes.js";
29
+ import {
30
+ DeviceInitiateBatchResult,
31
+ DevicePollingBatchRequest,
32
+ ITrustonicConnectorApi,
33
+ } from "./interfaces/ITrustonicConnectorApi.js";
34
+
35
+ /**
36
+ * Publisher HTTP del lambda `trustonic-connector` (segundo provider MDM de SureKeep). Contrato y
37
+ * semántica completos → `ITrustonicConnectorApi` (paths sin prefijo `/private`, sin tenant,
38
+ * `StandardResponse` → leer `result.data`, granularidad por ítem, y las cinco diferencias reales
39
+ * contra el connector de Datacultr).
40
+ *
41
+ * Env var requerida en el consumer: `TRUSTONIC_CONNECTOR_URL`.
42
+ * El template.yml del consumer la setea con:
43
+ *
44
+ * TRUSTONIC_CONNECTOR_URL: '{{resolve:ssm:trustonic-connector}}'
45
+ *
46
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
47
+ */
48
+ @injectable()
49
+ export default class TrustonicConnectorApi implements ITrustonicConnectorApi {
50
+ // El buildspec publica la URL en SSM con "/" final — se normaliza para no armar "//devices".
51
+ private readonly baseUrl = (process.env.TRUSTONIC_CONNECTOR_URL || "").replace(/\/+$/, "");
52
+
53
+ constructor(@inject("IHttpRequest") private httpRequest: IHttpRequest) {}
54
+
55
+ async enrollDevices(
56
+ input: DeviceBatchRequest<DeviceEnrollRequest>,
57
+ ): Promise<StandardResponse<DeviceInitiateBatchResult<DeviceEnrollInitiateResponse>>> {
58
+ return await this.httpRequest.post(`${this.baseUrl}/devices/enroll`, input);
59
+ }
60
+
61
+ async enrollStatus(
62
+ input: DevicePollingBatchRequest<DeviceEnrollStatusRequest>,
63
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceEnrollStatusResponse>>> {
64
+ return await this.httpRequest.post(`${this.baseUrl}/devices/enroll/status`, input);
65
+ }
66
+
67
+ async getStatus(
68
+ input: DeviceBatchRequest<DeviceStatusRequest>,
69
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceStatusResponse>>> {
70
+ return await this.httpRequest.post(`${this.baseUrl}/devices/status`, input);
71
+ }
72
+
73
+ async getLastSeen(
74
+ input: DeviceBatchRequest<DeviceLastSeenRequest>,
75
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceLastSeenResponse>>> {
76
+ return await this.httpRequest.post(`${this.baseUrl}/devices/last-seen`, input);
77
+ }
78
+
79
+ async lockDevices(
80
+ input: DeviceBatchRequest<DeviceLockRequest>,
81
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceLockResponse>>> {
82
+ return await this.httpRequest.post(`${this.baseUrl}/devices/lock`, input);
83
+ }
84
+
85
+ async unlockDevices(
86
+ input: DeviceBatchRequest<DeviceUnlockRequest>,
87
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceUnlockResponse>>> {
88
+ return await this.httpRequest.post(`${this.baseUrl}/devices/unlock`, input);
89
+ }
90
+
91
+ async autoLockSchedule(
92
+ input: DeviceBatchRequest<DeviceAutoLockScheduleRequest>,
93
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceAutoLockScheduleResponse>>> {
94
+ return await this.httpRequest.post(`${this.baseUrl}/devices/auto-lock-schedule`, input);
95
+ }
96
+
97
+ async pinUnlock(input: DevicePinUnlockRequest): Promise<StandardResponse<DevicePinUnlockResponse>> {
98
+ return await this.httpRequest.post(`${this.baseUrl}/devices/pin-unlock`, input);
99
+ }
100
+
101
+ async notifyDevices(
102
+ input: DeviceBatchRequest<DeviceNotifyRequest>,
103
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceNotifyResponse>>> {
104
+ return await this.httpRequest.post(`${this.baseUrl}/devices/notify`, input);
105
+ }
106
+
107
+ async releaseDevices(
108
+ input: DeviceBatchRequest<DeviceReleaseRequest>,
109
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseInitiateResponse>>> {
110
+ return await this.httpRequest.post(`${this.baseUrl}/devices/release`, input);
111
+ }
112
+
113
+ async releaseStatus(
114
+ input: DevicePollingBatchRequest<DeviceReleaseStatusRequest>,
115
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseStatusResponse>>> {
116
+ return await this.httpRequest.post(`${this.baseUrl}/devices/release/status`, input);
117
+ }
118
+ }
@@ -0,0 +1,216 @@
1
+ import { StandardResponse } from "@fiado/gateway-adapter";
2
+ import {
3
+ DeviceAutoLockScheduleRequest,
4
+ DeviceAutoLockScheduleResponse,
5
+ DeviceEnrollInitiateResponse,
6
+ DeviceEnrollRequest,
7
+ DeviceEnrollStatusRequest,
8
+ DeviceEnrollStatusResponse,
9
+ DeviceLastSeenRequest,
10
+ DeviceLastSeenResponse,
11
+ DeviceLockRequest,
12
+ DeviceLockResponse,
13
+ DeviceNotifyRequest,
14
+ DeviceNotifyResponse,
15
+ DevicePinUnlockRequest,
16
+ DevicePinUnlockResponse,
17
+ DeviceReleaseInitiateResponse,
18
+ DeviceReleaseRequest,
19
+ DeviceReleaseStatusRequest,
20
+ DeviceReleaseStatusResponse,
21
+ DeviceStatusRequest,
22
+ DeviceStatusResponse,
23
+ DeviceUnlockRequest,
24
+ DeviceUnlockResponse,
25
+ MdmProviderEnum,
26
+ } from "@fiado/type-kit/bin/mdm/index.js";
27
+ import { DeviceBatchRequest, DeviceBatchResult } from "../../../utils/MdmEnvelopes.js";
28
+
29
+ /**
30
+ * Contrato del publisher HTTP del lambda `trustonic-connector` — el segundo provider MDM de
31
+ * SureKeep, que traduce el contrato agnóstico de dispositivo (`@fiado/type-kit/bin/mdm`) a la API
32
+ * de Trustonic. Su consumidor es el módulo `device/` de `loan-credit-business`, que NUNCA le pega
33
+ * por `http-client` directo: entre lambdas Fiado se habla siempre por `@fiado/api-invoker`.
34
+ *
35
+ * ─────────────────────────────────────────────────────────────────────────────
36
+ * SUPERFICIE — 11 operaciones, las mismas que `IDatacultrConnectorApi`.
37
+ * ─────────────────────────────────────────────────────────────────────────────
38
+ * El connector expone 16 endpoints. Quedan afuera `restrictApps`, `archive`, `deactivate`,
39
+ * `deactivateStatus` y `deviceLog`: `IMdmProviderAdapter` de `loan-credit-business` no los pide y
40
+ * el adapter tiene un solo contrato para los dos providers. Sumar operaciones que solo soporta
41
+ * Trustonic es un cambio aparte, con su propia decisión.
42
+ *
43
+ * ─────────────────────────────────────────────────────────────────────────────
44
+ * PATHS — `/devices/...`, SIN prefijo `/private`. Igual que Datacultr.
45
+ * ─────────────────────────────────────────────────────────────────────────────
46
+ * El aislamiento no lo da el prefijo sino la red: la API privada es `EndpointConfiguration:
47
+ * PRIVATE` con ResourcePolicy que deniega todo lo que no venga de los VPC Endpoints de Fiado.
48
+ *
49
+ * ─────────────────────────────────────────────────────────────────────────────
50
+ * SIN TENANT y `Feature.ANONIMUS`.
51
+ * ─────────────────────────────────────────────────────────────────────────────
52
+ * Ningún método lleva `tenantId`: el `PrivateController` del destino no lee `X-Tenant-Id` ni
53
+ * `x-tenant-issuer`, y las credenciales de Trustonic salen de un único secret del lambda. Los
54
+ * privados son `Feature.ANONIMUS` — sin RBAC y sin claims, así que el caller no manda
55
+ * `Authorization`. Misma deuda que Datacultr: cuando el MDM sea multi-tenant, este contrato suma
56
+ * el tenant y pasa a ser un cambio MAJOR.
57
+ *
58
+ * ⚠️ Retorno `StandardResponse<T>` — el consumer lee `result.data`, NO `result.body`.
59
+ * Errores de transporte (falla el lambda entero, no un ítem): el publisher RECHAZA con el
60
+ * `DomainError` tipado del destino. Nunca fallback: el caller jamás recibe un batch vacío
61
+ * disfrazado de éxito.
62
+ *
63
+ * Granularidad POR ÍTEM — el batch NUNCA falla entero:
64
+ * - Cada `results[i]` trae su propio `status` (`SUCCESS` | `PENDING` | `ERROR`) y un `error`
65
+ * opcional. Un 200 puede traer ítems en `ERROR`: el caller TIENE que recorrer `results`.
66
+ * - El `error.code` del ítem es un `MdmErrorCodeEnum`. El `status` no lleva el motivo.
67
+ *
68
+ * ─────────────────────────────────────────────────────────────────────────────
69
+ * DIFERENCIAS DE CONTRATO CONTRA DATACULTR — no son intercambiables.
70
+ * ─────────────────────────────────────────────────────────────────────────────
71
+ * 1. `enrollDevices` devuelve `pollingHandle` + `provider` además de `results`; en Datacultr solo
72
+ * devuelve `results`. Acá el enroll es async de verdad y el handle es obligatorio para polear.
73
+ * 2. `enrollStatus` y `releaseStatus` EXIGEN `pollingHandle` en el body. En Datacultr el sobre de
74
+ * entrada es solo `{ items }`.
75
+ * 3. `lockDevices` soporta `TEMPORARY` de verdad; Datacultr lo degrada por ítem.
76
+ * 4. `autoLockSchedule` está degradado en Trustonic; en Datacultr es la vía real del bloqueo.
77
+ * 5. `notifyDevices` usa `title` + `content` (texto crudo) e ignora `notificationCode`; en
78
+ * Datacultr es al revés.
79
+ *
80
+ * Env var requerida en el consumer: `TRUSTONIC_CONNECTOR_URL`.
81
+ * El template.yml del consumer la setea con:
82
+ *
83
+ * TRUSTONIC_CONNECTOR_URL: '{{resolve:ssm:trustonic-connector}}'
84
+ *
85
+ * Convención CLAUDE.md global: SSM key = nombre del lambda owner de la URL.
86
+ */
87
+
88
+ /**
89
+ * Sobre de entrada de los endpoints `/status` de Trustonic: además de los ítems exige el
90
+ * `pollingHandle` que devolvió el initiate. Es un string opaco — no lo inspecciones.
91
+ */
92
+ export interface DevicePollingBatchRequest<TItem> {
93
+ pollingHandle: string;
94
+ items: TItem[];
95
+ }
96
+
97
+ /**
98
+ * Sobre de salida de un initiate async de Trustonic. `pollingHandle` es lo que el caller manda
99
+ * después a `/status`; `provider` identifica qué MDM atendió la operación.
100
+ */
101
+ export interface DeviceInitiateBatchResult<TItem> {
102
+ pollingHandle: string;
103
+ provider: MdmProviderEnum;
104
+ results: TItem[];
105
+ }
106
+
107
+ export interface ITrustonicConnectorApi {
108
+ /**
109
+ * POST `/devices/enroll` — inicia el enrolamiento de cada IMEI en Trustonic (upload de
110
+ * inventario + activación del servicio `DeviceFinancing` en una call atómica).
111
+ *
112
+ * ASYNC de verdad, a diferencia de Datacultr: el destino devuelve `pollingHandle` y el caller
113
+ * DEBE polear `enrollStatus` con ese handle hasta que todos los ítems sean terminales. El caso
114
+ * típico es que todos vuelvan en `PENDING`.
115
+ *
116
+ * `DeviceEnrollRequest.lockMode` (`ONDEMAND` pospago / `SCHEDULED` prepago) es opcional; si se
117
+ * omite el destino asume `ONDEMAND`.
118
+ */
119
+ enrollDevices(
120
+ input: DeviceBatchRequest<DeviceEnrollRequest>,
121
+ ): Promise<StandardResponse<DeviceInitiateBatchResult<DeviceEnrollInitiateResponse>>>;
122
+
123
+ /**
124
+ * POST `/devices/enroll/status` — estado del enrolamiento iniciado con `enrollDevices`.
125
+ *
126
+ * ⚠️ EXIGE `pollingHandle`: sin él el destino responde 400 `MISSING_POLLING_HANDLE`.
127
+ *
128
+ * Los campos `enrolledAt`, `enrollmentMode`, `enrollmentId`, `brand` y `model` siempre vienen
129
+ * `undefined` — el endpoint de Trustonic no los expone; existen para Datacultr.
130
+ */
131
+ enrollStatus(
132
+ input: DevicePollingBatchRequest<DeviceEnrollStatusRequest>,
133
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceEnrollStatusResponse>>>;
134
+
135
+ /** POST `/devices/status` — estado actual de cada IMEI, con `brand`, `model` y `lastSeenAt`. */
136
+ getStatus(
137
+ input: DeviceBatchRequest<DeviceStatusRequest>,
138
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceStatusResponse>>>;
139
+
140
+ /** POST `/devices/last-seen` — último contacto reportado por cada IMEI (heartbeat). */
141
+ getLastSeen(
142
+ input: DeviceBatchRequest<DeviceLastSeenRequest>,
143
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceLastSeenResponse>>>;
144
+
145
+ /**
146
+ * POST `/devices/lock` — bloquea cada IMEI, con mensaje opcional en pantalla.
147
+ * Acepta `mode: TEMPORARY` de verdad (con `durationSeconds`), que Datacultr degrada por ítem.
148
+ */
149
+ lockDevices(
150
+ input: DeviceBatchRequest<DeviceLockRequest>,
151
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceLockResponse>>>;
152
+
153
+ /**
154
+ * POST `/devices/unlock` — desbloquea cada IMEI.
155
+ * `unlockUntil` (ISO-8601) acota hasta cuándo vale el desbloqueo y solo aplica en modo
156
+ * `SCHEDULED`; si el modo lo exige y falta, el ítem vuelve en `ERROR` con
157
+ * `MdmErrorCodeEnum.UNLOCK_UNTIL_REQUIRED`.
158
+ */
159
+ unlockDevices(
160
+ input: DeviceBatchRequest<DeviceUnlockRequest>,
161
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceUnlockResponse>>>;
162
+
163
+ /**
164
+ * POST `/devices/auto-lock-schedule` — programa el bloqueo de cada IMEI en una fecha futura.
165
+ *
166
+ * ⚠️ DEGRADADO en Trustonic: el destino no llama al proveedor y devuelve cada ítem en `ERROR`
167
+ * con `PROVIDER_NOT_SUPPORTED`. Es el espejo exacto de Datacultr, donde ésta es la vía real del
168
+ * bloqueo. El caller no debe asumir la misma semántica entre providers.
169
+ */
170
+ autoLockSchedule(
171
+ input: DeviceBatchRequest<DeviceAutoLockScheduleRequest>,
172
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceAutoLockScheduleResponse>>>;
173
+
174
+ /**
175
+ * POST `/devices/pin-unlock` — pide a Trustonic el PIN offline de un equipo sin conectividad.
176
+ *
177
+ * ⚠️ NO ES BATCH y NO LLEVA SOBRE, a diferencia del resto del contrato: el body es el
178
+ * `DevicePinUnlockRequest` pelado y la respuesta es el `DevicePinUnlockResponse` directo en
179
+ * `data`, sin `{ result }` — ahí difiere del `pinUnlock` de Datacultr.
180
+ *
181
+ * Operación sensible: `pin`, `validitySeconds` y `generatedAt` solo vienen con `status`
182
+ * `SUCCESS`. El PIN viaja únicamente en esta respuesta — nunca loggearlo.
183
+ */
184
+ pinUnlock(input: DevicePinUnlockRequest): Promise<StandardResponse<DevicePinUnlockResponse>>;
185
+
186
+ /**
187
+ * POST `/devices/notify` — manda una notificación (`BANNER` o `FULLSCREEN`) a cada IMEI.
188
+ * Trustonic usa `title` y `content` como texto crudo e ignora `notificationCode`, al revés que
189
+ * Datacultr, que resuelve el texto por catálogo.
190
+ */
191
+ notifyDevices(
192
+ input: DeviceBatchRequest<DeviceNotifyRequest>,
193
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceNotifyResponse>>>;
194
+
195
+ /**
196
+ * POST `/devices/release` — libera definitivamente cada IMEI del MDM (fin de tenure).
197
+ *
198
+ * ⚠️ IRREVERSIBLE: un equipo liberado no se puede re-enrolar en Trustonic.
199
+ * Es sync y terminal — cada ítem vuelve `SUCCESS` o `ERROR`, nunca `PENDING`, y la respuesta NO
200
+ * trae `pollingHandle` (asimetría con `enrollDevices`).
201
+ */
202
+ releaseDevices(
203
+ input: DeviceBatchRequest<DeviceReleaseRequest>,
204
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseInitiateResponse>>>;
205
+
206
+ /**
207
+ * POST `/devices/release/status` — consulta el estado de una liberación.
208
+ *
209
+ * ⚠️ EXIGE `pollingHandle` aunque `releaseDevices` no devuelva ninguno: el caller tiene que
210
+ * inventar o reusar un identificador de tracing. Existe solo por simetría con Datacultr, donde
211
+ * el release sí es async; contra Trustonic normalmente no hace falta llamarlo.
212
+ */
213
+ releaseStatus(
214
+ input: DevicePollingBatchRequest<DeviceReleaseStatusRequest>,
215
+ ): Promise<StandardResponse<DeviceBatchResult<DeviceReleaseStatusResponse>>>;
216
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./api/interfaces/ITrustonicConnectorApi.js";
2
+ export { default as TrustonicConnectorApi } from "./api/TrustonicConnectorApi.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Sobres de request/response compartidos por los connectors MDM (`datacultr-connector`,
3
+ * `trustonic-connector`). No viven en `@fiado/type-kit/bin/mdm` porque los DTOs publicados
4
+ * son de UN imei; el sobre es dominio del líder (gap E8), migrar a type-kit cuando lo publique.
5
+ */
6
+
7
+ /** Sobre de entrada de los endpoints batch de un connector MDM. */
8
+ export interface DeviceBatchRequest<TItem> {
9
+ items: TItem[];
10
+ }
11
+
12
+ /** Sobre de salida de los endpoints batch: viaja dentro de `StandardResponse.data`. */
13
+ export interface DeviceBatchResult<TItem> {
14
+ results: TItem[];
15
+ }
16
+
17
+ /** Sobre de salida de los endpoints de UN solo IMEI. Hoy solo `pinUnlock` no es batch. */
18
+ export interface DeviceSingleResult<TItem> {
19
+ result: TItem;
20
+ }