const test = require('node:test'); const assert = require('node:assert/strict'); const Database = require('better-sqlite3'); const liveProjection = require('../server/services/liveProjectionService'); const { ensureColumns, LIVE_PROJECTION_COLUMNS, LIVE_PROJECTION_SCHEMA_SQL } = require('../server/db/liveProjectionSchema'); function createProjectionDb() { const db = new Database(':memory:'); db.exec(` CREATE TABLE categories ( id TEXT PRIMARY KEY, source_id INTEGER NOT NULL, category_id TEXT NOT NULL, type TEXT NOT NULL, name TEXT NOT NULL, parent_id TEXT, is_hidden INTEGER DEFAULT 0, data JSON ); CREATE TABLE playlist_items ( id TEXT PRIMARY KEY, source_id INTEGER NOT NULL, item_id TEXT NOT NULL, type TEXT NOT NULL, name TEXT NOT NULL, category_id TEXT, parent_id TEXT, stream_icon TEXT, stream_url TEXT, container_extension TEXT, rating REAL, year TEXT, added_at TEXT, is_hidden INTEGER DEFAULT 0, is_favorite INTEGER DEFAULT 0, data JSON ); CREATE TABLE favorites ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, source_id INTEGER NOT NULL, item_id TEXT NOT NULL, item_type TEXT NOT NULL ); `); ensureColumns(db, 'playlist_items', LIVE_PROJECTION_COLUMNS); db.exec(LIVE_PROJECTION_SCHEMA_SQL); return db; } function seedProjectedChannel(db, index) { const logicalId = `logical:${index}`; db.prepare(` INSERT INTO logical_channels (id, fingerprint, display_name, preferred_variant_id, variant_count, created_at, updated_at) VALUES (?, ?, ?, ?, 1, 1, 1) `).run(logicalId, `channel ${index}`, `Channel ${index}`, `1:${index}`); db.prepare(` INSERT INTO playlist_items (id, source_id, item_id, type, name, category_id, stream_icon, stream_url, data, logical_channel_id, grouping_fingerprint, grouping_input_hash, quality_label, quality_rank, variant_rank, language_code, language_confidence, language_detector, language_input_hash) VALUES (?, 1, ?, 'live', ?, 'general', '', ?, '{}', ?, ?, ?, 'HD', 2, 0, 'en', 1, 'laya', ?) `).run( `1:${index}`, String(index), `Channel ${index}`, `https://streams.test/${index}.m3u8`, logicalId, `channel ${index}`, `group-hash-${index}`, `language-hash-${index}` ); } test('/api/live/channels projection response is bounded for an oversized catalog', () => { const db = createProjectionDb(); for (let index = 0; index < 1500; index++) seedProjectedChannel(db, index); try { const result = liveProjection.getChannelPage({ includeHidden: false, userId: 7 }, db, { iptvOrgCatalog: { findMatch: () => null }, epgMatching: { findBestMatch: () => null } }); assert.ok(result.channels.length <= 250, `unbounded live channel response returned ${result.channels.length} entries`); } finally { db.close(); } }); test('projected live list returns only a bounded variant preview', () => { const db = createProjectionDb(); const logicalId = 'logical:heavy'; db.prepare(` INSERT INTO logical_channels (id, fingerprint, display_name, preferred_variant_id, variant_count, created_at, updated_at) VALUES (?, 'heavy channel', 'Heavy Channel', '1:0', 2500, 1, 1) `).run(logicalId); const insert = db.prepare(` INSERT INTO playlist_items (id, source_id, item_id, type, name, category_id, stream_icon, stream_url, data, logical_channel_id, grouping_fingerprint, grouping_input_hash, quality_label, quality_rank, variant_rank, language_code, language_confidence, language_detector, language_input_hash) VALUES (?, 1, ?, 'live', ?, 'general', '', ?, '{}', ?, 'heavy channel', ?, 'HD', 2, ?, 'en', 1, 'laya', ?) `); const insertAll = db.transaction(() => { for (let index = 0; index < 2500; index++) { insert.run(`1:${index}`, String(index), `Heavy Channel variant ${index}`, `https://streams.test/${index}.m3u8`, logicalId, `group-${index}`, index, `language-${index}`); } }); insertAll(); try { const result = liveProjection.getChannelPage({ includeHidden: false, userId: 7 }, db); assert.equal(result.channels.length, 1); assert.equal(result.channels[0].variantCount, 2500); assert.ok(result.channels[0].variants.length <= 3); } finally { db.close(); } });