zenit-sdk
v0.1.6
Published
TypeScript SDK for interacting with the Zenit backend APIs.
Readme
zenit-sdk
Introducción
zenit-sdk es una librería en TypeScript para consumir el backend de Zenit de forma sencilla. El core es agnóstico al framework y se enfoca en ofrecer clientes HTTP y helpers de autenticación. Además, incluye un componente React (ZenitMap) para integraciones de UI basado en Leaflet.
Instalación
npm install zenit-sdk
# o con yarn
yarn add zenit-sdkPara usar el componente React instala también sus peer dependencies en tu proyecto:
npm install react react-dom leaflet react-leaflet
# o con yarn
yarn add react react-dom leaflet react-leafletEntradas del SDK
- Core (Node/HTTP):
import { ZenitClient } from 'zenit-sdk'; - React (UI):
import { ZenitMap } from 'zenit-sdk/react';
Uso básico – Cliente de usuario (core)
import { ZenitClient } from 'zenit-sdk';
const client = new ZenitClient({
baseUrl: 'https://mi-zenit.com/api/v1'
});
async function demo() {
const login = await client.auth.login({
email: '<EMAIL>',
password: '<PASSWORD>'
});
console.log('User:', login.user);
const me = await client.auth.me();
console.log('Me:', me);
const valid = await client.auth.validate();
console.log('Validate:', valid);
const refreshed = await client.auth.refresh(login.refreshToken);
console.log('Refresh:', refreshed);
}Uso básico – SDK Token (core)
import { ZenitClient } from 'zenit-sdk';
const client = new ZenitClient({
baseUrl: 'https://mi-zenit.com/api/v1',
sdkToken: '<SDK_TOKEN>'
});
async function demoSdk() {
const validation = await client.sdkAuth.validateSdkToken();
console.log('SDK token validation:', validation);
const exchange = await client.sdkAuth.exchangeSdkToken();
console.log('SDK exchange:', exchange);
const me = await client.auth.me();
console.log('Me using SDK access token:', me);
}Runtime config (WebView / host) + filtros
El cliente ahora permite actualizar configuración y tokens en runtime sin recrear la app:
import {
ZenitClient,
mergeFilters,
normalizeFilters,
resolveRuntimeConfig,
} from 'zenit-sdk';
const runtime = resolveRuntimeConfig(window.__ZENIT_RUNTIME_CONFIG__);
const client = new ZenitClient({
baseUrl: runtime?.baseUrl ?? 'https://mi-zenit.com/api/v1',
accessToken: runtime?.accessToken,
sdkToken: runtime?.sdkToken,
});
client.setBaseUrl('https://mi-zenit.com/api/v2');
client.setAccessToken('token-2');
client.setSdkToken('sdk-2');
client.setAuth({ accessToken: 'token-3', sdkToken: 'sdk-3' });
client.setDefaultFilters(normalizeFilters({ CODREGION: 10 }));
const filters = mergeFilters(client.getDefaultFilters(), { CODDEPTO: 7 });
console.log('filters', filters);Todos los requests construyen Authorization dinámicamente, así que un setAccessToken() afecta a la siguiente
llamada sin reiniciar el cliente.
Uso básico – Componente React ZenitMap
import React from 'react';
import { ZenitClient } from 'zenit-sdk';
import { ZenitMap } from 'zenit-sdk/react';
import 'leaflet/dist/leaflet.css';
const client = new ZenitClient({
baseUrl: 'https://mi-zenit.com/api/v1',
sdkToken: '<SDK_TOKEN>'
});
export function App() {
return (
<div>
<h1>Demo ZenitMap</h1>
<ZenitMap client={client} mapId={123} />
</div>
);
}Si las capas del mapa incluyen layer.label, ZenitMap mostrará marcadores de etiqueta usando esa propiedad de las
features (respeta visibilidad y opacidad de la capa).
Chat flotante FloatingChatBox (Zenit AI)
El SDK incluye un chat flotante para conversar con Zenit AI usando los endpoints de mapas. Solo necesitas entregar
baseUrl y mapId (el token es opcional, pero se puede inyectar con accessToken o getAccessToken).
import React from 'react';
import { FloatingChatBox } from 'zenit-sdk/react';
export function App() {
return (
<>
<FloatingChatBox
baseUrl="https://mi-zenit.com/api/v1"
mapId={123}
filteredLayerIds={[45, 98]}
filters={{ CODREGION: 10 }}
getAccessToken={() => localStorage.getItem('access_token') ?? ''}
/>
</>
);
}El chat funciona también en modo guest (userId nulo/omitido). Si no hay mapId, el componente muestra un estado
deshabilitado con el mensaje “Selecciona un mapa para usar el asistente”.
Panel reutilizable de capas y filtros ZenitLayerManager
El SDK incluye un panel listo para usar que administra visibilidad, opacidad y filtros por propiedades usando los endpoints getLayerFeaturesCatalog y filter-multiple. Puedes combinarlo con ZenitMap para mostrar el GeoJSON filtrado como overlay:
import React, { useState } from 'react';
import { ZenitClient, type FilterMultipleMetadata, type GeoJsonFeatureCollection } from 'zenit-sdk';
import { ZenitLayerManager, ZenitMap } from 'zenit-sdk/react';
import 'leaflet/dist/leaflet.css';
const client = new ZenitClient({ baseUrl: 'https://mi-zenit.com/api/v1', sdkToken: '<SDK_TOKEN>' });
export function App() {
const [overlay, setOverlay] = useState<GeoJsonFeatureCollection | null>(null);
const [metadata, setMetadata] = useState<FilterMultipleMetadata | undefined>();
const [layerControls, setLayerControls] = useState<
Array<{ layerId: number | string; visible: boolean; opacity: number }>
>([]);
return (
<div style={{ display: 'flex', height: 600 }}>
<ZenitLayerManager
client={client}
mapId={11}
onFilteredGeojson={(geojson, meta) => {
setOverlay(geojson);
setMetadata(meta);
}}
onLayerStatesChange={setLayerControls}
/>
<ZenitMap
client={client}
mapId={11}
showLayerPanel={false}
overlayGeojson={overlay}
layerControls={layerControls}
/>
<pre>{JSON.stringify(metadata, null, 2)}</pre>
</div>
);
}API de mapas y capas (core)
import { ZenitClient, getCatalogSupport, ZenitCatalogNotSupportedError } from 'zenit-sdk';
const client = new ZenitClient({ baseUrl: 'https://mi-zenit.com/api/v1', accessToken: '<JWT>' });
// Metadatos de mapa (incluye capas visibles si includeLayers=true)
const map = await client.maps.getMap(11, true);
// Metadatos de capa (las respuestas usan ApiResponse con `data` y metadata opcional)
const layer = await client.layers.getLayer(123);
console.log('Layer:', layer.data);
// GeoJSON completo
const geojson = await client.layers.getLayerGeoJson(123);
console.log('GeoJSON features:', geojson.data.features?.length ?? 0);
// GeoJSON limitado por bounding box
const geojsonBBox = await client.layers.getLayerGeoJsonBBox({
id: 123,
bbox: {
minLon: -58.6,
minLat: -34.7,
maxLon: -58.3,
maxLat: -34.4,
},
});
console.log('GeoJSON bbox features:', geojsonBBox.data.features?.length ?? 0);
// Intersección con una geometría
const intersected = await client.layers.getLayerGeoJsonIntersect({ id: 123, geometry, maxFeatures: 5000 });
console.log('GeoJSON intersected features:', intersected.data.features?.length ?? 0);
// Catálogo de propiedades de features de una capa
const catalog = await client.layers.getLayerFeaturesCatalog(17);
console.log('Catalogo de capa', catalog.data);
// Catálogo con validación previa
const support = getCatalogSupport({ layerType: 'polygon' });
if (support.supported) {
const safeCatalog = await client.layers.getLayerFeaturesCatalog(17, {
layerType: 'polygon',
strict: true, // fail-fast sin request si la geometría no está soportada
});
console.log('Catálogo soportado', safeCatalog.data);
}
// Filtrado simultáneo en múltiples capas multipolygon
const filtered = await client.layers.filterMultipleLayersFeatures({
layerIds: [32, 17],
filters: { CODREGION: 10 },
});
console.log('filter-multiple data', filtered.data);
// Filtrado resiliente con capas mixtas (multipolygon + otras)
const mixedFiltered = await client.layers.filterMultipleWithFallback({
layerIds: [32, 17, 99],
filters: { CODREGION: 10 },
layerMetas: [
{ layerId: 32, layerType: 'multipolygon' },
{ layerId: 17, layerType: 'polygon' },
{ layerId: 99, layerType: 'mixed' },
],
});
console.log('filter-multiple fallback perLayer', mixedFiltered.perLayer);
// Helper de alto nivel
const loaded = await client.layers.loadFilteredFeatures({
layerIds: [32, 17],
filters: { CODREGION: 10 },
});
console.log('GeoJSON filtrado', loaded.geojson.features.length, 'elementos');El endpoint de catálogo solo admite capas polygon/multipolygon. Usa getCatalogSupport para decidir si corresponde
llamarlo, o pasa { strict: true } a getLayerFeaturesCatalog para que el SDK arroje un ZenitCatalogNotSupportedError
antes de hacer la request.
Los métodos expuestos en client.layers permiten construir el panel de filtros sin dependencias externas:
getLayerFeaturesCatalog(layerId)carga el catálogo de propiedades para cada capa.filterMultipleLayersFeatures({ layerIds, filters })ejecutafilter-multipley retorna GeoJSON + metadata.loadFilteredFeatureses un helper tipado que entregageojson,metadataytotalFeatureslistos para usar.
Notas de filtrado:
layerIdsse envía como CSV ([32,17]->layerIds=32,17).- Los filtros son pares dinámicos
key/value. Valores en arreglos se serializan comoa,b,c. - Valores
null/undefinedo cadenas vacías no se envían en la query.
Ejecutar ejemplos con .env opcional
Los ejemplos usan ts-node y leen variables de entorno. Puedes definirlas en tu shell o en un archivo .env (no se publica):
ZENIT_BASE_URL=http://localhost:3200/api/v1
ZENIT_EMAIL=<EMAIL>
ZENIT_PASSWORD=<PASSWORD>
ZENIT_SDK_TOKEN=<SDK_TOKEN>
ZENIT_ACCESS_TOKEN=<ACCESS_TOKEN>
ZENIT_MAP_ID=11En PowerShell:
$env:ZENIT_BASE_URL="http://localhost:3200/api/v1"
$env:ZENIT_EMAIL="[email protected]"
$env:ZENIT_PASSWORD="secret"Comandos disponibles:
npm run example:auth
npm run example:sdk
npm run example:mapEl baseUrl por defecto de los ejemplos es http://localhost:3200/api/v1 si no se especifica.
