@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.
- package/CHANGELOG.md +12 -0
- package/README.md +123 -700
- 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
|
-
|
|
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
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
- 🎯 **
|
|
8
|
-
- 🔐 **Auto-Refresh JWT**:
|
|
9
|
-
- 🗺️ **PrismaBaserowMapper**:
|
|
10
|
-
- 📋 **21/22
|
|
11
|
-
- 🚀 **HTTP
|
|
12
|
-
- 🔄 **API
|
|
13
|
-
- ⚡ **
|
|
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
|
-
##
|
|
15
|
+
## Installation
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
21
|
+
## Quick Start
|
|
43
22
|
|
|
44
23
|
```typescript
|
|
45
24
|
import { BaserowClient } from '@gzl10/baserow'
|
|
46
25
|
|
|
47
|
-
// 1.
|
|
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.
|
|
54
|
-
const
|
|
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.
|
|
60
|
-
const
|
|
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: '
|
|
42
|
+
workspace: 'My Workspace'
|
|
64
43
|
})
|
|
65
44
|
```
|
|
66
45
|
|
|
67
|
-
|
|
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
|
-
|
|
78
|
-
|
|
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
|
-
##
|
|
54
|
+
## PrismaBaserowMapper
|
|
82
55
|
|
|
83
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
128
|
-
// - TokenConfig = BaserowTokenConfig
|
|
129
|
-
// - CredentialsConfig = BaserowCredentialsConfig
|
|
130
|
-
// - CredentialsWorkspaceConfig = BaserowCredentialsWorkspaceConfig
|
|
131
|
-
```
|
|
74
|
+
## Basic Usage
|
|
132
75
|
|
|
133
|
-
###
|
|
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
|
-
//
|
|
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
|
-
###
|
|
90
|
+
### Admin Operations
|
|
167
91
|
|
|
168
92
|
```typescript
|
|
169
|
-
|
|
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: '
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
126
|
+
### Numeric & Boolean
|
|
240
127
|
|
|
241
128
|
```typescript
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
134
|
+
### Date & Audit
|
|
248
135
|
|
|
249
136
|
```typescript
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
142
|
+
### Selection
|
|
258
143
|
|
|
259
144
|
```typescript
|
|
260
|
-
|
|
145
|
+
await table.field.createSingleSelect('status', [
|
|
261
146
|
{ value: 'active', color: 'green' },
|
|
262
147
|
{ value: 'inactive', color: 'red' }
|
|
263
148
|
])
|
|
264
|
-
|
|
265
|
-
{ value: 'urgent', color: 'red' },
|
|
266
|
-
{ value: 'important', color: 'orange' }
|
|
267
|
-
])
|
|
149
|
+
await table.field.createMultipleSelect('tags', options)
|
|
268
150
|
```
|
|
269
151
|
|
|
270
|
-
|
|
152
|
+
### Relational
|
|
271
153
|
|
|
272
154
|
```typescript
|
|
273
|
-
|
|
274
|
-
|
|
155
|
+
await table.field.createLinkRow('related_items', targetTableId)
|
|
156
|
+
await table.field.createFormula('total', 'field("qty") * field("price")')
|
|
275
157
|
```
|
|
276
158
|
|
|
277
|
-
|
|
159
|
+
### Advanced
|
|
278
160
|
|
|
279
161
|
```typescript
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
-
|
|
169
|
+
## Configuration
|
|
297
170
|
|
|
298
|
-
|
|
171
|
+
### Performance Presets
|
|
299
172
|
|
|
300
173
|
```typescript
|
|
301
|
-
|
|
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
|
-
|
|
411
|
-
const adminClient = await BaserowClient.create({
|
|
176
|
+
const client = await BaserowClient.create({
|
|
412
177
|
url: 'https://baserow.example.com',
|
|
413
|
-
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
|
472
|
-
|
|
|
473
|
-
| `
|
|
474
|
-
| `
|
|
475
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
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 //
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
560
|
-
|
|
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
|
-
|
|
567
|
-
const
|
|
568
|
-
|
|
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
|
-
|
|
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
|
-
|
|
222
|
+
## Error Handling
|
|
593
223
|
|
|
594
224
|
```typescript
|
|
595
|
-
import {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
maxRequestsPerSecond: 20,
|
|
602
|
-
enableRateLimiting: true
|
|
603
|
-
})
|
|
225
|
+
import {
|
|
226
|
+
BaserowError,
|
|
227
|
+
BaserowNotFoundError,
|
|
228
|
+
BaserowValidationError,
|
|
229
|
+
BaserowAuthTokenExpiredError
|
|
230
|
+
} from '@gzl10/baserow'
|
|
604
231
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
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
|
-
##
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
260
|
+
## Compatibility
|
|
836
261
|
|
|
837
|
-
|
|
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
|
-
##
|
|
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
|
-
##
|
|
268
|
+
## License
|
|
846
269
|
|
|
847
|
-
MIT 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.
|
|
4
|
-
"description": "
|
|
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": "
|
|
46
|
+
"url": "https://gitlab.gzl10.com/oss/baserow.git"
|
|
47
47
|
},
|
|
48
|
-
"homepage": "https://
|
|
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": "
|
|
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",
|