diff --git a/.vscode/settings.json b/.vscode/settings.json index d5aad171..c2bfbbdd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ "cSpell.words": [ "Retryable", "typecheck" - ] + ], + "typescript.tsdk": "./node_modules/typescript/lib" } diff --git a/packages/auth/vite-legacy.config.ts b/packages/auth/vite-legacy.config.ts index 257b31d2..35c2d9e0 100644 --- a/packages/auth/vite-legacy.config.ts +++ b/packages/auth/vite-legacy.config.ts @@ -1,9 +1,13 @@ import topLevelAwait from 'vite-plugin-top-level-await'; -import { defineConfig, mergeConfig } from 'vitest/config'; +import { + type UserConfigFnObject, + defineConfig, + mergeConfig, +} from 'vitest/config'; import defaultViteConfig from './vite.config'; -export default defineConfig(configEnv => +const config: UserConfigFnObject = defineConfig(configEnv => mergeConfig( defaultViteConfig(configEnv), defineConfig({ @@ -20,3 +24,5 @@ export default defineConfig(configEnv => }), ), ); + +export default config; diff --git a/packages/auth/vite.config.ts b/packages/auth/vite.config.ts index e824abc5..2d402c73 100644 --- a/packages/auth/vite.config.ts +++ b/packages/auth/vite.config.ts @@ -1,7 +1,11 @@ import dts from 'vite-plugin-dts'; -import { type UserConfig, defineConfig } from 'vitest/config'; +import { + type UserConfig, + type UserConfigFnObject, + defineConfig, +} from 'vitest/config'; -export default defineConfig(({ command }) => { +const config: UserConfigFnObject = defineConfig(({ command }) => { // needed for demo cors const serverExtras: UserConfig = command === 'serve' @@ -49,3 +53,5 @@ export default defineConfig(({ command }) => { ...serverExtras, }; }); + +export default config; diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json index a8ed344e..84ca2fd5 100644 --- a/packages/common/tsconfig.json +++ b/packages/common/tsconfig.json @@ -1,7 +1,9 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "baseUrl": "." + "baseUrl": ".", + "declaration": true, + "isolatedDeclarations": true }, "include": ["."] } diff --git a/packages/common/vite.config.ts b/packages/common/vite.config.ts index ecbc7fc6..2b929455 100644 --- a/packages/common/vite.config.ts +++ b/packages/common/vite.config.ts @@ -1,7 +1,7 @@ import dts from 'vite-plugin-dts'; -import { configDefaults, defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig, type UserConfig } from 'vitest/config'; -export default defineConfig({ +const config: UserConfig = defineConfig({ build: { lib: { entry: 'src/index.ts', @@ -28,3 +28,5 @@ export default defineConfig({ unstubGlobals: true, }, }); + +export default config; diff --git a/packages/player/src/api/event/active-device-disconnected.ts b/packages/player/src/api/event/active-device-disconnected.ts index e73ebfda..f3597749 100644 --- a/packages/player/src/api/event/active-device-disconnected.ts +++ b/packages/player/src/api/event/active-device-disconnected.ts @@ -3,6 +3,6 @@ export const eventName = 'active-device-disconnected'; /** * Native player device disconnect event. */ -export function activeDeviceDisconnected() { +export function activeDeviceDisconnected(): CustomEvent { return new CustomEvent(eventName); } diff --git a/packages/player/src/api/event/preload-request.ts b/packages/player/src/api/event/preload-request.ts index 948e29d5..c7f85eb6 100644 --- a/packages/player/src/api/event/preload-request.ts +++ b/packages/player/src/api/event/preload-request.ts @@ -1,3 +1,3 @@ -export function preloadRequest() { +export function preloadRequest(): CustomEvent { return new CustomEvent('preload-request'); } diff --git a/packages/player/src/config.ts b/packages/player/src/config.ts index 95d1131d..75ecde34 100644 --- a/packages/player/src/config.ts +++ b/packages/player/src/config.ts @@ -44,4 +44,4 @@ export function update(updates: Partial): Config { return state; } -export const events = new EventTarget(); +export const events: EventTarget = new EventTarget(); diff --git a/packages/player/src/event-bus.ts b/packages/player/src/event-bus.ts index f328d067..a9d02996 100644 --- a/packages/player/src/event-bus.ts +++ b/packages/player/src/event-bus.ts @@ -1,7 +1,7 @@ import { PlayerError } from './internal'; class PlayerEventTarget extends EventTarget { - dispatchError(error: PlayerError) { + dispatchError(error: PlayerError): void { this.dispatchEvent( new CustomEvent('error', { detail: error.toJSON(), @@ -10,4 +10,4 @@ class PlayerEventTarget extends EventTarget { } } -export const events = new PlayerEventTarget(); +export const events: PlayerEventTarget = new PlayerEventTarget(); diff --git a/packages/player/src/index.ts b/packages/player/src/index.ts index c4c91d6d..00e4a1f8 100644 --- a/packages/player/src/index.ts +++ b/packages/player/src/index.ts @@ -44,7 +44,7 @@ export function getMediaElement(): HTMLMediaElement | null { * * @param {Options} options */ -export function bootstrap(options: Options) { +export function bootstrap(options: Options): void { playerState.activePlayer = undefined; if (options.outputDevices === true) { diff --git a/packages/player/src/internal/beacon/index.ts b/packages/player/src/internal/beacon/index.ts index cac386ef..3f19209b 100644 --- a/packages/player/src/internal/beacon/index.ts +++ b/packages/player/src/internal/beacon/index.ts @@ -9,7 +9,7 @@ import type { CommitData, PrematureEvents } from './types'; * Generates a Web Worker from a function. */ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -export function workerize(method: Function) { +export function workerize(method: Function): string { const functionBody = `(${method.toString()})();`; const workerBlob = new Blob([functionBody], { type: 'text/javascript' }); @@ -34,7 +34,7 @@ async function handleWorkerMessage( /** * Start the event beacon worker. */ -export async function start() { +export async function start(): Promise { if (!worker) { const { beacon } = await import('./worker'); @@ -54,7 +54,7 @@ function notEmpty(value: TValue | null | undefined): value is TValue { export async function commit( beaconWorker: Worker | undefined, data: Pick, -) { +): Promise { if (beaconWorker) { const finishedEvents = await Promise.all(data.events); const definedEvents: Array = @@ -86,4 +86,6 @@ export async function commit( } else { console.warn('Event beacon is not running.'); } + + return undefined; } diff --git a/packages/player/src/internal/beacon/worker.ts b/packages/player/src/internal/beacon/worker.ts index 74a403e3..c0cd75a3 100644 --- a/packages/player/src/internal/beacon/worker.ts +++ b/packages/player/src/internal/beacon/worker.ts @@ -34,7 +34,7 @@ type Sessions = { userId: number; }; -export function beacon() { +export function beacon(): void { let queue: Array = []; let accessToken: string | undefined; let clientId: string | undefined; diff --git a/packages/player/src/internal/event-tracking/play-log/index.ts b/packages/player/src/internal/event-tracking/play-log/index.ts index b6ae895f..ebeb2970 100644 --- a/packages/player/src/internal/event-tracking/play-log/index.ts +++ b/packages/player/src/internal/event-tracking/play-log/index.ts @@ -28,7 +28,7 @@ export function mapProductTypeToPlayLogProductType( /** * Send event to event system scoped to play_log category. */ -export function commit(data: Pick) { +export function commit(data: Pick): Promise { return runIfAuthorizedWithUser(() => beaconCommit(worker, { type: 'play_log' as const, diff --git a/packages/player/src/internal/event-tracking/play-log/playback-session.ts b/packages/player/src/internal/event-tracking/play-log/playback-session.ts index b6985eb5..5c9e9759 100644 --- a/packages/player/src/internal/event-tracking/play-log/playback-session.ts +++ b/packages/player/src/internal/event-tracking/play-log/playback-session.ts @@ -1,4 +1,4 @@ -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; import type { AssetPresentation, AudioMode, @@ -55,7 +55,7 @@ const defaultPayload: Payload = { startTimestamp: -1, }; -const reducer = await createReducer( +const reducer: Reducer = await createReducer( 'playback_session', defaultPayload, ); @@ -71,14 +71,22 @@ const reducer = await createReducer( * of media for a certain media product has been presented * to the user. */ -export function playbackSession(newData: Parameters[0]) { +export function playbackSession(newData: Parameters[0]): Promise<{ + payload: Payload; + name: "playback_session"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } export function playbackSessionAction( streamingSessionId: string, action: Action, -) { +): Promise<{ + payload: Payload; + name: "playback_session"; + streamingSessionId: string; +} | undefined> { return reducer({ actions: [action], streamingSessionId, diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/drm-license-fetch.ts b/packages/player/src/internal/event-tracking/streaming-metrics/drm-license-fetch.ts index 52e857e4..c66319e5 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/drm-license-fetch.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/drm-license-fetch.ts @@ -1,4 +1,4 @@ -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; export type Payload = { endReason: 'COMPLETE' | 'ERROR' | 'OTHER'; @@ -23,11 +23,15 @@ const defaultPayload: Payload = { streamingSessionId: '', }; -const reducer = await createReducer( +const reducer: Reducer = await createReducer( 'drm_license_fetch', defaultPayload, ); -export function drmLicenseFetch(newData: Parameters[0]) { +export function drmLicenseFetch(newData: Parameters[0]): Promise<{ + payload: Payload; + name: "drm_license_fetch"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/index.ts b/packages/player/src/internal/event-tracking/streaming-metrics/index.ts index dc0e3fb0..fe68760c 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/index.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/index.ts @@ -1,6 +1,6 @@ export { drmLicenseFetch } from './drm-license-fetch'; export { playbackInfoFetch } from './playback-info-fetch'; -export { playbackStatistics } from './playback-statistics'; +export { playbackStatisticsTrack, playbackStatisticsVideo, playbackStatistics } from './playback-statistics'; export { streamingSessionEnd } from './streaming-session-end'; export { streamingSessionStart } from './streaming-session-start'; @@ -11,7 +11,7 @@ import { runIfAuthorizedWithUser } from '../../helpers/run-if-authorized-with-us /** * Send event to event system scoped to streaming_metrics category. */ -export function commit(data: Pick) { +export function commit(data: Pick): Promise { return runIfAuthorizedWithUser(() => beaconCommit(worker, { type: 'streaming_metrics', diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/playback-info-fetch.ts b/packages/player/src/internal/event-tracking/streaming-metrics/playback-info-fetch.ts index 275b0c87..aacb754e 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/playback-info-fetch.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/playback-info-fetch.ts @@ -1,4 +1,4 @@ -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; export type Payload = { endReason: 'COMPLETE' | 'ERROR' | 'OTHER'; @@ -23,7 +23,7 @@ const defaultPayload: Payload = { streamingSessionId: '', }; -const reducer = await createReducer( +const reducer: Reducer = await createReducer( 'playback_info_fetch', defaultPayload, ); @@ -31,6 +31,10 @@ const reducer = await createReducer( /** * Create playbackInfoFetch event. */ -export function playbackInfoFetch(newData: Parameters[0]) { +export function playbackInfoFetch(newData: Parameters[0]): Promise<{ + payload: Payload; + name: "playback_info_fetch"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/playback-statistics.ts b/packages/player/src/internal/event-tracking/streaming-metrics/playback-statistics.ts index 7e9d9c4d..557e813a 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/playback-statistics.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/playback-statistics.ts @@ -1,4 +1,4 @@ -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; import type { OutputType } from '../../output-devices'; import type { AudioQuality, VideoQuality } from '../../types'; @@ -48,21 +48,19 @@ export type BasePayload = { streamingSessionId: string; }; -export type TrackPayload = { - actualQuality: AudioQuality; - productType: 'TRACK'; -}; - -export type VideoPayload = { +export type VideoPayload = BasePayload & { actualQuality: VideoQuality; productType: 'VIDEO'; }; -export type Payload = BasePayload & (TrackPayload | VideoPayload); +export type TrackPayload = BasePayload & { + actualQuality: AudioQuality; + productType: 'TRACK'; +}; export type PlaybackStatistics = { name: 'playback_statistics'; - payload: Payload; + payload: TrackPayload | VideoPayload; }; export function transformOutputType( @@ -89,7 +87,7 @@ export function transformOutputType( } } -const defaultPayload: Payload = { +const defaultTrackPayload: TrackPayload = { actualAssetPresentation: 'FULL', actualAudioMode: 'STEREO', actualProductId: null, @@ -111,14 +109,69 @@ const defaultPayload: Payload = { streamingSessionId: '', }; -const reducer = await createReducer( +const defaultVideoPayload: VideoPayload = { + actualAssetPresentation: 'FULL', + actualAudioMode: 'STEREO', + actualProductId: null, + actualQuality: 'HIGH', + actualStartTimestamp: 0, + actualStreamType: 'ON_DEMAND', + adaptations: [], + cdm: 'WIDEVINE', + cdmVersion: null, + endReason: 'COMPLETE', + endTimestamp: 0, + errorCode: null, + errorMessage: null, + hasAds: false, + idealStartTimestamp: 0, + outputDevice: null, + productType: 'VIDEO', + stalls: [], + streamingSessionId: '', +}; + +const reducer: Reducer = await createReducer( 'playback_statistics', - defaultPayload, + defaultTrackPayload, ); /** * Create playbackStatistics event. */ -export function playbackStatistics(newData: Parameters[0]) { +export function playbackStatistics(newData: Parameters[0]): Promise<{ + payload: TrackPayload | VideoPayload; + name: "playback_statistics"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } + +const trackPayloadReducer: Reducer = await createReducer( + 'playback_statistics', + defaultTrackPayload, +); + +/** + * Create playbackStatistics event. + */ +export function playbackStatisticsTrack(newData: Parameters[0]): Promise<{ + payload: TrackPayload; + name: "playback_statistics"; + streamingSessionId: string; +} | undefined> { + return trackPayloadReducer(newData); +} + +const videoPayloadReducer: Reducer = await createReducer( + 'playback_statistics', + defaultVideoPayload, +); + +export function playbackStatisticsVideo(newData: Parameters[0]): Promise<{ + payload: VideoPayload; + name: "playback_statistics"; + streamingSessionId: string; +} | undefined> { + return videoPayloadReducer(newData); +} diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-end.ts b/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-end.ts index ff053c78..751bd213 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-end.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-end.ts @@ -1,4 +1,4 @@ -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; export type Payload = { streamingSessionId: string; @@ -15,7 +15,7 @@ const defaultPayload: Payload = { timestamp: 0, }; -const reducer = await createReducer( +const reducer: Reducer = await createReducer( 'streaming_session_end', defaultPayload, ); @@ -24,6 +24,10 @@ const reducer = await createReducer( * The streaming session end event is sent by clients once a streaming session * ends, for whatever reason. It represents the end of a streaming session. */ -export function streamingSessionEnd(newData: Parameters[0]) { +export function streamingSessionEnd(newData: Parameters[0]): Promise<{ + payload: Payload; + name: "streaming_session_end"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } diff --git a/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-start.ts b/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-start.ts index 6f90c4a6..7f68dfc7 100644 --- a/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-start.ts +++ b/packages/player/src/internal/event-tracking/streaming-metrics/streaming-session-start.ts @@ -1,6 +1,6 @@ import Bowser from 'bowser'; -import { createReducer } from '../../helpers/reducer'; +import { createReducer, type Reducer } from '../../helpers/reducer'; const platform = Bowser.parse(navigator.userAgent); @@ -53,7 +53,7 @@ const defaultPayload: Payload = { timestamp: 0, }; -const reducer = await createReducer( +const reducer: Reducer = await createReducer( 'streaming_session_start', defaultPayload, ); @@ -68,6 +68,10 @@ const reducer = await createReducer( * A new streaming session starts whenever a client * decides that a media asset should be played. */ -export function streamingSessionStart(newData: Parameters[0]) { +export function streamingSessionStart(newData: Parameters[0]): Promise<{ + payload: Payload; + name: "streaming_session_start"; + streamingSessionId: string; +} | undefined> { return reducer(newData); } diff --git a/packages/player/src/internal/handlers/get-asset-position.ts b/packages/player/src/internal/handlers/get-asset-position.ts index aca36e78..35e5cf73 100644 --- a/packages/player/src/internal/handlers/get-asset-position.ts +++ b/packages/player/src/internal/handlers/get-asset-position.ts @@ -6,7 +6,7 @@ import { playerState } from '../../player/state'; * * @returns {number} */ -export function getAssetPosition() { +export function getAssetPosition(): number { const player = playerState.activePlayer; return player?.getPosition() ?? 0; diff --git a/packages/player/src/internal/handlers/get-output-devices.ts b/packages/player/src/internal/handlers/get-output-devices.ts index d36a2656..471db540 100644 --- a/packages/player/src/internal/handlers/get-output-devices.ts +++ b/packages/player/src/internal/handlers/get-output-devices.ts @@ -1,9 +1,11 @@ +import type { OutputDevice } from '../../internal/output-devices'; + /** * Get the available output devices. * - * @returns { Set} + * @returns {Array} */ -export async function getOutputDevices() { +export async function getOutputDevices(): Promise> { const { outputDevices } = await import('../../internal/output-devices'); return [...outputDevices.outputDevices]; diff --git a/packages/player/src/internal/handlers/get-volume-level.ts b/packages/player/src/internal/handlers/get-volume-level.ts index 537b51b6..3874989a 100644 --- a/packages/player/src/internal/handlers/get-volume-level.ts +++ b/packages/player/src/internal/handlers/get-volume-level.ts @@ -5,6 +5,6 @@ import * as Config from '../../config'; * * @returns {number} */ -export function getVolumeLevel() { +export function getVolumeLevel(): number { return Config.get('desiredVolumeLevel'); } diff --git a/packages/player/src/internal/handlers/load.ts b/packages/player/src/internal/handlers/load.ts index 3842606c..9701fba0 100644 --- a/packages/player/src/internal/handlers/load.ts +++ b/packages/player/src/internal/handlers/load.ts @@ -35,7 +35,7 @@ export async function load( mediaProduct: MediaProduct, assetPosition = 0, prefetch = false, -) { +): Promise { await trueTime.synchronize(); Pushkin.ensure().catch(console.error); diff --git a/packages/player/src/internal/handlers/pause.ts b/packages/player/src/internal/handlers/pause.ts index 749f125d..b5524111 100644 --- a/packages/player/src/internal/handlers/pause.ts +++ b/packages/player/src/internal/handlers/pause.ts @@ -7,6 +7,6 @@ import { playerState } from '../../player/state'; * * @see {@link import('../../api/event/playback-state-change').PlaybackStateChange} */ -export function pause() { +export function pause(): void { return playerState.activePlayer?.pause(); } diff --git a/packages/player/src/internal/handlers/play.ts b/packages/player/src/internal/handlers/play.ts index adb18bb7..7153b378 100644 --- a/packages/player/src/internal/handlers/play.ts +++ b/packages/player/src/internal/handlers/play.ts @@ -13,7 +13,7 @@ import { trueTime } from '../true-time'; * @returns {Promise} * @see {@link import('../../api/event/playback-state-change').PlaybackStateChange} */ -export async function play() { +export async function play(): Promise { await trueTime.synchronize(); const { activePlayer: player } = playerState; diff --git a/packages/player/src/internal/handlers/reset.ts b/packages/player/src/internal/handlers/reset.ts index 7a441d98..29313e9e 100644 --- a/packages/player/src/internal/handlers/reset.ts +++ b/packages/player/src/internal/handlers/reset.ts @@ -13,7 +13,7 @@ import ConnectionHandler from '../services/connection-handler'; * @returns {Promise} * @see {@link import('../../api/event/playback-state-change').PlaybackStateChange} */ -export async function reset() { +export async function reset(): Promise { cancelQueuedOnendedHandler(); ConnectionHandler.disable(); diff --git a/packages/player/src/internal/handlers/seek.ts b/packages/player/src/internal/handlers/seek.ts index 8fac7787..ea763e85 100644 --- a/packages/player/src/internal/handlers/seek.ts +++ b/packages/player/src/internal/handlers/seek.ts @@ -5,7 +5,7 @@ import { playerState } from '../../player/state'; * * @param {number} time - seconds */ -export async function seek(time: number) { +export async function seek(time: number): Promise { const { activePlayer: player } = playerState; return player?.seek(time); diff --git a/packages/player/src/internal/handlers/set-api-url.ts b/packages/player/src/internal/handlers/set-api-url.ts index e77b74b9..4642133a 100644 --- a/packages/player/src/internal/handlers/set-api-url.ts +++ b/packages/player/src/internal/handlers/set-api-url.ts @@ -5,7 +5,7 @@ import * as Config from '../../config'; * * @param {string} apiUrl */ -export function setApiUrl(apiUrl: string) { +export function setApiUrl(apiUrl: string): void { // eslint-disable-next-line no-useless-catch try { new URL(apiUrl); diff --git a/packages/player/src/internal/handlers/set-app-version.ts b/packages/player/src/internal/handlers/set-app-version.ts index ed534833..b32ca414 100644 --- a/packages/player/src/internal/handlers/set-app-version.ts +++ b/packages/player/src/internal/handlers/set-app-version.ts @@ -7,7 +7,7 @@ import * as Config from '../../config'; * * @param {string} appVersion */ -export function setAppVersion(appVersion: string) { +export function setAppVersion(appVersion: string): void { Config.update({ appVersion, }); diff --git a/packages/player/src/internal/handlers/set-client-platform.ts b/packages/player/src/internal/handlers/set-client-platform.ts index 2f13ce96..8abf9b37 100644 --- a/packages/player/src/internal/handlers/set-client-platform.ts +++ b/packages/player/src/internal/handlers/set-client-platform.ts @@ -7,7 +7,7 @@ import * as Config from '../../config'; * * @param {string} clientPlatform */ -export function setClientPlatform(clientPlatform: string) { +export function setClientPlatform(clientPlatform: string): void { Config.update({ clientPlatform, }); diff --git a/packages/player/src/internal/handlers/set-credentials-provider.ts b/packages/player/src/internal/handlers/set-credentials-provider.ts index 1fa8915e..7135d3a7 100644 --- a/packages/player/src/internal/handlers/set-credentials-provider.ts +++ b/packages/player/src/internal/handlers/set-credentials-provider.ts @@ -10,6 +10,6 @@ import { credentialsProviderStore } from '../index'; */ export function setCredentialsProvider( newCredentialsProvider: CredentialsProvider, -) { +): void { credentialsProviderStore.credentialsProvider = newCredentialsProvider; } diff --git a/packages/player/src/internal/handlers/set-event-url.ts b/packages/player/src/internal/handlers/set-event-url.ts index 2222c3c0..f32c839f 100644 --- a/packages/player/src/internal/handlers/set-event-url.ts +++ b/packages/player/src/internal/handlers/set-event-url.ts @@ -5,7 +5,7 @@ import * as Config from '../../config'; * * @param {string} eventUrl */ -export function setEventUrl(eventUrl: string) { +export function setEventUrl(eventUrl: string): void { // eslint-disable-next-line no-useless-catch try { new URL(eventUrl); diff --git a/packages/player/src/internal/handlers/set-loudness-normalization-mode.ts b/packages/player/src/internal/handlers/set-loudness-normalization-mode.ts index f1f19bf9..c8dad806 100644 --- a/packages/player/src/internal/handlers/set-loudness-normalization-mode.ts +++ b/packages/player/src/internal/handlers/set-loudness-normalization-mode.ts @@ -7,7 +7,7 @@ import { playerState } from '../../player/state'; * * @param {LoudnessNormalizationMode} mode */ -export function setLoudnessNormalizationMode(mode: LoudnessNormalizationMode) { +export function setLoudnessNormalizationMode(mode: LoudnessNormalizationMode): void { Config.update({ loudnessNormalizationMode: mode, }); diff --git a/packages/player/src/internal/handlers/set-next.ts b/packages/player/src/internal/handlers/set-next.ts index 98a83aa5..68233bff 100644 --- a/packages/player/src/internal/handlers/set-next.ts +++ b/packages/player/src/internal/handlers/set-next.ts @@ -31,7 +31,7 @@ export let latestNextCall: { async function _setNext( mediaProduct?: MediaProduct, sessionTags: Array = [], -) { +): Promise { cancelQueuedOnendedHandler(); // If next handler is called with undefined/null as media product, we treat that as an unset. @@ -184,7 +184,7 @@ async function _setNext( export function setNext( mediaProduct?: MediaProduct, sessionTags: Array = [], -) { +): Promise { /** * If next has already been called with the same media product, * return that promise instead of fetching playback info and diff --git a/packages/player/src/internal/handlers/set-streaming-wifi-audio-quality.ts b/packages/player/src/internal/handlers/set-streaming-wifi-audio-quality.ts index b263d1d3..3b9fa76a 100644 --- a/packages/player/src/internal/handlers/set-streaming-wifi-audio-quality.ts +++ b/packages/player/src/internal/handlers/set-streaming-wifi-audio-quality.ts @@ -8,7 +8,7 @@ import type { AudioQuality } from '../../internal/types'; */ export function setStreamingWifiAudioQuality( streamingWifiAudioQuality: AudioQuality, -) { +): void { Config.update({ streamingWifiAudioQuality, }); diff --git a/packages/player/src/internal/handlers/set-volume-level.ts b/packages/player/src/internal/handlers/set-volume-level.ts index 51417da8..ce3c9f61 100644 --- a/packages/player/src/internal/handlers/set-volume-level.ts +++ b/packages/player/src/internal/handlers/set-volume-level.ts @@ -6,7 +6,7 @@ import * as Config from '../../config'; * * @param {number} desiredVolumeLevel */ -export function setVolumeLevel(desiredVolumeLevel: number) { +export function setVolumeLevel(desiredVolumeLevel: number): void { Config.update({ desiredVolumeLevel, }); diff --git a/packages/player/src/internal/handlers/start-native-player.ts b/packages/player/src/internal/handlers/start-native-player.ts index 5ed2fbe8..430afa7f 100644 --- a/packages/player/src/internal/handlers/start-native-player.ts +++ b/packages/player/src/internal/handlers/start-native-player.ts @@ -3,7 +3,7 @@ import { getNativePlayer, setActivePlayer } from '../../player/index'; /** * Start native player before playback to access output devices. */ -export async function startNativePlayer() { +export async function startNativePlayer(): Promise { const nativePlayer = await getNativePlayer(); setActivePlayer(nativePlayer); diff --git a/packages/player/src/internal/helpers/event-session.ts b/packages/player/src/internal/helpers/event-session.ts index f18318c6..cc99d6d3 100644 --- a/packages/player/src/internal/helpers/event-session.ts +++ b/packages/player/src/internal/helpers/event-session.ts @@ -80,4 +80,4 @@ class EventSessionDB { } } -export const db = new EventSessionDB(); +export const db: EventSessionDB = new EventSessionDB(); diff --git a/packages/player/src/internal/helpers/on.ts b/packages/player/src/internal/helpers/on.ts index b98cb018..53eaa663 100644 --- a/packages/player/src/internal/helpers/on.ts +++ b/packages/player/src/internal/helpers/on.ts @@ -1,4 +1,4 @@ -export function on(target: EventTarget, eventName: string) { +export function on(target: EventTarget, eventName: string): Promise { return new Promise(resolve => { target.addEventListener(eventName, event => resolve(event), { once: true }); }); diff --git a/packages/player/src/internal/helpers/playback-info-resolver.ts b/packages/player/src/internal/helpers/playback-info-resolver.ts index a5e80813..5563393a 100644 --- a/packages/player/src/internal/helpers/playback-info-resolver.ts +++ b/packages/player/src/internal/helpers/playback-info-resolver.ts @@ -282,7 +282,7 @@ export function getDemoPlaybackInfo(options: Options): PlaybackInfo { }; } -export async function fetchPlaybackInfo(options: Options) { +export async function fetchPlaybackInfo(options: Options): Promise { const { streamingSessionId } = options; const events = []; @@ -312,7 +312,7 @@ export async function fetchPlaybackInfo(options: Options) { const hasAds = 'adInfo' in playbackInfo; if ('trackId' in playbackInfo) { - StreamingMetrics.playbackStatistics({ + StreamingMetrics.playbackStatisticsTrack({ actualAssetPresentation: playbackInfo.assetPresentation, actualAudioMode: playbackInfo.audioMode, actualProductId: String(playbackInfo.trackId), @@ -322,8 +322,8 @@ export async function fetchPlaybackInfo(options: Options) { productType: 'TRACK', streamingSessionId, }).catch(console.error); - } else { - StreamingMetrics.playbackStatistics({ + } else if ('videoId' in playbackInfo) { + StreamingMetrics.playbackStatisticsVideo({ actualAssetPresentation: playbackInfo.assetPresentation, actualAudioMode: undefined, actualProductId: String(playbackInfo.videoId), @@ -333,6 +333,8 @@ export async function fetchPlaybackInfo(options: Options) { productType: 'VIDEO', streamingSessionId, }).catch(console.error); + } else { + console.error('No trackId or videoId in playback info.'); } performance.mark('streaming_metrics:playback_info_fetch:endTimestamp', { diff --git a/packages/player/src/internal/helpers/reducer.ts b/packages/player/src/internal/helpers/reducer.ts index 790ac1f2..ebe12e1b 100644 --- a/packages/player/src/internal/helpers/reducer.ts +++ b/packages/player/src/internal/helpers/reducer.ts @@ -2,10 +2,16 @@ import * as Config from '../../config'; import { db } from './event-session'; +export type Reducer = (newData: { streamingSessionId: string } & Partial

) => Promise<{ + payload: P, + name: N, + streamingSessionId: string, +} | undefined>; + export async function createReducer( name: N, defaultPayload: P, -) { +): Promise> { if (!Config.get('gatherEvents')) { // @ts-expect-error - Not used // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -52,6 +58,8 @@ export async function createReducer( }; } catch (e) { console.error(e); + + return undefined; } }; } diff --git a/packages/player/src/internal/helpers/run-if-authorized-with-user.ts b/packages/player/src/internal/helpers/run-if-authorized-with-user.ts index 52319c4a..168ec059 100644 --- a/packages/player/src/internal/helpers/run-if-authorized-with-user.ts +++ b/packages/player/src/internal/helpers/run-if-authorized-with-user.ts @@ -4,7 +4,7 @@ import { isAuthorizedWithUser } from '../index'; * Run the provided function if we're authorized with a user. */ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -export async function runIfAuthorizedWithUser(fn: Function) { +export async function runIfAuthorizedWithUser(fn: Function): Promise { const authorizedWithUser = await isAuthorizedWithUser(); if (authorizedWithUser) { diff --git a/packages/player/src/internal/helpers/streaming-session-store.ts b/packages/player/src/internal/helpers/streaming-session-store.ts index 425c085f..2549e38d 100644 --- a/packages/player/src/internal/helpers/streaming-session-store.ts +++ b/packages/player/src/internal/helpers/streaming-session-store.ts @@ -18,7 +18,7 @@ class StreamingSessionStore { * @param from - streamingSessionId to clone * @param to - target streamingSessionId */ - clone(from: string, to: string) { + clone(from: string, to: string): void { const mediaProductTransition = this.getMediaProductTransition(from); const streamInfo = this.getStreamInfo(from); const playbackInfo = this.getPlaybackInfo(from); @@ -46,7 +46,7 @@ class StreamingSessionStore { }); } - deleteMediaProductTransition(streamingSessionId: string) { + deleteMediaProductTransition(streamingSessionId: string): void { this.#mediaProductTransitions.delete(streamingSessionId); } @@ -56,18 +56,18 @@ class StreamingSessionStore { * * @see {@link StreamingSessionStore.clone} */ - deleteSession(streamingSessionId: string) { + deleteSession(streamingSessionId: string): void { this.deleteMediaProductTransition(streamingSessionId); this.#playbackInfos.delete(streamingSessionId); this.#startedStreamInfos.delete(streamingSessionId); this.deleteStreamInfo(streamingSessionId); } - deleteStartedStreamInfo(streamingSessionId: string) { + deleteStartedStreamInfo(streamingSessionId: string): void { this.#startedStreamInfos.delete(streamingSessionId); } - deleteStreamInfo(streamingSessionId: string) { + deleteStreamInfo(streamingSessionId: string): void { this.#streamInfos.delete(streamingSessionId); } @@ -95,23 +95,23 @@ class StreamingSessionStore { : undefined; } - hasMediaProductTransition(streamingSessionId: string) { + hasMediaProductTransition(streamingSessionId: string): boolean { return this.#mediaProductTransitions.has(streamingSessionId); } - hasPlaybackInfo(streamingSessionId: string) { + hasPlaybackInfo(streamingSessionId: string): boolean { return this.#playbackInfos.has(streamingSessionId); } - hasStartedStreamInfo(streamingSessionId: string) { + hasStartedStreamInfo(streamingSessionId: string): boolean { return this.#startedStreamInfos.has(streamingSessionId); } - hasStreamInfo(streamingSessionId: string) { + hasStreamInfo(streamingSessionId: string): boolean { return this.#streamInfos.has(streamingSessionId); } - overwriteDuration(streamingSessionId: string, updatedDuration: number) { + overwriteDuration(streamingSessionId: string, updatedDuration: number): void { const mediaProductTransition = this.#mediaProductTransitions.get(streamingSessionId); @@ -130,18 +130,18 @@ class StreamingSessionStore { saveMediaProductTransition( streamingSessionId: string, mediaProductTransition: MediaProductTransitionPayload, - ) { + ): void { this.#mediaProductTransitions.set( streamingSessionId, mediaProductTransition, ); } - savePlaybackInfo(streamingSessionId: string, streamInfo: PlaybackInfo) { + savePlaybackInfo(streamingSessionId: string, streamInfo: PlaybackInfo): void { this.#playbackInfos.set(streamingSessionId, streamInfo); } - saveStreamInfo(streamingSessionId: string, streamInfo: StreamInfo) { + saveStreamInfo(streamingSessionId: string, streamInfo: StreamInfo): void { this.#streamInfos.set(streamingSessionId, streamInfo); } @@ -150,4 +150,4 @@ class StreamingSessionStore { } } -export const streamingSessionStore = new StreamingSessionStore(); +export const streamingSessionStore: StreamingSessionStore = new StreamingSessionStore(); diff --git a/packages/player/src/internal/helpers/string-similarity.ts b/packages/player/src/internal/helpers/string-similarity.ts index 26fe6557..953dab97 100644 --- a/packages/player/src/internal/helpers/string-similarity.ts +++ b/packages/player/src/internal/helpers/string-similarity.ts @@ -34,7 +34,11 @@ function compareTwoStrings(first: string, second: string) { export function findBestMatch( mainString: string, targetStrings: Array, -) { +): { + bestMatch: { rating: number; target: string } | undefined; + bestMatchIndex: number; + ratings: Array<{ rating: number; target: string }>; +} { if (!areArgsValid(mainString, targetStrings)) { throw new Error( 'Bad arguments: First argument should be a string, second should be an array of strings', diff --git a/packages/player/src/internal/helpers/wait-for-players.ts b/packages/player/src/internal/helpers/wait-for-players.ts index bba8cc49..f223df78 100644 --- a/packages/player/src/internal/helpers/wait-for-players.ts +++ b/packages/player/src/internal/helpers/wait-for-players.ts @@ -12,7 +12,7 @@ const handler = ( } }; -export function waitForPlayers() { +export function waitForPlayers(): Promise { const playerRoot = document.getElementById('tidal-player-root'); if (!playerRoot) { diff --git a/packages/player/src/internal/helpers/wait-for.ts b/packages/player/src/internal/helpers/wait-for.ts index ab87d63f..ee9f81ff 100644 --- a/packages/player/src/internal/helpers/wait-for.ts +++ b/packages/player/src/internal/helpers/wait-for.ts @@ -1,9 +1,9 @@ -export function waitFor(ms: number) { +export function waitFor(ms: number): Promise { // setTimeout are garbage collected on a "this" basis. return new Promise(resolve => setTimeout(() => resolve(), ms)); } -export function waitForEvent(target: EventTarget, eventName: string) { +export function waitForEvent(target: EventTarget, eventName: string): Promise { return new Promise(resolve => { target.addEventListener(eventName, event => resolve(event), false); }); diff --git a/packages/player/src/internal/index.ts b/packages/player/src/internal/index.ts index a15c9808..ad130422 100644 --- a/packages/player/src/internal/index.ts +++ b/packages/player/src/internal/index.ts @@ -9,7 +9,7 @@ class CredentialsProviderStore extends EventTarget { // @ts-ignore - Setter #credentialsProvider: CredentialsProvider; - async dispatchAuthorized() { + async dispatchAuthorized(): Promise { const credentials = await this.#credentialsProvider.getCredentials(); if (credentials?.token) { @@ -207,7 +207,11 @@ export class PlayerError extends Error { this.referenceId = referenceId; } - toJSON() { + toJSON(): { + errorCode: ErrorCodes | null, + errorId: ErrorIds | null, + referenceId: string | undefined, + } { return { errorCode: this.errorCode, errorId: this.errorId, @@ -215,7 +219,7 @@ export class PlayerError extends Error { }; } - toString() { + toString(): string { return JSON.stringify(this.toJSON()); } } @@ -226,7 +230,7 @@ export class PlayerError extends Error { * * @returns {Promise} */ -export async function isAuthorizedWithUser() { +export async function isAuthorizedWithUser(): Promise { if (credentialsProviderStore.credentialsProvider) { const credentials = await credentialsProviderStore.credentialsProvider.getCredentials(); @@ -239,7 +243,7 @@ export async function isAuthorizedWithUser() { return isAuthorizedWithUser(); } -export const credentialsProviderStore = new CredentialsProviderStore(); +export const credentialsProviderStore: CredentialsProviderStore = new CredentialsProviderStore(); /** * Starts streaming privileges and event code if the credentials allow it. @@ -285,7 +289,7 @@ credentialsProviderStore.addEventListener('authorized', () => { * Returns null if credentials provider is not set up or * if the token is undefined. */ -export async function getAccessToken() { +export async function getAccessToken(): Promise { if (credentialsProviderStore.credentialsProvider) { const credentials = await credentialsProviderStore.credentialsProvider.getCredentials(); diff --git a/packages/player/src/internal/output-devices.ts b/packages/player/src/internal/output-devices.ts index 053451e5..65402693 100644 --- a/packages/player/src/internal/output-devices.ts +++ b/packages/player/src/internal/output-devices.ts @@ -110,7 +110,7 @@ export function findOutputType( return undefined; } -export function marshalLabel(deviceLabel: string, operatingSystem: string) { +export function marshalLabel(deviceLabel: string, operatingSystem: string): string { const osName = operatingSystem.toLowerCase(); let nicerLabel = deviceLabel; @@ -141,7 +141,7 @@ export function isWindowsCommunicationsDevice( export function getOutputDeviceByName( devices: Set, name: string, -) { +): OutputDevice | undefined { name = marshalLabel(name, platform.os.name || ''); if ([...devices].length === 0 || name === '') { @@ -226,7 +226,7 @@ export class OutputDevices { }) as EventListener); } - addNativeDevices(devices: Array) { + addNativeDevices(devices: Array): void { this.#events.dispatchEvent( new CustomEvent('native-devices', { detail: devices, @@ -234,7 +234,7 @@ export class OutputDevices { ); } - addWebDevices(devices: Array) { + addWebDevices(devices: Array): void { // Filter out the default device. devices = devices.filter(d => d.deviceId !== 'default'); @@ -245,7 +245,7 @@ export class OutputDevices { ); } - emitDeviceChange() { + emitDeviceChange(): void { events.dispatchEvent(deviceChange([...this.outputDevices])); } @@ -255,14 +255,14 @@ export class OutputDevices { return [...this.#nativeDevices].find(nd => nd.id === id); } - async hydrateWebDevices() { + async hydrateWebDevices(): Promise { const mediaDevices = await navigator.mediaDevices.enumerateDevices(); const audioOutputs = mediaDevices.filter(d => d.kind === 'audiooutput'); this.addWebDevices(audioOutputs); } - mergeDevices() { + mergeDevices(): void { // Remove previous native and web IDs for non-default devices // but keep the names and id. [...this.outputDevices] @@ -327,7 +327,7 @@ export class OutputDevices { .forEach(od => this.outputDevices.delete(od)); } - async queueUpdate() { + async queueUpdate(): Promise { const nativeDeviceChange = new Promise< Array >(resolve => @@ -390,4 +390,4 @@ export class OutputDevices { } } -export const outputDevices = new OutputDevices(); +export const outputDevices: OutputDevices = new OutputDevices(); diff --git a/packages/player/src/internal/services/connection-handler.ts b/packages/player/src/internal/services/connection-handler.ts index 071d2223..6b54b440 100644 --- a/packages/player/src/internal/services/connection-handler.ts +++ b/packages/player/src/internal/services/connection-handler.ts @@ -92,7 +92,7 @@ export default class ConnectionHandler { } } - static disable() { + static disable(): void { if (this.#enabled) { if (this.#offlineHandler) { window.removeEventListener('offline', this.#offlineHandler, false); @@ -108,7 +108,7 @@ export default class ConnectionHandler { } } - static enable() { + static enable(): void { if (!this.#enabled) { this.#onlineHandler = () => this.#handleOnline(); this.#offlineHandler = () => this.#handleOffline(); diff --git a/packages/player/src/internal/services/pushkin.ts b/packages/player/src/internal/services/pushkin.ts index 33e06e3b..317029a4 100644 --- a/packages/player/src/internal/services/pushkin.ts +++ b/packages/player/src/internal/services/pushkin.ts @@ -48,7 +48,7 @@ let pushkin: Pushkin | undefined; // Only exported for testing. // eslint-disable-next-line disable-autofix/jsdoc/require-jsdoc -export async function fetchWebSocketURL(accessToken: string) { +export async function fetchWebSocketURL(accessToken: string): Promise { const apiUrl = Config.get('apiUrl'); const response = await fetch(apiUrl + '/rt/connect', { headers: new Headers({ @@ -69,7 +69,7 @@ export async function fetchWebSocketURL(accessToken: string) { // Only exported for testing. // eslint-disable-next-line disable-autofix/jsdoc/require-jsdoc -export function socketOpen(webSocket: WebSocket) { +export function socketOpen(webSocket: WebSocket): Promise { return new Promise(resolve => { webSocket.addEventListener('open', () => resolve(), { once: true }); }); @@ -104,7 +104,7 @@ export class Pushkin { /** * Call this method to ensure pushkin is running. */ - static async ensure() { + static async ensure(): Promise { const allowed = await isAuthorizedWithUser(); if (!allowed) { @@ -121,7 +121,7 @@ export class Pushkin { /** * Call this method when credentials changes to re-setup pushkin with the new credentials */ - static async refresh() { + static async refresh(): Promise{ const allowed = await isAuthorizedWithUser(); if (!allowed) { @@ -226,7 +226,7 @@ export class Pushkin { * Call this method to tell Pushkin a user action happened, so it can * make good qualified guesses if you're the session with allowed playback- */ - async userAction() { + async userAction(): Promise { if (!this.connected) { await this.reconnect(); } @@ -243,7 +243,7 @@ export class Pushkin { } } - get connected() { + get connected(): boolean | undefined { return this.#socket && this.#socket.readyState === WebSocket.OPEN; } } diff --git a/packages/player/src/player/adaptations.test.ts b/packages/player/src/player/adaptations.test.ts index f7603bb0..50c9960b 100644 --- a/packages/player/src/player/adaptations.test.ts +++ b/packages/player/src/player/adaptations.test.ts @@ -36,7 +36,7 @@ describe('saveAdaptation', () => { activeShakaTrack, 1337, ); - const event = await StreamingMetrics.playbackStatistics({ + const event = await StreamingMetrics.playbackStatisticsVideo({ streamingSessionId: 'jeremy-session', }); diff --git a/packages/player/src/player/adaptations.ts b/packages/player/src/player/adaptations.ts index 47d32725..0e28b1bc 100644 --- a/packages/player/src/player/adaptations.ts +++ b/packages/player/src/player/adaptations.ts @@ -36,7 +36,7 @@ export async function saveAdaptation( const adaptation = shakaTrackToAdaptation(activeTrack, currentTime); if (adaptation.mimeType && adaptation.codecs) { - await StreamingMetrics.playbackStatistics({ + await StreamingMetrics.playbackStatisticsVideo({ adaptations: [adaptation], streamingSessionId, }); @@ -77,7 +77,7 @@ export function registerAdaptations(shakaPlayer: shaka.Player) { events.addEventListener('media-product-transition', onMediaProductTransition); - return function unregister() { + return function unregister(): void { shakaPlayer.removeEventListener('adaptation', onAdaptation); shakaPlayer.removeEventListener('variantchanged', onAdaptation); events.removeEventListener( diff --git a/packages/player/src/player/audio-context-store.ts b/packages/player/src/player/audio-context-store.ts index 4d71890a..e813c26b 100644 --- a/packages/player/src/player/audio-context-store.ts +++ b/packages/player/src/player/audio-context-store.ts @@ -1,6 +1,6 @@ import { waitForPlayers } from '../internal/helpers/wait-for-players'; -export const mediaElementOne = document.createElement('video'); +export const mediaElementOne: HTMLVideoElement = document.createElement('video'); const prepareMediaElement = (mediaEl: HTMLMediaElement) => { mediaEl.setAttribute('crossorigin', 'anonymous'); @@ -12,7 +12,7 @@ mediaElementOne.id = 'video-one'; const tidalPlayerRootId = 'tidal-player-root'; -export function mountVideoElements() { +export function mountVideoElements(): Promise { let templateEl = document.getElementById(tidalPlayerRootId); if (!templateEl) { @@ -26,7 +26,7 @@ export function mountVideoElements() { return ensureVideoElementsMounted(); } -export function ensureVideoElementsMounted() { +export function ensureVideoElementsMounted(): Promise { const templateEl = document.getElementById( tidalPlayerRootId, ) as HTMLTemplateElement | null; @@ -40,8 +40,8 @@ export function ensureVideoElementsMounted() { return waitForPlayers(); } -export function activateVideoElements() { - return new Promise(resolve => +export function activateVideoElements(): Promise { + return new Promise(resolve => document.addEventListener( 'click', () => { diff --git a/packages/player/src/player/basePlayer.ts b/packages/player/src/player/basePlayer.ts index 3e647f78..9b6306b5 100644 --- a/packages/player/src/player/basePlayer.ts +++ b/packages/player/src/player/basePlayer.ts @@ -158,7 +158,7 @@ export class BasePlayer { } // Implements - attachPlaybackEngineEndedHandler() { + attachPlaybackEngineEndedHandler(): void { if (!this.#endedHandler) { this.#endedHandler = this.playbackEngineEndedHandler.bind(this); // TS is weird with CustomEvent event listeners. @@ -174,7 +174,7 @@ export class BasePlayer { * for preloadedStreamingSessionId if it does not match * currentStreamingSessionId. */ - cleanUpStoredPreloadInfo() { + cleanUpStoredPreloadInfo(): void { if ( this.preloadedStreamingSessionId && this.preloadedStreamingSessionId !== this.currentStreamingSessionId @@ -185,7 +185,7 @@ export class BasePlayer { } // Implements - debugLog(...args: Array) { + debugLog(...args: Array): void { if ( document.location.href.includes('localhost') && document.location.hash.includes('debug') @@ -221,7 +221,7 @@ export class BasePlayer { } } - detachPlaybackEngineEndedHandler() { + detachPlaybackEngineEndedHandler(): void { if (this.#endedHandler) { // TS is weird with CustomEvent event listeners. events.removeEventListener( @@ -246,7 +246,7 @@ export class BasePlayer { endAssetPosition: number; endReason: EndReason; }, - ) { + ): void { const endTimestamp = trueTime.now(); PlayLog.commit({ @@ -274,7 +274,7 @@ export class BasePlayer { }).catch(console.error); } - eventTrackingStreamingStarted(streamingSessionId: string) { + eventTrackingStreamingStarted(streamingSessionId: string): void { if (!streamingSessionId) { return; } @@ -374,7 +374,7 @@ export class BasePlayer { }).catch(console.error); } - finishCurrentMediaProduct(endReason: EndReason) { + finishCurrentMediaProduct(endReason: EndReason): void { // A media product was loaded but never started. if (!this.hasStarted()) { return; @@ -406,7 +406,7 @@ export class BasePlayer { /** * Refetches playbackinfo. */ - async hardReload(mediaProduct: MediaProduct, assetPosition: number) { + async hardReload(mediaProduct: MediaProduct, assetPosition: number): Promise { if (this.currentStreamingSessionId) { this.finishCurrentMediaProduct('skip'); } @@ -414,19 +414,19 @@ export class BasePlayer { return load(mediaProduct, assetPosition); } - hasNextItem() { - return this.preloadedStreamingSessionId; + hasNextItem(): boolean { + return Boolean(this.preloadedStreamingSessionId); } - hasStarted() { - return ( + hasStarted(): boolean { + return Boolean( this.currentStreamingSessionId && streamingSessionStore.hasStartedStreamInfo(this.currentStreamingSessionId) ); } // eslint-disable-next-line @typescript-eslint/no-unused-vars - load(_lp: LoadPayload, _transition: 'explicit' | 'implicit') { + load(_lp: LoadPayload, _transition: 'explicit' | 'implicit'): Promise { return Promise.resolve(); } @@ -435,7 +435,7 @@ export class BasePlayer { * * @returns {boolean} True if hard reloaded, else false. */ - async maybeHardReload() { + async maybeHardReload(): Promise { // Not the same as OR in an if statement. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const prefetchedOrExpired = this.prefetched || this.expired; @@ -455,7 +455,7 @@ export class BasePlayer { * * @param streamingSessionId */ - mediaProductStarted(streamingSessionId: string | undefined) { + mediaProductStarted(streamingSessionId: string | undefined): void { if ( !streamingSessionId || streamingSessionStore.hasStartedStreamInfo(streamingSessionId) @@ -477,7 +477,7 @@ export class BasePlayer { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - next(_lp: LoadPayload) { + next(_lp: LoadPayload): Promise { return Promise.resolve(); } @@ -492,7 +492,7 @@ export class BasePlayer { overwriteMediaProduct( streamingSessionId: string, partialMediaProduct: Partial, - ) { + ): void { const oldMediaProductTransition = streamingSessionStore.getMediaProductTransition(streamingSessionId); @@ -516,30 +516,30 @@ export class BasePlayer { } } - pause() {} + pause(): void {} - play() { + play(): Promise { return Promise.resolve(); } // eslint-disable-next-line @typescript-eslint/no-unused-vars - playbackEngineEndedHandler(_e: EndedEvent) { + playbackEngineEndedHandler(_e: EndedEvent): Promise { return Promise.resolve(); } // eslint-disable-next-line @typescript-eslint/no-unused-vars - reset(_options: { keepPreload: boolean }) { + reset(_options: { keepPreload: boolean }): Promise { return Promise.resolve(); } // eslint-disable-next-line @typescript-eslint/no-unused-vars - seek(_number: number) {} + seek(_number: number): void {} /** * Handle play log reporting for seeking. * Seek start should log a PLAYBACK_START action if playing post seek. */ - seekEnd(assetPosition: number) { + seekEnd(assetPosition: number): void { const streamingSessionId = this.currentStreamingSessionId; if (streamingSessionId) { @@ -575,7 +575,7 @@ export class BasePlayer { * Handle play log reporting for seeking. * Seek start should log a PLAYBACK_STOP action. */ - seekStart(assetPosition: number) { + seekStart(assetPosition: number): void { if (this.currentStreamingSessionId) { PlayLog.playbackSessionAction(this.currentStreamingSessionId, { actionType: 'PLAYBACK_STOP', @@ -589,7 +589,7 @@ export class BasePlayer { ms: number, ifNotState: PlaybackState, setToState: PlaybackState, - ) { + ): Promise { await waitFor(ms); if (this.playbackState !== ifNotState) { @@ -597,15 +597,15 @@ export class BasePlayer { } } - skipToPreloadedMediaProduct() { + skipToPreloadedMediaProduct(): Promise { return Promise.resolve(); } - unloadPreloadedMediaProduct() { + unloadPreloadedMediaProduct(): Promise { return Promise.resolve(); } - updateOutputDevice() { + updateOutputDevice(): Promise { return Promise.resolve(); } @@ -614,7 +614,7 @@ export class BasePlayer { * it before setting, if loudness normalization is * enabled. */ - updateVolumeLevel() { + updateVolumeLevel(): void { const streamInfo = streamingSessionStore.getStreamInfo( this.currentStreamingSessionId, ); @@ -630,7 +630,7 @@ export class BasePlayer { * Adjusts the volume for the next track. * Can be called on product ended to have the level ready. */ - updateVolumeLevelForNextProduct() { + updateVolumeLevelForNextProduct(): void { const streamInfo = streamingSessionStore.getStreamInfo( this.preloadedStreamingSessionId, ); @@ -640,7 +640,7 @@ export class BasePlayer { } // else: Will be adjusted on start instead. } - get currentMediaProduct() { + get currentMediaProduct(): MediaProduct | null { return ( streamingSessionStore.getMediaProductTransition( this.currentStreamingSessionId, @@ -665,7 +665,7 @@ export class BasePlayer { return this.#currentTime; } - get duration() { + get duration(): number | null { const mtp = streamingSessionStore.getMediaProductTransition( this.currentStreamingSessionId, ); @@ -677,7 +677,7 @@ export class BasePlayer { return null; } - get expired() { + get expired(): boolean { const streamInfo = streamingSessionStore.getStreamInfo( this.currentStreamingSessionId, ); @@ -690,13 +690,13 @@ export class BasePlayer { return streamInfo.expires <= Date.now(); } - get isActivePlayer() { + get isActivePlayer(): boolean | undefined { return ( playerState.activePlayer && this.name === playerState.activePlayer.name ); } - get nextItem() { + get nextItem(): MediaProductTransitionPayload | undefined { if (this.preloadedStreamingSessionId) { return streamingSessionStore.getMediaProductTransition( this.preloadedStreamingSessionId, @@ -768,12 +768,12 @@ export class BasePlayer { return this.#playbackState; } - get prefetched() { + get prefetched(): boolean { const streamInfo = streamingSessionStore.getStreamInfo( this.currentStreamingSessionId, ); - return streamInfo?.prefetched; + return Boolean(streamInfo?.prefetched); } set preloadedStreamingSessionId(ssi: string | undefined) { diff --git a/packages/player/src/player/browserPlayer.ts b/packages/player/src/player/browserPlayer.ts index 4e1a79d3..d980c139 100644 --- a/packages/player/src/player/browserPlayer.ts +++ b/packages/player/src/player/browserPlayer.ts @@ -20,7 +20,7 @@ export default class BrowserPlayer extends BasePlayer { #instanceOne: HTMLVideoElement; #isReset = true; - #librariesLoad: Promise | undefined; + #librariesLoad: Promise = Promise.resolve(); #mediaElementEventHandlers: { durationChangeHandler: EventListener; @@ -199,7 +199,7 @@ export default class BrowserPlayer extends BasePlayer { ); } - getPosition() { + getPosition(): number { this.debugLog('getPosition'); if (this.mediaElement) { @@ -213,7 +213,7 @@ export default class BrowserPlayer extends BasePlayer { return this.currentTime; } - async load(payload: LoadPayload, transition: 'explicit' | 'implicit') { + async load(payload: LoadPayload, transition: 'explicit' | 'implicit'): Promise { this.debugLog('load', payload); this.currentTime = payload.assetPosition; @@ -295,7 +295,7 @@ export default class BrowserPlayer extends BasePlayer { return Promise.resolve(); } - async next(payload: LoadPayload) { + async next(payload: LoadPayload): Promise { this.debugLog('next', payload); /* @@ -350,7 +350,7 @@ export default class BrowserPlayer extends BasePlayer { this.#isReset = false; } - pause() { + pause(): void { this.debugLog('pause'); if (this.mediaElement) { @@ -358,7 +358,7 @@ export default class BrowserPlayer extends BasePlayer { } } - async play() { + async play(): Promise { this.debugLog('play'); await this.maybeHardReload(); @@ -385,7 +385,7 @@ export default class BrowserPlayer extends BasePlayer { } } - async playbackEngineEndedHandler(e: EndedEvent) { + async playbackEngineEndedHandler(e: EndedEvent): Promise { if (this.isActivePlayer) { const { reason } = e.detail; @@ -403,7 +403,7 @@ export default class BrowserPlayer extends BasePlayer { async reset( { keepPreload }: { keepPreload: boolean } = { keepPreload: false }, - ) { + ): Promise { if (this.#isReset) { return Promise.resolve(); } @@ -439,14 +439,14 @@ export default class BrowserPlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/no-misused-promises - seek(currentTime: number) { + seek(currentTime: number): Promise { this.debugLog('seek', currentTime); const { currentPlayer: mediaEl } = this; const seconds = currentTime; if (!mediaEl) { - return; + return Promise.resolve(0); } this.seekStart(this.currentTime); @@ -466,7 +466,7 @@ export default class BrowserPlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/require-await - async skipToPreloadedMediaProduct() { + async skipToPreloadedMediaProduct(): Promise { const mediaProductTransition = streamingSessionStore.getMediaProductTransition( this.preloadedStreamingSessionId, @@ -500,7 +500,7 @@ export default class BrowserPlayer extends BasePlayer { } } - togglePlayback() { + togglePlayback(): void { this.debugLog('togglePlayback'); if (this.mediaElement) { @@ -513,7 +513,7 @@ export default class BrowserPlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/require-await - async unloadPreloadedMediaProduct() { + async unloadPreloadedMediaProduct(): Promise { this.debugLog( 'unloadPreloadedMediaProduct', this.preloadedStreamingSessionId, @@ -551,7 +551,7 @@ export default class BrowserPlayer extends BasePlayer { return this.currentPlayer ?? null; } - get ready() { + get ready(): Promise { return this.#librariesLoad; } diff --git a/packages/player/src/player/fairplay-drm.ts b/packages/player/src/player/fairplay-drm.ts index 572c0358..8256565b 100644 --- a/packages/player/src/player/fairplay-drm.ts +++ b/packages/player/src/player/fairplay-drm.ts @@ -1,7 +1,7 @@ /** * Certificate loading logic: */ -export async function loadServerCertificate() { +export async function loadServerCertificate(): Promise { try { const response = await fetch( 'https://resources.tidal.com/drm/fairplay/certificate', diff --git a/packages/player/src/player/filters.ts b/packages/player/src/player/filters.ts index f7243e43..7884c937 100644 --- a/packages/player/src/player/filters.ts +++ b/packages/player/src/player/filters.ts @@ -9,7 +9,7 @@ function stringToUint8Array(str: string) { return new Uint8Array(arr); } -export function manipulateLicenseResponse(response: shaka.extern.Response) { +export function manipulateLicenseResponse(response: shaka.extern.Response): void { // This is the wrapped license, which is a JSON string. const wrappedString = shaka.util.StringUtils.fromUTF8(response.data); // Parse the JSON string into an object @@ -39,7 +39,7 @@ export function manipulateLicenseRequest( securityToken: string; streamingSessionId: string; }, -) { +): void { if ( request.body instanceof ArrayBuffer || request.body instanceof Uint8Array diff --git a/packages/player/src/player/index.ts b/packages/player/src/player/index.ts index c73ffe7b..0d458624 100644 --- a/packages/player/src/player/index.ts +++ b/packages/player/src/player/index.ts @@ -32,11 +32,11 @@ const players = { shaka: undefined as ShakaPlayerType | undefined, }; -export function setPlayerConfig(allowedPlayers: Array) { +export function setPlayerConfig(allowedPlayers: Array): void { playerConfig = allowedPlayers; } -export async function resetAllPlayers() { +export async function resetAllPlayers(): Promise { await Promise.all( playerConfig.map(pc => { const player = players[pc.player]; @@ -53,7 +53,7 @@ export async function resetAllPlayers() { playerState.preloadPlayer = undefined; } -export function setActivePlayer(player: Player) { +export function setActivePlayer(player: Player): void { if (player.name !== 'nativePlayer' && players.native) { players.native.abandon(); } @@ -92,11 +92,11 @@ async function switchPlayerOnPlaybackEnd(_preloadPlayer: Player) { * * @see maybeSwitchPlayerOnEnd */ -export function cancelQueuedOnendedHandler() { +export function cancelQueuedOnendedHandler(): void { events.removeEventListener('ended', endedHandler); } -export function maybeSwitchPlayerOnEnd(preloadPlayer: Player) { +export function maybeSwitchPlayerOnEnd(preloadPlayer: Player): void { if ( playerState.activePlayer && preloadPlayer.name === playerState.activePlayer.name @@ -110,7 +110,7 @@ export function maybeSwitchPlayerOnEnd(preloadPlayer: Player) { events.addEventListener('ended', endedHandler, { once: true }); } -export async function getNativePlayer() { +export async function getNativePlayer(): Promise { const { default: NativePlayer } = await import('./nativePlayer'); if (!players.native) { @@ -120,7 +120,7 @@ export async function getNativePlayer() { return players.native; } -async function getBrowserPlayer() { +async function getBrowserPlayer(): Promise { const { default: BrowserPlayer } = await import('./browserPlayer'); if (!players.browser) { @@ -143,7 +143,7 @@ async function getShakaPlayer() { export async function getAppropriatePlayer( productType: 'demo' | 'track' | 'video', audioQuality: AudioQuality | undefined, -) { +): Promise { const appropriatePlayers = playerConfig .filter(pc => pc.itemTypes.includes(productType)) .filter(pc => @@ -178,7 +178,7 @@ export async function getAppropriatePlayer( /** * Unload preloads in all booted players. */ -export async function unloadPreloadedMediaProduct() { +export async function unloadPreloadedMediaProduct(): Promise { await Promise.all( playerConfig.map(pc => { const player = players[pc.player]; diff --git a/packages/player/src/player/nativePlayer.ts b/packages/player/src/player/nativePlayer.ts index 1f9cff04..6f943863 100644 --- a/packages/player/src/player/nativePlayer.ts +++ b/packages/player/src/player/nativePlayer.ts @@ -205,7 +205,7 @@ export default class NativePlayer extends BasePlayer { /** * Clean up native player before leaving for another player. */ - abandon() { + abandon(): void { if (outputDevices && outputDevices.deviceMode === 'exclusive') { /* Remove lock on audio device so shaka can use it. Otherwise throws error later when shaka is @@ -215,7 +215,7 @@ export default class NativePlayer extends BasePlayer { } } - getPosition() { + getPosition(): number { return this.currentTime; } @@ -226,7 +226,7 @@ export default class NativePlayer extends BasePlayer { * I.e. wait for player to load it and emit mediaduration event, then we * can gather the duration data and send a media product transition. */ - async handleAutomaticTransitionToPreloadedMediaProduct() { + async handleAutomaticTransitionToPreloadedMediaProduct(): Promise { await this.nativeEvent('mediaduration'); this.#preloadedLoadPayload = undefined; @@ -273,7 +273,7 @@ export default class NativePlayer extends BasePlayer { this.mediaProductStarted(this.currentStreamingSessionId); } - async load(payload: LoadPayload, transition: 'explicit' | 'implicit') { + async load(payload: LoadPayload, transition: 'explicit' | 'implicit'): Promise { this.debugLog('load', payload); this.currentTime = payload.assetPosition; @@ -361,7 +361,7 @@ export default class NativePlayer extends BasePlayer { }); } - async next(payload: LoadPayload) { + async next(payload: LoadPayload): Promise { this.debugLog('next', payload); // Cancel previous preload to load a new one. @@ -404,11 +404,11 @@ export default class NativePlayer extends BasePlayer { this.#preloadedLoadPayload = payload; } - pause() { + pause(): void { this.#player.pause(); } - async play() { + async play(): Promise { this.debugLog('play'); await this.maybeHardReload(); @@ -429,7 +429,7 @@ export default class NativePlayer extends BasePlayer { this.#player.play(); } - async playbackEngineEndedHandler(e: EndedEvent) { + async playbackEngineEndedHandler(e: EndedEvent): Promise { if (this.isActivePlayer) { const { reason } = e.detail; @@ -452,7 +452,7 @@ export default class NativePlayer extends BasePlayer { } } - registerEventListeners() { + registerEventListeners(): void { this.debugLog('registerEventListeners'); this.#player.addEventListener('mediacurrenttime', (e: Event) => { @@ -525,7 +525,7 @@ export default class NativePlayer extends BasePlayer { async reset( { keepPreload }: { keepPreload: boolean } = { keepPreload: false }, - ) { + ): Promise { if (this.currentStreamingSessionId === undefined) { return; } @@ -554,7 +554,7 @@ export default class NativePlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/no-misused-promises - async seek(seconds: number) { + async seek(seconds: number): Promise { // Native player cannot seek until active state has happened. if (!this.hasStarted()) { await this.mediaStateChange('active'); @@ -569,7 +569,7 @@ export default class NativePlayer extends BasePlayer { } // Handles track "skip next" and progressions between shaka and native player - async skipToPreloadedMediaProduct() { + async skipToPreloadedMediaProduct(): Promise { this.debugLog( 'skipToPreloadedMediaProduct', this.preloadedStreamingSessionId, @@ -608,7 +608,7 @@ export default class NativePlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/require-await - async unloadPreloadedMediaProduct() { + async unloadPreloadedMediaProduct(): Promise { this.debugLog( 'unloadPreloadedMediaProduct', this.preloadedStreamingSessionId, @@ -625,7 +625,7 @@ export default class NativePlayer extends BasePlayer { } } - updateDeviceMode() { + updateDeviceMode(): void { this.updateOutputDevice()?.catch(console.error); if (outputDevices) { @@ -635,7 +635,7 @@ export default class NativePlayer extends BasePlayer { } } - updateOutputDevice() { + updateOutputDevice(): Promise { if (!outputDevices) { return Promise.resolve(); } @@ -676,7 +676,7 @@ export default class NativePlayer extends BasePlayer { return Promise.resolve(); } - get ready() { + get ready(): Promise { return Promise.resolve(); } diff --git a/packages/player/src/player/shakaPlayer.ts b/packages/player/src/player/shakaPlayer.ts index fee166af..4e88d113 100644 --- a/packages/player/src/player/shakaPlayer.ts +++ b/packages/player/src/player/shakaPlayer.ts @@ -829,11 +829,14 @@ export default class ShakaPlayer extends BasePlayer { ); } - getPosition() { + getPosition(): number { return this.currentTime; } - async load(payload: LoadPayload, transition: 'explicit' | 'implicit') { + async load( + payload: LoadPayload, + transition: 'explicit' | 'implicit', + ): Promise { this.debugLog('load', payload); await this.ready; @@ -874,7 +877,7 @@ export default class ShakaPlayer extends BasePlayer { }); } - async next(payload: LoadPayload) { + async next(payload: LoadPayload): Promise { this.debugLog('next', payload); if (!this.shakaInstance) { @@ -920,7 +923,7 @@ export default class ShakaPlayer extends BasePlayer { this.#isReset = false; } - pause() { + pause(): void { this.debugLog('pause'); if (this.mediaElement) { @@ -928,7 +931,7 @@ export default class ShakaPlayer extends BasePlayer { } } - async play() { + async play(): Promise { this.debugLog('play'); await this.maybeHardReload(); @@ -964,7 +967,7 @@ export default class ShakaPlayer extends BasePlayer { await this.mediaElement?.play(); } - async playbackEngineEndedHandler(e: EndedEvent) { + async playbackEngineEndedHandler(e: EndedEvent): Promise { if (this.isActivePlayer) { const { reason } = e.detail; @@ -989,7 +992,7 @@ export default class ShakaPlayer extends BasePlayer { async reset( { keepPreload }: { keepPreload: boolean } = { keepPreload: false }, - ) { + ): Promise { this.debugLog('reset'); if (this.#isReset) { @@ -1026,13 +1029,13 @@ export default class ShakaPlayer extends BasePlayer { } // eslint-disable-next-line @typescript-eslint/no-misused-promises - seek(currentTime: number) { + seek(currentTime: number): Promise { this.debugLog('seek', currentTime); const { mediaElement } = this; if (!mediaElement) { - return; + return Promise.resolve(0); } this.seekStart(this.currentTime); @@ -1058,7 +1061,7 @@ export default class ShakaPlayer extends BasePlayer { }); } - async skipToPreloadedMediaProduct() { + async skipToPreloadedMediaProduct(): Promise { this.debugLog( 'skipToPreloadedMediaProduct', this.preloadedStreamingSessionId, @@ -1092,7 +1095,7 @@ export default class ShakaPlayer extends BasePlayer { return Promise.reject('Nothing preloaded.'); } - togglePlayback() { + togglePlayback(): void { this.debugLog('togglePlayback'); const { mediaElement } = this; @@ -1105,7 +1108,7 @@ export default class ShakaPlayer extends BasePlayer { } } - async unloadPreloadedMediaProduct() { + async unloadPreloadedMediaProduct(): Promise { this.debugLog( 'unloadPreloadedMediaProduct', this.preloadedStreamingSessionId, @@ -1120,7 +1123,7 @@ export default class ShakaPlayer extends BasePlayer { await this.#preloadManager?.destroy(); } - async updateOutputDevice() { + async updateOutputDevice(): Promise { if (!outputDevices) { return; } @@ -1154,7 +1157,7 @@ export default class ShakaPlayer extends BasePlayer { return mediaElementOne; } - get ready() { + get ready(): Promise { return this.#librariesLoad; } diff --git a/packages/player/src/player/stalls.ts b/packages/player/src/player/stalls.ts index 5f8d00d4..d8bf3db5 100644 --- a/packages/player/src/player/stalls.ts +++ b/packages/player/src/player/stalls.ts @@ -59,7 +59,7 @@ async function handlePlayingEvent( startTimestamp, }; - StreamingMetrics.playbackStatistics({ + StreamingMetrics.playbackStatisticsVideo({ stalls: [stall], streamingSessionId, }); @@ -92,7 +92,7 @@ export function registerStalls(mediaEl: HTMLMediaElement) { mediaEl.addEventListener('playing', onPlaying); mediaEl.addEventListener('paused', onPaused); - return function unregister() { + return function unregister(): void { mediaEl.removeEventListener('seeking', onSeeking); mediaEl.removeEventListener('seeked', onSeeked); mediaEl.removeEventListener('playing', onPlaying); diff --git a/packages/player/src/player/state.ts b/packages/player/src/player/state.ts index 9a46c738..3e3f679c 100644 --- a/packages/player/src/player/state.ts +++ b/packages/player/src/player/state.ts @@ -1,3 +1,4 @@ +import type { MediaProduct } from '../api/interfaces'; import { streamingSessionStore } from '../internal/helpers/streaming-session-store'; import type BrowserPlayer from './browserPlayer'; @@ -10,7 +11,7 @@ class PlayerState { activePlayer: Player | undefined; preloadPlayer: Player | undefined; - get preloadedMediaProduct() { + get preloadedMediaProduct(): MediaProduct | undefined { return ( streamingSessionStore.getMediaProductTransition( this.preloadedStreamingSessionId, @@ -18,9 +19,9 @@ class PlayerState { ); } - get preloadedStreamingSessionId() { + get preloadedStreamingSessionId(): string | undefined { return this.preloadPlayer?.preloadedStreamingSessionId ?? undefined; } } -export const playerState = new PlayerState(); +export const playerState: PlayerState = new PlayerState(); diff --git a/packages/player/src/test-helpers.ts b/packages/player/src/test-helpers.ts index e2409fe1..19671050 100644 --- a/packages/player/src/test-helpers.ts +++ b/packages/player/src/test-helpers.ts @@ -6,8 +6,9 @@ import { playerState } from './player/state'; export { waitFor } from './internal/helpers/wait-for'; import * as Player from './index'; +import type { CredentialsProvider } from '@tidal-music/common'; -export function getPreloadedStreamingSessionId() { +export function getPreloadedStreamingSessionId(): string | undefined { return playerState.preloadedStreamingSessionId; } @@ -45,9 +46,9 @@ await Auth.setCredentials({ }); Player.setCredentialsProvider(Auth.credentialsProvider); -export const credentialsProvider = Auth.credentialsProvider; +export const credentialsProvider: CredentialsProvider = Auth.credentialsProvider; -export function waitForEvent(target: EventTarget, eventName: string) { +export function waitForEvent(target: EventTarget, eventName: string): Promise { return new Promise(resolve => { target.addEventListener(eventName, event => resolve(event), false); }); @@ -89,7 +90,7 @@ class NativePlayerMock extends EventTarget { } } -export function mockNativePlayer() { +export function mockNativePlayer(): void { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore window.NativePlayerComponent = { diff --git a/packages/player/tsconfig.json b/packages/player/tsconfig.json index ef0a939b..3fcb7a8b 100644 --- a/packages/player/tsconfig.json +++ b/packages/player/tsconfig.json @@ -12,7 +12,9 @@ "types": [ "mocha" ], - "sourceMap": false + "sourceMap": false, + "declaration": true, + "isolatedDeclarations": true, }, "include": [ "." diff --git a/packages/player/vite-legacy.config.ts b/packages/player/vite-legacy.config.ts index f8e07a69..da2bb46d 100644 --- a/packages/player/vite-legacy.config.ts +++ b/packages/player/vite-legacy.config.ts @@ -1,10 +1,10 @@ import version from 'vite-plugin-package-version'; import topLevelAwait from 'vite-plugin-top-level-await'; -import { defineConfig, mergeConfig } from 'vitest/config'; +import { defineConfig, mergeConfig, type UserConfig } from 'vitest/config'; import defaultViteConfig from './vite.config'; -export default mergeConfig( +const config: UserConfig = mergeConfig( defaultViteConfig, defineConfig({ build: { @@ -19,3 +19,5 @@ export default mergeConfig( plugins: [version(), topLevelAwait()], }), ); + +export default config; diff --git a/packages/player/vite.config.ts b/packages/player/vite.config.ts index 22f1f7a6..e8b5248f 100644 --- a/packages/player/vite.config.ts +++ b/packages/player/vite.config.ts @@ -1,8 +1,8 @@ import dts from 'vite-plugin-dts'; import version from 'vite-plugin-package-version'; -import { defineConfig } from 'vitest/config'; +import { type UserConfig, defineConfig } from 'vitest/config'; -export default defineConfig({ +const config: UserConfig = defineConfig({ build: { lib: { entry: 'src/index.ts', @@ -27,3 +27,5 @@ export default defineConfig({ unstubGlobals: true, }, }); + +export default config; diff --git a/packages/true-time/src/index.ts b/packages/true-time/src/index.ts index ddfd9d0e..745a0959 100644 --- a/packages/true-time/src/index.ts +++ b/packages/true-time/src/index.ts @@ -19,7 +19,7 @@ export class TrueTime { * @returns The current adjusted time (or the client time if not synced yet). */ // eslint-disable-next-line no-restricted-syntax - now(clientCurrentTime = Date.now()): number { + now(clientCurrentTime: number = Date.now()): number { if (!this.#serverTime || !this.#clientStartTime) { console.warn('TrueTime is not yet synchronized'); return clientCurrentTime; @@ -91,4 +91,4 @@ export class TrueTime { } } -export const trueTime = new TrueTime('https://api.tidal.com/v1/ping'); +export const trueTime: TrueTime = new TrueTime('https://api.tidal.com/v1/ping'); diff --git a/packages/true-time/tsconfig.json b/packages/true-time/tsconfig.json index a8ed344e..bbbb6299 100644 --- a/packages/true-time/tsconfig.json +++ b/packages/true-time/tsconfig.json @@ -1,7 +1,9 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "baseUrl": "." + "baseUrl": ".", + "declaration": true, + "isolatedDeclarations": true, }, "include": ["."] } diff --git a/packages/true-time/vite.config.ts b/packages/true-time/vite.config.ts index 5e08bd4e..25efaced 100644 --- a/packages/true-time/vite.config.ts +++ b/packages/true-time/vite.config.ts @@ -1,7 +1,7 @@ import dts from 'vite-plugin-dts'; -import { defineConfig } from 'vitest/config'; +import { defineConfig, type UserConfig } from 'vitest/config'; -export default defineConfig({ +const config: UserConfig = defineConfig({ build: { lib: { entry: 'src/index.ts', @@ -26,3 +26,5 @@ export default defineConfig({ unstubGlobals: true, }, }); + +export default config;