nexabase-report 0.1.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.
@@ -0,0 +1,376 @@
1
+ # NexaBase Report - API REST
2
+
3
+ Guía de despliegue y uso de la API REST del reporteador.
4
+
5
+ ---
6
+
7
+ ## 📡 Endpoints Disponibles
8
+
9
+ | Método | Endpoint | Descripción |
10
+ |--------|----------|-------------|
11
+ | `GET` | `/api/reports` | Listar todos los reportes guardados |
12
+ | `GET` | `/api/reports/:id` | Obtener definición completa de un reporte |
13
+ | `POST` | `/api/reports/:id/render` | Renderizar reporte con datos y parámetros |
14
+ | `POST` | `/api/reports/:id/export/pdf` | Preparar exportación a PDF |
15
+ | `POST` | `/api/reports/:id/export/excel` | Preparar exportación a Excel |
16
+ | `POST` | `/api/reports/:id/export/csv` | Preparar exportación a CSV |
17
+ | `POST` | `/api/reports/:id/export/word` | Preparar exportación a Word (.docx) |
18
+
19
+ ---
20
+
21
+ ## 🔐 Autenticación
22
+
23
+ Todos los endpoints requieren autenticación vía API Key:
24
+
25
+ ### Opción 1: Header dedicado
26
+ ```
27
+ X-API-Key: nb_sk_tu_api_key_aqui
28
+ ```
29
+
30
+ ### Opción 2: Bearer token
31
+ ```
32
+ Authorization: Bearer nb_sk_tu_api_key_aqui
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 📋 Ejemplos de Uso
38
+
39
+ ### 1. Listar Reportes
40
+
41
+ ```bash
42
+ curl -X GET "https://tu-nexabase.url/api/reports" \
43
+ -H "X-API-Key: nb_sk_tu_api_key"
44
+ ```
45
+
46
+ **Respuesta:**
47
+ ```json
48
+ {
49
+ "success": true,
50
+ "count": 3,
51
+ "reports": [
52
+ {
53
+ "id": "abc123",
54
+ "name": "Ventas Mensuales",
55
+ "description": "Reporte de ventas del mes",
56
+ "author": "Admin",
57
+ "createdAt": "2024-01-15T10:00:00.000Z",
58
+ "updatedAt": "2024-01-20T14:30:00.000Z"
59
+ }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ ---
65
+
66
+ ### 2. Obtener Definición de Reporte
67
+
68
+ ```bash
69
+ curl -X GET "https://tu-nexabase.url/api/reports/abc123" \
70
+ -H "X-API-Key: nb_sk_tu_api_key"
71
+ ```
72
+
73
+ **Respuesta:**
74
+ ```json
75
+ {
76
+ "success": true,
77
+ "report": {
78
+ "id": "abc123",
79
+ "metadata": {
80
+ "version": "1.0",
81
+ "name": "Ventas Mensuales",
82
+ "author": "Admin",
83
+ "createdAt": "2024-01-15T10:00:00.000Z"
84
+ },
85
+ "layout": { ... },
86
+ "dataSources": [ ... ]
87
+ }
88
+ }
89
+ ```
90
+
91
+ ---
92
+
93
+ ### 3. Renderizar Reporte con Parámetros
94
+
95
+ ```bash
96
+ curl -X POST "https://tu-nexabase.url/api/reports/abc123/render" \
97
+ -H "X-API-Key: nb_sk_tu_api_key" \
98
+ -H "Content-Type: application/json" \
99
+ -d '{
100
+ "parameters": {
101
+ "fecha_inicio": "2024-01-01",
102
+ "fecha_fin": "2024-01-31"
103
+ },
104
+ "limit": 500
105
+ }'
106
+ ```
107
+
108
+ **Respuesta:**
109
+ ```json
110
+ {
111
+ "success": true,
112
+ "report": { ... },
113
+ "parameters": {
114
+ "fecha_inicio": "2024-01-01",
115
+ "fecha_fin": "2024-01-31"
116
+ },
117
+ "data": {
118
+ "main": [ ... ],
119
+ "detalle": [ ... ]
120
+ },
121
+ "metadata": {
122
+ "renderedAt": "2024-01-20T15:00:00.000Z",
123
+ "dataSources": 2,
124
+ "bands": 5
125
+ }
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ### 4. Exportar a PDF
132
+
133
+ ```bash
134
+ curl -X POST "https://tu-nexabase.url/api/reports/abc123/export/pdf" \
135
+ -H "X-API-Key: nb_sk_tu_api_key" \
136
+ -H "Content-Type: application/json" \
137
+ -d '{
138
+ "parameters": {
139
+ "fecha_inicio": "2024-01-01"
140
+ },
141
+ "limit": 1000
142
+ }'
143
+ ```
144
+
145
+ **Respuesta:**
146
+ ```json
147
+ {
148
+ "success": true,
149
+ "format": "pdf",
150
+ "filename": "Ventas_Mensuales.pdf",
151
+ "report": { ... },
152
+ "data": { ... },
153
+ "parameters": { ... },
154
+ "exportedAt": "2024-01-20T15:00:00.000Z",
155
+ "note": "Para exportación completa de PDF, use el cliente con los datos devueltos"
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 🚀 Despliegue en NexaBase
162
+
163
+ ### Opción 1: Usando MCP (Recomendado)
164
+
165
+ Ejecuta en Qwen Code:
166
+
167
+ ```
168
+ mcp__nexabase__create_function({
169
+ name: "report-api",
170
+ code: "<contenido de src/functions/report-api.ts>",
171
+ trigger: "http",
172
+ config: {
173
+ path: "/api/reports/*",
174
+ httpMethod: ["GET", "POST", "OPTIONS"],
175
+ memoryLimit: 256,
176
+ timeout: 60
177
+ },
178
+ environment: {
179
+ "NEXABASE_URL": "https://api.nexabase.online",
180
+ "NEXABASE_API_KEY": "nb_sk_tu_api_key"
181
+ }
182
+ })
183
+ ```
184
+
185
+ ### Opción 2: Usando NexaBase Dashboard
186
+
187
+ 1. Ve a **Functions** → **Nueva Función**
188
+ 2. Nombre: `report-api`
189
+ 3. Runtime: `typescript`
190
+ 4. Trigger: `http`
191
+ 5. Path: `/api/reports/*`
192
+ 6. Pega el código de `src/functions/report-api.ts`
193
+ 7. Agrega variables de entorno:
194
+ - `NEXABASE_URL`
195
+ - `NEXABASE_API_KEY`
196
+ 8. Despliega
197
+
198
+ ---
199
+
200
+ ## 🔧 Uso desde Cliente (Ejemplo)
201
+
202
+ ### JavaScript/TypeScript
203
+
204
+ ```typescript
205
+ const API_URL = 'https://tu-nexabase.url';
206
+ const API_KEY = 'nb_sk_tu_api_key';
207
+
208
+ // Listar reportes
209
+ async function listReports() {
210
+ const res = await fetch(`${API_URL}/api/reports`, {
211
+ headers: { 'X-API-Key': API_KEY }
212
+ });
213
+ return res.json();
214
+ }
215
+
216
+ // Renderizar reporte
217
+ async function renderReport(id: string, params: Record<string, any>) {
218
+ const res = await fetch(`${API_URL}/api/reports/${id}/render`, {
219
+ method: 'POST',
220
+ headers: {
221
+ 'X-API-Key': API_KEY,
222
+ 'Content-Type': 'application/json'
223
+ },
224
+ body: JSON.stringify({ parameters: params })
225
+ });
226
+ return res.json();
227
+ }
228
+
229
+ // Exportar a PDF (requiere html2pdf.js en cliente)
230
+ async function exportPdf(reportDef: any, data: any) {
231
+ // 1. Obtener datos renderizados
232
+ const rendered = await renderReport(reportDef.id, {});
233
+
234
+ // 2. Usar nexabase-report viewer para exportar
235
+ import { registerNexaReport } from 'nexabase-report';
236
+ registerNexaReport();
237
+
238
+ // 3. Crear elemento viewer y llamar exportPdf
239
+ const viewer = document.createElement('nexa-viewer');
240
+ viewer.report = rendered.report;
241
+ viewer.data = rendered.data;
242
+ document.body.appendChild(viewer);
243
+
244
+ // 4. Esperar render y exportar
245
+ await viewer.exportPdf();
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ### Python
252
+
253
+ ```python
254
+ import requests
255
+
256
+ API_URL = "https://tu-nexabase.url"
257
+ API_KEY = "nb_sk_tu_api_key"
258
+
259
+ def list_reports():
260
+ res = requests.get(
261
+ f"{API_URL}/api/reports",
262
+ headers={"X-API-Key": API_KEY}
263
+ )
264
+ return res.json()
265
+
266
+ def render_report(report_id: str, params: dict = None):
267
+ res = requests.post(
268
+ f"{API_URL}/api/reports/{report_id}/render",
269
+ headers={
270
+ "X-API-Key": API_KEY,
271
+ "Content-Type": "application/json"
272
+ },
273
+ json={"parameters": params or {}}
274
+ )
275
+ return res.json()
276
+
277
+ # Ejemplo
278
+ reports = list_reports()
279
+ print(f"Encontrados {reports['count']} reportes")
280
+
281
+ data = render_report("abc123", {"fecha": "2024-01-01"})
282
+ print(f"Reporte renderizado con {len(data['data']['main'])} registros")
283
+ ```
284
+
285
+ ---
286
+
287
+ ## ⚠️ Notas Importantes
288
+
289
+ ### Exportación PDF/Excel/Word
290
+
291
+ La API REST **prepara los datos** para exportación pero la generación final del archivo requiere ejecución en cliente (browser) debido a:
292
+
293
+ - **PDF**: Usa `html2pdf.js` que requiere DOM del navegador
294
+ - **Excel**: Usa `xlsx` (SheetJS) que funciona en cliente
295
+ - **Word**: Usa `docx` que genera archivo en memoria del cliente
296
+
297
+ **Flujo recomendado:**
298
+
299
+ 1. Cliente llama `POST /api/reports/:id/export/pdf`
300
+ 2. API devuelve `{ report, data, parameters }`
301
+ 3. Cliente crea elemento `<nexa-viewer>` con los datos
302
+ 4. Cliente llama `viewer.exportPdf()` (ejecuta html2pdf.js)
303
+ 5. Archivo se descarga automáticamente
304
+
305
+ ### Límites
306
+
307
+ - **Timeout**: 60 segundos (configurable en función)
308
+ - **Memoria**: 256MB recomendado
309
+ - **Registros por defecto**: 1000 (configurable con `limit`)
310
+
311
+ ### CORS
312
+
313
+ Todos los endpoints incluyen headers CORS:
314
+ ```
315
+ Access-Control-Allow-Origin: *
316
+ Access-Control-Allow-Methods: GET, POST, OPTIONS
317
+ Access-Control-Allow-Headers: Content-Type, Authorization, X-API-Key
318
+ ```
319
+
320
+ ---
321
+
322
+ ## 📊 Códigos de Error
323
+
324
+ | Código | Significado |
325
+ |--------|-------------|
326
+ | `200` | Éxito |
327
+ | `404` | Reporte no encontrado |
328
+ | `500` | Error interno del servidor |
329
+
330
+ ---
331
+
332
+ ## 🔄 Migración de Funciones Existentes
333
+
334
+ Si ya tienes una función serverless en NexaBase, actualiza con:
335
+
336
+ ```typescript
337
+ mcp__nexabase__update_function({
338
+ functionId: "report-api",
339
+ code: "<nuevo código>"
340
+ })
341
+ ```
342
+
343
+ ---
344
+
345
+ ## 🛡️ Seguridad
346
+
347
+ ### Mejores Prácticas
348
+
349
+ 1. **No expongas API Keys en cliente frontend**
350
+ 2. Usa **CORS restringido** para producción:
351
+ ```
352
+ Access-Control-Allow-Origin: https://tu-dominio.com
353
+ ```
354
+ 3. **Rate limiting**: Configura en NexaBase dashboard
355
+ 4. **Validación de parámetros**: Agrega middleware si es necesario
356
+
357
+ ### Ejemplo con Validación
358
+
359
+ ```typescript
360
+ // Dentro de renderReport()
361
+ if (parameters.fecha_inicio && !isValidDate(parameters.fecha_inicio)) {
362
+ return jsonResponse({ error: 'Invalid date format' }, 400);
363
+ }
364
+
365
+ function isValidDate(dateStr: string): boolean {
366
+ return /^\d{4}-\d{2}-\d{2}$/.test(dateStr) && !isNaN(Date.parse(dateStr));
367
+ }
368
+ ```
369
+
370
+ ---
371
+
372
+ ## 📞 Soporte
373
+
374
+ - **Docs**: `docs/VIEWER_API.md`, `docs/PUBLISHING.md`
375
+ - **Issues**: GitHub Issues
376
+ - **API SDK**: `@nexabase/sdk` v2.12.6+
@@ -0,0 +1,54 @@
1
+ # Export Regression Checklist
2
+
3
+ Checklist corto para validar fidelidad de export después de cada cambio.
4
+
5
+ ## 1) Setup
6
+
7
+ - Ejecutar: `npm.cmd run build`
8
+ - En local, reiniciar dev server si cambió `vite.config.ts`: `npm.cmd run dev`
9
+
10
+ ## 2) PDF (Alta prioridad)
11
+
12
+ - Caso A: imágenes same-origin (`/assets/...`)
13
+ - Deben verse en visor y PDF.
14
+ - Caso B: imágenes cross-origin (`https://...`)
15
+ - Deben verse en visor.
16
+ - En PDF deben verse vía `/api/image?url=...`.
17
+ - Caso C: imágenes base64 (`data:image/...`)
18
+ - Deben verse en visor y PDF sin depender de proxy.
19
+ - Validar:
20
+ - Sin página extra al final.
21
+ - Header/footer correctos por página.
22
+ - Tabla multipágina continua (sin huecos/saltos extraños).
23
+
24
+ ## 3) Excel
25
+
26
+ - Hojas de tablas:
27
+ - Columnas y encabezados correctos.
28
+ - Filas deben coincidir con filtros/sort/joins del viewer.
29
+ - Hojas por datasource:
30
+ - Alias correcto.
31
+ - Datos procesados (no crudos) si aplica lógica de datasource.
32
+ - Validar:
33
+ - Celdas no vacías cuando en visor sí hay valores.
34
+
35
+ ## 4) Word
36
+
37
+ - ReportHeader y PageHeader deben exportar textos correctos.
38
+ - DataBand:
39
+ - Si hay `Table`, exporta tabla con encabezados + filas.
40
+ - Si no hay `Table`, exporta textos por fila.
41
+ - Validar:
42
+ - Valores iguales al visor para 5-10 registros de muestra.
43
+
44
+ ## 5) Casos de estrés
45
+
46
+ - Dataset mediano (200 filas) y grande (1000 filas).
47
+ - Con filtros (`dataSource.filter` + `band.filter`).
48
+ - Con `starts_with` y `regex` en formato condicional.
49
+
50
+ ## 6) Criterio de OK
51
+
52
+ - PDF fiel al visor (incluyendo imágenes).
53
+ - Excel/Word con datos completos y coherentes con visor.
54
+ - Sin errores en consola durante export.
@@ -0,0 +1,211 @@
1
+ # Integración Externa con NexaReport
2
+
3
+ ## Visión General
4
+
5
+ NexaReport puede usarse en cualquier aplicación externa (Vue, React, Angular, HTML puro) pasando los datos del reporte via JSON. No requiere conexión a NexaBase para funcionar.
6
+
7
+ ## Uso Básico
8
+
9
+ ### 1. Instalar
10
+
11
+ ```bash
12
+ npm install nexabase-report
13
+ ```
14
+
15
+ ### 2. Registrar el componente
16
+
17
+ ```ts
18
+ import { registerNexaReport } from 'nexabase-report';
19
+ import 'nexabase-report/style.css';
20
+
21
+ registerNexaReport();
22
+ ```
23
+
24
+ ### 3. Usar en tu app
25
+
26
+ ```vue
27
+ <template>
28
+ <nexa-viewer
29
+ :definition="reportDefinition"
30
+ :data="reportData"
31
+ minimal
32
+ />
33
+ </template>
34
+
35
+ <script setup>
36
+ import { ref } from 'vue';
37
+
38
+ // Definición del reporte (puede venir de un archivo JSON o API)
39
+ const reportDefinition = ref({
40
+ metadata: { name: 'Mi Reporte', version: '1.0', createdAt: '2024-01-15' },
41
+ layout: {
42
+ page: { format: 'A4', orientation: 'portrait' },
43
+ bands: [ /* ... */ ]
44
+ },
45
+ dataSources: [{ id: 'ds1', alias: 'main', collection: '', enabled: true }]
46
+ });
47
+
48
+ // Datos del reporte
49
+ const reportData = ref([
50
+ { id: 1, nombre: 'Producto A', precio: 100, cantidad: 5 },
51
+ { id: 2, nombre: 'Producto B', precio: 200, cantidad: 3 }
52
+ ]);
53
+ </script>
54
+ ```
55
+
56
+ ## Formato de Datos
57
+
58
+ ### Single DataSource (array simple)
59
+
60
+ ```json
61
+ [
62
+ { "id": 1, "nombre": "Juan Pérez", "email": "juan@mail.com" },
63
+ { "id": 2, "nombre": "María López", "email": "maria@mail.com" }
64
+ ]
65
+ ```
66
+
67
+ ### Multiple DataSources (objeto con alias)
68
+
69
+ ```json
70
+ {
71
+ "clientes": [
72
+ { "id": 1, "nombre": "Juan Pérez", "email": "juan@mail.com" },
73
+ { "id": 2, "nombre": "María López", "email": "maria@mail.com" }
74
+ ],
75
+ "pedidos": [
76
+ { "id": 101, "cliente_id": 1, "monto": 1500, "fecha": "2024-03-01" },
77
+ { "id": 102, "cliente_id": 2, "monto": 2300, "fecha": "2024-03-02" }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ ## API del Viewer
83
+
84
+ ### Métodos
85
+
86
+ ```ts
87
+ const viewer = document.querySelector('nexa-viewer');
88
+
89
+ // Exportar a diferentes formatos
90
+ await viewer.exportPdf();
91
+ await viewer.exportExcel();
92
+ await viewer.exportWord();
93
+ await viewer.exportCsv();
94
+
95
+ // Actualizar datos dinámicamente
96
+ viewer.updateData({
97
+ clientes: [ /* nuevos datos */ ],
98
+ pedidos: [ /* nuevos datos */ ]
99
+ });
100
+
101
+ // Obtener campos disponibles del diccionario
102
+ const fields = viewer.getDictionaryFields();
103
+ // [{ alias: 'clientes', fields: [{ name: 'id', type: 'number' }, ...] }]
104
+
105
+ // Navegación de páginas
106
+ viewer.goToPage(2);
107
+ console.log(viewer.currentPage); // 2
108
+ console.log(viewer.totalPages); // 5
109
+ ```
110
+
111
+ ### Eventos
112
+
113
+ ```vue
114
+ <nexa-viewer
115
+ :definition="report"
116
+ @data-request="(alias) => fetch(`/api/data/${alias}`).then(r => r.json())"
117
+ />
118
+ ```
119
+
120
+ ## Diccionario Manual
121
+
122
+ Puedés definir la estructura de datos sin conexión a NexaBase:
123
+
124
+ ```json
125
+ {
126
+ "dictionary": {
127
+ "dataSources": [
128
+ {
129
+ "alias": "clientes",
130
+ "label": "Tabla de Clientes",
131
+ "fields": [
132
+ { "name": "id", "type": "number", "label": "ID", "primaryKey": true },
133
+ { "name": "nombre", "type": "string", "label": "Nombre Completo" },
134
+ { "name": "email", "type": "string", "label": "Email" },
135
+ { "name": "fecha_registro", "type": "date", "label": "Fecha de Registro" }
136
+ ]
137
+ }
138
+ ],
139
+ "relationships": [
140
+ {
141
+ "from": "pedidos.cliente_id",
142
+ "to": "clientes.id",
143
+ "type": "many-to-one"
144
+ }
145
+ ]
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Variables de Sistema
151
+
152
+ Disponibles en bindings `{{...}}`:
153
+
154
+ | Variable | Descripción | Ejemplo |
155
+ |----------|-------------|---------|
156
+ | `{{Page}}` | Número de página actual | `1` |
157
+ | `{{TotalPages}}` | Total de páginas | `5` |
158
+ | `{{Now}}` | Fecha y hora actual | `2024-01-15 14:30:00` |
159
+ | `{{Today}}` | Fecha actual | `2024-01-15` |
160
+ | `{{ReportName}}` | Nombre del reporte | `Ventas Mensuales` |
161
+ | `{{RowNumber}}` | Número de fila | `1` |
162
+
163
+ ## Ejemplo Completo
164
+
165
+ ```html
166
+ <!DOCTYPE html>
167
+ <html>
168
+ <head>
169
+ <script src="https://cdn.jsdelivr.net/npm/nexabase-report/dist/nexabase-report.umd.js"></script>
170
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nexabase-report/dist/style.css">
171
+ </head>
172
+ <body>
173
+ <h1>Mi Reporte</h1>
174
+ <nexa-viewer id="viewer" minimal></nexa-viewer>
175
+
176
+ <script>
177
+ NexaReport.registerNexaReport();
178
+
179
+ const viewer = document.getElementById('viewer');
180
+
181
+ // Cargar definición del reporte
182
+ fetch('/api/reports/ventas.json')
183
+ .then(r => r.json())
184
+ .then(def => { viewer.definition = def; });
185
+
186
+ // Cargar datos
187
+ fetch('/api/data/ventas?desde=2024-01-01')
188
+ .then(r => r.json())
189
+ .then(data => { viewer.data = data; });
190
+ </script>
191
+ </body>
192
+ </html>
193
+ ```
194
+
195
+ ## Tipos de Datos Soportados
196
+
197
+ | Tipo JSON | Tipo en Diccionario | Icono |
198
+ |-----------|---------------------|-------|
199
+ | `string` | `string` | 🏷️ |
200
+ | `number` | `number` | #️⃣ |
201
+ | `boolean` | `boolean` | ☑️ |
202
+ | `string` (formato fecha) | `date` | 📅 |
203
+ | `object` | `object` | 📦 |
204
+ | `array` | `array` | 📋 |
205
+
206
+ ## Tips
207
+
208
+ 1. **Datos grandes**: Usá paginación en tu API y pasá los datos por páginas
209
+ 2. **Actualización en tiempo real**: Usá `viewer.updateData()` para refrescar sin recargar
210
+ 3. **Validación**: Usá `viewer.getDictionaryFields()` para validar bindings antes de renderizar
211
+ 4. **Export**: Los métodos de export funcionan sin conexión a internet