Files
iptvnator/apps/electron-backend-e2e/src/performance/xtream-phase-semantic-source.ts
T
4gray a2fafcfc08 test(performance): add end-to-end Xtream benchmark harness (#1300)
* docs(performance): plan Xtream benchmark

* feat(xtream-mock-server): add deterministic 100k fixture

* style(xtream-mock-server): apply repository formatting

* fix(xtream-mock-server): harden performance fixture data

* feat(xtream-mock-server): add performance control plane

* docs(performance): correct Xtream capture plan

* fix(xtream-mock-server): harden performance controls

* fix(xtream-mock-server): harden control lifecycle

* feat(performance): add Xtream preload markers

* feat(performance): trace Xtream main phases

* feat(performance): mark Xtream store publications

* feat(performance): trace Xtream database phases

* feat(performance): trace Xtream delete cancellation

* feat(performance): capture Xtream phase attribution

* feat(performance): mark Sources Xtream refresh

* test(performance): define Xtream benchmark evidence contracts

* test(performance): add Xtream benchmark runner

* test(performance): surface failure evidence writes

* test(performance): align database read clock

* test(performance): preserve capture failure contracts
2026-07-28 08:08:07 +02:00

110 lines
4.1 KiB
TypeScript

import { XtreamCodeActions } from '@iptvnator/shared/interfaces';
import {
XTREAM_PHASE_SEMANTIC_TYPE as SEMANTIC,
type XtreamPhaseSemanticType,
} from './xtream-phase-inventory';
export type XtreamPhaseCategoryType = 'live' | 'movies' | 'series';
export type XtreamPhaseContentType = 'live' | 'movie' | 'series';
export type XtreamPhaseProviderAction =
| XtreamCodeActions.GetAccountInfo
| XtreamCodeActions.GetLiveCategories
| XtreamCodeActions.GetLiveStreams
| XtreamCodeActions.GetSeries
| XtreamCodeActions.GetSeriesCategories
| XtreamCodeActions.GetVodCategories
| XtreamCodeActions.GetVodStreams;
export interface XtreamPhaseSemanticSource {
readonly categoryType: XtreamPhaseCategoryType | null;
readonly contentType: XtreamPhaseContentType | null;
readonly providerAction: XtreamPhaseProviderAction | null;
}
const ACTION_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
[XtreamCodeActions.GetAccountInfo, SEMANTIC.ACCOUNT],
[XtreamCodeActions.GetLiveCategories, SEMANTIC.LIVE_CATEGORIES],
[XtreamCodeActions.GetVodCategories, SEMANTIC.VOD_CATEGORIES],
[XtreamCodeActions.GetSeriesCategories, SEMANTIC.SERIES_CATEGORIES],
[XtreamCodeActions.GetLiveStreams, SEMANTIC.LIVE_CONTENT],
[XtreamCodeActions.GetVodStreams, SEMANTIC.VOD_CONTENT],
[XtreamCodeActions.GetSeries, SEMANTIC.SERIES_CONTENT],
]);
const CATEGORY_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
['live', SEMANTIC.LIVE_CATEGORIES],
['movies', SEMANTIC.VOD_CATEGORIES],
['series', SEMANTIC.SERIES_CATEGORIES],
]);
const CONTENT_SEMANTICS = new Map<string, XtreamPhaseSemanticType>([
['live', SEMANTIC.LIVE_CONTENT],
['movie', SEMANTIC.VOD_CONTENT],
['series', SEMANTIC.SERIES_CONTENT],
]);
export function semanticTypeFromXtreamPhaseSource(
source: Readonly<Record<keyof XtreamPhaseSemanticSource, unknown>>
): XtreamPhaseSemanticType | null | undefined {
const populated = [
source.providerAction,
source.categoryType,
source.contentType,
].filter((value) => value !== null);
if (populated.length === 0) return null;
if (populated.length !== 1) return undefined;
if (source.providerAction !== null) {
return typeof source.providerAction === 'string'
? ACTION_SEMANTICS.get(source.providerAction)
: undefined;
}
if (source.categoryType !== null) {
return typeof source.categoryType === 'string'
? CATEGORY_SEMANTICS.get(source.categoryType)
: undefined;
}
return typeof source.contentType === 'string'
? CONTENT_SEMANTICS.get(source.contentType)
: undefined;
}
export function xtreamDataSemanticSource(
semanticType: XtreamPhaseSemanticType | null
): XtreamPhaseSemanticSource {
switch (semanticType) {
case SEMANTIC.LIVE_CATEGORIES:
return source(null, 'live', null);
case SEMANTIC.VOD_CATEGORIES:
return source(null, 'movies', null);
case SEMANTIC.SERIES_CATEGORIES:
return source(null, 'series', null);
case SEMANTIC.LIVE_CONTENT:
return source(null, null, 'live');
case SEMANTIC.VOD_CONTENT:
return source(null, null, 'movie');
case SEMANTIC.SERIES_CONTENT:
return source(null, null, 'series');
case SEMANTIC.ACCOUNT:
throw new Error('account has no database semantic source');
case null:
return source(null, null, null);
}
}
export function xtreamProviderSemanticSource(
semanticType: XtreamPhaseSemanticType
): XtreamPhaseSemanticSource {
const action = [...ACTION_SEMANTICS].find(
([, mapped]) => mapped === semanticType
)?.[0];
if (!action) throw new Error('invalid provider semantic type');
return source(action as XtreamPhaseProviderAction, null, null);
}
function source(
providerAction: XtreamPhaseProviderAction | null,
categoryType: XtreamPhaseCategoryType | null,
contentType: XtreamPhaseContentType | null
): XtreamPhaseSemanticSource {
return Object.freeze({ categoryType, contentType, providerAction });
}