From 7a3fbe455d61d395dfbb604838a3d0eb513dc44e Mon Sep 17 00:00:00 2001 From: Corentin JOGUET Date: Thu, 7 May 2026 20:09:27 +0200 Subject: [PATCH] =?UTF-8?q?fix(bridge):=20smoke=20test=20fixes=20=E2=80=94?= =?UTF-8?q?=20skip=20rows=20malformees=20+=20BASEROW=5FTABLE=5FIDS=20overr?= =?UTF-8?q?ide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Decouverts via smoke test local contre Baserow + Docmost reels. 1. **BaseRepo.list robuste** : try/catch toDomain par row, skip + log warn si throw (ex Personne avec splits null != 100). Avant : 500 sur la liste entiere. Apres : 200 avec items valides + meta.skipped count pour visibilite. `get()` continue de propager (un get sur row corrompue = legitimement 500 pour investigation manuelle). 2. **BASEROW_TABLE_IDS env override** : BaserowClient.resolveTableIds appelle /api/database/tables/database/:id/ qui requiert un JWT user (Baserow API distingue DB tokens reservees aux endpoints rows, et JWT pour les endpoints admin). En dev/prod simple on passe le mapping directement par env var : BASEROW_TABLE_IDS={"personne":609,"formation":610,...}. Le code resolveTableIds reste en place pour Phase 3+ (bridge avec JWT user). Smoke test post-fix : - GET /api/health, /api/ready : 200 - Auth : 401 absent / 401 invalide / 200 valide - GET /personnes (rows test invalides) : 200 data:[] meta.skipped:2 - GET /formations, /projets : 200 avec rows - GET /personnes/9999 : 404 Tests Vitest : 163/163 verts. tsc + biome ci verts. Co-Authored-By: Claude Opus 4.7 (1M context) --- bridge/src/index.ts | 19 ++++++++++++++----- bridge/src/repos/baserow-repo.ts | 26 ++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/bridge/src/index.ts b/bridge/src/index.ts index 9f10f37..f2c8eb4 100644 --- a/bridge/src/index.ts +++ b/bridge/src/index.ts @@ -57,13 +57,22 @@ export async function buildApp(): Promise> { async function main() { const config = loadConfig(); - // BASEROW_DATABASE_ID requis pour resolveTableIds. Cf .env + // Soit BASEROW_TABLE_IDS={"personne":609,...} (preferred — DB tokens n'ont pas + // acces a /api/database/tables/database/:id/), soit BASEROW_DATABASE_ID + un JWT + // user (Phase 3+). Cf doc 19 §5. + const tableIdsRaw = process.env.BASEROW_TABLE_IDS; const databaseIdRaw = process.env.BASEROW_DATABASE_ID; - const databaseId = databaseIdRaw ? Number.parseInt(databaseIdRaw, 10) : undefined; - if (!databaseId || Number.isNaN(databaseId)) { - throw new Error('BASEROW_DATABASE_ID env var requis pour resolve table ids'); + let initOpts: Parameters[0]; + if (tableIdsRaw) { + initOpts = { config, tableIds: JSON.parse(tableIdsRaw) }; + } else { + const databaseId = databaseIdRaw ? Number.parseInt(databaseIdRaw, 10) : undefined; + if (!databaseId || Number.isNaN(databaseId)) { + throw new Error('BASEROW_TABLE_IDS ou BASEROW_DATABASE_ID requis'); + } + initOpts = { config, databaseId }; } - await initContainer({ config, databaseId }); + await initContainer(initOpts); const app = await buildApp(); serve({ fetch: app.fetch, port: config.port }, (info) => { diff --git a/bridge/src/repos/baserow-repo.ts b/bridge/src/repos/baserow-repo.ts index cf42b6a..27c4d91 100644 --- a/bridge/src/repos/baserow-repo.ts +++ b/bridge/src/repos/baserow-repo.ts @@ -131,7 +131,13 @@ abstract class BaseRepo { async list(opts: BaserowListOptions = {}): Promise<{ items: TDomain[]; - meta: { page: number; per_page: number; total: number; total_pages: number }; + meta: { + page: number; + per_page: number; + total: number; + total_pages: number; + skipped?: number; + }; }> { const page = opts.page ?? 1; const size = Math.min(opts.size ?? 50, 200); @@ -140,7 +146,22 @@ abstract class BaseRepo { page, size, }); - const items = res.results.map((row) => this.toDomain(row)); + // Skip rows that fail domain validation (split != 100, etc.) plutot que + // de casser la liste entiere. La row corrompue est loguee pour investigation + // manuelle. cf doc 19 §10 : robustness vs visibility. + const items: TDomain[] = []; + let skipped = 0; + for (const row of res.results) { + try { + items.push(this.toDomain(row)); + } catch (err) { + skipped++; + this.logger.warn( + { rowId: row.id, err: err instanceof Error ? err.message : String(err) }, + 'row skipped — invalid domain mapping', + ); + } + } return { items, meta: { @@ -148,6 +169,7 @@ abstract class BaseRepo { per_page: size, total: res.count, total_pages: Math.max(1, Math.ceil(res.count / size)), + ...(skipped > 0 ? { skipped } : {}), }, }; }