1import { describe, expect, it } from 'vitest';2import { flattenCatalog } from '../src/models-sync';34const FIXTURE = {5 'some-host': {6 name: 'Some Host',7 models: {8 'deepseek/deepseek-v4': {9 id: 'deepseek/deepseek-v4',10 name: 'DeepSeek V4',11 open_weights: true,12 release_date: '2026-04-24',13 reasoning: true,14 last_updated: '2026-05-01',15 },16 'mystery-model': { name: 'Mystery' }, // no id field -> key is the id17 },18 },19 'another-host': {20 models: {21 // same model, poorer metadata: must not clobber the richer entry22 'deepseek/deepseek-v4': { id: 'deepseek/deepseek-v4', name: 'DeepSeek V4' },23 'gpt-9': { id: 'gpt-9', name: 'GPT-9', open_weights: false, release_date: '2027-01-15' },24 },25 },26 junk: 'not an object',27};2829describe('flattenCatalog', () => {30 it('flattens providers and dedupes by model id, preferring richer entries', () => {31 const flat = flattenCatalog(FIXTURE);32 const ids = flat.map((m) => m.id).sort();33 expect(ids).toEqual(['deepseek/deepseek-v4', 'gpt-9', 'mystery-model']);34 const ds = flat.find((m) => m.id === 'deepseek/deepseek-v4')!;35 expect(ds.releaseDate).toBe('2026-04-24'); // richer entry won36 expect(ds.openWeights).toBe(true);37 expect(ds.reasoning).toBe(true);38 });3940 it('derives lab from the id prefix, falling back to the provider', () => {41 const flat = flattenCatalog(FIXTURE);42 expect(flat.find((m) => m.id === 'deepseek/deepseek-v4')!.lab).toBe('deepseek');43 expect(flat.find((m) => m.id === 'gpt-9')!.lab).toBe('another-host');44 });4546 it('rejects malformed payloads without throwing', () => {47 expect(flattenCatalog(null)).toEqual([]);48 expect(flattenCatalog('nope')).toEqual([]);49 expect(flattenCatalog({ p: { models: null } })).toEqual([]);50 });5152 it('drops invalid release dates instead of storing garbage', () => {53 const flat = flattenCatalog({54 h: { models: { m1: { id: 'm1', name: 'M1', release_date: 'soon(tm)' } } },55 });56 expect(flat[0]!.releaseDate).toBeNull();57 });58});