@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,331 @@
1
+ import {
2
+ Logger,
3
+ DatabaseToken,
4
+ CreateDatabaseTokenRequest,
5
+ UpdateDatabaseTokenRequest,
6
+ DatabaseTokenPermissions,
7
+ LIBRARY_TOKEN_PREFIX
8
+ } from '../types'
9
+ import { DatabaseTokenService } from '../services/DatabaseTokenService'
10
+ import { WorkspaceService } from '../services/WorkspaceService'
11
+
12
+ /**
13
+ * Context para operaciones de database tokens en un workspace específico
14
+ *
15
+ * Proporciona una API completa para gestionar database tokens que permiten
16
+ * acceso limitado a databases y tablas específicas. Los tokens pueden
17
+ * configurarse con diferentes niveles de permisos y scope.
18
+ *
19
+ * **Características principales:**
20
+ * - Gestión completa de database tokens (CRUD)
21
+ * - Control granular de permisos (create, read, update, delete)
22
+ * - Sistema de prefijos para tokens de librería ('br-lib:')
23
+ * - Métodos de conveniencia para casos comunes
24
+ * - Limpieza automática de tokens de test
25
+ * - Resolución automática de workspace por nombre o ID
26
+ * - Validación de existencia y búsqueda por nombre o valor
27
+ *
28
+ * **Nomenclatura de Tokens:**
29
+ * - `create()`: Control total del nombre (para uso directo del usuario)
30
+ * - `createLibraryToken()`: Agrega prefijo 'br-lib:' automáticamente
31
+ * - `createFullAccess()/createReadOnly()`: Métodos de conveniencia con prefijo 'br-lib:'
32
+ *
33
+ * **Tipos de Permisos:**
34
+ * - **create**: Permite crear nuevas filas
35
+ * - **read**: Permite leer datos existentes
36
+ * - **update**: Permite modificar filas existentes
37
+ * - **delete**: Permite eliminar filas
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * // Métodos de conveniencia
42
+ * const fullToken = await workspace.databaseToken.createFullAccess('api-client')
43
+ * const readToken = await workspace.databaseToken.createReadOnly('dashboard')
44
+ *
45
+ * // Control granular de permisos
46
+ * const customToken = await workspace.databaseToken.create('custom', {
47
+ * create: true,
48
+ * read: true,
49
+ * update: false,
50
+ * delete: false
51
+ * })
52
+ *
53
+ * // Gestión de tokens
54
+ * const tokens = await workspace.databaseToken.list()
55
+ * const token = await workspace.databaseToken.findByName('br-lib:api-client')
56
+ * await workspace.databaseToken.update(token.id, { name: 'nuevo-nombre' })
57
+ *
58
+ * // Limpieza de tokens de test
59
+ * const cleanup = await workspace.databaseToken.cleanupLibraryTokens()
60
+ * console.log(`Eliminados: ${cleanup.deleted}, Errores: ${cleanup.errors}`)
61
+ * ```
62
+ *
63
+ * @since 1.0.0
64
+ */
65
+ export class DatabaseTokenContext {
66
+ private workspaceIdentifier: string | number
67
+ private resolvedWorkspaceId?: number
68
+ private logger?: Logger
69
+
70
+ /**
71
+ * Crea un nuevo context de database tokens
72
+ *
73
+ * @param workspaceService - Servicio para operaciones de workspace
74
+ * @param workspaceIdentifier - Nombre o ID del workspace donde gestionar tokens
75
+ * @param databaseTokenService - Servicio para operaciones de database tokens
76
+ * @param logger - Logger opcional para debug y trazabilidad
77
+ *
78
+ * @since 1.0.0
79
+ */
80
+ constructor(
81
+ private workspaceService: WorkspaceService,
82
+ workspaceIdentifier: string | number,
83
+ private databaseTokenService: DatabaseTokenService,
84
+ logger?: Logger
85
+ ) {
86
+ this.workspaceIdentifier = workspaceIdentifier
87
+ this.logger = logger
88
+ }
89
+
90
+ /**
91
+ * Listar todos los database tokens del workspace
92
+ * @returns Promise<DatabaseToken[]> Lista de todos los database tokens
93
+ * @throws {BaserowError} Si el workspace no existe o hay error de red
94
+ */
95
+ async list(): Promise<DatabaseToken[]> {
96
+ const workspaceId = await this.resolveWorkspaceId()
97
+ return await this.databaseTokenService.list(workspaceId)
98
+ }
99
+
100
+ /**
101
+ * Obtener database token por ID
102
+ * @param tokenId - ID numérico del database token
103
+ * @returns Promise<DatabaseToken> Database token encontrado
104
+ * @throws {BaserowNotFoundError} Si el token no existe
105
+ * @throws {BaserowError} Si hay error de red o validación
106
+ */
107
+ async get(tokenId: number): Promise<DatabaseToken> {
108
+ return await this.databaseTokenService.get(tokenId)
109
+ }
110
+
111
+ /**
112
+ * Obtener database token por su valor (key)
113
+ * Busca en la lista de tokens del workspace
114
+ * @param tokenValue - Valor string del token (ej: "abc123def456...")
115
+ * @returns Promise<DatabaseToken> Database token encontrado
116
+ * @throws {Error} Si el token no se encuentra en el workspace
117
+ * @throws {BaserowError} Si hay error de red
118
+ */
119
+ async getToken(tokenValue: string): Promise<DatabaseToken> {
120
+ const workspaceId = await this.resolveWorkspaceId()
121
+ const tokens = await this.databaseTokenService.list(workspaceId)
122
+ const found = tokens.find(token => token.token === tokenValue)
123
+
124
+ if (!found) {
125
+ throw new Error(`Database token with value ${tokenValue.substring(0, 8)}... not found in workspace`)
126
+ }
127
+
128
+ return found
129
+ }
130
+
131
+ /**
132
+ * Crear nuevo database token con control total del nombre
133
+ * Para tokens de librería, usar createLibraryToken() o métodos de conveniencia
134
+ * @param name - Nombre del token (sin modificar)
135
+ * @param permissions - Permisos del token (create, read, update, delete)
136
+ * @returns Promise<DatabaseToken> Database token creado
137
+ * @throws {BaserowValidationError} Si el nombre o permisos son inválidos
138
+ * @throws {BaserowError} Si hay error de red
139
+ */
140
+ async create(name: string, permissions: DatabaseTokenPermissions): Promise<DatabaseToken> {
141
+ const workspaceId = await this.resolveWorkspaceId()
142
+ const request: CreateDatabaseTokenRequest = {
143
+ name,
144
+ permissions
145
+ }
146
+ return await this.databaseTokenService.createToken(workspaceId, request)
147
+ }
148
+
149
+ /**
150
+ * Crear database token con prefijo de librería para identificación
151
+ * Equivalente a create() pero agrega automáticamente el prefijo 'br-lib:'
152
+ * @param name - Nombre base del token (se le agregará 'br-lib:' automáticamente)
153
+ * @param permissions - Permisos del token (create, read, update, delete)
154
+ * @returns Promise<DatabaseToken> Database token creado con prefijo 'br-lib:'
155
+ * @throws {BaserowValidationError} Si el nombre o permisos son inválidos
156
+ * @throws {BaserowError} Si hay error de red
157
+ */
158
+ async createLibraryToken(name: string, permissions: DatabaseTokenPermissions): Promise<DatabaseToken> {
159
+ const prefixedName = `${LIBRARY_TOKEN_PREFIX}${name}`
160
+ return await this.create(prefixedName, permissions)
161
+ }
162
+
163
+ /**
164
+ * Crear database token con permisos completos (CRUD)
165
+ * Automáticamente agrega prefijo 'br-lib:' para identificación de librería
166
+ * Equivalente a: createLibraryToken(name, {create: true, read: true, update: true, delete: true})
167
+ * @param name - Nombre base del token (se le agregará 'br-lib:' automáticamente)
168
+ * @returns Promise<DatabaseToken> Database token con permisos completos y prefijo 'br-lib:'
169
+ * @throws {BaserowValidationError} Si el nombre es inválido
170
+ * @throws {BaserowError} Si hay error de red
171
+ */
172
+ async createFullAccess(name: string): Promise<DatabaseToken> {
173
+ const prefixedName = `${LIBRARY_TOKEN_PREFIX}${name}`
174
+ return await this.create(prefixedName, {
175
+ create: true,
176
+ read: true,
177
+ update: true,
178
+ delete: true
179
+ })
180
+ }
181
+
182
+ /**
183
+ * Crear database token de solo lectura
184
+ * Automáticamente agrega prefijo 'br-lib:' para identificación de librería
185
+ * Equivalente a: createLibraryToken(name, {create: false, read: true, update: false, delete: false})
186
+ * @param name - Nombre base del token (se le agregará 'br-lib:' automáticamente)
187
+ * @returns Promise<DatabaseToken> Database token de solo lectura con prefijo 'br-lib:'
188
+ * @throws {BaserowValidationError} Si el nombre es inválido
189
+ * @throws {BaserowError} Si hay error de red
190
+ */
191
+ async createReadOnly(name: string): Promise<DatabaseToken> {
192
+ const prefixedName = `${LIBRARY_TOKEN_PREFIX}${name}`
193
+ return await this.create(prefixedName, {
194
+ create: false,
195
+ read: true,
196
+ update: false,
197
+ delete: false
198
+ })
199
+ }
200
+
201
+ /**
202
+ * Actualizar database token
203
+ * @param tokenId - ID numérico del database token
204
+ * @param data - Datos a actualizar (nombre y/o permisos)
205
+ * @returns Promise<DatabaseToken> Database token actualizado
206
+ * @throws {BaserowNotFoundError} Si el token no existe
207
+ * @throws {BaserowValidationError} Si los datos son inválidos
208
+ * @throws {BaserowError} Si hay error de red
209
+ */
210
+ async update(tokenId: number, data: UpdateDatabaseTokenRequest): Promise<DatabaseToken> {
211
+ return await this.databaseTokenService.updateToken(tokenId, data)
212
+ }
213
+
214
+ /**
215
+ * Eliminar database token
216
+ * @param tokenId - ID numérico del database token a eliminar
217
+ * @returns Promise<void>
218
+ * @throws {BaserowNotFoundError} Si el token no existe
219
+ * @throws {BaserowError} Si hay error de red
220
+ */
221
+ async delete(tokenId: number): Promise<void> {
222
+ return await this.databaseTokenService.delete(tokenId)
223
+ }
224
+
225
+ /**
226
+ * Verificar si un database token existe
227
+ * @param tokenId - ID numérico del database token
228
+ * @returns Promise<boolean> true si existe, false si no existe
229
+ * @throws {BaserowError} Si hay error de red
230
+ */
231
+ async exists(tokenId: number): Promise<boolean> {
232
+ return await this.databaseTokenService.exists(tokenId)
233
+ }
234
+
235
+ /**
236
+ * Buscar database token por nombre
237
+ * @param name - Nombre exacto del database token a buscar
238
+ * @returns Promise<DatabaseToken | null> Token encontrado o null si no existe
239
+ * @throws {BaserowError} Si hay error de red
240
+ */
241
+ async findByName(name: string): Promise<DatabaseToken | null> {
242
+ const workspaceId = await this.resolveWorkspaceId()
243
+ return await this.databaseTokenService.findByName(workspaceId, name)
244
+ }
245
+
246
+ /**
247
+ * Listar solo tokens creados por la librería (con prefijo br-lib:)
248
+ * @returns Promise<DatabaseToken[]> Lista de tokens que empiezan con 'br-lib:'
249
+ * @throws {BaserowError} Si hay error de red
250
+ */
251
+ async listLibraryTokens(): Promise<DatabaseToken[]> {
252
+ const allTokens = await this.list()
253
+ return allTokens.filter(token => token.name.startsWith(LIBRARY_TOKEN_PREFIX))
254
+ }
255
+
256
+ /**
257
+ * Verificar si un token fue creado por la librería
258
+ * @param token - Database token a verificar
259
+ * @returns boolean true si el token tiene prefijo 'br-lib:', false si no
260
+ */
261
+ isLibraryToken(token: DatabaseToken): boolean {
262
+ return token.name.startsWith(LIBRARY_TOKEN_PREFIX)
263
+ }
264
+
265
+ /**
266
+ * Limpiar todos los tokens creados por la librería en el workspace
267
+ * Elimina solo tokens que empiecen con 'br-lib:'
268
+ * @returns Promise<{deleted: number, errors: number}> Resumen de tokens eliminados y errores
269
+ * @throws {BaserowError} Si hay error crítico de red
270
+ */
271
+ async cleanupLibraryTokens(): Promise<{ deleted: number; errors: number }> {
272
+ const libraryTokens = await this.listLibraryTokens()
273
+ let deleted = 0
274
+ let errors = 0
275
+
276
+ for (const token of libraryTokens) {
277
+ try {
278
+ await this.delete(token.id)
279
+ deleted++
280
+ if (this.logger) {
281
+ this.logger.info(`Deleted library token: "${token.name}" (ID: ${token.id})`)
282
+ }
283
+ } catch (error) {
284
+ errors++
285
+ if (this.logger) {
286
+ this.logger.error(`Error deleting library token "${token.name}":`, error)
287
+ }
288
+ }
289
+ }
290
+
291
+ return { deleted, errors }
292
+ }
293
+
294
+ /**
295
+ * Resolver workspace ID (lazy loading)
296
+ * Convierte nombre de workspace a ID numérico si es necesario
297
+ * @returns Promise<number> ID numérico del workspace
298
+ * @throws {BaserowNotFoundError} Si el workspace no existe
299
+ * @throws {BaserowError} Si hay error de red
300
+ * @private
301
+ */
302
+ private async resolveWorkspaceId(): Promise<number> {
303
+ // Si ya tenemos un ID resuelto Y es un nombre string, podemos usar el cache
304
+ if (this.resolvedWorkspaceId && typeof this.workspaceIdentifier === 'string') {
305
+ return this.resolvedWorkspaceId
306
+ }
307
+
308
+ let workspace
309
+ if (typeof this.workspaceIdentifier === 'number') {
310
+ // Es un ID numérico - retornar directamente sin verificación adicional
311
+ // La verificación se asume hecha por el caller (BaserowAdminWorkspace)
312
+ if (this.logger?.debug) {
313
+ this.logger.debug(`Using workspace ID for database tokens: ${this.workspaceIdentifier}`)
314
+ }
315
+ return this.workspaceIdentifier
316
+ } else {
317
+ // Es un nombre string - se puede cachear
318
+ workspace = await this.workspaceService.findUnique(this.workspaceIdentifier)
319
+ if (!workspace) {
320
+ throw new Error(`Workspace "${this.workspaceIdentifier}" not found`)
321
+ }
322
+ this.resolvedWorkspaceId = workspace.id
323
+
324
+ if (this.logger) {
325
+ this.logger.info(`Resolved workspace for database tokens: "${workspace.name}" (ID: ${workspace.id})`)
326
+ }
327
+
328
+ return this.resolvedWorkspaceId!
329
+ }
330
+ }
331
+ }