@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.
- package/CHANGELOG.md +435 -0
- package/README.md +847 -0
- package/dist/index.d.ts +8749 -0
- package/dist/index.js +11167 -0
- package/dist/index.js.map +1 -0
- package/package.json +91 -0
- package/src/BaserowClient.ts +501 -0
- package/src/ClientWithCreds.ts +545 -0
- package/src/ClientWithCredsWs.ts +852 -0
- package/src/ClientWithToken.ts +171 -0
- package/src/contexts/DatabaseClientContext.ts +114 -0
- package/src/contexts/DatabaseContext.ts +870 -0
- package/src/contexts/DatabaseTokenContext.ts +331 -0
- package/src/contexts/FieldContext.ts +399 -0
- package/src/contexts/RowContext.ts +99 -0
- package/src/contexts/TableClientContext.ts +291 -0
- package/src/contexts/TableContext.ts +1247 -0
- package/src/contexts/TableOnlyContext.ts +74 -0
- package/src/contexts/WorkspaceContext.ts +490 -0
- package/src/express/errors.ts +260 -0
- package/src/express/index.ts +69 -0
- package/src/express/middleware.ts +225 -0
- package/src/express/serializers.ts +314 -0
- package/src/index.ts +247 -0
- package/src/presets/performance.ts +262 -0
- package/src/services/AuthService.ts +472 -0
- package/src/services/DatabaseService.ts +246 -0
- package/src/services/DatabaseTokenService.ts +186 -0
- package/src/services/FieldService.ts +1543 -0
- package/src/services/RowService.ts +982 -0
- package/src/services/SchemaControlService.ts +420 -0
- package/src/services/TableService.ts +781 -0
- package/src/services/WorkspaceService.ts +113 -0
- package/src/services/core/BaseAuthClient.ts +111 -0
- package/src/services/core/BaseClient.ts +107 -0
- package/src/services/core/BaseService.ts +71 -0
- package/src/services/core/HttpService.ts +115 -0
- package/src/services/core/ValidationService.ts +149 -0
- package/src/types/auth.ts +177 -0
- package/src/types/core.ts +91 -0
- package/src/types/errors.ts +105 -0
- package/src/types/fields.ts +456 -0
- package/src/types/index.ts +222 -0
- package/src/types/requests.ts +333 -0
- package/src/types/responses.ts +50 -0
- package/src/types/schema.ts +446 -0
- package/src/types/tokens.ts +36 -0
- package/src/types.ts +11 -0
- package/src/utils/auth.ts +174 -0
- package/src/utils/axios.ts +647 -0
- package/src/utils/field-cache.ts +164 -0
- package/src/utils/httpFactory.ts +66 -0
- package/src/utils/jwt-decoder.ts +188 -0
- package/src/utils/jwtTokens.ts +50 -0
- package/src/utils/performance.ts +105 -0
- package/src/utils/prisma-mapper.ts +961 -0
- package/src/utils/validation.ts +463 -0
- 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
|
+
}
|