CI / build-and-test (push) Successful in 14m43s
7.3: capturedAt/source au registre + 6 adaptateurs + module provenance.ts + ?debug=1 (search-transport.mjs). 7.4: ProviderHealthService + badge source degradee. 7.6: squelettes par provider + snapshots progressifs + transport NDJSON /api/search. 8.1: ProviderAdapter unifie (search enveloppe + channelContent/channelMeta/capabilities) via getProviderAdapter + test de contrat offline.
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import type { ProviderId } from '../shared/providers/provider-ids';
|
|
import type { ChannelRef } from '../shared/providers/channel-ref';
|
|
|
|
export type { ProviderId, ChannelRef };
|
|
|
|
/**
|
|
* Contrat `Suggestion` v2 — doit rester aligné avec le JSDoc de
|
|
* `server/providers/registry.mjs` (vérifié par `npm run test:contract`).
|
|
*
|
|
* v1 (inchangé, rétrocompatible) : title, id, duration, isShort, thumbnail,
|
|
* uploaderName, url, type.
|
|
* v2 (additif) : compteurs, dates ISO, identité de chaîne, avatars, et flags.
|
|
*
|
|
* Règle : un champ absent est `undefined`, jamais `0` ni `''`. Une durée nulle
|
|
* n'existe pas — elle casse les règles de classification (voir §2.2 du plan).
|
|
*/
|
|
export interface SuggestionItemV1 {
|
|
title: string;
|
|
id: string;
|
|
/** Secondes, strictement > 0. `undefined` = durée inconnue. */
|
|
duration?: number;
|
|
isShort?: boolean;
|
|
thumbnail?: string;
|
|
uploaderName?: string;
|
|
url?: string;
|
|
type?: string;
|
|
|
|
// --- v2 ---
|
|
/** Vues (> 0). */
|
|
views?: number;
|
|
/**
|
|
* Phase 3.8 / 7.3 — spectateurs EN DIRECT (Twitch `viewer_count`).
|
|
* Distinct de `views` : ne jamais afficher comme un compteur de vues.
|
|
*/
|
|
viewers?: number;
|
|
likes?: number;
|
|
dislikes?: number;
|
|
/** ISO 8601. Jamais « il y a 2 mois ». */
|
|
publishedAt?: string;
|
|
channelId?: string;
|
|
channelExternalId?: string;
|
|
channelHandle?: string;
|
|
channelUrl?: string;
|
|
uploaderAvatar?: string;
|
|
channelAvatarUrl?: string;
|
|
slug?: string;
|
|
channel?: string;
|
|
/** 'vod' | 'live' | 'clip' (Twitch). */
|
|
kind?: string;
|
|
game?: string;
|
|
/** BCP-47. */
|
|
language?: string;
|
|
hasSubtitles?: boolean;
|
|
isLive?: boolean;
|
|
embeddable?: boolean;
|
|
description?: string;
|
|
tags?: string[];
|
|
/** Libellés bruts, pour afficher « valeur approchée » plutôt que « — ». */
|
|
durationRaw?: string;
|
|
viewCountRaw?: string;
|
|
/**
|
|
* Phase 6 — identité de chaîne normalisée. `channelExternalId` reste lu en
|
|
* repli (transition non cassante) mais `channelRef` est la forme canonique :
|
|
* `scheme` dit comment lire `value`.
|
|
*/
|
|
channelRef?: ChannelRef;
|
|
}
|
|
|
|
export interface SearchResponseV1 {
|
|
/** Version du contrat `Suggestion` (2 depuis la phase 0). */
|
|
v?: number;
|
|
q: string;
|
|
providers: ProviderId[];
|
|
groups: Record<ProviderId, SuggestionItemV1[]>;
|
|
page?: number;
|
|
pageSize?: number;
|
|
sort?: 'relevance' | 'date' | 'views';
|
|
/** Filtres appliqués côté serveur (les valeurs par défaut sont omises). */
|
|
filters?: Record<string, string>;
|
|
/** Per-provider backend failures, keyed by provider id. */
|
|
errors?: Partial<Record<ProviderId, string>>;
|
|
}
|