@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.
- package/bin/datacultrConnector/api/interfaces/IDatacultrConnectorApi.d.ts +2 -16
- package/bin/datacultrConnector/api/interfaces/IDatacultrConnectorApi.js +49 -1
- package/bin/index.d.ts +1 -0
- package/bin/index.js +1 -0
- package/bin/trustonicConnector/api/TrustonicConnectorApi.d.ts +34 -0
- package/bin/trustonicConnector/api/TrustonicConnectorApi.js +73 -0
- package/bin/trustonicConnector/api/interfaces/ITrustonicConnectorApi.d.ts +158 -0
- package/bin/trustonicConnector/api/interfaces/ITrustonicConnectorApi.js +1 -0
- package/bin/trustonicConnector/index.d.ts +2 -0
- package/bin/trustonicConnector/index.js +2 -0
- package/bin/utils/MdmEnvelopes.d.ts +17 -0
- package/bin/utils/MdmEnvelopes.js +6 -0
- package/package.json +2 -2
- package/src/datacultrConnector/api/interfaces/IDatacultrConnectorApi.ts +4 -18
- package/src/index.ts +1 -0
- package/src/trustonicConnector/api/TrustonicConnectorApi.ts +118 -0
- package/src/trustonicConnector/api/interfaces/ITrustonicConnectorApi.ts +216 -0
- package/src/trustonicConnector/index.ts +2 -0
- package/src/utils/MdmEnvelopes.ts +20 -0
|
@@ -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
|
-
|
|
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
package/bin/index.js
CHANGED
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
76
|
-
*
|
|
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
|
@@ -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,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
|
+
}
|