diff --git a/bridge/src/index.ts b/bridge/src/index.ts index 3c4808d..9ea848a 100644 --- a/bridge/src/index.ts +++ b/bridge/src/index.ts @@ -18,6 +18,7 @@ import { type AuthVariables, authMiddleware } from './middleware/auth.js'; import { errorHandler } from './middleware/error-handler.js'; import { defaultRateLimitKey, rateLimit } from './middleware/rate-limit.js'; import { eventsRoutes } from './routes/events.js'; +import { adminRoutes } from './routes/admin.js'; import { tablesRoutes } from './routes/tables.js'; import { viewsRoutes } from './routes/views.js'; import { webhooksRoutes } from './routes/webhooks.js'; @@ -83,6 +84,8 @@ export async function buildApp(): Promise> { v1.route('/tables', tablesRoutes); // R3.1.a : routes views — liste vues par table + donnees paginées d'une vue. v1.route('/views', viewsRoutes); + // Phase B (acadenice) : CRUD tables/fields/views via Baserow user JWT. + v1.route('/admin', adminRoutes); app.route('/api/v1', v1); // R3.1.b : SSE realtime stream — monté sur /api/events hors /api/v1 pour diff --git a/bridge/src/lib/baserow-jwt-manager.ts b/bridge/src/lib/baserow-jwt-manager.ts index a6bb02e..26bfb2f 100644 --- a/bridge/src/lib/baserow-jwt-manager.ts +++ b/bridge/src/lib/baserow-jwt-manager.ts @@ -173,7 +173,7 @@ export class BaserowJwtManagerImpl implements BaserowJwtManager { private async doLogin(): Promise { this.logger.debug({ email: this.email }, 'baserow jwt login'); - const url = `${this.baseUrl}/api/user/token-auth/`; + const url = `${this.baseUrl}/user/token-auth/`; const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -202,7 +202,7 @@ export class BaserowJwtManagerImpl implements BaserowJwtManager { private async doRefresh(currentToken: string): Promise { this.logger.debug('baserow jwt refresh'); - const url = `${this.baseUrl}/api/user/token-refresh/`; + const url = `${this.baseUrl}/user/token-refresh/`; const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/bridge/src/lib/container.ts b/bridge/src/lib/container.ts index 5cfa073..3c9c6e5 100644 --- a/bridge/src/lib/container.ts +++ b/bridge/src/lib/container.ts @@ -9,6 +9,7 @@ */ import type { Logger } from 'pino'; +import { BaserowAdminClient } from '../adapters/baserow-admin-client.js'; import { BaserowClient } from '../adapters/baserow-client.js'; import { RedisCache } from '../adapters/redis-cache.js'; import type { ApiTokenRecord } from '../middleware/auth.js'; @@ -47,6 +48,9 @@ export interface Container { logger: Logger; /** Gestionnaire JWT user Baserow pour endpoints metadata. Toujours present. */ baserowJwt: BaserowJwtManager; + /** Client admin Baserow (CRUD tables/fields/views). Lève + * BASEROW_USER_AUTH_NOT_CONFIGURED si appelé sans creds user. */ + baserowAdmin: BaserowAdminClient; } let _container: Container | null = null; @@ -146,6 +150,12 @@ export async function initContainer(opts: InitOptions): Promise { ); } + const baserowAdmin = new BaserowAdminClient({ + baseUrl: config.baserowApiUrl, + jwtManager: baserowJwt, + logger: rootLogger, + }); + const container: Container = { config, baserow, @@ -157,6 +167,7 @@ export async function initContainer(opts: InitOptions): Promise { groupsScopesMap, logger: rootLogger, baserowJwt, + baserowAdmin, }; setContainer(container); return container; diff --git a/bridge/src/lib/errors.ts b/bridge/src/lib/errors.ts index 0e3d9ea..a7ec684 100644 --- a/bridge/src/lib/errors.ts +++ b/bridge/src/lib/errors.ts @@ -14,6 +14,7 @@ export type ErrorCode = | 'CONFLICT' | 'RATE_LIMITED' | 'BASEROW_UNAVAILABLE' + | 'BASEROW_USER_AUTH_NOT_CONFIGURED' | 'DOCMOST_UNAVAILABLE' | 'INTERNAL'; @@ -57,6 +58,12 @@ export const errors = { rateLimited: (retryAfter: number) => new BridgeError('RATE_LIMITED', 429, 'Too many requests', { retry_after: retryAfter }), baserowDown: () => new BridgeError('BASEROW_UNAVAILABLE', 502, 'Baserow API unreachable'), + baserowUserAuthNotConfigured: () => + new BridgeError( + 'BASEROW_USER_AUTH_NOT_CONFIGURED', + 503, + 'Baserow user JWT not configured (BASEROW_USER_EMAIL/PASSWORD missing)', + ), docmostDown: () => new BridgeError('DOCMOST_UNAVAILABLE', 502, 'Docmost API unreachable'), internal: (message: string) => new BridgeError('INTERNAL', 500, message), };