@gzl10/baserow 1.2.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +435 -0
  2. package/README.md +847 -0
  3. package/dist/index.d.ts +8749 -0
  4. package/dist/index.js +11167 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +91 -0
  7. package/src/BaserowClient.ts +501 -0
  8. package/src/ClientWithCreds.ts +545 -0
  9. package/src/ClientWithCredsWs.ts +852 -0
  10. package/src/ClientWithToken.ts +171 -0
  11. package/src/contexts/DatabaseClientContext.ts +114 -0
  12. package/src/contexts/DatabaseContext.ts +870 -0
  13. package/src/contexts/DatabaseTokenContext.ts +331 -0
  14. package/src/contexts/FieldContext.ts +399 -0
  15. package/src/contexts/RowContext.ts +99 -0
  16. package/src/contexts/TableClientContext.ts +291 -0
  17. package/src/contexts/TableContext.ts +1247 -0
  18. package/src/contexts/TableOnlyContext.ts +74 -0
  19. package/src/contexts/WorkspaceContext.ts +490 -0
  20. package/src/express/errors.ts +260 -0
  21. package/src/express/index.ts +69 -0
  22. package/src/express/middleware.ts +225 -0
  23. package/src/express/serializers.ts +314 -0
  24. package/src/index.ts +247 -0
  25. package/src/presets/performance.ts +262 -0
  26. package/src/services/AuthService.ts +472 -0
  27. package/src/services/DatabaseService.ts +246 -0
  28. package/src/services/DatabaseTokenService.ts +186 -0
  29. package/src/services/FieldService.ts +1543 -0
  30. package/src/services/RowService.ts +982 -0
  31. package/src/services/SchemaControlService.ts +420 -0
  32. package/src/services/TableService.ts +781 -0
  33. package/src/services/WorkspaceService.ts +113 -0
  34. package/src/services/core/BaseAuthClient.ts +111 -0
  35. package/src/services/core/BaseClient.ts +107 -0
  36. package/src/services/core/BaseService.ts +71 -0
  37. package/src/services/core/HttpService.ts +115 -0
  38. package/src/services/core/ValidationService.ts +149 -0
  39. package/src/types/auth.ts +177 -0
  40. package/src/types/core.ts +91 -0
  41. package/src/types/errors.ts +105 -0
  42. package/src/types/fields.ts +456 -0
  43. package/src/types/index.ts +222 -0
  44. package/src/types/requests.ts +333 -0
  45. package/src/types/responses.ts +50 -0
  46. package/src/types/schema.ts +446 -0
  47. package/src/types/tokens.ts +36 -0
  48. package/src/types.ts +11 -0
  49. package/src/utils/auth.ts +174 -0
  50. package/src/utils/axios.ts +647 -0
  51. package/src/utils/field-cache.ts +164 -0
  52. package/src/utils/httpFactory.ts +66 -0
  53. package/src/utils/jwt-decoder.ts +188 -0
  54. package/src/utils/jwtTokens.ts +50 -0
  55. package/src/utils/performance.ts +105 -0
  56. package/src/utils/prisma-mapper.ts +961 -0
  57. package/src/utils/validation.ts +463 -0
  58. package/src/validators/schema.ts +419 -0
@@ -0,0 +1,446 @@
1
+ import type { Table } from './core'
2
+
3
+ /**
4
+ * Tipos TypeScript para el sistema de definición declarativa de schemas
5
+ *
6
+ * Permite definir esquemas de base de datos completos usando un formato
7
+ * JSON/TypeScript que luego puede ser aplicado usando database().loadSchema()
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const ecommerceSchema: DatabaseSchema = {
12
+ * version: "1.0.0",
13
+ * tables: [
14
+ * {
15
+ * name: "clientes",
16
+ * fields: [
17
+ * { name: "nombre", type: "text" },
18
+ * { name: "email", type: "email" },
19
+ * {
20
+ * name: "categoria",
21
+ * type: "single_select",
22
+ * config: {
23
+ * options: [
24
+ * { value: "Premium", color: "blue" }
25
+ * ]
26
+ * }
27
+ * }
28
+ * ]
29
+ * }
30
+ * ],
31
+ * relationships: [
32
+ * {
33
+ * name: "cliente",
34
+ * sourceTable: "pedidos",
35
+ * targetTable: "clientes"
36
+ * }
37
+ * ]
38
+ * }
39
+ * ```
40
+ *
41
+ */
42
+
43
+ /**
44
+ * Schema completo de una base de datos
45
+ */
46
+ export interface DatabaseSchema {
47
+ /** Versión del schema para control de cambios */
48
+ version?: string
49
+ /** Descripción del propósito de la base de datos */
50
+ description?: string
51
+ /** Definición de todas las tablas */
52
+ tables: TableSchema[]
53
+ /** Relaciones entre tablas (se crean después de las tablas) */
54
+ relationships?: RelationshipSchema[]
55
+ }
56
+
57
+ /**
58
+ * Schema de una tabla individual
59
+ */
60
+ export interface TableSchema {
61
+ /** Nombre de la tabla */
62
+ name: string
63
+ /** Descripción opcional de la tabla */
64
+ description?: string
65
+ /** Definición de todos los campos de la tabla */
66
+ fields: FieldSchema[]
67
+ }
68
+
69
+ /**
70
+ * Schema de un campo individual
71
+ */
72
+ export interface FieldSchema {
73
+ /** Nombre del campo */
74
+ name: string
75
+ /** Tipo de campo de Baserow */
76
+ type: FieldType
77
+ /** Descripción opcional del campo */
78
+ description?: string
79
+ /** Configuración específica según el tipo de campo */
80
+ config?: FieldConfig
81
+ }
82
+
83
+ /**
84
+ * Schema de una relación entre tablas
85
+ */
86
+ export interface RelationshipSchema {
87
+ /** Nombre del campo de relación */
88
+ name: string
89
+ /** Tabla que contiene la relación (tabla origen) */
90
+ sourceTable: string
91
+ /** Tabla objetivo de la relación */
92
+ targetTable: string
93
+ /** Descripción opcional de la relación */
94
+ description?: string
95
+ }
96
+
97
+ /**
98
+ * Tipos de campos soportados por Baserow
99
+ */
100
+ export type FieldType =
101
+ // Campos de texto
102
+ | 'text'
103
+ | 'long_text'
104
+ | 'url'
105
+ | 'email'
106
+ | 'phone_number'
107
+
108
+ // Campos numéricos
109
+ | 'number'
110
+ | 'rating'
111
+
112
+ // Campos de fecha
113
+ | 'date'
114
+ | 'last_modified'
115
+ | 'created_on'
116
+ | 'last_modified_by'
117
+ | 'created_by'
118
+
119
+ // Campos de selección
120
+ | 'single_select'
121
+ | 'multiple_select'
122
+
123
+ // Campos booleanos
124
+ | 'boolean'
125
+
126
+ // Campos de relación
127
+ | 'link_row'
128
+ | 'formula'
129
+
130
+ // Campos avanzados
131
+ | 'file'
132
+ | 'autonumber'
133
+ | 'count'
134
+ | 'rollup'
135
+ | 'lookup'
136
+
137
+ /**
138
+ * Configuración específica por tipo de campo
139
+ */
140
+ export type FieldConfig =
141
+ | TextFieldConfig
142
+ | NumberFieldConfig
143
+ | DateFieldConfig
144
+ | SelectFieldConfig
145
+ | MultiSelectFieldConfig
146
+ | BooleanFieldConfig
147
+ | LinkRowFieldConfig
148
+ | FormulaFieldConfig
149
+ | FileFieldConfig
150
+ | CountFieldConfig
151
+ | RollupFieldConfig
152
+ | LookupFieldConfig
153
+
154
+ /**
155
+ * Configuración para campos de texto
156
+ */
157
+ export interface TextFieldConfig {
158
+ /** Valor por defecto */
159
+ default?: string
160
+ /** Texto de placeholder */
161
+ placeholder?: string
162
+ }
163
+
164
+ /**
165
+ * Configuración para campos numéricos
166
+ */
167
+ export interface NumberFieldConfig {
168
+ /** Número de decimales (0 para enteros) */
169
+ decimals?: number
170
+ /** Valor mínimo permitido */
171
+ min?: number
172
+ /** Valor máximo permitido */
173
+ max?: number
174
+ /** Valor por defecto */
175
+ default?: number
176
+ /** Prefijo (ej: "$") */
177
+ prefix?: string
178
+ /** Sufijo (ej: " €") */
179
+ suffix?: string
180
+ /** Formato de separadores */
181
+ separators?: 'COMMA_PERIOD' | 'PERIOD_COMMA'
182
+ }
183
+
184
+ /**
185
+ * Configuración para campos de fecha
186
+ */
187
+ export interface DateFieldConfig {
188
+ /** Incluir tiempo además de fecha */
189
+ includeTime?: boolean
190
+ /** Formato de fecha */
191
+ format?: 'ISO' | 'US' | 'EU'
192
+ /** Formato de hora */
193
+ timeFormat?: '24' | '12'
194
+ /** Valor por defecto */
195
+ default?: string
196
+ /** Zona horaria */
197
+ timezone?: string
198
+ }
199
+
200
+ /**
201
+ * Configuración para campos single_select
202
+ */
203
+ export interface SelectFieldConfig {
204
+ /** Opciones disponibles */
205
+ options: SelectOption[]
206
+ }
207
+
208
+ /**
209
+ * Configuración para campos multiple_select
210
+ */
211
+ export interface MultiSelectFieldConfig {
212
+ /** Opciones disponibles */
213
+ options: SelectOption[]
214
+ }
215
+
216
+ /**
217
+ * Opción para campos de selección
218
+ */
219
+ export interface SelectOption {
220
+ /** Valor de la opción */
221
+ value: string
222
+ /** Color de la opción */
223
+ color: SelectOptionColor
224
+ }
225
+
226
+ /**
227
+ * Colores disponibles para opciones de select
228
+ */
229
+ export type SelectOptionColor =
230
+ | 'blue'
231
+ | 'green'
232
+ | 'red'
233
+ | 'yellow'
234
+ | 'orange'
235
+ | 'purple'
236
+ | 'pink'
237
+ | 'brown'
238
+ | 'gray'
239
+ | 'dark_blue'
240
+ | 'dark_green'
241
+ | 'dark_red'
242
+ | 'dark_yellow'
243
+ | 'dark_orange'
244
+ | 'dark_purple'
245
+ | 'dark_pink'
246
+ | 'dark_brown'
247
+ | 'dark_gray'
248
+
249
+ /**
250
+ * Configuración para campos boolean
251
+ */
252
+ export interface BooleanFieldConfig {
253
+ /** Valor por defecto */
254
+ default?: boolean
255
+ }
256
+
257
+ /**
258
+ * Configuración para campos link_row (relaciones)
259
+ */
260
+ export interface LinkRowFieldConfig {
261
+ /** ID de la tabla objetivo */
262
+ targetTableId?: number
263
+ /** Nombre de la tabla objetivo (se resuelve en runtime) */
264
+ targetTableName?: string
265
+ }
266
+
267
+ /**
268
+ * Configuración para campos de fórmula
269
+ */
270
+ export interface FormulaFieldConfig {
271
+ /** Fórmula a ejecutar */
272
+ formula: string
273
+ }
274
+
275
+ /**
276
+ * Configuración para campos de archivo
277
+ */
278
+ export interface FileFieldConfig {
279
+ /** Tipos de archivo permitidos */
280
+ allowedFileTypes?: string[]
281
+ /** Tamaño máximo en bytes */
282
+ maxFileSize?: number
283
+ }
284
+
285
+ /**
286
+ * Configuración para campos count
287
+ */
288
+ export interface CountFieldConfig {
289
+ /** ID de la tabla a contar */
290
+ targetTableId?: number
291
+ /** Nombre de la tabla a contar (se resuelve en runtime) */
292
+ targetTableName?: string
293
+ }
294
+
295
+ /**
296
+ * Configuración para campos rollup
297
+ */
298
+ export interface RollupFieldConfig {
299
+ /** ID de la tabla objetivo */
300
+ targetTableId?: number
301
+ /** Nombre de la tabla objetivo */
302
+ targetTableName?: string
303
+ /** ID del campo objetivo */
304
+ targetFieldId?: number
305
+ /** Nombre del campo objetivo */
306
+ targetFieldName?: string
307
+ /** Función de agregación */
308
+ aggregation: 'sum' | 'avg' | 'min' | 'max' | 'count'
309
+ }
310
+
311
+ /**
312
+ * Configuración para campos lookup
313
+ */
314
+ export interface LookupFieldConfig {
315
+ /** ID de la tabla objetivo */
316
+ targetTableId?: number
317
+ /** Nombre de la tabla objetivo */
318
+ targetTableName?: string
319
+ /** ID del campo objetivo */
320
+ targetFieldId?: number
321
+ /** Nombre del campo objetivo */
322
+ targetFieldName?: string
323
+ }
324
+
325
+ /**
326
+ * Opciones para cargar un schema
327
+ */
328
+ export interface LoadSchemaOptions {
329
+ /** Modo de carga */
330
+ mode?: LoadSchemaMode
331
+ /** Versión del schema (para tracking) */
332
+ version?: string
333
+ /** Forzar carga aunque no haya cambios */
334
+ force?: boolean
335
+ /** Limpiar tablas que no estén en el schema */
336
+ cleanup?: boolean
337
+ }
338
+
339
+ /**
340
+ * Modos de carga de schema
341
+ */
342
+ export type LoadSchemaMode =
343
+ /** Solo crear, no actualizar existentes */
344
+ | 'create-only'
345
+ /** Crear y actualizar campos existentes */
346
+ | 'update'
347
+ /** Recrear todo desde cero */
348
+ | 'recreate'
349
+
350
+ /**
351
+ * Resultado de cargar un schema
352
+ */
353
+ export interface LoadSchemaResult {
354
+ /** Tablas creadas/actualizadas */
355
+ tables: Table[]
356
+ /** Tablas indexadas por nombre para fácil acceso */
357
+ tablesByName: Record<string, Table>
358
+ /** Información de control del schema */
359
+ schemaControl: SchemaControl
360
+ /** Lista de cambios aplicados */
361
+ changes: SchemaChange[]
362
+ /** Estadísticas de la operación */
363
+ stats: LoadSchemaStats
364
+ }
365
+
366
+ /**
367
+ * Información de control del schema cargado
368
+ */
369
+ export interface SchemaControl {
370
+ /** ID único del control */
371
+ id: string
372
+ /** Versión del schema */
373
+ version: string
374
+ /** Hash del schema para detectar cambios */
375
+ schemaHash: string
376
+ /** Fecha de carga */
377
+ loadedAt: Date
378
+ /** Nombres de tablas creadas por este schema */
379
+ tablesCreated: string[]
380
+ /** Estado del schema */
381
+ status: SchemaControlStatus
382
+ /** Opciones usadas para la carga */
383
+ loadOptions: LoadSchemaOptions
384
+ }
385
+
386
+ /**
387
+ * Estados del control de schema
388
+ */
389
+ export type SchemaControlStatus =
390
+ /** Schema activo y actualizado */
391
+ | 'active'
392
+ /** Schema desactualizado */
393
+ | 'outdated'
394
+ /** Error en la carga */
395
+ | 'error'
396
+ /** Carga en progreso */
397
+ | 'loading'
398
+
399
+ /**
400
+ * Tipos de cambios aplicados durante la carga
401
+ */
402
+ export interface SchemaChange {
403
+ /** Tipo de cambio */
404
+ type: SchemaChangeType
405
+ /** Elemento afectado */
406
+ target: string
407
+ /** Descripción del cambio */
408
+ description: string
409
+ /** Detalles adicionales */
410
+ details?: any
411
+ }
412
+
413
+ /**
414
+ * Tipos de cambios de schema
415
+ */
416
+ export type SchemaChangeType =
417
+ | 'table_created'
418
+ | 'table_updated'
419
+ | 'table_deleted'
420
+ | 'field_created'
421
+ | 'field_updated'
422
+ | 'field_deleted'
423
+ | 'relationship_created'
424
+ | 'relationship_updated'
425
+ | 'relationship_deleted'
426
+
427
+ /**
428
+ * Estadísticas de la operación de carga
429
+ */
430
+ export interface LoadSchemaStats {
431
+ /** Tiempo total de ejecución en ms */
432
+ duration: number
433
+ /** Número de tablas procesadas */
434
+ tablesProcessed: number
435
+ /** Número de campos procesados */
436
+ fieldsProcessed: number
437
+ /** Número de relaciones procesadas */
438
+ relationshipsProcessed: number
439
+ /** Número de errores encontrados */
440
+ errors: number
441
+ /** Número de warnings */
442
+ warnings: number
443
+ }
444
+
445
+ // Re-export tipos necesarios de otros archivos
446
+ export type { Table, Field, Row } from './index'
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Tipos relacionados con Database Tokens de Baserow
3
+ */
4
+
5
+ /**
6
+ * Prefijo único para identificar tokens creados por la librería
7
+ * vs tokens creados manualmente por usuarios
8
+ */
9
+ export const LIBRARY_TOKEN_PREFIX = 'br-lib:'
10
+
11
+ export interface DatabaseTokenPermissions {
12
+ create: boolean
13
+ read: boolean
14
+ update: boolean
15
+ delete: boolean
16
+ }
17
+
18
+ export interface DatabaseToken {
19
+ id: number
20
+ name: string
21
+ token: string
22
+ workspace: number
23
+ permissions: DatabaseTokenPermissions
24
+ created_on: string
25
+ }
26
+
27
+ export interface CreateDatabaseTokenRequest {
28
+ name: string
29
+ permissions: DatabaseTokenPermissions
30
+ }
31
+
32
+ export interface UpdateDatabaseTokenRequest {
33
+ name?: string
34
+ permissions?: DatabaseTokenPermissions
35
+ rotate_token?: boolean
36
+ }
package/src/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tipos TypeScript para Baserow API
3
+ *
4
+ * DEPRECATED: Este archivo mantiene compatibilidad hacia atrás.
5
+ * Usa imports específicos desde src/types/ para mejor tree-shaking.
6
+ *
7
+ * @deprecated Use imports from './types/index.js' instead
8
+ */
9
+
10
+ // Re-export todo desde el nuevo index modular
11
+ export * from './types/index'
@@ -0,0 +1,174 @@
1
+ import { HttpClient } from './axios'
2
+ import { BaserowCredentials, BaserowError, LoginResponse, Logger } from '../types'
3
+ import { validateRequired, validateString, validateUrl } from './validation'
4
+
5
+ /**
6
+ * Opciones para la verificación de login
7
+ */
8
+ export interface VerifyLoginOptions {
9
+ /** Timeout en milisegundos (default: 10000) */
10
+ timeout?: number
11
+ /** Logger para debug (opcional) */
12
+ logger?: Logger
13
+ }
14
+
15
+ /**
16
+ * Verificar si las credenciales de Baserow son válidas sin crear cliente
17
+ *
18
+ * Esta función es útil para:
19
+ * - Validar credenciales en formularios de login
20
+ * - Health checks de credenciales
21
+ * - Verificación de configuración antes de inicializar la aplicación
22
+ *
23
+ * @param url URL base de Baserow (ej: 'https://baserow.gzl10.com')
24
+ * @param credentials Credenciales de usuario (email y password)
25
+ * @param options Opciones adicionales (timeout, logger)
26
+ * @returns Promise<boolean> - true si las credenciales son válidas
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * import { verifyLogin } from '@gzl10/baserow'
31
+ *
32
+ * const isValid = await verifyLogin('https://baserow.gzl10.com', {
33
+ * email: 'user@example.com',
34
+ * password: 'password123'
35
+ * })
36
+ *
37
+ * if (isValid) {
38
+ * // Proceder a crear BaserowAdmin
39
+ * const admin = await BaserowAdmin.create({ ... })
40
+ * } else {
41
+ * // Mostrar error en UI
42
+ * console.error('Credenciales inválidas')
43
+ * }
44
+ * ```
45
+ */
46
+ export async function verifyLogin(
47
+ url: string,
48
+ credentials: BaserowCredentials,
49
+ options: VerifyLoginOptions = {}
50
+ ): Promise<boolean> {
51
+ // Validación de parámetros
52
+ validateRequired(url, 'url')
53
+ validateRequired(credentials, 'credentials')
54
+ validateString(credentials.email, 'email')
55
+ validateString(credentials.password, 'password')
56
+
57
+ if (!validateUrl(url)) {
58
+ throw new Error('url must be a valid URL')
59
+ }
60
+
61
+ const { timeout = 10000, logger } = options
62
+
63
+ // Crear HttpClient temporal (sin almacenar estado)
64
+ let tempHttp: HttpClient | undefined
65
+
66
+ try {
67
+ tempHttp = new HttpClient({
68
+ baseURL: `${url.replace(/\/$/, '')}/api`,
69
+ token: '', // Sin token inicial
70
+ timeout,
71
+ logger
72
+ })
73
+
74
+ logger?.info?.('BaserowAuth: Verifying credentials...')
75
+
76
+ // Intentar login con las credenciales proporcionadas
77
+ const loginData = {
78
+ username: credentials.email,
79
+ password: credentials.password
80
+ }
81
+
82
+ const response = await tempHttp.post<LoginResponse>('/user/token-auth/', loginData)
83
+
84
+ // Si llegamos aquí, el login fue exitoso
85
+ logger?.info?.(`BaserowAuth: Credentials valid for user ${response.user.username}`)
86
+ return true
87
+ } catch (error) {
88
+ // Manejar diferentes tipos de errores
89
+ if (error instanceof BaserowError) {
90
+ switch (error.status) {
91
+ case 401:
92
+ // Credenciales inválidas
93
+ logger?.warn?.('BaserowAuth: Invalid credentials provided')
94
+ return false
95
+
96
+ case 400:
97
+ // Bad request (formato incorrecto)
98
+ logger?.warn?.('BaserowAuth: Bad request - invalid data format')
99
+ return false
100
+
101
+ case 403:
102
+ // Usuario bloqueado o sin permisos
103
+ logger?.warn?.('BaserowAuth: User forbidden or blocked')
104
+ return false
105
+
106
+ case 429:
107
+ // Rate limit - técnicamente las credenciales podrían ser válidas
108
+ logger?.warn?.('BaserowAuth: Rate limited - cannot verify at this time')
109
+ return false
110
+
111
+ case 500:
112
+ case 502:
113
+ case 503:
114
+ case 504:
115
+ // Errores del servidor
116
+ logger?.error?.('BaserowAuth: Server error during login verification')
117
+ return false
118
+
119
+ default:
120
+ // Otros errores HTTP
121
+ logger?.error?.(`BaserowAuth: HTTP error ${error.status}: ${error.message}`)
122
+ return false
123
+ }
124
+ }
125
+
126
+ // Errores de red, timeout, etc.
127
+ logger?.error?.('BaserowAuth: Network or connection error:', error)
128
+ return false
129
+ } finally {
130
+ // Limpieza: el HttpClient temporal se garbage-collectea automáticamente
131
+ // No necesitamos limpiar tokens porque no los almacenamos
132
+ tempHttp = undefined
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Verificar si una URL de Baserow es accesible (health check básico)
138
+ *
139
+ * @param url URL base de Baserow
140
+ * @param options Opciones de verificación
141
+ * @returns Promise<boolean> - true si el servidor es accesible
142
+ */
143
+ export async function verifyBaserowHealth(
144
+ url: string,
145
+ options: Pick<VerifyLoginOptions, 'timeout' | 'logger'> = {}
146
+ ): Promise<boolean> {
147
+ validateRequired(url, 'url')
148
+
149
+ if (!validateUrl(url)) {
150
+ throw new Error('url must be a valid URL')
151
+ }
152
+
153
+ const { timeout = 5000, logger } = options
154
+
155
+ try {
156
+ logger?.info?.('BaserowAuth: Checking Baserow health...')
157
+
158
+ // Usar endpoint público de health que no requiere autenticación
159
+ const healthUrl = `${url.replace(/\/$/, '')}/api/_health/`
160
+ const response = await fetch(healthUrl, {
161
+ method: 'GET',
162
+ headers: { 'Content-Type': 'application/json' },
163
+ signal: AbortSignal.timeout(timeout)
164
+ })
165
+
166
+ const isHealthy = response.ok
167
+ logger?.info?.(`BaserowAuth: Baserow health check ${isHealthy ? 'passed' : 'failed'}`)
168
+
169
+ return isHealthy
170
+ } catch (error) {
171
+ logger?.error?.('BaserowAuth: Health check failed:', error)
172
+ return false
173
+ }
174
+ }