const test = require('node:test'); const assert = require('node:assert/strict'); const Database = require('better-sqlite3'); const liveProjection = require('../server/services/liveProjectionService'); const { LIVE_PROJECTION_SCHEMA_SQL } = require('../server/db/liveProjectionSchema'); function createDb() { const db = new Database(':memory:'); db.exec(` 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, logical_channel_id TEXT, grouping_fingerprint TEXT, grouping_input_hash TEXT, quality_label TEXT, quality_rank INTEGER, variant_rank INTEGER, language_code TEXT, language_confidence REAL, language_scores JSON, language_evidence JSON, language_detector TEXT, language_input_hash TEXT ); `); db.exec(LIVE_PROJECTION_SCHEMA_SQL); return db; } test('full refresh marks projection busy before awaiting source refresh work', () => { const db = createDb(); db.prepare(` INSERT INTO catalog_projection_state (projection, status, started_at, completed_at, input_hash, projected_count, phase, processed_count, total_count, laya_processed_count, laya_total_count, error) VALUES ('live', 'success', 100, 200, 'old-hash', 12, 'complete', 12, 12, 0, 0, NULL) `).run(); let liveRefreshStarted = false; liveProjection.fullRebuildOrchestrator(db, { syncService: { refreshEnabledLiveSources: () => { liveRefreshStarted = true; return new Promise(() => {}); }, refreshEnabledEpgSources: async () => {} }, sources: { getByType: async () => [] } }); const state = liveProjection.projectionState(db); assert.equal(liveRefreshStarted, true); assert.equal(state.status, 'building'); assert.equal(state.phase, 'refreshing_live_sources'); assert.equal(state.completed_at, null); });