@gzl10/baserow 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +123 -700
  3. package/package.json +9 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @gzl10/baserow
2
2
 
3
+ ## 1.2.1 (2025-01-03)
4
+
5
+ ### Patch Changes
6
+
7
+ - README translated to English and simplified (848 → 275 lines)
8
+ - Fixed npm compatibility: docs links now use absolute GitLab URLs
9
+ - Added `funding` field to package.json (Buy Me A Coffee)
10
+ - Updated `homepage` to www.gzl10.com
11
+ - Changed license to MIT
12
+
13
+ ---
14
+
3
15
  ## 1.2.0 (2025-01-02)
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -1,93 +1,61 @@
1
1
  # @gzl10/baserow
2
2
 
3
- Cliente TypeScript moderno para Baserow API v1.35+ (2025) con **arquitectura de tres clientes**, **PrismaBaserowMapper**, **21/22 tipos de campos** y **gestión automática de JWT con refresh tokens**.
3
+ Modern TypeScript client for Baserow API v1.35+ with **3-client architecture**, **PrismaBaserowMapper**, **21/22 field types**, and **automatic JWT refresh**.
4
4
 
5
- ## ✨ Características Principales
5
+ ## Features
6
6
 
7
- - 🎯 **Arquitectura de 3 Clientes**: Token, Admin Global y Admin Workspace
8
- - 🔐 **Auto-Refresh JWT**: Gestión automática de access y refresh tokens con renovación inteligente
9
- - 🗺️ **PrismaBaserowMapper**: Sintaxis familiar estilo Prisma para consultas (35+ tests)
10
- - 📋 **21/22 Tipos de Campos**: Cobertura completa incluyendo file, autonumber, count, rollup, lookup
11
- - 🚀 **HTTP Optimizado**: axios-retry + axios-rate-limit oficiales (36% menos código)
12
- - 🔄 **API Jerárquica**: Navegación intuitiva workspace → database → table → fields/rows
13
- - ⚡ **Operaciones Bulk**: Procesamiento batch optimizado con retry logic
14
- - 🧪 **Testing Robusto**: 60+ tests (35+ integración + 34 error handling), 42% cobertura error handling
7
+ - 🎯 **3-Client Architecture**: Token, Admin Global, and Admin Workspace
8
+ - 🔐 **Auto-Refresh JWT**: Automatic access/refresh token management
9
+ - 🗺️ **PrismaBaserowMapper**: Familiar Prisma-style query syntax (35+ tests)
10
+ - 📋 **21/22 Field Types**: Complete coverage including file, autonumber, count, rollup, lookup
11
+ - 🚀 **Optimized HTTP**: axios-retry + axios-rate-limit (36% less code)
12
+ - 🔄 **Hierarchical API**: Intuitive workspace → database → table → fields/rows navigation
13
+ - ⚡ **Bulk Operations**: Optimized batch processing with retry logic
15
14
 
16
- ## 📚 Documentación
15
+ ## Installation
17
16
 
18
- Esta es una guía de inicio rápido. **[Ver índice completo de documentación →](docs/README.md)**
19
-
20
- ### 📖 Guías de Usuario
21
-
22
- - **[Filtros y Ordenaciones](docs/FILTERS_AND_SORTING.md)** - Guía completa de búsquedas, filtros y ordenaciones
23
- - **[API Reference](docs/BASEROW_API_REFERENCE.md)** - Referencia completa de la API
24
- - **[Keep-Alive](docs/KEEP_ALIVE.md)** - Configuración de keep-alive para backends 24/7
25
- - **[Migración](docs/MIGRATION.md)** - Guía de migración desde versiones anteriores
26
-
27
- ### 🔧 Documentación Técnica
28
-
29
- - **[Testing](docs/TESTING.md)** - Guía de tests y cobertura
30
- - **[Debugging](docs/DEBUGGING.md)** - Solución de problemas comunes
31
- - **[Roadmap](docs/ROADMAP.md)** - Plan de evolución de la librería
32
-
33
- ### 📊 Análisis y Referencia
34
-
35
- - **[Baserow 1.35.3 Impact](docs/BASEROW_1.35.3_IMPACT_ANALYSIS.md)** - Análisis de compatibilidad con Baserow 1.35.3
36
- - **[Endpoint Validation](docs/ENDPOINT_VALIDATION_RESULTS.md)** - Validación de endpoints de API
37
-
38
- ---
39
-
40
- ## 🎯 Arquitectura
17
+ ```bash
18
+ pnpm add @gzl10/baserow
19
+ ```
41
20
 
42
- ### Cliente Principal Unificado
21
+ ## Quick Start
43
22
 
44
23
  ```typescript
45
24
  import { BaserowClient } from '@gzl10/baserow'
46
25
 
47
- // 1. Cliente con Database Token (solo lectura de datos)
26
+ // 1. Database Token (read-only)
48
27
  const client = await BaserowClient.create({
49
28
  url: 'https://baserow.example.com',
50
29
  token: 'db_token_123'
51
30
  })
52
31
 
53
- // 2. Cliente Admin Global (acceso multi-workspace)
54
- const adminGlobal = await BaserowClient.create({
32
+ // 2. Admin Global (multi-workspace)
33
+ const admin = await BaserowClient.create({
55
34
  url: 'https://baserow.example.com',
56
35
  credentials: { email: 'admin@example.com', password: 'password' }
57
36
  })
58
37
 
59
- // 3. Cliente Admin Workspace (scope específico)
60
- const adminWorkspace = await BaserowClient.create({
38
+ // 3. Admin Workspace (scoped)
39
+ const adminWS = await BaserowClient.create({
61
40
  url: 'https://baserow.example.com',
62
41
  credentials: { email: 'admin@example.com', password: 'password' },
63
- workspace: 'Mi Workspace'
42
+ workspace: 'My Workspace'
64
43
  })
65
44
  ```
66
45
 
67
- ### Tres Arquitecturas Especializadas
68
-
69
- | Cliente | Autenticación | Capacidades | Casos de Uso |
70
- | ------------------ | ------------------- | ------------------------------------------------- | ------------------------------------------------- |
71
- | **BaserowClient** | Database Token | CRUD de datos, operaciones bulk | Apps cliente, integración de datos, APIs públicas |
72
- | **AdminGlobal** | JWT Multi-workspace | Gestión completa de workspaces, databases, tables | Scripts administrativos, herramientas DevOps |
73
- | **AdminWorkspace** | JWT Scope limitado | Operaciones dentro de un workspace específico | Apps empresariales, dashboards especializados |
74
-
75
- ## 🚀 Instalación
46
+ ## Client Types
76
47
 
77
- ```bash
78
- pnpm install @gzl10/baserow
79
- ```
48
+ | Client | Auth | Capabilities | Use Cases |
49
+ | ------------------ | -------------- | ------------------------------------ | ---------------------------- |
50
+ | **BaserowClient** | Database Token | Data CRUD, bulk operations | Apps, data integration, APIs |
51
+ | **AdminGlobal** | JWT Multi-WS | Full workspace/database/table mgmt | Admin scripts, DevOps tools |
52
+ | **AdminWorkspace** | JWT Scoped | Operations within specific workspace | Enterprise apps, dashboards |
80
53
 
81
- ## 🔍 PrismaBaserowMapper - Sintaxis Familiar
54
+ ## PrismaBaserowMapper
82
55
 
83
- Sintaxis estilo Prisma.js para consultas Baserow con **35+ tests** de validación:
56
+ Familiar Prisma-style syntax for Baserow queries:
84
57
 
85
58
  ```typescript
86
- import { BaserowClient } from '@gzl10/baserow'
87
-
88
- const client = await BaserowClient.create({ url, token })
89
-
90
- // Sintaxis Prisma familiar
91
59
  const employees = await client
92
60
  .database(123)
93
61
  .table(456)
@@ -97,95 +65,39 @@ const employees = await client
97
65
  },
98
66
  orderBy: [{ created_at: 'desc' }, { name: 'asc' }],
99
67
  take: 20,
100
- skip: 40,
101
- select: { id: true, name: true, email: true }
68
+ skip: 40
102
69
  })
103
70
  ```
104
71
 
105
- **Operadores soportados:**
106
-
107
- - **Comparación**: `equals`, `not`, `contains`, `startsWith`, `endsWith`, `gt`, `gte`, `lt`, `lte`
108
- - **Lógicos**: `AND`, `OR` (flat), `NOT`
109
- - **Estado**: `isEmpty`, `isNotEmpty`
110
- - **Fechas**: Conversión automática a ISO strings
111
-
112
- **📖 Ver guía completa:** [Filtros y Ordenaciones](docs/FILTERS_AND_SORTING.md)
113
-
114
- ## 📖 Uso Básico
115
-
116
- ### Tipos de Configuración (Aliases DX-friendly)
117
-
118
- Para facilitar el desarrollo, la librería exporta aliases descriptivos:
119
-
120
- ```typescript
121
- // Tipos de configuración (aliases cortos)
122
- import type { TokenConfig, CredentialsConfig, CredentialsWorkspaceConfig } from '@gzl10/baserow'
123
-
124
- // Clases de cliente (para tipado avanzado)
125
- import type { ClientWithToken, ClientWithCreds, ClientWithCredsWs } from '@gzl10/baserow'
72
+ **Supported operators:** `equals`, `not`, `contains`, `startsWith`, `endsWith`, `gt`, `gte`, `lt`, `lte`, `AND`, `OR`, `NOT`, `isEmpty`, `isNotEmpty`
126
73
 
127
- // Equivalencias:
128
- // - TokenConfig = BaserowTokenConfig
129
- // - CredentialsConfig = BaserowCredentialsConfig
130
- // - CredentialsWorkspaceConfig = BaserowCredentialsWorkspaceConfig
131
- ```
74
+ ## Basic Usage
132
75
 
133
- ### 1. Cliente con Database Token (Solo datos)
76
+ ### Data Operations (Token Client)
134
77
 
135
78
  ```typescript
136
- import { BaserowClient } from '@gzl10/baserow'
137
- import type { TokenConfig } from '@gzl10/baserow'
138
-
139
- const config: TokenConfig = {
140
- url: 'https://baserow.example.com',
141
- token: 'your_database_token'
142
- }
143
-
144
- const client = await BaserowClient.create(config)
145
-
146
- // API jerárquica simple
147
79
  const rows = await client.database(123).table(456).rows.list()
80
+
148
81
  const newRow = await client.database(123).table(456).rows.create({
149
82
  name: 'John Doe',
150
83
  email: 'john@example.com'
151
84
  })
152
85
 
153
- // Operaciones bulk optimizadas
154
- const bulkRows = await client
155
- .database(123)
156
- .table(456)
157
- .rows.createBulk(
158
- [
159
- { name: 'Alice', email: 'alice@example.com' },
160
- { name: 'Bob', email: 'bob@example.com' }
161
- ],
162
- { batchSize: 100 }
163
- )
86
+ // Bulk operations
87
+ const bulkRows = await client.database(123).table(456).rows.createBulk(items, { batchSize: 100 })
164
88
  ```
165
89
 
166
- ### 2. Cliente Admin Global (Multi-workspace)
90
+ ### Admin Operations
167
91
 
168
92
  ```typescript
169
- import type { CredentialsConfig } from '@gzl10/baserow'
170
-
171
- const config: CredentialsConfig = {
172
- url: 'https://baserow.example.com',
173
- credentials: {
174
- email: 'admin@example.com',
175
- password: 'your_password'
176
- }
177
- }
178
-
179
- const admin = await BaserowClient.create(config)
180
-
181
- // Gestión completa de workspaces
93
+ // Workspaces
182
94
  const workspaces = await admin.workspaces.list()
183
- const newWS = await admin.workspaces.create({ name: 'Nueva Empresa' })
184
- const updatedWS = await admin.workspace('Company').update({ name: 'New Company' })
185
- await admin.workspace('Old Company').delete()
95
+ const newWS = await admin.workspaces.create({ name: 'New Company' })
186
96
 
187
- // Creación jerárquica de recursos
97
+ // Databases
188
98
  const database = await admin.workspace('Company').databases.create('CRM')
99
+
100
+ // Tables
189
101
  const table = await admin
190
102
  .workspace('Company')
191
103
  .database('CRM')
@@ -199,649 +111,160 @@ const table = await admin
199
111
  })
200
112
  ```
201
113
 
202
- ### 3. Cliente Admin Workspace (Scope limitado)
203
-
204
- ```typescript
205
- import type { CredentialsWorkspaceConfig } from '@gzl10/baserow'
206
-
207
- const config: CredentialsWorkspaceConfig = {
208
- url: 'https://baserow.example.com',
209
- credentials: {
210
- email: 'admin@example.com',
211
- password: 'your_password'
212
- },
213
- workspace: 'Company'
214
- }
114
+ ## Field Types (21/22)
215
115
 
216
- const adminWS = await BaserowClient.create(config)
217
-
218
- // API simplificada sin prefijo workspace
219
- const databases = await adminWS.databases.list()
220
- const table = await adminWS.database('CRM').tables.create({ name: 'Products' })
221
- ```
222
-
223
- ## 📋 Cobertura Completa de Campos (21/22 tipos)
224
-
225
- La librería soporta **prácticamente todos los tipos de campos** de Baserow v1.35+ incluyendo los nuevos campos avanzados:
226
-
227
- ### ✅ Campos Implementados por Categoría
228
-
229
- #### Texto y Comunicación (5 tipos)
116
+ ### Text & Communication
230
117
 
231
118
  ```typescript
232
- const nameField = await table.field.createText('full_name')
233
- const descField = await table.field.createLongText('description')
234
- const websiteField = await table.field.createUrl('website')
235
- const emailField = await table.field.createEmail('contact_email')
236
- const phoneField = await table.field.createPhoneNumber('phone')
119
+ await table.field.createText('full_name')
120
+ await table.field.createLongText('description')
121
+ await table.field.createUrl('website')
122
+ await table.field.createEmail('contact_email')
123
+ await table.field.createPhoneNumber('phone')
237
124
  ```
238
125
 
239
- #### Numéricos y Lógicos (3 tipos)
126
+ ### Numeric & Boolean
240
127
 
241
128
  ```typescript
242
- const priceField = await table.field.createNumber('price', 2) // 2 decimales
243
- const activeField = await table.field.createBoolean('is_active')
244
- const ratingField = await table.field.createRating('rating', 5) // máx 5 estrellas
129
+ await table.field.createNumber('price', 2) // 2 decimals
130
+ await table.field.createBoolean('is_active')
131
+ await table.field.createRating('rating', 5)
245
132
  ```
246
133
 
247
- #### Fecha y Auditoría (5 tipos)
134
+ ### Date & Audit
248
135
 
249
136
  ```typescript
250
- const birthdateField = await table.field.createDate('birthdate')
251
- const lastModField = await table.field.createLastModified('updated_at')
252
- const lastUserField = await table.field.createLastModifiedBy('updated_by')
253
- const createdField = await table.field.createCreatedOn('created_at')
254
- const creatorField = await table.field.createCreatedBy('created_by')
137
+ await table.field.createDate('birthdate')
138
+ await table.field.createLastModified('updated_at')
139
+ await table.field.createCreatedOn('created_at')
255
140
  ```
256
141
 
257
- #### Selección y Opciones (2 tipos)
142
+ ### Selection
258
143
 
259
144
  ```typescript
260
- const statusField = await table.field.createSingleSelect('status', [
145
+ await table.field.createSingleSelect('status', [
261
146
  { value: 'active', color: 'green' },
262
147
  { value: 'inactive', color: 'red' }
263
148
  ])
264
- const tagsField = await table.field.createMultipleSelect('tags', [
265
- { value: 'urgent', color: 'red' },
266
- { value: 'important', color: 'orange' }
267
- ])
149
+ await table.field.createMultipleSelect('tags', options)
268
150
  ```
269
151
 
270
- #### Relacionales (2 tipos)
152
+ ### Relational
271
153
 
272
154
  ```typescript
273
- const linkField = await table.field.createLinkRow('related_items', targetTableId)
274
- const formulaField = await table.field.createFormula('total_price', 'field("quantity") * field("price")')
155
+ await table.field.createLinkRow('related_items', targetTableId)
156
+ await table.field.createFormula('total', 'field("qty") * field("price")')
275
157
  ```
276
158
 
277
- #### 🆕 Campos Avanzados (5 tipos) - ¡Nuevos en v1.1.0+!
159
+ ### Advanced
278
160
 
279
161
  ```typescript
280
- // Archivos adjuntos
281
- const docsField = await table.field.createFile('documents')
282
-
283
- // Numeración automática
284
- const ticketField = await table.field.createAutonumber('ticket_id')
285
-
286
- // Conteo de relaciones
287
- const itemsCountField = await table.field.createCount('items_count', targetTableId)
288
-
289
- // Agregación desde tabla relacionada
290
- const totalField = await table.field.createRollup('total_amount', tableId, fieldId, 'sum')
291
-
292
- // Búsqueda desde tabla relacionada
293
- const namesField = await table.field.createLookup('item_names', tableId, fieldId)
162
+ await table.field.createFile('documents')
163
+ await table.field.createAutonumber('ticket_id')
164
+ await table.field.createCount('items_count', targetTableId)
165
+ await table.field.createRollup('total_amount', tableId, fieldId, 'sum')
166
+ await table.field.createLookup('item_names', tableId, fieldId)
294
167
  ```
295
168
 
296
- ### API Fluida Consistente
169
+ ## Configuration
297
170
 
298
- Todos los tipos de campos siguen el mismo patrón de API para máxima consistencia:
171
+ ### Performance Presets
299
172
 
300
173
  ```typescript
301
- // Patrón: table.field.create[TipoCampo](nombre, ...parametrosEspecificos)
302
- const field = await table.field.createText('campo_nombre')
303
-
304
- // Operaciones CRUD disponibles para todos los tipos
305
- const updatedField = await table.field.update(fieldId, { name: 'nuevo_nombre' })
306
- await table.field.delete(fieldId)
307
- const allFields = await table.field.list()
308
- ```
309
-
310
- ## 🔧 Utilidades Express (Opcionales)
311
-
312
- La librería incluye utilidades opcionales para integración con Express **sin crear dependencias**.
313
-
314
- ### Configuración Básica
315
-
316
- ```typescript
317
- import express from 'express'
318
- import { BaserowClient, express as baserowExpress } from '@gzl10/baserow'
319
-
320
- const app = express()
321
- const client = await BaserowClient.create({ url, token })
322
-
323
- // Middlewares
324
- app.use('/api', baserowExpress.baserowContext(client))
325
- app.use('/api', baserowExpress.requireAuth())
326
-
327
- // Routes con cliente automático
328
- app.get('/api/tables/:tableId/rows', async (req, res, next) => {
329
- try {
330
- const rows = await req.baserow!.database(123).table(parseInt(req.params.tableId)).rows.list()
331
- res.json(baserowExpress.serializePaginated(rows))
332
- } catch (error) {
333
- next(error)
334
- }
335
- })
336
-
337
- // Error handler
338
- app.use(baserowExpress.errorHandler())
339
- ```
340
-
341
- ### Middlewares Disponibles
342
-
343
- ```typescript
344
- // Auto-crear cliente por request
345
- app.use(
346
- '/api',
347
- baserowExpress.baserowAuth({
348
- url: process.env.BASEROW_URL!,
349
- token: process.env.BASEROW_TOKEN!
350
- })
351
- )
352
-
353
- // Validar autenticación
354
- app.use('/api', baserowExpress.requireAuth())
355
-
356
- // Cleanup automático de recursos
357
- app.use('/api', baserowExpress.baserowCleanup())
358
- ```
359
-
360
- ### Serializadores
361
-
362
- ```typescript
363
- // Paginated responses
364
- const paginatedRows = baserowExpress.serializePaginated(result)
365
-
366
- // Response con metadatos
367
- const rowsWithMeta = baserowExpress.serializeRowsWithMeta(rows, table, fields)
368
-
369
- // Clean entities
370
- const cleanTable = baserowExpress.serializeTable(table, true)
371
- ```
372
-
373
- ### Error Handling
374
-
375
- ```typescript
376
- // Error handler con logging
377
- app.use(
378
- baserowExpress.errorHandler({
379
- includeStack: process.env.NODE_ENV === 'development',
380
- logger: console
381
- })
382
- )
383
-
384
- // Handler simplificado
385
- app.use(baserowExpress.simpleErrorHandler())
386
- ```
387
-
388
- ## ⚡ Características Técnicas
389
-
390
- - ✅ **TypeScript**: Tipado fuerte con inferencia automática de tipos
391
- - ✅ **ESM Moderno**: Compilación optimizada con tsup (5-10x más rápido que tsc)
392
- - ✅ **HTTP Simplificado**: 36% menos código usando axios-retry + axios-rate-limit oficiales
393
- - ✅ **Connection Pooling**: Node.js 20+ keepAlive nativo (eliminado agentkeepalive)
394
- - ✅ **PrismaMapper**: Sintaxis familiar Prisma con 35+ tests de transformaciones
395
- - ✅ **21/22 Campos**: Cobertura prácticamente completa incluyendo campos avanzados
396
- - ✅ **API Jerárquica**: workspace → database → table → fields/rows navegación intuitiva
397
- - ✅ **Retry Logic**: Manejo robusto de rate limiting y timeouts configurable
398
- - ✅ **Error Handling**: Errores tipados (BaserowError, ValidationError, etc.) + 34 tests de validación (v1.0.2)
399
- - ✅ **Express Ready**: Utilidades opcionales sin dependencias obligatorias
400
- - ✅ **Testing Robusto**: 60+ tests (35+ integración + 34 error handling), 42% cobertura
401
-
402
- ## 🔧 Configuración Avanzada
403
-
404
- ### 🔐 Autenticación y Refresh Tokens
405
-
406
- La librería gestiona automáticamente **JWT access tokens** y **refresh tokens** con renovación automática:
407
-
408
- #### Persistencia de Tokens (Por Instancia)
174
+ import { BaserowClient, PERFORMANCE_PRESETS } from '@gzl10/baserow'
409
175
 
410
- ```typescript
411
- const adminClient = await BaserowClient.create({
176
+ const client = await BaserowClient.create({
412
177
  url: 'https://baserow.example.com',
413
- credentials: { email: 'admin@example.com', password: 'password' }
178
+ token: 'your_token',
179
+ performance: PERFORMANCE_PRESETS.production
414
180
  })
415
-
416
- // ✅ Tokens almacenados en memoria de la instancia
417
- // ✅ TTL leído automáticamente del claim 'exp' del JWT (~10 min en Baserow)
418
- // ✅ Auto-refresh cuando el access token expira
419
- // ✅ Thread-safe: cada instancia tiene sus propios tokens
420
- // ❌ No persistidos en disco: re-login necesario después de reinicio
421
-
422
- // Verificar estado de autenticación
423
- console.log(adminClient.isAuthenticated()) // true
424
- console.log(adminClient.getCurrentToken()) // 'eyJhbGc...'
425
-
426
- // Renovar manualmente si es necesario
427
- const newToken = await adminClient.refreshToken()
428
- ```
429
-
430
- **Nota sobre expiración de tokens:**
431
- La librería usa **decodificación estándar JWT** para leer el claim `exp` del token, no asume ningún TTL hardcoded. Esto garantiza:
432
-
433
- - ✅ **Precisión perfecta**: usa el tiempo real del servidor Baserow
434
- - ✅ **Adaptabilidad**: funciona si Baserow cambia la configuración de TTL
435
- - ✅ **Estándar JWT**: sigue las mejores prácticas de la industria
436
-
437
- #### Auto-Refresh en Errores 401
438
-
439
- ```typescript
440
- // El cliente configura automáticamente un interceptor
441
- // que renueva el token en caso de 401 Unauthorized
442
- adminClient.setupAutoRefresh() // Opcional, ya configurado internamente
443
-
444
- // Cualquier request que falle con 401 intentará:
445
- // 1. Renovar el access token con el refresh token
446
- // 2. Reintentar la request original con el nuevo token
447
- // 3. Si el refresh falla, limpiar tokens y lanzar error
448
- ```
449
-
450
- #### Manejo de Errores de Autenticación
451
-
452
- ```typescript
453
- import { BaserowAuthTokenExpiredError, BaserowAuthTokenInvalidError } from '@gzl10/baserow'
454
-
455
- try {
456
- await adminClient.refreshToken()
457
- } catch (error) {
458
- if (error instanceof BaserowAuthTokenExpiredError) {
459
- // Refresh token expirado - re-login necesario
460
- console.error('❌ Refresh token expired - please login again')
461
- // Redirigir a login o solicitar nuevas credenciales
462
- } else if (error instanceof BaserowAuthTokenInvalidError) {
463
- // Refresh token inválido o corrupto
464
- console.error('❌ Invalid refresh token - check credentials')
465
- }
466
- }
467
181
  ```
468
182
 
469
- #### Códigos de Error Específicos
470
-
471
- | Error | Código | Descripción | Acción Recomendada |
472
- | ------------------------------ | --------------------- | ------------------------------- | -------------------------------------- |
473
- | `BaserowAuthTokenExpiredError` | `AUTH_TOKEN_EXPIRED` | Access o refresh token expirado | Re-login con credenciales |
474
- | `BaserowAuthTokenInvalidError` | `AUTH_TOKEN_INVALID` | Token inválido o corrupto | Verificar credenciales y configuración |
475
- | `BaserowError` | `NO_REFRESH_TOKEN` | No hay refresh token disponible | Hacer login primero |
476
- | `BaserowError` | `INVALID_CREDENTIALS` | Credenciales incorrectas | Verificar email y password |
477
-
478
- #### Keep-Alive para Backends 24/7 (v1.3.0+)
183
+ | Preset | Timeout | Retries | Rate (req/s) |
184
+ | -------------- | ------- | ------- | ------------ |
185
+ | `production` | 30s | 3 | 10 |
186
+ | `development` | 60s | 2 | 5 |
187
+ | `testing` | 45s | 2 | 5 |
188
+ | `aggressive` | 15s | 5 | 20 |
189
+ | `conservative` | 60s | 1 | 2 |
479
190
 
480
- ⚠️ **Limitación de Baserow**: El refresh token expira **7 días después del login** (fijo, NO se renueva al hacer refresh).
481
-
482
- **Solución**: Keep-alive ejecuta **re-login automático** cada 5 días para obtener tokens frescos, previniendo la expiración.
191
+ ### Keep-Alive (24/7 Backends)
483
192
 
484
193
  ```typescript
485
- // Backend de larga duración con keep-alive
486
- const backendClient = await BaserowClient.create({
194
+ const client = await BaserowClient.create({
487
195
  url: 'https://baserow.example.com',
488
196
  credentials: { email: 'backend@example.com', password: 'password' },
489
197
  keepAlive: {
490
198
  enabled: true,
491
- intervalMinutes: 7200 // Default: 7200 (5 días)
199
+ intervalMinutes: 7200 // Re-login every 5 days
492
200
  }
493
201
  })
494
-
495
- // ✅ Re-login automático cada 5 días → tokens siempre frescos
496
- // ✅ Backend funciona indefinidamente sin intervención manual
497
- // ✅ Se detiene automáticamente en logout() o destroy()
498
- // ⚠️ Credenciales almacenadas en memoria (solo backends confiables)
499
- ```
500
-
501
- **Recomendaciones de intervalo:**
502
-
503
- | Tipo de Backend | Intervalo | Motivo |
504
- | ------------------- | ----------------- | ---------------------------------------------------- |
505
- | **Producción 24/7** | 7200 min (5 días) | Balance óptimo: margen de 2 días antes de expiración |
506
- | **Crítico** | 4320 min (3 días) | Extra conservador: margen de 4 días |
507
- | **Desarrollo** | 1440 min (1 día) | Testing frecuente, detección rápida de problemas |
508
-
509
- **Ejemplo completo backend Express:**
510
-
511
- ```typescript
512
- import { BaserowClient } from '@gzl10/baserow'
513
-
514
- // Inicializar cliente con keep-alive al arrancar servidor
515
- const client = await BaserowClient.create({
516
- url: process.env.BASEROW_URL!,
517
- credentials: {
518
- email: process.env.BASEROW_EMAIL!,
519
- password: process.env.BASEROW_PASSWORD!
520
- },
521
- keepAlive: { enabled: true }, // Default: 5 días
522
- workspace: 'Production'
523
- })
524
-
525
- // Usar cliente en rutas Express
526
- app.get('/api/data', async (req, res) => {
527
- const databases = await client.databases.findMany()
528
- res.json(databases)
529
- })
530
-
531
- // Limpiar al cerrar servidor
532
- process.on('SIGTERM', () => {
533
- client.destroy() // Detiene keep-alive y limpia credenciales
534
- process.exit(0)
535
- })
536
202
  ```
537
203
 
538
- **⚠️ Seguridad**:
539
-
540
- - Credenciales se almacenan en memoria del proceso
541
- - Solo usar en backends propios/confiables
542
- - NO usar en frontends o aplicaciones compartidas
543
- - Se limpian automáticamente en `logout()`/`destroy()`
204
+ ⚠️ **Baserow limitation**: Refresh token expires 7 days after login (fixed). Keep-alive performs automatic re-login to prevent expiration.
544
205
 
545
- ### Performance con Presets Predefinidos
546
-
547
- La librería incluye **presets de performance optimizados** para diferentes entornos:
206
+ ## Express Utilities (Optional)
548
207
 
549
208
  ```typescript
550
- import { BaserowClient, PERFORMANCE_PRESETS } from '@gzl10/baserow'
551
-
552
- // Producción (balanceado): 30s timeout, 3 retries, 10 req/s
553
- const prodClient = await BaserowClient.create({
554
- url: 'https://baserow.example.com',
555
- token: 'your_token',
556
- performance: PERFORMANCE_PRESETS.production
557
- })
209
+ import { BaserowClient, express as baserowExpress } from '@gzl10/baserow'
558
210
 
559
- // Desarrollo (relajado): 60s timeout, 2 retries, 5 req/s
560
- const devClient = await BaserowClient.create({
561
- url: 'http://localhost:3000',
562
- credentials: { email: 'dev@example.com', password: 'password' },
563
- performance: PERFORMANCE_PRESETS.development
564
- })
211
+ app.use('/api', baserowExpress.baserowContext(client))
212
+ app.use('/api', baserowExpress.requireAuth())
565
213
 
566
- // Testing (conservador): 45s timeout, 2 retries, 5 req/s
567
- const testClient = await BaserowClient.create({
568
- url: 'https://test.baserow.com',
569
- token: 'test_token',
570
- performance: PERFORMANCE_PRESETS.testing
214
+ app.get('/api/rows', async (req, res) => {
215
+ const rows = await req.baserow!.database(123).table(456).rows.list()
216
+ res.json(baserowExpress.serializePaginated(rows))
571
217
  })
572
- ```
573
-
574
- #### Presets Disponibles
575
-
576
- | Preset | Timeout | Retries | Rate (req/s) | Uso Ideal |
577
- | -------------- | ------- | ------- | ------------ | --------------------- |
578
- | `production` | 30s | 3 | 10 | Producción balanceada |
579
- | `development` | 60s | 2 | 5 | Desarrollo local |
580
- | `testing` | 45s | 2 | 5 | Tests automatizados |
581
- | `aggressive` | 15s | 5 | 20 | Servidores robustos |
582
- | `conservative` | 60s | 1 | 2 | Recursos limitados |
583
218
 
584
- ```typescript
585
- // Helper function para obtener presets dinámicamente
586
- import { getPerformancePreset } from '@gzl10/baserow'
587
-
588
- const preset = getPerformancePreset('production')
589
- // Equivalente a: PERFORMANCE_PRESETS.production
219
+ app.use(baserowExpress.errorHandler())
590
220
  ```
591
221
 
592
- ### Performance Global
222
+ ## Error Handling
593
223
 
594
224
  ```typescript
595
- import { PerformanceManager } from '@gzl10/baserow'
596
-
597
- // Configurar defaults globales
598
- PerformanceManager.setGlobal({
599
- timeout: 45000,
600
- retries: 5,
601
- maxRequestsPerSecond: 20,
602
- enableRateLimiting: true
603
- })
225
+ import {
226
+ BaserowError,
227
+ BaserowNotFoundError,
228
+ BaserowValidationError,
229
+ BaserowAuthTokenExpiredError
230
+ } from '@gzl10/baserow'
604
231
 
605
- // Ver configuración actual
606
- const currentDefaults = PerformanceManager.getGlobal()
607
- ```
608
-
609
- ### Por Instancia (Custom)
610
-
611
- ```typescript
612
- const client = await BaserowClient.create({
613
- url: 'https://baserow.example.com',
614
- token: 'your_token',
615
- performance: {
616
- timeout: 60000,
617
- retries: 3,
618
- maxRequestsPerSecond: 10
232
+ try {
233
+ await client.database(999).table(456).rows.list()
234
+ } catch (error) {
235
+ if (error instanceof BaserowNotFoundError) {
236
+ console.error('Resource not found:', error.message)
619
237
  }
620
- })
621
- ```
622
-
623
- ## 🗂️ Operaciones Avanzadas
624
-
625
- ### API Jerárquica CRUD Completa
626
-
627
- La librería proporciona una API jerárquica consistente para operaciones CRUD en todos los niveles:
628
-
629
- ```typescript
630
- // ✅ Gestión de Workspaces
631
- const workspaces = await admin.workspaces.list()
632
- const newWS = await admin.workspaces.create({ name: 'Nueva Empresa' })
633
- const updatedWS = await admin.workspace('Mi Empresa').update({ name: 'Empresa Actualizada' })
634
- await admin.workspace('Empresa Vieja').delete()
635
-
636
- // ✅ Gestión de Databases (dentro de workspace)
637
- const databases = await admin.workspace('Mi Empresa').databases.list()
638
- const newDB = await admin.workspace('Mi Empresa').databases.create('Nueva Database')
639
- const updatedDB = await admin.workspace('Mi Empresa').database('CRM').update({ name: 'CRM v2' })
640
- await admin.workspace('Mi Empresa').database('CRM Viejo').delete()
641
-
642
- // ✅ Gestión de Tables (dentro de database)
643
- const tables = await admin.workspace('Mi Empresa').database('CRM').tables.list()
644
- const newTable = await admin
645
- .workspace('Mi Empresa')
646
- .database('CRM')
647
- .tables.create({
648
- name: 'Customers',
649
- data: [
650
- ['Name', 'Email'],
651
- ['Alice', 'alice@example.com']
652
- ],
653
- first_row_header: true
654
- })
655
- const updatedTable = await admin.workspace('Mi Empresa').database('CRM').table('Customers').update({ name: 'Clients' })
656
- await admin.workspace('Mi Empresa').database('CRM').table('Old Table').delete()
657
- ```
658
-
659
- ### Operaciones Bulk
660
-
661
- ```typescript
662
- // Crear múltiples filas
663
- const newRows = await client
664
- .database(123)
665
- .table(456)
666
- .rows.createBulk(
667
- [
668
- { name: 'Alice', email: 'alice@example.com' },
669
- { name: 'Bob', email: 'bob@example.com' }
670
- ],
671
- { batchSize: 100 }
672
- )
673
-
674
- // Descargar tabla completa
675
- const allRows = await client.database(123).table(456).rows.listAll()
676
- ```
677
-
678
- ### Gestión de Campos
679
-
680
- ```typescript
681
- // Crear campos de todos los tipos
682
- const textField = await admin.workspace('Company').database('CRM').table('Customers').field.createText('company_name')
683
-
684
- const emailField = await admin
685
- .workspace('Company')
686
- .database('CRM')
687
- .table('Customers')
688
- .field.createEmail('contact_email')
689
-
690
- const selectField = await admin
691
- .workspace('Company')
692
- .database('CRM')
693
- .table('Customers')
694
- .field.createSingleSelect('status', [
695
- { value: 'active', color: 'green' },
696
- { value: 'inactive', color: 'red' }
697
- ])
698
- ```
699
-
700
- ### Database Tokens
701
-
702
- ```typescript
703
- // Crear tokens con permisos específicos
704
- const token = await admin
705
- .workspace('Company')
706
- .database('CRM')
707
- .tokens.create({
708
- name: 'API Integration Token',
709
- permissions: {
710
- create: true,
711
- read: true,
712
- update: true,
713
- delete: false
714
- }
715
- })
238
+ }
716
239
  ```
717
240
 
718
- ## 🧪 Testing Comprehensivo
719
-
720
- La librería incluye **60+ tests** de integración con **cobertura de error handling del 42%**:
721
-
722
- ### Suite de Tests Disponibles
241
+ ## Testing
723
242
 
724
243
  ```bash
725
- # Todos los tests (rápido)
726
- pnpm test
727
-
728
- # Tests en modo watch
729
- pnpm test:watch
730
-
731
- # Solo tests de smoke (CI/CD)
732
- pnpm test:smoke
733
-
734
- # Tests específicos de error handling
735
- pnpm test admin-database.test.ts admin-table.test.ts admin-field-basic.test.ts admin-field-advanced.test.ts
244
+ pnpm test # All tests
245
+ pnpm test:watch # Watch mode
246
+ pnpm test:smoke # CI/CD smoke tests
736
247
  ```
737
248
 
738
- ### 📊 Cobertura de Testing
739
-
740
- - **✅ 60+ Tests Totales**: 35+ integración + 34 error handling (v1.0.2)
741
- - **✅ Tests de Campos**: 8 archivos especializados por tipo de campo
742
- - **✅ PrismaMapper**: 35+ tests de transformaciones complejas
743
- - **✅ Error Handling**: 42% archivos con cobertura completa (+17% en v1.0.2)
744
- - **✅ Retry Logic**: Tests de manejo de errores y rate limiting
745
- - **✅ Operaciones Bulk**: Validación de procesamiento optimizado
746
- - **✅ API Jerárquica**: Tests de navegación workspace → database → table
747
-
748
- ### 🆕 Error Handling Tests (v1.0.2)
749
-
750
- **Helpers Reutilizables**:
751
-
752
- - `tests/helpers/error-assertions.ts` - Funciones para validar errores tipados
753
- - `tests/fixtures/invalid-data.ts` - Datos inválidos para testing consistente
754
-
755
- **Servicios con Error Handling Completo**:
756
-
757
- - ✅ `admin-database.test.ts` - 8 tests de error (404, 400/422, validaciones)
758
- - ✅ `admin-table.test.ts` - 9 tests de error (404, validaciones, edge cases)
759
- - ✅ `admin-field-basic.test.ts` - 10 tests de error (validaciones por tipo)
760
- - ✅ `admin-field-advanced.test.ts` - 7 tests de error (campos complejos)
761
-
762
- **Códigos HTTP Validados**:
763
-
764
- - 404 (Not Found) - BaserowNotFoundError con contexto
765
- - 400/422 (Validation) - Nombres vacíos, longitud, parámetros inválidos
766
- - Comportamiento Baserow - Documentado lo que acepta vs rechaza
767
-
768
- ### Categorías de Tests
769
-
770
- #### Tests de Campos por Tipo
771
-
772
- - `admin-field-basic.test.ts` - Campos básicos (text, number, boolean) + **10 error tests**
773
- - `admin-field-text.test.ts` - Campos de texto (url, email, phone)
774
- - `admin-field-numeric.test.ts` - Campos numéricos (number, rating)
775
- - `admin-field-datetime.test.ts` - Campos de fecha y auditoría
776
- - `admin-field-select.test.ts` - Campos de selección
777
- - `admin-field-relations.test.ts` - Campos relacionales con retry logic
778
- - `admin-field-advanced.test.ts` - Campos avanzados (file, autonumber, count, rollup, lookup) + **7 error tests**
779
- - `admin-field-audit.test.ts` - Campos de auditoría automática
780
-
781
- #### Tests CRUD Core
782
-
783
- - `admin-database.test.ts` - CRUD databases + **8 error tests**
784
- - `admin-table.test.ts` - CRUD tables + **9 error tests**
785
- - `admin-row.test.ts` - CRUD rows (próximo: error handling)
786
- - `admin-workspace.test.ts` - Gestión workspaces
787
-
788
- #### Tests del PrismaMapper
789
-
790
- - `prisma-mapper.test.ts` - **35+ tests** de transformaciones Prisma → Baserow
791
-
792
- ### 📝 Variables de Entorno para Tests
793
-
794
- ```env
795
- BASEROW_URL=https://baserow.example.com
796
- BASEROW_ADMIN_MAIL=admin@example.com
797
- BASEROW_ADMIN_PASSWORD=your_password
798
- BASEROW_DB_TOKEN=your_database_token
799
- ```
800
-
801
- ### 🔧 Configuración de Tests
802
-
803
- Los tests están configurados para:
804
-
805
- - **Cleanup automático**: Destrucción de recursos tras cada test
806
- - **Retry logic**: Manejo de campos que se crean de forma asíncrona
807
- - **Timeouts configurables**: Adaptados para diferentes entornos
808
- - **Mock y real API**: Soporte para tests unitarios e integración
809
-
810
- ## 🔗 Compatibilidad y Versiones
811
-
812
- ### Baserow v1.35.3 - Totalmente Compatible
813
-
814
- ✅ **Sin Breaking Changes** - Upgrade seguro desde v1.35.0+
815
-
816
- **Mejoras Automáticas (sin código requerido):**
817
-
818
- - 🚀 **Búsquedas optimizadas** (v1.35.2) - Queries con `search` más rápidas
819
- - 🔍 **Filtros robustos** (v1.35.2) - Mejor confiabilidad en operadores complejos (`AND`, `OR`, `NOT`)
820
- - 🔐 **Permisos expandidos** (v1.35.3) - Exportaciones disponibles para roles visualizador
821
- - 🪝 **Webhooks retroactivos** (v1.35.2) - Compatible con webhooks para registros pasados
822
-
823
- **Funcionalidades Nuevas de Baserow:**
824
-
825
- - **Date Dependency** (v1.35.2) - Conexión automática entre fechas inicio/fin/duración
826
- - ⚠️ Configuración via UI de Baserow (API no documentada públicamente aún)
827
- - ✅ Nuestra librería puede leer/escribir campos relacionados normalmente
828
- - **PostgreSQL Sync bidireccional** (v1.35.0) - Feature de servidor
829
- - Usar @gzl10/baserow para sincronizar datos post-sync
249
+ 60+ tests including 35+ integration tests and 34 error handling tests.
830
250
 
831
- **Análisis Completo:** Ver [docs/BASEROW_1.35.3_IMPACT_ANALYSIS.md](docs/BASEROW_1.35.3_IMPACT_ANALYSIS.md)
251
+ ## Documentation
832
252
 
833
- ---
253
+ - [Filters & Sorting](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/FILTERS_AND_SORTING.md)
254
+ - [API Reference](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/BASEROW_API_REFERENCE.md)
255
+ - [Keep-Alive Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/KEEP_ALIVE.md)
256
+ - [Migration Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/MIGRATION.md)
257
+ - [Testing Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/TESTING.md)
258
+ - [Debugging](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/DEBUGGING.md)
834
259
 
835
- ## 🔗 Enlaces
260
+ ## Compatibility
836
261
 
837
- - [Baserow API Documentation](https://baserow.io/docs)
838
- - [TypeScript Documentation](https://www.typescriptlang.org/docs)
839
- - [Express.js](https://expressjs.com)
262
+ **Baserow v1.35.3** - Fully compatible, safe upgrade from v1.35.0+
840
263
 
841
- ## Support
264
+ ## Support
842
265
 
843
266
  <a href="https://www.buymeacoffee.com/gzl10g" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
844
267
 
845
- ## 📄 Licencia
268
+ ## License
846
269
 
847
- MIT License - Ver archivo [LICENSE](LICENSE)
270
+ MIT License - See [LICENSE](LICENSE)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gzl10/baserow",
3
- "version": "1.2.0",
4
- "description": "Cliente TypeScript avanzado para Baserow API con arquitectura de 3 clientes, 21 tipos de campos soportados y operaciones bulk optimizadas",
3
+ "version": "1.2.1",
4
+ "description": "Modern TypeScript client for Baserow API with 3-client architecture, 21 field types, and optimized bulk operations",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -43,16 +43,20 @@
43
43
  ],
44
44
  "repository": {
45
45
  "type": "git",
46
- "url": "git@ssh.gitlab.gzl10.com:oss/baserow.git"
46
+ "url": "https://gitlab.gzl10.com/oss/baserow.git"
47
47
  },
48
- "homepage": "https://gitlab.gzl10.com/oss/baserow",
48
+ "homepage": "https://www.gzl10.com",
49
49
  "bugs": "https://gitlab.gzl10.com/oss/baserow/-/issues",
50
50
  "author": {
51
51
  "name": "Gonzalo Díez",
52
52
  "email": "gonzalo@gzl10.com",
53
53
  "url": "https://gitlab.gzl10.com/oss"
54
54
  },
55
- "license": "UNLICENSED",
55
+ "license": "MIT",
56
+ "funding": {
57
+ "type": "buymeacoffee",
58
+ "url": "https://www.buymeacoffee.com/gzl10g"
59
+ },
56
60
  "devDependencies": {
57
61
  "@types/chance": "^1.1.7",
58
62
  "@types/node": "^20.19.5",