@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,419 @@
1
+ /**
2
+ * Validadores Zod para el sistema de schemas
3
+ *
4
+ * Proporciona validación robusta de schemas antes de aplicarlos,
5
+ * previniendo errores y asegurando consistencia en los datos.
6
+ *
7
+ */
8
+
9
+ import { z } from 'zod'
10
+ import type {
11
+ DatabaseSchema,
12
+ TableSchema,
13
+ FieldSchema,
14
+ RelationshipSchema,
15
+ LoadSchemaOptions,
16
+ SelectOption
17
+ } from '../types/schema'
18
+
19
+ /**
20
+ * Colores válidos para opciones de select
21
+ */
22
+ const selectOptionColors = [
23
+ 'blue',
24
+ 'green',
25
+ 'red',
26
+ 'yellow',
27
+ 'orange',
28
+ 'purple',
29
+ 'pink',
30
+ 'brown',
31
+ 'gray',
32
+ 'dark_blue',
33
+ 'dark_green',
34
+ 'dark_red',
35
+ 'dark_yellow',
36
+ 'dark_orange',
37
+ 'dark_purple',
38
+ 'dark_pink',
39
+ 'dark_brown',
40
+ 'dark_gray'
41
+ ] as const
42
+
43
+ /**
44
+ * Tipos de campos válidos de Baserow
45
+ */
46
+ const fieldTypes = [
47
+ // Texto
48
+ 'text',
49
+ 'long_text',
50
+ 'url',
51
+ 'email',
52
+ 'phone_number',
53
+ // Numéricos
54
+ 'number',
55
+ 'rating',
56
+ // Fecha
57
+ 'date',
58
+ 'last_modified',
59
+ 'created_on',
60
+ 'last_modified_by',
61
+ 'created_by',
62
+ // Selección
63
+ 'single_select',
64
+ 'multiple_select',
65
+ // Boolean
66
+ 'boolean',
67
+ // Relación
68
+ 'link_row',
69
+ 'formula',
70
+ // Avanzados
71
+ 'file',
72
+ 'autonumber',
73
+ 'count',
74
+ 'rollup',
75
+ 'lookup'
76
+ ] as const
77
+
78
+ /**
79
+ * Validador para opciones de select
80
+ */
81
+ export const SelectOptionValidator = z.object({
82
+ value: z.string().min(1, 'El valor de la opción no puede estar vacío'),
83
+ color: z.enum(selectOptionColors, {
84
+ errorMap: () => ({ message: 'Color de opción no válido' })
85
+ })
86
+ }) satisfies z.ZodType<SelectOption>
87
+
88
+ /**
89
+ * Validadores para configuraciones específicas de campos
90
+ */
91
+ export const FieldConfigValidators = {
92
+ text: z
93
+ .object({
94
+ default: z.string().optional(),
95
+ placeholder: z.string().optional()
96
+ })
97
+ .optional(),
98
+
99
+ number: z
100
+ .object({
101
+ decimals: z.number().int().min(0).max(10).optional(),
102
+ min: z.number().optional(),
103
+ max: z.number().optional(),
104
+ default: z.number().optional(),
105
+ prefix: z.string().optional(),
106
+ suffix: z.string().optional(),
107
+ separators: z.enum(['COMMA_PERIOD', 'PERIOD_COMMA']).optional()
108
+ })
109
+ .optional(),
110
+
111
+ date: z
112
+ .object({
113
+ includeTime: z.boolean().optional(),
114
+ format: z.enum(['ISO', 'US', 'EU']).optional(),
115
+ timeFormat: z.enum(['24', '12']).optional(),
116
+ default: z.string().optional(),
117
+ timezone: z.string().optional()
118
+ })
119
+ .optional(),
120
+
121
+ single_select: z.object({
122
+ options: z.array(SelectOptionValidator).min(1, 'Debe haber al menos una opción')
123
+ }),
124
+
125
+ multiple_select: z.object({
126
+ options: z.array(SelectOptionValidator).min(1, 'Debe haber al menos una opción')
127
+ }),
128
+
129
+ boolean: z
130
+ .object({
131
+ default: z.boolean().optional()
132
+ })
133
+ .optional(),
134
+
135
+ link_row: z
136
+ .object({
137
+ targetTableId: z.number().int().positive().optional(),
138
+ targetTableName: z.string().min(1).optional()
139
+ })
140
+ .refine(data => data.targetTableId || data.targetTableName, 'Debe especificar targetTableId o targetTableName'),
141
+
142
+ formula: z.object({
143
+ formula: z.string().min(1, 'La fórmula no puede estar vacía')
144
+ }),
145
+
146
+ file: z
147
+ .object({
148
+ allowedFileTypes: z.array(z.string()).optional(),
149
+ maxFileSize: z.number().int().positive().optional()
150
+ })
151
+ .optional(),
152
+
153
+ count: z
154
+ .object({
155
+ targetTableId: z.number().int().positive().optional(),
156
+ targetTableName: z.string().min(1).optional()
157
+ })
158
+ .refine(data => data.targetTableId || data.targetTableName, 'Debe especificar targetTableId o targetTableName'),
159
+
160
+ rollup: z
161
+ .object({
162
+ targetTableId: z.number().int().positive().optional(),
163
+ targetTableName: z.string().min(1).optional(),
164
+ targetFieldId: z.number().int().positive().optional(),
165
+ targetFieldName: z.string().min(1).optional(),
166
+ aggregation: z.enum(['sum', 'avg', 'min', 'max', 'count'])
167
+ })
168
+ .refine(data => data.targetTableId || data.targetTableName, 'Debe especificar targetTableId o targetTableName')
169
+ .refine(data => data.targetFieldId || data.targetFieldName, 'Debe especificar targetFieldId o targetFieldName'),
170
+
171
+ lookup: z
172
+ .object({
173
+ targetTableId: z.number().int().positive().optional(),
174
+ targetTableName: z.string().min(1).optional(),
175
+ targetFieldId: z.number().int().positive().optional(),
176
+ targetFieldName: z.string().min(1).optional()
177
+ })
178
+ .refine(data => data.targetTableId || data.targetTableName, 'Debe especificar targetTableId o targetTableName')
179
+ .refine(data => data.targetFieldId || data.targetFieldName, 'Debe especificar targetFieldId o targetFieldName')
180
+ }
181
+
182
+ /**
183
+ * Validador dinámico para configuración de campos
184
+ * Valida la configuración específica según el tipo de campo
185
+ */
186
+ function createFieldConfigValidator(fieldType: string) {
187
+ const validator = FieldConfigValidators[fieldType as keyof typeof FieldConfigValidators]
188
+ return validator || z.any().optional()
189
+ }
190
+
191
+ // FieldConfigValidator removido - ahora se usa createFieldConfigValidator para validación tipada
192
+
193
+ /**
194
+ * Validador para schema de campo
195
+ */
196
+ export const FieldSchemaValidator = z
197
+ .object({
198
+ name: z
199
+ .string()
200
+ .min(1, 'El nombre del campo no puede estar vacío')
201
+ .max(255, 'El nombre del campo no puede exceder 255 caracteres')
202
+ .regex(
203
+ /^[a-zA-Z][a-zA-Z0-9_]*$/,
204
+ 'El nombre del campo debe empezar con letra y contener solo letras, números y guiones bajos'
205
+ ),
206
+
207
+ type: z.enum(fieldTypes, {
208
+ errorMap: () => ({ message: 'Tipo de campo no válido' })
209
+ }),
210
+
211
+ description: z.string().max(1000, 'La descripción no puede exceder 1000 caracteres').optional(),
212
+
213
+ config: z.any().optional()
214
+ })
215
+ .refine(
216
+ field => {
217
+ // Validar que la configuración sea apropiada para el tipo de campo usando validadores específicos
218
+ try {
219
+ if (field.config !== undefined) {
220
+ const specificValidator = createFieldConfigValidator(field.type)
221
+ specificValidator.parse(field.config)
222
+ }
223
+
224
+ // Verificar campos que requieren configuración obligatoria
225
+ const requiredConfigTypes = [
226
+ 'single_select',
227
+ 'multiple_select',
228
+ 'link_row',
229
+ 'formula',
230
+ 'count',
231
+ 'rollup',
232
+ 'lookup'
233
+ ]
234
+
235
+ if (requiredConfigTypes.includes(field.type) && !field.config) {
236
+ return false
237
+ }
238
+
239
+ return true
240
+ } catch {
241
+ // Error de validación específica del tipo de campo
242
+ return false
243
+ }
244
+ },
245
+ {
246
+ message: 'La configuración no es válida para este tipo de campo'
247
+ }
248
+ ) satisfies z.ZodType<FieldSchema>
249
+
250
+ /**
251
+ * Validador para schema de tabla
252
+ */
253
+ export const TableSchemaValidator = z
254
+ .object({
255
+ name: z
256
+ .string()
257
+ .min(1, 'El nombre de la tabla no puede estar vacío')
258
+ .max(255, 'El nombre de la tabla no puede exceder 255 caracteres')
259
+ .regex(
260
+ /^[a-zA-Z][a-zA-Z0-9_]*$/,
261
+ 'El nombre de la tabla debe empezar con letra y contener solo letras, números y guiones bajos'
262
+ ),
263
+
264
+ description: z.string().max(1000, 'La descripción no puede exceder 1000 caracteres').optional(),
265
+
266
+ fields: z
267
+ .array(FieldSchemaValidator)
268
+ .min(1, 'La tabla debe tener al menos un campo')
269
+ .max(200, 'La tabla no puede tener más de 200 campos')
270
+ })
271
+ .refine(
272
+ table => {
273
+ // Validar que no haya nombres de campos duplicados
274
+ const fieldNames = table.fields.map(f => f.name.toLowerCase())
275
+ const uniqueNames = new Set(fieldNames)
276
+ return fieldNames.length === uniqueNames.size
277
+ },
278
+ {
279
+ message: 'Los nombres de campos deben ser únicos dentro de la tabla'
280
+ }
281
+ ) satisfies z.ZodType<TableSchema>
282
+
283
+ /**
284
+ * Validador para schema de relación
285
+ */
286
+ export const RelationshipSchemaValidator = z
287
+ .object({
288
+ name: z
289
+ .string()
290
+ .min(1, 'El nombre de la relación no puede estar vacío')
291
+ .max(255, 'El nombre de la relación no puede exceder 255 caracteres')
292
+ .regex(
293
+ /^[a-zA-Z][a-zA-Z0-9_]*$/,
294
+ 'El nombre de la relación debe empezar con letra y contener solo letras, números y guiones bajos'
295
+ ),
296
+
297
+ sourceTable: z.string().min(1, 'El nombre de la tabla origen no puede estar vacío'),
298
+
299
+ targetTable: z.string().min(1, 'El nombre de la tabla destino no puede estar vacío'),
300
+
301
+ description: z.string().max(1000, 'La descripción no puede exceder 1000 caracteres').optional()
302
+ })
303
+ .refine(
304
+ rel => {
305
+ // No permitir auto-relaciones por simplicidad
306
+ return rel.sourceTable !== rel.targetTable
307
+ },
308
+ {
309
+ message: 'Las auto-relaciones no están soportadas'
310
+ }
311
+ ) satisfies z.ZodType<RelationshipSchema>
312
+
313
+ /**
314
+ * Validador para schema de base de datos completo
315
+ */
316
+ export const DatabaseSchemaValidator = z
317
+ .object({
318
+ version: z.string().optional(),
319
+
320
+ description: z.string().max(1000, 'La descripción no puede exceder 1000 caracteres').optional(),
321
+
322
+ tables: z
323
+ .array(TableSchemaValidator)
324
+ .min(1, 'El schema debe contener al menos una tabla')
325
+ .max(100, 'El schema no puede contener más de 100 tablas'),
326
+
327
+ relationships: z.array(RelationshipSchemaValidator).optional()
328
+ })
329
+ .refine(
330
+ schema => {
331
+ // Validar que no haya nombres de tablas duplicados
332
+ const tableNames = schema.tables.map(t => t.name.toLowerCase())
333
+ const uniqueNames = new Set(tableNames)
334
+ return tableNames.length === uniqueNames.size
335
+ },
336
+ {
337
+ message: 'Los nombres de tablas deben ser únicos'
338
+ }
339
+ )
340
+ .refine(
341
+ schema => {
342
+ // Validar que las relaciones referencien tablas existentes
343
+ if (!schema.relationships) return true
344
+
345
+ const tableNames = new Set(schema.tables.map(t => t.name.toLowerCase()))
346
+
347
+ for (const rel of schema.relationships) {
348
+ if (!tableNames.has(rel.sourceTable.toLowerCase()) || !tableNames.has(rel.targetTable.toLowerCase())) {
349
+ return false
350
+ }
351
+ }
352
+
353
+ return true
354
+ },
355
+ {
356
+ message: 'Las relaciones deben referenciar tablas existentes en el schema'
357
+ }
358
+ ) satisfies z.ZodType<DatabaseSchema>
359
+
360
+ /**
361
+ * Validador para opciones de carga de schema
362
+ */
363
+ export const LoadSchemaOptionsValidator = z.object({
364
+ mode: z.enum(['create-only', 'update', 'recreate']).default('create-only'),
365
+ version: z.string().optional(),
366
+ force: z.boolean().default(false),
367
+ cleanup: z.boolean().default(false)
368
+ })
369
+
370
+ /**
371
+ * Función helper para validar un schema completo
372
+ */
373
+ export function validateDatabaseSchema(schema: unknown): DatabaseSchema {
374
+ try {
375
+ return DatabaseSchemaValidator.parse(schema)
376
+ } catch (error) {
377
+ if (error instanceof z.ZodError) {
378
+ const errorMessages = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join('\n')
379
+
380
+ throw new Error(`Schema validation failed:\n${errorMessages}`)
381
+ }
382
+ throw error
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Función helper para validar opciones de carga
388
+ */
389
+ export function validateLoadSchemaOptions(options: unknown): LoadSchemaOptions {
390
+ return LoadSchemaOptionsValidator.parse(options || {})
391
+ }
392
+
393
+ /**
394
+ * Función helper para obtener validador específico de configuración por tipo de campo
395
+ */
396
+ export function getFieldConfigValidator(fieldType: string) {
397
+ return createFieldConfigValidator(fieldType)
398
+ }
399
+
400
+ /**
401
+ * Validador para nombres de campos y tablas seguros
402
+ */
403
+ export const SafeNameValidator = z
404
+ .string()
405
+ .min(1, 'El nombre no puede estar vacío')
406
+ .max(255, 'El nombre no puede exceder 255 caracteres')
407
+ .regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, 'El nombre debe empezar con letra y contener solo letras, números y guiones bajos')
408
+
409
+ /**
410
+ * Validar si un nombre es seguro para usar en Baserow
411
+ */
412
+ export function validateSafeName(name: string): boolean {
413
+ try {
414
+ SafeNameValidator.parse(name)
415
+ return true
416
+ } catch {
417
+ return false
418
+ }
419
+ }