@gentomiyano/optimized-web-audio-player 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,115 @@
1
+ // src/consumer/content-context.ts
2
+ function contentContextMatches(context, expected) {
3
+ if (context?.sourceType !== expected.sourceType) {
4
+ return false;
5
+ }
6
+ if (context.sourceType === "release-track") {
7
+ return context.releaseId === expected.parentId && context.trackId === expected.entryId;
8
+ }
9
+ return context.programId === expected.parentId && context.episodeId === expected.entryId;
10
+ }
11
+ function buildIntrinsicContext(entries, contextId, label, expectedSourceType, parentId) {
12
+ const queue = [];
13
+ const rejected = [];
14
+ const contentIds = /* @__PURE__ */ new Set();
15
+ const queueItemIds = /* @__PURE__ */ new Set();
16
+ entries.forEach((entry, entryIndex) => {
17
+ if (contentIds.has(entry.id)) {
18
+ rejected.push({
19
+ entryId: entry.id,
20
+ entryIndex,
21
+ reason: "duplicate-content-id"
22
+ });
23
+ return;
24
+ }
25
+ contentIds.add(entry.id);
26
+ if (entry.availability.state !== "ready") {
27
+ if (entry.queueItem !== void 0) {
28
+ rejected.push({
29
+ entryId: entry.id,
30
+ entryIndex,
31
+ reason: "non-ready-with-queue-item"
32
+ });
33
+ }
34
+ return;
35
+ }
36
+ if (entry.queueItem === void 0) {
37
+ rejected.push({
38
+ entryId: entry.id,
39
+ entryIndex,
40
+ reason: "ready-without-queue-item"
41
+ });
42
+ return;
43
+ }
44
+ if (queueItemIds.has(entry.queueItem.queueItemId)) {
45
+ rejected.push({
46
+ entryId: entry.id,
47
+ entryIndex,
48
+ reason: "duplicate-queue-item-id"
49
+ });
50
+ return;
51
+ }
52
+ if (!contentContextMatches(entry.queueItem.item.contentContext, {
53
+ sourceType: expectedSourceType,
54
+ parentId,
55
+ entryId: entry.id
56
+ })) {
57
+ rejected.push({
58
+ entryId: entry.id,
59
+ entryIndex,
60
+ reason: "content-context-mismatch"
61
+ });
62
+ return;
63
+ }
64
+ queueItemIds.add(entry.queueItem.queueItemId);
65
+ queue.push(entry.queueItem);
66
+ });
67
+ return Object.freeze({
68
+ context: Object.freeze({
69
+ id: contextId,
70
+ mode: "ordered-queue",
71
+ label,
72
+ queue: Object.freeze(queue)
73
+ }),
74
+ rejected: Object.freeze(
75
+ rejected.map((rejection) => Object.freeze(rejection))
76
+ )
77
+ });
78
+ }
79
+ function buildReleasePlaybackContext(release) {
80
+ return buildIntrinsicContext(
81
+ release.tracks,
82
+ release.contextId ?? `release:${release.id}`,
83
+ release.title,
84
+ "release-track",
85
+ release.id
86
+ );
87
+ }
88
+ function buildPodcastPlaybackContext(program) {
89
+ return buildIntrinsicContext(
90
+ program.episodes,
91
+ program.contextId ?? `podcast:${program.id}`,
92
+ program.title,
93
+ "podcast-episode",
94
+ program.id
95
+ );
96
+ }
97
+ function findActivePodcastChapter(chapters, currentTimeSec) {
98
+ if (chapters === void 0 || !Number.isFinite(currentTimeSec)) {
99
+ return null;
100
+ }
101
+ let active = null;
102
+ for (const chapter of chapters) {
103
+ if (!Number.isFinite(chapter.startTimeSec) || chapter.startTimeSec < 0 || chapter.startTimeSec > currentTimeSec) {
104
+ continue;
105
+ }
106
+ if (active === null || chapter.startTimeSec >= active.startTimeSec) {
107
+ active = chapter;
108
+ }
109
+ }
110
+ return active;
111
+ }
112
+
1
113
  // src/consumer/queue.ts
2
114
  function buildPlayerQueue(candidates, adapter) {
3
115
  const queue = [];
@@ -33,6 +145,6 @@ function buildPlayerQueue(candidates, adapter) {
33
145
  });
34
146
  }
35
147
 
36
- export { buildPlayerQueue };
148
+ export { buildPlayerQueue, buildPodcastPlaybackContext, buildReleasePlaybackContext, findActivePodcastChapter };
37
149
  //# sourceMappingURL=index.js.map
38
150
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/consumer/queue.ts"],"names":[],"mappings":";AAiCO,SAAS,gBAAA,CACd,YACA,OAAA,EACwB;AACxB,EAAA,MAAM,QAAqB,EAAC;AAC5B,EAAA,MAAM,WAAmC,EAAC;AAC1C,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAY;AAEzC,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAC,SAAA,EAAW,cAAA,KAAmB;AAChD,IAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC/C,MAAA,QAAA,CAAS,IAAA,CAAK,OAAO,MAAA,CAAO;AAAA,QAC1B,cAAA;AAAA,QACA,aAAa,SAAA,CAAU,WAAA;AAAA,QACvB,MAAA,EAAQ;AAAA,OACT,CAAC,CAAA;AACF,MAAA;AAAA,IACF;AACA,IAAA,gBAAA,CAAiB,GAAA,CAAI,UAAU,WAAW,CAAA;AAE1C,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,iBAAA,CAAkB,SAAA,CAAU,MAAM,CAAA;AACvD,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,QAAA,CAAS,IAAA,CAAK,OAAO,MAAA,CAAO;AAAA,QAC1B,cAAA;AAAA,QACA,aAAa,SAAA,CAAU,WAAA;AAAA,QACvB,MAAA,EAAQ;AAAA,OACT,CAAC,CAAA;AACF,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,IAAA,CAAK,OAAO,MAAA,CAAO;AAAA,MACvB,aAAa,SAAA,CAAU,WAAA;AAAA,MACvB;AAAA,KACD,CAAC,CAAA;AAAA,EACJ,CAAC,CAAA;AAED,EAAA,OAAO,OAAO,MAAA,CAAO;AAAA,IACnB,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAAA,IAC1B,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,QAAQ;AAAA,GACjC,CAAA;AACH","file":"index.js","sourcesContent":["import type {\r\n PlayerMediaAdapter,\r\n QueueItem,\r\n} from \"../contracts/player\";\r\n\r\nexport interface PlayerQueueCandidate<TSource> {\r\n /** Host-owned stable identity for this occurrence in a queue context. */\r\n readonly queueItemId: string;\r\n readonly source: TSource;\r\n}\r\n\r\nexport type PlayerQueueRejectionReason =\r\n | \"not-playable\"\r\n | \"duplicate-queue-item-id\";\r\n\r\nexport interface PlayerQueueRejection {\r\n readonly candidateIndex: number;\r\n readonly queueItemId: string;\r\n readonly reason: PlayerQueueRejectionReason;\r\n}\r\n\r\nexport interface PlayerQueueBuildResult {\r\n readonly queue: readonly QueueItem[];\r\n readonly rejected: readonly PlayerQueueRejection[];\r\n}\r\n\r\n/**\r\n * Builds a Core queue from consumer records that already passed Host access\r\n * policy. Candidate order is preserved. The same media item may occur more\r\n * than once when each occurrence has a unique queueItemId.\r\n *\r\n * The result retains only Player items, never the consumer record itself.\r\n */\r\nexport function buildPlayerQueue<TSource>(\r\n candidates: readonly PlayerQueueCandidate<TSource>[],\r\n adapter: PlayerMediaAdapter<TSource>,\r\n): PlayerQueueBuildResult {\r\n const queue: QueueItem[] = [];\r\n const rejected: PlayerQueueRejection[] = [];\r\n const seenQueueItemIds = new Set<string>();\r\n\r\n candidates.forEach((candidate, candidateIndex) => {\r\n if (seenQueueItemIds.has(candidate.queueItemId)) {\r\n rejected.push(Object.freeze({\r\n candidateIndex,\r\n queueItemId: candidate.queueItemId,\r\n reason: \"duplicate-queue-item-id\",\r\n }));\r\n return;\r\n }\r\n seenQueueItemIds.add(candidate.queueItemId);\r\n\r\n const item = adapter.toPlayerMediaItem(candidate.source);\r\n if (item === null) {\r\n rejected.push(Object.freeze({\r\n candidateIndex,\r\n queueItemId: candidate.queueItemId,\r\n reason: \"not-playable\",\r\n }));\r\n return;\r\n }\r\n\r\n queue.push(Object.freeze({\r\n queueItemId: candidate.queueItemId,\r\n item,\r\n }));\r\n });\r\n\r\n return Object.freeze({\r\n queue: Object.freeze(queue),\r\n rejected: Object.freeze(rejected),\r\n });\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../src/consumer/content-context.ts","../../src/consumer/queue.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n PlaybackContextInput,\n PlayerContentContext,\n PodcastChapter,\n PodcastProgramPlaybackModel,\n QueueItem,\n ReleasePlaybackModel,\n} from \"../contracts\";\n\nexport type PlayerContentContextRejectionReason =\n | \"duplicate-content-id\"\n | \"duplicate-queue-item-id\"\n | \"ready-without-queue-item\"\n | \"non-ready-with-queue-item\"\n | \"content-context-mismatch\";\n\nexport interface PlayerContentContextRejection {\n readonly entryId: string;\n readonly entryIndex: number;\n readonly reason: PlayerContentContextRejectionReason;\n}\n\nexport interface PlayerContentContextBuildResult {\n readonly context: Extract<\n PlaybackContextInput,\n { readonly mode: \"ordered-queue\" }\n >;\n readonly rejected: readonly PlayerContentContextRejection[];\n}\n\ninterface ContentEntryLike {\n readonly id: string;\n readonly availability: { readonly state: string };\n readonly queueItem?: QueueItem;\n}\n\nfunction contentContextMatches(\n context: PlayerContentContext | undefined,\n expected:\n | {\n readonly sourceType: \"release-track\";\n readonly parentId: string;\n readonly entryId: string;\n }\n | {\n readonly sourceType: \"podcast-episode\";\n readonly parentId: string;\n readonly entryId: string;\n },\n): boolean {\n if (context?.sourceType !== expected.sourceType) {\n return false;\n }\n if (context.sourceType === \"release-track\") {\n return (\n context.releaseId === expected.parentId &&\n context.trackId === expected.entryId\n );\n }\n return (\n context.programId === expected.parentId &&\n context.episodeId === expected.entryId\n );\n}\n\nfunction buildIntrinsicContext(\n entries: readonly ContentEntryLike[],\n contextId: string,\n label: string,\n expectedSourceType: \"release-track\" | \"podcast-episode\",\n parentId: string,\n): PlayerContentContextBuildResult {\n const queue: QueueItem[] = [];\n const rejected: PlayerContentContextRejection[] = [];\n const contentIds = new Set<string>();\n const queueItemIds = new Set<string>();\n\n entries.forEach((entry, entryIndex) => {\n if (contentIds.has(entry.id)) {\n rejected.push({\n entryId: entry.id,\n entryIndex,\n reason: \"duplicate-content-id\",\n });\n return;\n }\n contentIds.add(entry.id);\n\n if (entry.availability.state !== \"ready\") {\n if (entry.queueItem !== undefined) {\n rejected.push({\n entryId: entry.id,\n entryIndex,\n reason: \"non-ready-with-queue-item\",\n });\n }\n return;\n }\n\n if (entry.queueItem === undefined) {\n rejected.push({\n entryId: entry.id,\n entryIndex,\n reason: \"ready-without-queue-item\",\n });\n return;\n }\n\n if (queueItemIds.has(entry.queueItem.queueItemId)) {\n rejected.push({\n entryId: entry.id,\n entryIndex,\n reason: \"duplicate-queue-item-id\",\n });\n return;\n }\n\n if (!contentContextMatches(entry.queueItem.item.contentContext, {\n sourceType: expectedSourceType,\n parentId,\n entryId: entry.id,\n })) {\n rejected.push({\n entryId: entry.id,\n entryIndex,\n reason: \"content-context-mismatch\",\n });\n return;\n }\n\n queueItemIds.add(entry.queueItem.queueItemId);\n queue.push(entry.queueItem);\n });\n\n return Object.freeze({\n context: Object.freeze({\n id: contextId,\n mode: \"ordered-queue\" as const,\n label,\n queue: Object.freeze(queue),\n }),\n rejected: Object.freeze(\n rejected.map((rejection) => Object.freeze(rejection)),\n ),\n });\n}\n\nexport function buildReleasePlaybackContext(\n release: ReleasePlaybackModel,\n): PlayerContentContextBuildResult {\n return buildIntrinsicContext(\n release.tracks,\n release.contextId ?? `release:${release.id}`,\n release.title,\n \"release-track\",\n release.id,\n );\n}\n\nexport function buildPodcastPlaybackContext(\n program: PodcastProgramPlaybackModel,\n): PlayerContentContextBuildResult {\n return buildIntrinsicContext(\n program.episodes,\n program.contextId ?? `podcast:${program.id}`,\n program.title,\n \"podcast-episode\",\n program.id,\n );\n}\n\nexport function findActivePodcastChapter(\n chapters: readonly PodcastChapter[] | undefined,\n currentTimeSec: number,\n): PodcastChapter | null {\n if (chapters === undefined || !Number.isFinite(currentTimeSec)) {\n return null;\n }\n\n let active: PodcastChapter | null = null;\n for (const chapter of chapters) {\n if (\n !Number.isFinite(chapter.startTimeSec) ||\n chapter.startTimeSec < 0 ||\n chapter.startTimeSec > currentTimeSec\n ) {\n continue;\n }\n if (active === null || chapter.startTimeSec >= active.startTimeSec) {\n active = chapter;\n }\n }\n return active;\n}\n","import type {\n PlayerMediaAdapter,\n QueueItem,\n} from \"../contracts/player\";\n\nexport interface PlayerQueueCandidate<TSource> {\n /** Host-owned stable identity for this occurrence in a queue context. */\n readonly queueItemId: string;\n readonly source: TSource;\n}\n\nexport type PlayerQueueRejectionReason =\n | \"not-playable\"\n | \"duplicate-queue-item-id\";\n\nexport interface PlayerQueueRejection {\n readonly candidateIndex: number;\n readonly queueItemId: string;\n readonly reason: PlayerQueueRejectionReason;\n}\n\nexport interface PlayerQueueBuildResult {\n readonly queue: readonly QueueItem[];\n readonly rejected: readonly PlayerQueueRejection[];\n}\n\n/**\n * Builds a Core queue from consumer records that already passed Host access\n * policy. Candidate order is preserved. The same media item may occur more\n * than once when each occurrence has a unique queueItemId.\n *\n * The result retains only Player items, never the consumer record itself.\n */\nexport function buildPlayerQueue<TSource>(\n candidates: readonly PlayerQueueCandidate<TSource>[],\n adapter: PlayerMediaAdapter<TSource>,\n): PlayerQueueBuildResult {\n const queue: QueueItem[] = [];\n const rejected: PlayerQueueRejection[] = [];\n const seenQueueItemIds = new Set<string>();\n\n candidates.forEach((candidate, candidateIndex) => {\n if (seenQueueItemIds.has(candidate.queueItemId)) {\n rejected.push(Object.freeze({\n candidateIndex,\n queueItemId: candidate.queueItemId,\n reason: \"duplicate-queue-item-id\",\n }));\n return;\n }\n seenQueueItemIds.add(candidate.queueItemId);\n\n const item = adapter.toPlayerMediaItem(candidate.source);\n if (item === null) {\n rejected.push(Object.freeze({\n candidateIndex,\n queueItemId: candidate.queueItemId,\n reason: \"not-playable\",\n }));\n return;\n }\n\n queue.push(Object.freeze({\n queueItemId: candidate.queueItemId,\n item,\n }));\n });\n\n return Object.freeze({\n queue: Object.freeze(queue),\n rejected: Object.freeze(rejected),\n });\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import { w as PlayerMediaItem, Q as QueueItem } from './player-DRQO7SLs.js';
2
+
3
+ type PlayerContentAvailabilityState = "ready" | "processing" | "locked" | "unavailable" | "failed";
4
+ /**
5
+ * Player-facing availability only. The Host remains responsible for access,
6
+ * entitlement, publication, and asset-pipeline policy.
7
+ */
8
+ interface PlayerContentAvailability {
9
+ readonly state: PlayerContentAvailabilityState;
10
+ readonly messageKey?: string;
11
+ readonly retryable?: boolean;
12
+ }
13
+ interface PlayerContentEntryBase {
14
+ /** Stable content identity, independent from queue occurrence identity. */
15
+ readonly id: string;
16
+ readonly title: string;
17
+ readonly durationHintSec?: number;
18
+ readonly availability: PlayerContentAvailability;
19
+ /** Present only when the Host has authorized a ready playback asset. */
20
+ readonly queueItem?: QueueItem;
21
+ }
22
+ interface ReleaseTrackPlaybackEntry extends PlayerContentEntryBase {
23
+ readonly trackNumber?: number;
24
+ }
25
+ interface ReleasePlaybackModel {
26
+ readonly id: string;
27
+ readonly title: string;
28
+ readonly artistName: string;
29
+ readonly releaseDate?: string;
30
+ readonly releaseType?: string;
31
+ readonly credits?: readonly string[];
32
+ readonly notes?: string;
33
+ readonly artwork?: PlayerMediaItem["artwork"];
34
+ /** Stable ordered Tracklist supplied by Release/CMS data. */
35
+ readonly tracks: readonly ReleaseTrackPlaybackEntry[];
36
+ readonly contextId?: string;
37
+ }
38
+ interface PodcastChapter {
39
+ readonly id: string;
40
+ readonly title: string;
41
+ readonly startTimeSec: number;
42
+ }
43
+ interface PodcastEpisodePlaybackEntry extends PlayerContentEntryBase {
44
+ readonly publishedAt?: string;
45
+ readonly description?: string;
46
+ readonly chapters?: readonly PodcastChapter[];
47
+ }
48
+ interface PodcastProgramPlaybackModel {
49
+ readonly id: string;
50
+ readonly title: string;
51
+ readonly description?: string;
52
+ readonly hosts?: readonly string[];
53
+ readonly credits?: readonly string[];
54
+ readonly artwork?: PlayerMediaItem["artwork"];
55
+ /** Stable Episode order supplied by Program/CMS data. */
56
+ readonly episodes: readonly PodcastEpisodePlaybackEntry[];
57
+ readonly contextId?: string;
58
+ }
59
+
60
+ export type { PlayerContentAvailability as P, ReleasePlaybackModel as R, PlayerContentAvailabilityState as a, PlayerContentEntryBase as b, PodcastChapter as c, PodcastEpisodePlaybackEntry as d, PodcastProgramPlaybackModel as e, ReleaseTrackPlaybackEntry as f };
@@ -1,15 +1,3 @@
1
- import { p as PlayerExperienceConfig } from '../player-CE714iU_.js';
2
- export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as PlayerRuntimeStatus, z as PlayerState, C as PlayerStore, D as PlayerViewProps, E as PlayerWaveform, G as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, H as SetQueueOptions, I as StopOptions } from '../player-CE714iU_.js';
3
-
4
- interface ConfigValidationSuccess {
5
- readonly ok: true;
6
- readonly value: Readonly<PlayerExperienceConfig>;
7
- readonly errors: readonly [];
8
- }
9
- interface ConfigValidationFailure {
10
- readonly ok: false;
11
- readonly errors: readonly string[];
12
- }
13
- type PlayerExperienceConfigValidationResult = ConfigValidationSuccess | ConfigValidationFailure;
14
-
15
- export { type ConfigValidationFailure, type ConfigValidationSuccess, PlayerExperienceConfig, type PlayerExperienceConfigValidationResult };
1
+ export { C as ConfigValidationFailure, a as ConfigValidationSuccess, P as PlayerExperienceConfigValidationResult } from '../config-Bhyo_y05.js';
2
+ export { P as PlayerContentAvailability, a as PlayerContentAvailabilityState, b as PlayerContentEntryBase, c as PodcastChapter, d as PodcastEpisodePlaybackEntry, e as PodcastProgramPlaybackModel, R as ReleasePlaybackModel, f as ReleaseTrackPlaybackEntry } from '../content-CVe0cm0y.js';
3
+ export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerContentContext, m as PlayerDebugController, n as PlayerDebugSnapshot, o as PlayerError, p as PlayerErrorCode, q as PlayerExperienceConfig, r as PlayerExperienceConfigEnvelope, s as PlayerExperienceConfigStore, t as PlayerExperiencePreset, u as PlayerHostConfig, v as PlayerMediaAdapter, w as PlayerMediaItem, x as PlayerMediaSource, y as PlayerMediaSyncReason, z as PlayerRuntimeStatus, C as PlayerState, D as PlayerStore, E as PlayerViewProps, G as PlayerWaveform, H as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, I as SetQueueOptions, J as StopOptions } from '../player-DRQO7SLs.js';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export { ConfigValidationFailure, ConfigValidationSuccess, PlayerExperienceConfigValidationResult } from './contracts/index.js';
2
- export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerDebugController, m as PlayerDebugSnapshot, n as PlayerError, o as PlayerErrorCode, p as PlayerExperienceConfig, q as PlayerExperienceConfigEnvelope, r as PlayerExperienceConfigStore, s as PlayerExperiencePreset, t as PlayerHostConfig, u as PlayerMediaAdapter, v as PlayerMediaItem, w as PlayerMediaSource, x as PlayerMediaSyncReason, y as PlayerRuntimeStatus, z as PlayerState, C as PlayerStore, D as PlayerViewProps, E as PlayerWaveform, G as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, H as SetQueueOptions, I as StopOptions } from './player-CE714iU_.js';
1
+ export { C as ConfigValidationFailure, a as ConfigValidationSuccess, P as PlayerExperienceConfigValidationResult } from './config-Bhyo_y05.js';
2
+ export { P as PlayerContentAvailability, a as PlayerContentAvailabilityState, b as PlayerContentEntryBase, c as PodcastChapter, d as PodcastEpisodePlaybackEntry, e as PodcastProgramPlaybackModel, R as ReleasePlaybackModel, f as ReleaseTrackPlaybackEntry } from './content-CVe0cm0y.js';
3
+ export { A as ActivatePlaybackContextOptions, B as BoundPlayerCommands, a as BoundPlayerViewState, F as FadeCurve, M as MediaKind, P as PauseOptions, b as PersistMode, c as PlaybackContextInput, d as PlaybackContextMode, e as PlaybackContextState, f as PlaybackStatus, g as PlaybackTransitionCause, h as PlayerAppearance, i as PlayerCommandResult, j as PlayerCommands, k as PlayerConfigImportResult, l as PlayerContentContext, m as PlayerDebugController, n as PlayerDebugSnapshot, o as PlayerError, p as PlayerErrorCode, q as PlayerExperienceConfig, r as PlayerExperienceConfigEnvelope, s as PlayerExperienceConfigStore, t as PlayerExperiencePreset, u as PlayerHostConfig, v as PlayerMediaAdapter, w as PlayerMediaItem, x as PlayerMediaSource, y as PlayerMediaSyncReason, z as PlayerRuntimeStatus, C as PlayerState, D as PlayerStore, E as PlayerViewProps, G as PlayerWaveform, H as PodcastPreviousMode, Q as QueueItem, R as RepeatMode, S as SeekCommitMode, I as SetQueueOptions, J as StopOptions } from './player-DRQO7SLs.js';
3
4
  export { PLAYER_EXPERIENCE_CONFIG_LIMITS, PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION, PREVIEW_PLAYER_EXPERIENCE_CONFIG, createInitialPlayerState, parsePlayerExperienceConfigJson, resolvePlayerExperienceConfig, serializePlayerExperienceConfig, validatePlayerExperienceConfig, validatePlayerExperienceConfigOverride } from './config/index.js';
4
5
  export { AudioSampleEncoding, FutureUploadFormat, MEDIA_DELIVERY_CONTRACT_VERSION, MediaAccessClass, MediaDeliveryDescriptor, MediaDeliverySourceReference, MediaLoudnessMetadata, MediaSourceRole, MediaStorageReferences, MediaUploadEvidence, MediaUploadValidationResult, NormalizedUploadIdentity, PlaybackSourceResolveErrorCode, PlaybackSourceResolveReason, PlaybackSourceResolveRequest, PlaybackSourceResolveResult, PlayerDeliveryHostAdapter, PlayerMediaDescriptor, ProcessedMediaMetadata, ResolvedPlaybackSource, SupportedUploadFormat, UploadHeaderFormat, UploadValidationError, UploadValidationErrorCode, WaveformPeaksV1, validateMediaUploadEvidence, validateWaveformPeaks } from './media-delivery/index.js';
5
6
  export { GainPort, GainTransition, PlayerPersistencePort, PodcastProgress, PodcastProgressPort } from './ports/index.js';
6
- export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from './media-element-vFtmw4mQ.js';
7
+ export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from './media-element-BBgNBpqF.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config/defaults.ts","../src/config/validation.ts","../src/config/initial-state.ts","../src/media-delivery/validation.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerExperienceConfig } from \"../contracts/player\";\r\n\r\nexport const PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION = 2 as const;\r\n\r\nexport const PLAYER_EXPERIENCE_CONFIG_LIMITS = Object.freeze({\r\n fadeMs: Object.freeze({ min: 0, max: 10_000 }),\r\n previousRestartThresholdSec: Object.freeze({ min: 0, max: 60 }),\r\n waveformOpacity: Object.freeze({ min: 0, max: 1 }),\r\n initialVolume: Object.freeze({ min: 0, max: 1 }),\r\n podcastSkipSec: Object.freeze({ minExclusive: 0, max: 3_600 }),\r\n});\r\n\r\nexport const PREVIEW_PLAYER_EXPERIENCE_CONFIG: Readonly<PlayerExperienceConfig> =\r\n Object.freeze({\r\n playFadeInMs: 300,\r\n pauseFadeOutMs: 600,\r\n trackChangeFadeOutMs: 300,\r\n trackChangeFadeInMs: 300,\r\n seekFadeMs: 120,\r\n fadeCurve: \"ease-out\",\r\n previousRestartThresholdSec: 3,\r\n seekCommitMode: \"on-release\",\r\n waveformPlayedStateEnabled: true,\r\n waveformOpacity: 0.72,\r\n initialShuffleEnabled: false,\r\n initialRepeatMode: \"off\",\r\n initialVolume: 0.8,\r\n persistMode: \"none\",\r\n podcastBackSec: 15,\r\n podcastForwardSec: 30,\r\n podcastPreviousMode: \"previous-episode\",\r\n });\r\n","import type {\r\n FadeCurve,\r\n PersistMode,\r\n PlayerExperienceConfig,\r\n PodcastPreviousMode,\r\n RepeatMode,\r\n SeekCommitMode,\r\n} from \"../contracts/player\";\r\nimport type { PlayerExperienceConfigValidationResult } from \"../contracts/config\";\r\nimport {\r\n PLAYER_EXPERIENCE_CONFIG_LIMITS,\r\n PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION,\r\n PREVIEW_PLAYER_EXPERIENCE_CONFIG,\r\n} from \"./defaults\";\r\n\r\nconst CONFIG_KEYS = [\r\n \"playFadeInMs\",\r\n \"pauseFadeOutMs\",\r\n \"trackChangeFadeOutMs\",\r\n \"trackChangeFadeInMs\",\r\n \"seekFadeMs\",\r\n \"fadeCurve\",\r\n \"previousRestartThresholdSec\",\r\n \"seekCommitMode\",\r\n \"waveformPlayedStateEnabled\",\r\n \"waveformOpacity\",\r\n \"initialShuffleEnabled\",\r\n \"initialRepeatMode\",\r\n \"initialVolume\",\r\n \"persistMode\",\r\n \"podcastBackSec\",\r\n \"podcastForwardSec\",\r\n \"podcastPreviousMode\",\r\n] as const satisfies readonly (keyof PlayerExperienceConfig)[];\r\n\r\nconst FADE_CURVES = new Set<FadeCurve>([\r\n \"linear\",\r\n \"ease-in\",\r\n \"ease-out\",\r\n \"equal-power\",\r\n]);\r\nconst SEEK_COMMIT_MODES = new Set<SeekCommitMode>([\"live\", \"on-release\"]);\r\nconst REPEAT_MODES = new Set<RepeatMode>([\"off\", \"all\", \"one\"]);\r\nconst PERSIST_MODES = new Set<PersistMode>([\"none\", \"session\", \"local\"]);\r\nconst PODCAST_PREVIOUS_MODES = new Set<PodcastPreviousMode>([\r\n \"previous-episode\",\r\n \"restart-episode\",\r\n]);\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction validateFiniteRange(\r\n value: unknown,\r\n path: string,\r\n min: number,\r\n max: number,\r\n errors: string[],\r\n): value is number {\r\n if (\r\n typeof value !== \"number\" ||\r\n !Number.isFinite(value) ||\r\n value < min ||\r\n value > max\r\n ) {\r\n errors.push(\r\n `${path} must be a finite number between ${String(min)} and ${String(max)}.`,\r\n );\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\nfunction validateBoolean(\r\n value: unknown,\r\n path: string,\r\n errors: string[],\r\n): value is boolean {\r\n if (typeof value !== \"boolean\") {\r\n errors.push(`${path} must be a boolean.`);\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\nfunction validateConfigRecord(\r\n value: unknown,\r\n options: { readonly partial: boolean },\r\n): PlayerExperienceConfigValidationResult {\r\n if (!isRecord(value)) {\r\n return { ok: false, errors: [\"config must be an object.\"] };\r\n }\r\n\r\n const errors: string[] = [];\r\n const allowedKeys = new Set<string>(CONFIG_KEYS);\r\n\r\n for (const key of Object.keys(value)) {\r\n if (!allowedKeys.has(key)) {\r\n errors.push(`config.${key} is not supported.`);\r\n }\r\n }\r\n\r\n if (!options.partial) {\r\n for (const key of CONFIG_KEYS) {\r\n if (!Object.hasOwn(value, key)) {\r\n errors.push(`config.${key} is required.`);\r\n }\r\n }\r\n }\r\n\r\n const has = (key: keyof PlayerExperienceConfig): boolean =>\r\n Object.hasOwn(value, key);\r\n const fadeLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.fadeMs;\r\n\r\n for (const key of [\r\n \"playFadeInMs\",\r\n \"pauseFadeOutMs\",\r\n \"trackChangeFadeOutMs\",\r\n \"trackChangeFadeInMs\",\r\n \"seekFadeMs\",\r\n ] as const) {\r\n if (has(key)) {\r\n validateFiniteRange(value[key], `config.${key}`, fadeLimits.min, fadeLimits.max, errors);\r\n }\r\n }\r\n\r\n const thresholdLimits =\r\n PLAYER_EXPERIENCE_CONFIG_LIMITS.previousRestartThresholdSec;\r\n if (has(\"previousRestartThresholdSec\")) {\r\n validateFiniteRange(\r\n value.previousRestartThresholdSec,\r\n \"config.previousRestartThresholdSec\",\r\n thresholdLimits.min,\r\n thresholdLimits.max,\r\n errors,\r\n );\r\n }\r\n\r\n const volumeLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.initialVolume;\r\n if (has(\"initialVolume\")) {\r\n validateFiniteRange(\r\n value.initialVolume,\r\n \"config.initialVolume\",\r\n volumeLimits.min,\r\n volumeLimits.max,\r\n errors,\r\n );\r\n }\r\n\r\n const waveformOpacityLimits =\r\n PLAYER_EXPERIENCE_CONFIG_LIMITS.waveformOpacity;\r\n if (has(\"waveformOpacity\")) {\r\n validateFiniteRange(\r\n value.waveformOpacity,\r\n \"config.waveformOpacity\",\r\n waveformOpacityLimits.min,\r\n waveformOpacityLimits.max,\r\n errors,\r\n );\r\n }\r\n\r\n for (const key of [\r\n \"waveformPlayedStateEnabled\",\r\n \"initialShuffleEnabled\",\r\n ] as const) {\r\n if (has(key)) {\r\n validateBoolean(value[key], `config.${key}`, errors);\r\n }\r\n }\r\n\r\n const skipLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.podcastSkipSec;\r\n for (const key of [\"podcastBackSec\", \"podcastForwardSec\"] as const) {\r\n if (has(key)) {\r\n const candidate = value[key];\r\n const valid = validateFiniteRange(\r\n candidate,\r\n `config.${key}`,\r\n skipLimits.minExclusive,\r\n skipLimits.max,\r\n errors,\r\n );\r\n if (valid && candidate <= skipLimits.minExclusive) {\r\n errors.push(`config.${key} must be greater than 0.`);\r\n }\r\n }\r\n }\r\n\r\n if (has(\"fadeCurve\") && !FADE_CURVES.has(value.fadeCurve as FadeCurve)) {\r\n errors.push(\"config.fadeCurve is not supported.\");\r\n }\r\n if (\r\n has(\"seekCommitMode\") &&\r\n !SEEK_COMMIT_MODES.has(value.seekCommitMode as SeekCommitMode)\r\n ) {\r\n errors.push(\"config.seekCommitMode is not supported.\");\r\n }\r\n if (\r\n has(\"initialRepeatMode\") &&\r\n !REPEAT_MODES.has(value.initialRepeatMode as RepeatMode)\r\n ) {\r\n errors.push(\"config.initialRepeatMode is not supported.\");\r\n }\r\n if (has(\"persistMode\") && !PERSIST_MODES.has(value.persistMode as PersistMode)) {\r\n errors.push(\"config.persistMode is not supported.\");\r\n }\r\n if (\r\n has(\"podcastPreviousMode\") &&\r\n !PODCAST_PREVIOUS_MODES.has(\r\n value.podcastPreviousMode as PodcastPreviousMode,\r\n )\r\n ) {\r\n errors.push(\"config.podcastPreviousMode is not supported.\");\r\n }\r\n\r\n if (errors.length > 0) {\r\n return { ok: false, errors: Object.freeze(errors) };\r\n }\r\n\r\n const merged = options.partial\r\n ? { ...PREVIEW_PLAYER_EXPERIENCE_CONFIG, ...value }\r\n : value;\r\n\r\n return {\r\n ok: true,\r\n errors: [],\r\n value: Object.freeze({ ...merged }) as Readonly<PlayerExperienceConfig>,\r\n };\r\n}\r\n\r\nexport function validatePlayerExperienceConfig(\r\n value: unknown,\r\n): PlayerExperienceConfigValidationResult {\r\n return validateConfigRecord(value, { partial: false });\r\n}\r\n\r\nexport function validatePlayerExperienceConfigOverride(\r\n value: unknown,\r\n): PlayerExperienceConfigValidationResult {\r\n return validateConfigRecord(value, { partial: true });\r\n}\r\n\r\nexport function resolvePlayerExperienceConfig(\r\n override?: Partial<PlayerExperienceConfig>,\r\n): PlayerExperienceConfigValidationResult {\r\n return validatePlayerExperienceConfigOverride(override ?? {});\r\n}\r\n\r\nexport function parsePlayerExperienceConfigJson(\r\n json: string,\r\n): PlayerExperienceConfigValidationResult {\r\n let parsed: unknown;\r\n\r\n try {\r\n parsed = JSON.parse(json) as unknown;\r\n } catch {\r\n return { ok: false, errors: [\"Config JSON is not valid JSON.\"] };\r\n }\r\n\r\n if (!isRecord(parsed)) {\r\n return { ok: false, errors: [\"Config JSON envelope must be an object.\"] };\r\n }\r\n\r\n const envelopeKeys = Object.keys(parsed);\r\n const errors: string[] = [];\r\n\r\n for (const key of envelopeKeys) {\r\n if (key !== \"schemaVersion\" && key !== \"config\") {\r\n errors.push(`envelope.${key} is not supported.`);\r\n }\r\n }\r\n if (!Object.hasOwn(parsed, \"schemaVersion\")) {\r\n errors.push(\"envelope.schemaVersion is required.\");\r\n } else if (\r\n parsed.schemaVersion !== PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION\r\n ) {\r\n errors.push(\"envelope.schemaVersion is not supported.\");\r\n }\r\n if (!Object.hasOwn(parsed, \"config\")) {\r\n errors.push(\"envelope.config is required.\");\r\n }\r\n\r\n if (errors.length > 0) {\r\n return { ok: false, errors: Object.freeze(errors) };\r\n }\r\n\r\n return validatePlayerExperienceConfig(parsed.config);\r\n}\r\n\r\nexport function serializePlayerExperienceConfig(\r\n config: PlayerExperienceConfig,\r\n): string {\r\n const result = validatePlayerExperienceConfig(config);\r\n\r\n if (!result.ok) {\r\n throw new TypeError(result.errors.join(\" \"));\r\n }\r\n\r\n return JSON.stringify(\r\n {\r\n schemaVersion: PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION,\r\n config: result.value,\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n","import type {\r\n PlayerExperienceConfig,\r\n PlayerState,\r\n} from \"../contracts/player\";\r\nimport { resolvePlayerExperienceConfig } from \"./validation\";\r\n\r\nexport function createInitialPlayerState(\r\n experienceConfig?: Partial<PlayerExperienceConfig>,\r\n): Readonly<PlayerState> {\r\n const resolved = resolvePlayerExperienceConfig(experienceConfig);\r\n\r\n if (!resolved.ok) {\r\n throw new TypeError(resolved.errors.join(\" \"));\r\n }\r\n\r\n return Object.freeze({\r\n currentItem: null,\r\n currentItemId: null,\r\n currentQueueItemId: null,\r\n mediaKind: null,\r\n status: \"idle\",\r\n currentTimeSec: 0,\r\n durationSec: null,\r\n volume: resolved.value.initialVolume,\r\n muted: false,\r\n shuffleEnabled: resolved.value.initialShuffleEnabled,\r\n repeatMode: resolved.value.initialRepeatMode,\r\n queue: Object.freeze([]),\r\n activeContext: null,\r\n currentQueueIndex: null,\r\n canSeek: false,\r\n canGoPrevious: false,\r\n canGoNext: false,\r\n needsUserGesture: false,\r\n lastTransitionCause: null,\r\n error: null,\r\n experienceConfig: resolved.value,\r\n });\r\n}\r\n","import type {\r\n MediaUploadEvidence,\r\n MediaUploadValidationResult,\r\n SupportedUploadFormat,\r\n UploadValidationError,\r\n WaveformPeaksV1,\r\n} from \"./contracts\";\r\n\r\nconst EXTENSION_FORMATS = new Map<string, SupportedUploadFormat>([\r\n [\".wav\", \"wav\"],\r\n [\".mp3\", \"mp3\"],\r\n]);\r\n\r\nconst MIME_FORMATS = new Map<string, SupportedUploadFormat>([\r\n [\"audio/wave\", \"wav\"],\r\n [\"audio/wav\", \"wav\"],\r\n [\"audio/x-wav\", \"wav\"],\r\n [\"audio/vnd.wave\", \"wav\"],\r\n [\"audio/mpeg\", \"mp3\"],\r\n [\"audio/mp3\", \"mp3\"],\r\n]);\r\n\r\nfunction normalizeExtension(extension: string): string {\r\n const normalized = extension.trim().toLowerCase();\r\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\r\n}\r\n\r\nfunction normalizeMimeType(mimeType: string): string {\r\n return mimeType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\r\n}\r\n\r\nexport function validateMediaUploadEvidence(\r\n evidence: MediaUploadEvidence,\r\n): MediaUploadValidationResult {\r\n const extension = normalizeExtension(evidence.extension);\r\n const mimeType = normalizeMimeType(evidence.declaredMimeType);\r\n const extensionFormat = EXTENSION_FORMATS.get(extension);\r\n const mimeFormat = MIME_FORMATS.get(mimeType);\r\n const headerFormat =\r\n evidence.detectedHeaderFormat === \"unknown\"\r\n ? undefined\r\n : evidence.detectedHeaderFormat;\r\n const errors: UploadValidationError[] = [];\r\n\r\n if (extensionFormat === undefined) {\r\n errors.push({\r\n code: \"unsupported-extension\",\r\n field: \"extension\",\r\n });\r\n }\r\n if (mimeFormat === undefined) {\r\n errors.push({\r\n code: \"unsupported-mime-type\",\r\n field: \"declaredMimeType\",\r\n });\r\n }\r\n if (headerFormat === undefined) {\r\n errors.push({\r\n code: \"unrecognized-header\",\r\n field: \"detectedHeaderFormat\",\r\n });\r\n }\r\n if (\r\n extensionFormat !== undefined &&\r\n headerFormat !== undefined &&\r\n extensionFormat !== headerFormat\r\n ) {\r\n errors.push({\r\n code: \"extension-header-mismatch\",\r\n field: \"extension\",\r\n });\r\n }\r\n if (\r\n mimeFormat !== undefined &&\r\n headerFormat !== undefined &&\r\n mimeFormat !== headerFormat\r\n ) {\r\n errors.push({\r\n code: \"mime-header-mismatch\",\r\n field: \"declaredMimeType\",\r\n });\r\n }\r\n\r\n if (\r\n errors.length > 0 ||\r\n extensionFormat === undefined ||\r\n mimeFormat === undefined ||\r\n headerFormat === undefined\r\n ) {\r\n return Object.freeze({\r\n ok: false,\r\n errors: Object.freeze(errors),\r\n });\r\n }\r\n\r\n return Object.freeze({\r\n ok: true,\r\n value: Object.freeze({\r\n format: headerFormat,\r\n extension: headerFormat === \"wav\" ? \".wav\" : \".mp3\",\r\n mimeType: headerFormat === \"wav\" ? \"audio/wave\" : \"audio/mpeg\",\r\n }),\r\n errors: [] as const,\r\n });\r\n}\r\n\r\nexport function validateWaveformPeaks(\r\n waveform: WaveformPeaksV1,\r\n): readonly string[] {\r\n const errors: string[] = [];\r\n\r\n if (waveform.peaks.length === 0) {\r\n errors.push(\"waveform.peaks must contain at least one value.\");\r\n }\r\n\r\n waveform.peaks.forEach((peak, index) => {\r\n if (!Number.isFinite(peak) || peak < 0 || peak > 1) {\r\n errors.push(\r\n `waveform.peaks[${String(index)}] must be a finite number between 0 and 1.`,\r\n );\r\n }\r\n });\r\n\r\n return Object.freeze(errors);\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/config/defaults.ts","../src/config/validation.ts","../src/config/initial-state.ts","../src/media-delivery/validation.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerExperienceConfig } from \"../contracts/player\";\n\nexport const PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION = 2 as const;\n\nexport const PLAYER_EXPERIENCE_CONFIG_LIMITS = Object.freeze({\n fadeMs: Object.freeze({ min: 0, max: 10_000 }),\n previousRestartThresholdSec: Object.freeze({ min: 0, max: 60 }),\n waveformOpacity: Object.freeze({ min: 0, max: 1 }),\n initialVolume: Object.freeze({ min: 0, max: 1 }),\n podcastSkipSec: Object.freeze({ minExclusive: 0, max: 3_600 }),\n});\n\nexport const PREVIEW_PLAYER_EXPERIENCE_CONFIG: Readonly<PlayerExperienceConfig> =\n Object.freeze({\n playFadeInMs: 300,\n pauseFadeOutMs: 600,\n trackChangeFadeOutMs: 300,\n trackChangeFadeInMs: 300,\n seekFadeMs: 120,\n fadeCurve: \"ease-out\",\n previousRestartThresholdSec: 3,\n seekCommitMode: \"on-release\",\n waveformPlayedStateEnabled: true,\n waveformOpacity: 0.72,\n initialShuffleEnabled: false,\n initialRepeatMode: \"off\",\n initialVolume: 0.8,\n persistMode: \"none\",\n podcastBackSec: 15,\n podcastForwardSec: 30,\n podcastPreviousMode: \"previous-episode\",\n });\n","import type {\n FadeCurve,\n PersistMode,\n PlayerExperienceConfig,\n PodcastPreviousMode,\n RepeatMode,\n SeekCommitMode,\n} from \"../contracts/player\";\nimport type { PlayerExperienceConfigValidationResult } from \"../contracts/config\";\nimport {\n PLAYER_EXPERIENCE_CONFIG_LIMITS,\n PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION,\n PREVIEW_PLAYER_EXPERIENCE_CONFIG,\n} from \"./defaults\";\n\nconst CONFIG_KEYS = [\n \"playFadeInMs\",\n \"pauseFadeOutMs\",\n \"trackChangeFadeOutMs\",\n \"trackChangeFadeInMs\",\n \"seekFadeMs\",\n \"fadeCurve\",\n \"previousRestartThresholdSec\",\n \"seekCommitMode\",\n \"waveformPlayedStateEnabled\",\n \"waveformOpacity\",\n \"initialShuffleEnabled\",\n \"initialRepeatMode\",\n \"initialVolume\",\n \"persistMode\",\n \"podcastBackSec\",\n \"podcastForwardSec\",\n \"podcastPreviousMode\",\n] as const satisfies readonly (keyof PlayerExperienceConfig)[];\n\nconst FADE_CURVES = new Set<FadeCurve>([\n \"linear\",\n \"ease-in\",\n \"ease-out\",\n \"equal-power\",\n]);\nconst SEEK_COMMIT_MODES = new Set<SeekCommitMode>([\"live\", \"on-release\"]);\nconst REPEAT_MODES = new Set<RepeatMode>([\"off\", \"all\", \"one\"]);\nconst PERSIST_MODES = new Set<PersistMode>([\"none\", \"session\", \"local\"]);\nconst PODCAST_PREVIOUS_MODES = new Set<PodcastPreviousMode>([\n \"previous-episode\",\n \"restart-episode\",\n]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validateFiniteRange(\n value: unknown,\n path: string,\n min: number,\n max: number,\n errors: string[],\n): value is number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < min ||\n value > max\n ) {\n errors.push(\n `${path} must be a finite number between ${String(min)} and ${String(max)}.`,\n );\n return false;\n }\n return true;\n}\n\nfunction validateBoolean(\n value: unknown,\n path: string,\n errors: string[],\n): value is boolean {\n if (typeof value !== \"boolean\") {\n errors.push(`${path} must be a boolean.`);\n return false;\n }\n return true;\n}\n\nfunction validateConfigRecord(\n value: unknown,\n options: { readonly partial: boolean },\n): PlayerExperienceConfigValidationResult {\n if (!isRecord(value)) {\n return { ok: false, errors: [\"config must be an object.\"] };\n }\n\n const errors: string[] = [];\n const allowedKeys = new Set<string>(CONFIG_KEYS);\n\n for (const key of Object.keys(value)) {\n if (!allowedKeys.has(key)) {\n errors.push(`config.${key} is not supported.`);\n }\n }\n\n if (!options.partial) {\n for (const key of CONFIG_KEYS) {\n if (!Object.hasOwn(value, key)) {\n errors.push(`config.${key} is required.`);\n }\n }\n }\n\n const has = (key: keyof PlayerExperienceConfig): boolean =>\n Object.hasOwn(value, key);\n const fadeLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.fadeMs;\n\n for (const key of [\n \"playFadeInMs\",\n \"pauseFadeOutMs\",\n \"trackChangeFadeOutMs\",\n \"trackChangeFadeInMs\",\n \"seekFadeMs\",\n ] as const) {\n if (has(key)) {\n validateFiniteRange(value[key], `config.${key}`, fadeLimits.min, fadeLimits.max, errors);\n }\n }\n\n const thresholdLimits =\n PLAYER_EXPERIENCE_CONFIG_LIMITS.previousRestartThresholdSec;\n if (has(\"previousRestartThresholdSec\")) {\n validateFiniteRange(\n value.previousRestartThresholdSec,\n \"config.previousRestartThresholdSec\",\n thresholdLimits.min,\n thresholdLimits.max,\n errors,\n );\n }\n\n const volumeLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.initialVolume;\n if (has(\"initialVolume\")) {\n validateFiniteRange(\n value.initialVolume,\n \"config.initialVolume\",\n volumeLimits.min,\n volumeLimits.max,\n errors,\n );\n }\n\n const waveformOpacityLimits =\n PLAYER_EXPERIENCE_CONFIG_LIMITS.waveformOpacity;\n if (has(\"waveformOpacity\")) {\n validateFiniteRange(\n value.waveformOpacity,\n \"config.waveformOpacity\",\n waveformOpacityLimits.min,\n waveformOpacityLimits.max,\n errors,\n );\n }\n\n for (const key of [\n \"waveformPlayedStateEnabled\",\n \"initialShuffleEnabled\",\n ] as const) {\n if (has(key)) {\n validateBoolean(value[key], `config.${key}`, errors);\n }\n }\n\n const skipLimits = PLAYER_EXPERIENCE_CONFIG_LIMITS.podcastSkipSec;\n for (const key of [\"podcastBackSec\", \"podcastForwardSec\"] as const) {\n if (has(key)) {\n const candidate = value[key];\n const valid = validateFiniteRange(\n candidate,\n `config.${key}`,\n skipLimits.minExclusive,\n skipLimits.max,\n errors,\n );\n if (valid && candidate <= skipLimits.minExclusive) {\n errors.push(`config.${key} must be greater than 0.`);\n }\n }\n }\n\n if (has(\"fadeCurve\") && !FADE_CURVES.has(value.fadeCurve as FadeCurve)) {\n errors.push(\"config.fadeCurve is not supported.\");\n }\n if (\n has(\"seekCommitMode\") &&\n !SEEK_COMMIT_MODES.has(value.seekCommitMode as SeekCommitMode)\n ) {\n errors.push(\"config.seekCommitMode is not supported.\");\n }\n if (\n has(\"initialRepeatMode\") &&\n !REPEAT_MODES.has(value.initialRepeatMode as RepeatMode)\n ) {\n errors.push(\"config.initialRepeatMode is not supported.\");\n }\n if (has(\"persistMode\") && !PERSIST_MODES.has(value.persistMode as PersistMode)) {\n errors.push(\"config.persistMode is not supported.\");\n }\n if (\n has(\"podcastPreviousMode\") &&\n !PODCAST_PREVIOUS_MODES.has(\n value.podcastPreviousMode as PodcastPreviousMode,\n )\n ) {\n errors.push(\"config.podcastPreviousMode is not supported.\");\n }\n\n if (errors.length > 0) {\n return { ok: false, errors: Object.freeze(errors) };\n }\n\n const merged = options.partial\n ? { ...PREVIEW_PLAYER_EXPERIENCE_CONFIG, ...value }\n : value;\n\n return {\n ok: true,\n errors: [],\n value: Object.freeze({ ...merged }) as Readonly<PlayerExperienceConfig>,\n };\n}\n\nexport function validatePlayerExperienceConfig(\n value: unknown,\n): PlayerExperienceConfigValidationResult {\n return validateConfigRecord(value, { partial: false });\n}\n\nexport function validatePlayerExperienceConfigOverride(\n value: unknown,\n): PlayerExperienceConfigValidationResult {\n return validateConfigRecord(value, { partial: true });\n}\n\nexport function resolvePlayerExperienceConfig(\n override?: Partial<PlayerExperienceConfig>,\n): PlayerExperienceConfigValidationResult {\n return validatePlayerExperienceConfigOverride(override ?? {});\n}\n\nexport function parsePlayerExperienceConfigJson(\n json: string,\n): PlayerExperienceConfigValidationResult {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(json) as unknown;\n } catch {\n return { ok: false, errors: [\"Config JSON is not valid JSON.\"] };\n }\n\n if (!isRecord(parsed)) {\n return { ok: false, errors: [\"Config JSON envelope must be an object.\"] };\n }\n\n const envelopeKeys = Object.keys(parsed);\n const errors: string[] = [];\n\n for (const key of envelopeKeys) {\n if (key !== \"schemaVersion\" && key !== \"config\") {\n errors.push(`envelope.${key} is not supported.`);\n }\n }\n if (!Object.hasOwn(parsed, \"schemaVersion\")) {\n errors.push(\"envelope.schemaVersion is required.\");\n } else if (\n parsed.schemaVersion !== PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION\n ) {\n errors.push(\"envelope.schemaVersion is not supported.\");\n }\n if (!Object.hasOwn(parsed, \"config\")) {\n errors.push(\"envelope.config is required.\");\n }\n\n if (errors.length > 0) {\n return { ok: false, errors: Object.freeze(errors) };\n }\n\n return validatePlayerExperienceConfig(parsed.config);\n}\n\nexport function serializePlayerExperienceConfig(\n config: PlayerExperienceConfig,\n): string {\n const result = validatePlayerExperienceConfig(config);\n\n if (!result.ok) {\n throw new TypeError(result.errors.join(\" \"));\n }\n\n return JSON.stringify(\n {\n schemaVersion: PLAYER_EXPERIENCE_CONFIG_SCHEMA_VERSION,\n config: result.value,\n },\n null,\n 2,\n );\n}\n","import type {\n PlayerExperienceConfig,\n PlayerState,\n} from \"../contracts/player\";\nimport { resolvePlayerExperienceConfig } from \"./validation\";\n\nexport function createInitialPlayerState(\n experienceConfig?: Partial<PlayerExperienceConfig>,\n): Readonly<PlayerState> {\n const resolved = resolvePlayerExperienceConfig(experienceConfig);\n\n if (!resolved.ok) {\n throw new TypeError(resolved.errors.join(\" \"));\n }\n\n return Object.freeze({\n currentItem: null,\n currentItemId: null,\n currentQueueItemId: null,\n mediaKind: null,\n status: \"idle\",\n currentTimeSec: 0,\n durationSec: null,\n volume: resolved.value.initialVolume,\n muted: false,\n shuffleEnabled: resolved.value.initialShuffleEnabled,\n repeatMode: resolved.value.initialRepeatMode,\n queue: Object.freeze([]),\n activeContext: null,\n currentQueueIndex: null,\n canSeek: false,\n canGoPrevious: false,\n canGoNext: false,\n needsUserGesture: false,\n lastTransitionCause: null,\n error: null,\n experienceConfig: resolved.value,\n });\n}\n","import type {\n MediaUploadEvidence,\n MediaUploadValidationResult,\n SupportedUploadFormat,\n UploadValidationError,\n WaveformPeaksV1,\n} from \"./contracts\";\n\nconst EXTENSION_FORMATS = new Map<string, SupportedUploadFormat>([\n [\".wav\", \"wav\"],\n [\".mp3\", \"mp3\"],\n]);\n\nconst MIME_FORMATS = new Map<string, SupportedUploadFormat>([\n [\"audio/wave\", \"wav\"],\n [\"audio/wav\", \"wav\"],\n [\"audio/x-wav\", \"wav\"],\n [\"audio/vnd.wave\", \"wav\"],\n [\"audio/mpeg\", \"mp3\"],\n [\"audio/mp3\", \"mp3\"],\n]);\n\nfunction normalizeExtension(extension: string): string {\n const normalized = extension.trim().toLowerCase();\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\n}\n\nfunction normalizeMimeType(mimeType: string): string {\n return mimeType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\n}\n\nexport function validateMediaUploadEvidence(\n evidence: MediaUploadEvidence,\n): MediaUploadValidationResult {\n const extension = normalizeExtension(evidence.extension);\n const mimeType = normalizeMimeType(evidence.declaredMimeType);\n const extensionFormat = EXTENSION_FORMATS.get(extension);\n const mimeFormat = MIME_FORMATS.get(mimeType);\n const headerFormat =\n evidence.detectedHeaderFormat === \"unknown\"\n ? undefined\n : evidence.detectedHeaderFormat;\n const errors: UploadValidationError[] = [];\n\n if (extensionFormat === undefined) {\n errors.push({\n code: \"unsupported-extension\",\n field: \"extension\",\n });\n }\n if (mimeFormat === undefined) {\n errors.push({\n code: \"unsupported-mime-type\",\n field: \"declaredMimeType\",\n });\n }\n if (headerFormat === undefined) {\n errors.push({\n code: \"unrecognized-header\",\n field: \"detectedHeaderFormat\",\n });\n }\n if (\n extensionFormat !== undefined &&\n headerFormat !== undefined &&\n extensionFormat !== headerFormat\n ) {\n errors.push({\n code: \"extension-header-mismatch\",\n field: \"extension\",\n });\n }\n if (\n mimeFormat !== undefined &&\n headerFormat !== undefined &&\n mimeFormat !== headerFormat\n ) {\n errors.push({\n code: \"mime-header-mismatch\",\n field: \"declaredMimeType\",\n });\n }\n\n if (\n errors.length > 0 ||\n extensionFormat === undefined ||\n mimeFormat === undefined ||\n headerFormat === undefined\n ) {\n return Object.freeze({\n ok: false,\n errors: Object.freeze(errors),\n });\n }\n\n return Object.freeze({\n ok: true,\n value: Object.freeze({\n format: headerFormat,\n extension: headerFormat === \"wav\" ? \".wav\" : \".mp3\",\n mimeType: headerFormat === \"wav\" ? \"audio/wave\" : \"audio/mpeg\",\n }),\n errors: [] as const,\n });\n}\n\nexport function validateWaveformPeaks(\n waveform: WaveformPeaksV1,\n): readonly string[] {\n const errors: string[] = [];\n\n if (waveform.peaks.length === 0) {\n errors.push(\"waveform.peaks must contain at least one value.\");\n }\n\n waveform.peaks.forEach((peak, index) => {\n if (!Number.isFinite(peak) || peak < 0 || peak > 1) {\n errors.push(\n `waveform.peaks[${String(index)}] must be a finite number between 0 and 1.`,\n );\n }\n });\n\n return Object.freeze(errors);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { w as PlayerMediaSource, v as PlayerMediaItem } from '../player-CE714iU_.js';
1
+ import { x as PlayerMediaSource, w as PlayerMediaItem } from '../player-DRQO7SLs.js';
2
2
 
3
3
  declare const MEDIA_DELIVERY_CONTRACT_VERSION: 1;
4
4
  type SupportedUploadFormat = "wav" | "mp3";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/media-delivery/validation.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\r\n MediaUploadEvidence,\r\n MediaUploadValidationResult,\r\n SupportedUploadFormat,\r\n UploadValidationError,\r\n WaveformPeaksV1,\r\n} from \"./contracts\";\r\n\r\nconst EXTENSION_FORMATS = new Map<string, SupportedUploadFormat>([\r\n [\".wav\", \"wav\"],\r\n [\".mp3\", \"mp3\"],\r\n]);\r\n\r\nconst MIME_FORMATS = new Map<string, SupportedUploadFormat>([\r\n [\"audio/wave\", \"wav\"],\r\n [\"audio/wav\", \"wav\"],\r\n [\"audio/x-wav\", \"wav\"],\r\n [\"audio/vnd.wave\", \"wav\"],\r\n [\"audio/mpeg\", \"mp3\"],\r\n [\"audio/mp3\", \"mp3\"],\r\n]);\r\n\r\nfunction normalizeExtension(extension: string): string {\r\n const normalized = extension.trim().toLowerCase();\r\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\r\n}\r\n\r\nfunction normalizeMimeType(mimeType: string): string {\r\n return mimeType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\r\n}\r\n\r\nexport function validateMediaUploadEvidence(\r\n evidence: MediaUploadEvidence,\r\n): MediaUploadValidationResult {\r\n const extension = normalizeExtension(evidence.extension);\r\n const mimeType = normalizeMimeType(evidence.declaredMimeType);\r\n const extensionFormat = EXTENSION_FORMATS.get(extension);\r\n const mimeFormat = MIME_FORMATS.get(mimeType);\r\n const headerFormat =\r\n evidence.detectedHeaderFormat === \"unknown\"\r\n ? undefined\r\n : evidence.detectedHeaderFormat;\r\n const errors: UploadValidationError[] = [];\r\n\r\n if (extensionFormat === undefined) {\r\n errors.push({\r\n code: \"unsupported-extension\",\r\n field: \"extension\",\r\n });\r\n }\r\n if (mimeFormat === undefined) {\r\n errors.push({\r\n code: \"unsupported-mime-type\",\r\n field: \"declaredMimeType\",\r\n });\r\n }\r\n if (headerFormat === undefined) {\r\n errors.push({\r\n code: \"unrecognized-header\",\r\n field: \"detectedHeaderFormat\",\r\n });\r\n }\r\n if (\r\n extensionFormat !== undefined &&\r\n headerFormat !== undefined &&\r\n extensionFormat !== headerFormat\r\n ) {\r\n errors.push({\r\n code: \"extension-header-mismatch\",\r\n field: \"extension\",\r\n });\r\n }\r\n if (\r\n mimeFormat !== undefined &&\r\n headerFormat !== undefined &&\r\n mimeFormat !== headerFormat\r\n ) {\r\n errors.push({\r\n code: \"mime-header-mismatch\",\r\n field: \"declaredMimeType\",\r\n });\r\n }\r\n\r\n if (\r\n errors.length > 0 ||\r\n extensionFormat === undefined ||\r\n mimeFormat === undefined ||\r\n headerFormat === undefined\r\n ) {\r\n return Object.freeze({\r\n ok: false,\r\n errors: Object.freeze(errors),\r\n });\r\n }\r\n\r\n return Object.freeze({\r\n ok: true,\r\n value: Object.freeze({\r\n format: headerFormat,\r\n extension: headerFormat === \"wav\" ? \".wav\" : \".mp3\",\r\n mimeType: headerFormat === \"wav\" ? \"audio/wave\" : \"audio/mpeg\",\r\n }),\r\n errors: [] as const,\r\n });\r\n}\r\n\r\nexport function validateWaveformPeaks(\r\n waveform: WaveformPeaksV1,\r\n): readonly string[] {\r\n const errors: string[] = [];\r\n\r\n if (waveform.peaks.length === 0) {\r\n errors.push(\"waveform.peaks must contain at least one value.\");\r\n }\r\n\r\n waveform.peaks.forEach((peak, index) => {\r\n if (!Number.isFinite(peak) || peak < 0 || peak > 1) {\r\n errors.push(\r\n `waveform.peaks[${String(index)}] must be a finite number between 0 and 1.`,\r\n );\r\n }\r\n });\r\n\r\n return Object.freeze(errors);\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../src/media-delivery/validation.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n MediaUploadEvidence,\n MediaUploadValidationResult,\n SupportedUploadFormat,\n UploadValidationError,\n WaveformPeaksV1,\n} from \"./contracts\";\n\nconst EXTENSION_FORMATS = new Map<string, SupportedUploadFormat>([\n [\".wav\", \"wav\"],\n [\".mp3\", \"mp3\"],\n]);\n\nconst MIME_FORMATS = new Map<string, SupportedUploadFormat>([\n [\"audio/wave\", \"wav\"],\n [\"audio/wav\", \"wav\"],\n [\"audio/x-wav\", \"wav\"],\n [\"audio/vnd.wave\", \"wav\"],\n [\"audio/mpeg\", \"mp3\"],\n [\"audio/mp3\", \"mp3\"],\n]);\n\nfunction normalizeExtension(extension: string): string {\n const normalized = extension.trim().toLowerCase();\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\n}\n\nfunction normalizeMimeType(mimeType: string): string {\n return mimeType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\n}\n\nexport function validateMediaUploadEvidence(\n evidence: MediaUploadEvidence,\n): MediaUploadValidationResult {\n const extension = normalizeExtension(evidence.extension);\n const mimeType = normalizeMimeType(evidence.declaredMimeType);\n const extensionFormat = EXTENSION_FORMATS.get(extension);\n const mimeFormat = MIME_FORMATS.get(mimeType);\n const headerFormat =\n evidence.detectedHeaderFormat === \"unknown\"\n ? undefined\n : evidence.detectedHeaderFormat;\n const errors: UploadValidationError[] = [];\n\n if (extensionFormat === undefined) {\n errors.push({\n code: \"unsupported-extension\",\n field: \"extension\",\n });\n }\n if (mimeFormat === undefined) {\n errors.push({\n code: \"unsupported-mime-type\",\n field: \"declaredMimeType\",\n });\n }\n if (headerFormat === undefined) {\n errors.push({\n code: \"unrecognized-header\",\n field: \"detectedHeaderFormat\",\n });\n }\n if (\n extensionFormat !== undefined &&\n headerFormat !== undefined &&\n extensionFormat !== headerFormat\n ) {\n errors.push({\n code: \"extension-header-mismatch\",\n field: \"extension\",\n });\n }\n if (\n mimeFormat !== undefined &&\n headerFormat !== undefined &&\n mimeFormat !== headerFormat\n ) {\n errors.push({\n code: \"mime-header-mismatch\",\n field: \"declaredMimeType\",\n });\n }\n\n if (\n errors.length > 0 ||\n extensionFormat === undefined ||\n mimeFormat === undefined ||\n headerFormat === undefined\n ) {\n return Object.freeze({\n ok: false,\n errors: Object.freeze(errors),\n });\n }\n\n return Object.freeze({\n ok: true,\n value: Object.freeze({\n format: headerFormat,\n extension: headerFormat === \"wav\" ? \".wav\" : \".mp3\",\n mimeType: headerFormat === \"wav\" ? \"audio/wave\" : \"audio/mpeg\",\n }),\n errors: [] as const,\n });\n}\n\nexport function validateWaveformPeaks(\n waveform: WaveformPeaksV1,\n): readonly string[] {\n const errors: string[] = [];\n\n if (waveform.peaks.length === 0) {\n errors.push(\"waveform.peaks must contain at least one value.\");\n }\n\n waveform.peaks.forEach((peak, index) => {\n if (!Number.isFinite(peak) || peak < 0 || peak > 1) {\n errors.push(\n `waveform.peaks[${String(index)}] must be a finite number between 0 and 1.`,\n );\n }\n });\n\n return Object.freeze(errors);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { n as PlayerError, w as PlayerMediaSource } from './player-CE714iU_.js';
1
+ import { o as PlayerError, x as PlayerMediaSource } from './player-DRQO7SLs.js';
2
2
 
3
3
  type PlayerMediaEventType = "loadstart" | "loadedmetadata" | "canplay" | "play" | "playing" | "pause" | "waiting" | "stalled" | "seeking" | "seeked" | "timeupdate" | "ended" | "error" | "durationchange" | "volumechange";
4
4
  interface PlayerMediaEvent {
@@ -56,7 +56,25 @@ interface PlayerMediaItem {
56
56
  readonly source: PlayerMediaSource;
57
57
  readonly durationHintSec?: number;
58
58
  readonly waveform?: PlayerWaveform;
59
+ /**
60
+ * Consumer-neutral identity for intrinsic Release or Podcast content.
61
+ * Generic/Cue media leaves this undefined. Core preserves but does not
62
+ * interpret this metadata.
63
+ */
64
+ readonly contentContext?: PlayerContentContext;
59
65
  }
66
+ type PlayerContentContext = {
67
+ readonly sourceType: "release-track";
68
+ readonly releaseId: string;
69
+ readonly trackId: string;
70
+ readonly releaseTitle: string;
71
+ readonly artistName: string;
72
+ } | {
73
+ readonly sourceType: "podcast-episode";
74
+ readonly programId: string;
75
+ readonly episodeId: string;
76
+ readonly programTitle: string;
77
+ };
60
78
  interface QueueItem {
61
79
  readonly queueItemId: string;
62
80
  readonly item: PlayerMediaItem;
@@ -82,7 +100,7 @@ type PlaybackContextInput = {
82
100
  readonly label?: string;
83
101
  readonly queue: readonly QueueItem[];
84
102
  };
85
- type PlayerErrorCode = "autoplay-blocked" | "network" | "cors" | "decode" | "unsupported" | "audio-context" | "unknown";
103
+ type PlayerErrorCode = "autoplay-blocked" | "network" | "cors" | "decode" | "unsupported" | "seek" | "audio-context" | "unknown";
86
104
  interface PlayerError {
87
105
  readonly code: PlayerErrorCode;
88
106
  readonly recoverable: boolean;
@@ -262,4 +280,4 @@ interface PlayerDebugController {
262
280
  exportProductionConfigJson(): string;
263
281
  }
264
282
 
265
- export type { ActivatePlaybackContextOptions as A, BoundPlayerCommands as B, PlayerStore as C, PlayerViewProps as D, PlayerWaveform as E, FadeCurve as F, PodcastPreviousMode as G, SetQueueOptions as H, StopOptions as I, MediaKind as M, PauseOptions as P, QueueItem as Q, RepeatMode as R, SeekCommitMode as S, BoundPlayerViewState as a, PersistMode as b, PlaybackContextInput as c, PlaybackContextMode as d, PlaybackContextState as e, PlaybackStatus as f, PlaybackTransitionCause as g, PlayerAppearance as h, PlayerCommandResult as i, PlayerCommands as j, PlayerConfigImportResult as k, PlayerDebugController as l, PlayerDebugSnapshot as m, PlayerError as n, PlayerErrorCode as o, PlayerExperienceConfig as p, PlayerExperienceConfigEnvelope as q, PlayerExperienceConfigStore as r, PlayerExperiencePreset as s, PlayerHostConfig as t, PlayerMediaAdapter as u, PlayerMediaItem as v, PlayerMediaSource as w, PlayerMediaSyncReason as x, PlayerRuntimeStatus as y, PlayerState as z };
283
+ export type { ActivatePlaybackContextOptions as A, BoundPlayerCommands as B, PlayerState as C, PlayerStore as D, PlayerViewProps as E, FadeCurve as F, PlayerWaveform as G, PodcastPreviousMode as H, SetQueueOptions as I, StopOptions as J, MediaKind as M, PauseOptions as P, QueueItem as Q, RepeatMode as R, SeekCommitMode as S, BoundPlayerViewState as a, PersistMode as b, PlaybackContextInput as c, PlaybackContextMode as d, PlaybackContextState as e, PlaybackStatus as f, PlaybackTransitionCause as g, PlayerAppearance as h, PlayerCommandResult as i, PlayerCommands as j, PlayerConfigImportResult as k, PlayerContentContext as l, PlayerDebugController as m, PlayerDebugSnapshot as n, PlayerError as o, PlayerErrorCode as p, PlayerExperienceConfig as q, PlayerExperienceConfigEnvelope as r, PlayerExperienceConfigStore as s, PlayerExperiencePreset as t, PlayerHostConfig as u, PlayerMediaAdapter as v, PlayerMediaItem as w, PlayerMediaSource as x, PlayerMediaSyncReason as y, PlayerRuntimeStatus as z };
@@ -1,5 +1,5 @@
1
- import { F as FadeCurve } from '../player-CE714iU_.js';
2
- export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from '../media-element-vFtmw4mQ.js';
1
+ import { F as FadeCurve } from '../player-DRQO7SLs.js';
2
+ export { M as MediaElementPort, a as MediaElementStateSnapshot, P as PlayerMediaEvent, b as PlayerMediaEventListener, c as PlayerMediaEventType } from '../media-element-BBgNBpqF.js';
3
3
 
4
4
  interface GainTransition {
5
5
  readonly durationMs: number;
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { j as PlayerCommands, x as PlayerMediaSyncReason, Q as QueueItem, p as PlayerExperienceConfig, y as PlayerRuntimeStatus, C as PlayerStore, r as PlayerExperienceConfigStore, z as PlayerState, c as PlaybackContextInput, a as BoundPlayerViewState, B as BoundPlayerCommands, h as PlayerAppearance } from '../player-CE714iU_.js';
4
- import { c as PlayerMediaEventType, a as MediaElementStateSnapshot } from '../media-element-vFtmw4mQ.js';
3
+ import { j as PlayerCommands, y as PlayerMediaSyncReason, Q as QueueItem, q as PlayerExperienceConfig, z as PlayerRuntimeStatus, D as PlayerStore, s as PlayerExperienceConfigStore, C as PlayerState, c as PlaybackContextInput, a as BoundPlayerViewState, B as BoundPlayerCommands, h as PlayerAppearance } from '../player-DRQO7SLs.js';
4
+ import { c as PlayerMediaEventType, a as MediaElementStateSnapshot } from '../media-element-BBgNBpqF.js';
5
5
 
6
6
  type PlayerAudioMode = "auto" | "web-audio" | "html-media";
7
7
  type ResolvedPlayerAudioMode = "web-audio" | "html-media";