@mattebox/player-diagnostics 0.9.0 → 0.10.1

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.
Files changed (99) hide show
  1. package/README.md +2 -0
  2. package/dist/cdn/mattebox-player-diagnostics.min.js +1 -1
  3. package/dist/charts.js +1 -2
  4. package/dist/dom.js +1 -2
  5. package/dist/element.d.ts +13 -2
  6. package/dist/element.d.ts.map +1 -1
  7. package/dist/element.js +35 -11
  8. package/dist/element.js.map +1 -1
  9. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/asyncToGenerator.js +1 -2
  10. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/defineProperty.js +1 -2
  11. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/objectSpread2.js +1 -2
  12. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/toPrimitive.js +1 -2
  13. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/toPropertyKey.js +1 -2
  14. package/dist/es2015/_virtual/{_@oxc-project_runtime@0.154.0 → _@oxc-project_runtime@0.155.0}/helpers/esm/typeof.js +1 -2
  15. package/dist/es2015/charts.js +1 -2
  16. package/dist/es2015/dom.js +1 -2
  17. package/dist/es2015/element.js +39 -17
  18. package/dist/es2015/format.js +1 -2
  19. package/dist/es2015/host.js +1 -2
  20. package/dist/es2015/icon.js +1 -2
  21. package/dist/es2015/index.js +1 -2
  22. package/dist/es2015/locales/ar.js +8 -0
  23. package/dist/es2015/locales/ca.js +8 -0
  24. package/dist/es2015/locales/de.js +8 -0
  25. package/dist/es2015/locales/es.js +8 -0
  26. package/dist/es2015/locales/fr.js +8 -0
  27. package/dist/es2015/locales/hi.js +8 -0
  28. package/dist/es2015/locales/it.js +8 -0
  29. package/dist/es2015/locales/ja.js +8 -0
  30. package/dist/es2015/locales/ko.js +8 -0
  31. package/dist/es2015/locales/pt.js +8 -0
  32. package/dist/es2015/locales/zh.js +8 -0
  33. package/dist/es2015/report.js +16 -4
  34. package/dist/es2015/sampler.js +1 -2
  35. package/dist/es2015/style.js +0 -1
  36. package/dist/es2015/support.js +3 -4
  37. package/dist/es2015/trace.js +2 -3
  38. package/dist/format.js +1 -2
  39. package/dist/host.js +1 -2
  40. package/dist/icon.js +1 -2
  41. package/dist/index.d.ts +2 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/locales/ar.d.ts +8 -0
  46. package/dist/locales/ar.d.ts.map +1 -0
  47. package/dist/locales/ar.js +10 -0
  48. package/dist/locales/ar.js.map +1 -0
  49. package/dist/locales/ca.d.ts +8 -0
  50. package/dist/locales/ca.d.ts.map +1 -0
  51. package/dist/locales/ca.js +10 -0
  52. package/dist/locales/ca.js.map +1 -0
  53. package/dist/locales/de.d.ts +8 -0
  54. package/dist/locales/de.d.ts.map +1 -0
  55. package/dist/locales/de.js +10 -0
  56. package/dist/locales/de.js.map +1 -0
  57. package/dist/locales/es.d.ts +8 -0
  58. package/dist/locales/es.d.ts.map +1 -0
  59. package/dist/locales/es.js +10 -0
  60. package/dist/locales/es.js.map +1 -0
  61. package/dist/locales/fr.d.ts +8 -0
  62. package/dist/locales/fr.d.ts.map +1 -0
  63. package/dist/locales/fr.js +10 -0
  64. package/dist/locales/fr.js.map +1 -0
  65. package/dist/locales/hi.d.ts +8 -0
  66. package/dist/locales/hi.d.ts.map +1 -0
  67. package/dist/locales/hi.js +10 -0
  68. package/dist/locales/hi.js.map +1 -0
  69. package/dist/locales/it.d.ts +8 -0
  70. package/dist/locales/it.d.ts.map +1 -0
  71. package/dist/locales/it.js +10 -0
  72. package/dist/locales/it.js.map +1 -0
  73. package/dist/locales/ja.d.ts +8 -0
  74. package/dist/locales/ja.d.ts.map +1 -0
  75. package/dist/locales/ja.js +10 -0
  76. package/dist/locales/ja.js.map +1 -0
  77. package/dist/locales/ko.d.ts +8 -0
  78. package/dist/locales/ko.d.ts.map +1 -0
  79. package/dist/locales/ko.js +10 -0
  80. package/dist/locales/ko.js.map +1 -0
  81. package/dist/locales/pt.d.ts +8 -0
  82. package/dist/locales/pt.d.ts.map +1 -0
  83. package/dist/locales/pt.js +10 -0
  84. package/dist/locales/pt.js.map +1 -0
  85. package/dist/locales/zh.d.ts +8 -0
  86. package/dist/locales/zh.d.ts.map +1 -0
  87. package/dist/locales/zh.js +10 -0
  88. package/dist/locales/zh.js.map +1 -0
  89. package/dist/messages.d.ts +22 -0
  90. package/dist/messages.d.ts.map +1 -0
  91. package/dist/report.d.ts +9 -0
  92. package/dist/report.d.ts.map +1 -1
  93. package/dist/report.js +12 -4
  94. package/dist/report.js.map +1 -1
  95. package/dist/sampler.js +1 -2
  96. package/dist/style.js +0 -1
  97. package/dist/support.js +1 -2
  98. package/dist/trace.js +1 -2
  99. package/package.json +9 -4
package/dist/report.js CHANGED
@@ -1,4 +1,12 @@
1
- //#region src/report.ts
1
+ // src/report.ts
2
+ /** The trackers of `player`, or none on a player older than trackers. */
3
+ function trackersOf(player) {
4
+ return (player.trackers?.list ?? []).map((tracker) => ({
5
+ name: tracker.name,
6
+ session: tracker.session ?? null,
7
+ device: tracker.device ?? null
8
+ }));
9
+ }
2
10
  function ranges(list) {
3
11
  return Array.from({ length: list.length }, (_, i) => ({
4
12
  start: list.start(i),
@@ -132,10 +140,10 @@ function buildReport(sources) {
132
140
  samples,
133
141
  marks: sources.marks.filter((mark) => mark.t >= since),
134
142
  support: sources.support,
135
- trace: engine === null ? null : sources.history
143
+ trace: engine === null ? null : sources.history,
144
+ trackers: trackersOf(player)
136
145
  };
137
146
  }
138
- //#endregion
139
- export { buildReport, engineFacts, playbackFacts };
147
+ export { buildReport, engineFacts, playbackFacts, trackersOf };
140
148
 
141
149
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","names":[],"sources":["../src/report.ts"],"sourcesContent":["/**\n * The report: everything the panel shows, as one plain object a page can\n * send when something goes wrong, and the trace the engine's guide asks\n * for with every error report (chapter 12), as the element kept it: see\n * `trace.ts` for what is kept of each entry. Every field is serializable;\n * a native session has no engine part.\n */\nimport type { Mattebox } from 'mattebox';\nimport type { PlayerError, PlayerHost } from './host.js';\nimport type { Counters, Mark, Sample } from './sampler.js';\nimport type { Support } from './support.js';\n\nexport interface RangeReport {\n readonly start: number;\n readonly end: number;\n}\n\nexport interface PlaybackReport {\n readonly currentTime: number;\n readonly duration: number;\n readonly paused: boolean;\n readonly ended: boolean;\n readonly seeking: boolean;\n readonly readyState: number;\n readonly networkState: number;\n readonly playbackRate: number;\n readonly volume: number;\n readonly muted: boolean;\n readonly videoWidth: number;\n readonly videoHeight: number;\n readonly buffered: readonly RangeReport[];\n readonly seekable: readonly RangeReport[];\n readonly frames: { readonly decoded: number; readonly dropped: number } | null;\n readonly mediaError: { readonly code: number; readonly message: string } | null;\n}\n\nexport interface EngineReport {\n readonly phase: string;\n readonly capabilities: readonly string[];\n readonly throughput: { readonly slow: number; readonly fast: number };\n readonly bufferGoal: number;\n readonly buffers: ReadonlyArray<{\n readonly id: string;\n readonly codecs: string;\n readonly ranges: readonly RangeReport[];\n }>;\n readonly inflight: ReadonlyArray<{\n readonly trackId: string;\n readonly seq: number;\n readonly url: string;\n }>;\n readonly live: {\n readonly start: number;\n readonly end: number;\n readonly edge: number;\n readonly latency: number | null;\n } | null;\n readonly tracks: {\n readonly active: Readonly<Record<string, string | null>>;\n readonly available: ReadonlyArray<{\n readonly id: string;\n readonly contentType: string;\n readonly mimeType: string;\n readonly lang: string | null;\n readonly role: string | null;\n readonly renditions: number;\n }>;\n };\n readonly quality: {\n readonly playing: string | null;\n readonly active: string | null;\n readonly pinned: string | null;\n readonly allowed: readonly string[];\n readonly renditions: ReadonlyArray<{\n readonly id: string;\n readonly bitrate: number;\n readonly width: number | null;\n readonly height: number | null;\n readonly frameRate: number | null;\n readonly codecs: string | null;\n }>;\n };\n readonly drm: {\n readonly keySystem: string | null;\n readonly sessions: ReadonlyArray<{ readonly keyId: string; readonly status: string }>;\n } | null;\n /** The engine's qoe stage figures for this load, or null without the stage. */\n readonly qoe: QoeFigures | null;\n readonly error: {\n readonly category: string;\n readonly code: string;\n readonly fatal: boolean;\n readonly recoverable: boolean;\n readonly context: Readonly<Record<string, unknown>> | null;\n } | null;\n}\n\nexport interface DiagnosticsReport {\n /** When the report was taken, ISO 8601. */\n readonly at: string;\n readonly userAgent: string;\n readonly source: {\n readonly url: string | null;\n readonly type: string | null;\n /** The name of the handler that won, or null before a session. */\n readonly handler: string | null;\n };\n readonly playback: PlaybackReport;\n /** The player's fatal error of the current load, or null. */\n readonly error: PlayerError | null;\n /** Null for a native session. */\n readonly engine: EngineReport | null;\n readonly counters: Counters;\n /** The last two minutes of samples, and the marks in them. */\n readonly samples: readonly Sample[];\n readonly marks: readonly Mark[];\n /** What the browser supports, when it was probed before the report. */\n readonly support: Support | null;\n /** The trace entries the element kept, slimmed, oldest first, or null for a native session. */\n readonly trace: readonly unknown[] | null;\n}\n\n/** The figures of the engine's qoe stage, as `engine.qoe` gives them. */\nexport interface QoeFigures {\n /** Seconds from the load, or the first play if later, to the first frame playing. */\n readonly startupTime: number | null;\n readonly rebuffers: number;\n /** Seconds spent rebuffering, the current wait included. */\n readonly rebufferDuration: number;\n /** Video quality changes after the first selection. */\n readonly switches: number;\n}\n\n/** The optional namespaces the report reads, as the player reads them: a cast, once. */\ninterface Namespaces {\n readonly live?: { readonly latency: number | null };\n readonly qoe?: QoeFigures;\n readonly drm?: {\n readonly keySystem: string | null;\n readonly sessions: ReadonlyArray<{ readonly keyId: string; readonly status: string }>;\n };\n}\n\nfunction ranges(list: TimeRanges): RangeReport[] {\n return Array.from({ length: list.length }, (_, i) => ({\n start: list.start(i),\n end: list.end(i),\n }));\n}\n\nexport function playbackFacts(video: HTMLVideoElement): PlaybackReport {\n const quality = video.getVideoPlaybackQuality?.();\n return {\n currentTime: video.currentTime,\n duration: video.duration,\n paused: video.paused,\n ended: video.ended,\n seeking: video.seeking,\n readyState: video.readyState,\n networkState: video.networkState,\n playbackRate: video.playbackRate,\n volume: video.volume,\n muted: video.muted,\n videoWidth: video.videoWidth,\n videoHeight: video.videoHeight,\n buffered: ranges(video.buffered),\n seekable: ranges(video.seekable),\n frames:\n quality === undefined\n ? null\n : { decoded: quality.totalVideoFrames, dropped: quality.droppedVideoFrames },\n mediaError:\n video.error === null ? null : { code: video.error.code, message: video.error.message },\n };\n}\n\nexport function engineFacts(engine: Mattebox): EngineReport {\n const state = engine.stats.snapshot();\n const optional = engine as Namespaces;\n const error = engine.error;\n return {\n phase: state.lifecycle.phase,\n capabilities: [...engine.capabilities()],\n throughput: { slow: state.stats.throughputEwma, fast: state.stats.throughputFastEwma },\n bufferGoal: state.scheduling.bufferGoal,\n buffers: [...state.buffers.entries()].map(([id, buffer]) => ({\n id,\n codecs: buffer.codecs,\n ranges: buffer.ranges.map((range) => ({ start: range.start, end: range.end })),\n })),\n inflight: [...state.scheduling.inflight.values()].map((request) => ({\n trackId: request.trackId,\n seq: request.seq,\n url: request.url,\n })),\n live:\n state.live === null\n ? null\n : {\n start: state.live.span.start,\n end: state.live.span.end,\n edge: state.live.edge,\n latency: optional.live?.latency ?? null,\n },\n tracks: {\n active: Object.fromEntries(\n (['video', 'audio', 'text'] as const).map((type) => [\n type,\n engine.tracks.active(type)?.id ?? null,\n ]),\n ),\n available: engine.tracks.available.map((track) => ({\n id: track.id,\n contentType: track.contentType,\n mimeType: track.mimeType,\n lang: track.lang ?? null,\n role: track.role ?? null,\n renditions: track.renditions.length,\n })),\n },\n quality: {\n playing: engine.quality.playing?.id ?? null,\n active: engine.quality.active?.id ?? null,\n pinned: engine.quality.pinned,\n allowed: engine.quality.allowed.map((r) => r.id),\n renditions: engine.quality.renditions.map((r) => ({\n id: r.id,\n bitrate: r.bitrate,\n width: r.width ?? null,\n height: r.height ?? null,\n frameRate: r.frameRate ?? null,\n codecs: r.codecs,\n })),\n },\n drm:\n optional.drm === undefined\n ? null\n : { keySystem: optional.drm.keySystem, sessions: [...optional.drm.sessions] },\n qoe:\n optional.qoe === undefined\n ? null\n : {\n startupTime: optional.qoe.startupTime,\n rebuffers: optional.qoe.rebuffers,\n rebufferDuration: optional.qoe.rebufferDuration,\n switches: optional.qoe.switches,\n },\n error:\n error === null\n ? null\n : {\n category: error.category,\n code: error.code,\n fatal: error.fatal,\n recoverable: error.recoverable,\n context: error.context ?? null,\n },\n };\n}\n\n/** Two minutes of samples at two a second, and the marks of the same two minutes. */\nconst KEEP_SAMPLES = 240;\nconst KEEP_MS = 120_000;\n\nexport interface ReportSources {\n readonly player: PlayerHost;\n readonly samples: readonly Sample[];\n readonly marks: readonly Mark[];\n readonly counters: Counters;\n /** The trace entries kept, slimmed, oldest first. */\n readonly history: readonly unknown[];\n readonly support: Support | null;\n}\n\nexport function buildReport(sources: ReportSources): DiagnosticsReport {\n const { player } = sources;\n const engine = player.engine;\n const samples = sources.samples.slice(-KEEP_SAMPLES);\n const since = performance.now() - KEEP_MS;\n return {\n at: new Date().toISOString(),\n userAgent: navigator.userAgent,\n source: {\n url: player.getAttribute('src'),\n type: player.getAttribute('type'),\n handler: player.player?.session?.handler ?? null,\n },\n playback: playbackFacts(player.video),\n error: player.error,\n engine: engine === null ? null : engineFacts(engine),\n counters: sources.counters,\n samples,\n marks: sources.marks.filter((mark) => mark.t >= since),\n support: sources.support,\n trace: engine === null ? null : sources.history,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"report.js","names":[],"sources":["../src/report.ts"],"sourcesContent":["/**\n * The report: everything the panel shows, as one plain object a page can\n * send when something goes wrong, and the trace the engine's guide asks\n * for with every error report (chapter 12), as the element kept it: see\n * `trace.ts` for what is kept of each entry. Every field is serializable;\n * a native session has no engine part.\n */\nimport type { Mattebox } from 'mattebox';\nimport type { PlayerError, PlayerHost } from './host.js';\nimport type { Counters, Mark, Sample } from './sampler.js';\nimport type { Support } from './support.js';\n\nexport interface RangeReport {\n readonly start: number;\n readonly end: number;\n}\n\nexport interface PlaybackReport {\n readonly currentTime: number;\n readonly duration: number;\n readonly paused: boolean;\n readonly ended: boolean;\n readonly seeking: boolean;\n readonly readyState: number;\n readonly networkState: number;\n readonly playbackRate: number;\n readonly volume: number;\n readonly muted: boolean;\n readonly videoWidth: number;\n readonly videoHeight: number;\n readonly buffered: readonly RangeReport[];\n readonly seekable: readonly RangeReport[];\n readonly frames: { readonly decoded: number; readonly dropped: number } | null;\n readonly mediaError: { readonly code: number; readonly message: string } | null;\n}\n\nexport interface EngineReport {\n readonly phase: string;\n readonly capabilities: readonly string[];\n readonly throughput: { readonly slow: number; readonly fast: number };\n readonly bufferGoal: number;\n readonly buffers: ReadonlyArray<{\n readonly id: string;\n readonly codecs: string;\n readonly ranges: readonly RangeReport[];\n }>;\n readonly inflight: ReadonlyArray<{\n readonly trackId: string;\n readonly seq: number;\n readonly url: string;\n }>;\n readonly live: {\n readonly start: number;\n readonly end: number;\n readonly edge: number;\n readonly latency: number | null;\n } | null;\n readonly tracks: {\n readonly active: Readonly<Record<string, string | null>>;\n readonly available: ReadonlyArray<{\n readonly id: string;\n readonly contentType: string;\n readonly mimeType: string;\n readonly lang: string | null;\n readonly role: string | null;\n readonly renditions: number;\n }>;\n };\n readonly quality: {\n readonly playing: string | null;\n readonly active: string | null;\n readonly pinned: string | null;\n readonly allowed: readonly string[];\n readonly renditions: ReadonlyArray<{\n readonly id: string;\n readonly bitrate: number;\n readonly width: number | null;\n readonly height: number | null;\n readonly frameRate: number | null;\n readonly codecs: string | null;\n }>;\n };\n readonly drm: {\n readonly keySystem: string | null;\n readonly sessions: ReadonlyArray<{ readonly keyId: string; readonly status: string }>;\n } | null;\n /** The engine's qoe stage figures for this load, or null without the stage. */\n readonly qoe: QoeFigures | null;\n readonly error: {\n readonly category: string;\n readonly code: string;\n readonly fatal: boolean;\n readonly recoverable: boolean;\n readonly context: Readonly<Record<string, unknown>> | null;\n } | null;\n}\n\nexport interface DiagnosticsReport {\n /** When the report was taken, ISO 8601. */\n readonly at: string;\n readonly userAgent: string;\n readonly source: {\n readonly url: string | null;\n readonly type: string | null;\n /** The name of the handler that won, or null before a session. */\n readonly handler: string | null;\n };\n readonly playback: PlaybackReport;\n /** The player's fatal error of the current load, or null. */\n readonly error: PlayerError | null;\n /** Null for a native session. */\n readonly engine: EngineReport | null;\n readonly counters: Counters;\n /** The last two minutes of samples, and the marks in them. */\n readonly samples: readonly Sample[];\n readonly marks: readonly Mark[];\n /** What the browser supports, when it was probed before the report. */\n readonly support: Support | null;\n /** The trace entries the element kept, slimmed, oldest first, or null for a native session. */\n readonly trace: readonly unknown[] | null;\n /** The page's trackers on the player, with the ids support asks for. */\n readonly trackers: readonly TrackerReport[];\n}\n\nexport interface TrackerReport {\n readonly name: string;\n readonly session: string | null;\n readonly device: string | null;\n}\n\n/** The trackers of `player`, or none on a player older than trackers. */\nexport function trackersOf(player: PlayerHost): TrackerReport[] {\n const list = (player as Partial<PlayerHost>).trackers?.list ?? [];\n return list.map((tracker) => ({\n name: tracker.name,\n session: tracker.session ?? null,\n device: tracker.device ?? null,\n }));\n}\n\n/** The figures of the engine's qoe stage, as `engine.qoe` gives them. */\nexport interface QoeFigures {\n /** Seconds from the load, or the first play if later, to the first frame playing. */\n readonly startupTime: number | null;\n readonly rebuffers: number;\n /** Seconds spent rebuffering, the current wait included. */\n readonly rebufferDuration: number;\n /** Video quality changes after the first selection. */\n readonly switches: number;\n}\n\n/** The optional namespaces the report reads, as the player reads them: a cast, once. */\ninterface Namespaces {\n readonly live?: { readonly latency: number | null };\n readonly qoe?: QoeFigures;\n readonly drm?: {\n readonly keySystem: string | null;\n readonly sessions: ReadonlyArray<{ readonly keyId: string; readonly status: string }>;\n };\n}\n\nfunction ranges(list: TimeRanges): RangeReport[] {\n return Array.from({ length: list.length }, (_, i) => ({\n start: list.start(i),\n end: list.end(i),\n }));\n}\n\nexport function playbackFacts(video: HTMLVideoElement): PlaybackReport {\n const quality = video.getVideoPlaybackQuality?.();\n return {\n currentTime: video.currentTime,\n duration: video.duration,\n paused: video.paused,\n ended: video.ended,\n seeking: video.seeking,\n readyState: video.readyState,\n networkState: video.networkState,\n playbackRate: video.playbackRate,\n volume: video.volume,\n muted: video.muted,\n videoWidth: video.videoWidth,\n videoHeight: video.videoHeight,\n buffered: ranges(video.buffered),\n seekable: ranges(video.seekable),\n frames:\n quality === undefined\n ? null\n : { decoded: quality.totalVideoFrames, dropped: quality.droppedVideoFrames },\n mediaError:\n video.error === null ? null : { code: video.error.code, message: video.error.message },\n };\n}\n\nexport function engineFacts(engine: Mattebox): EngineReport {\n const state = engine.stats.snapshot();\n const optional = engine as Namespaces;\n const error = engine.error;\n return {\n phase: state.lifecycle.phase,\n capabilities: [...engine.capabilities()],\n throughput: { slow: state.stats.throughputEwma, fast: state.stats.throughputFastEwma },\n bufferGoal: state.scheduling.bufferGoal,\n buffers: [...state.buffers.entries()].map(([id, buffer]) => ({\n id,\n codecs: buffer.codecs,\n ranges: buffer.ranges.map((range) => ({ start: range.start, end: range.end })),\n })),\n inflight: [...state.scheduling.inflight.values()].map((request) => ({\n trackId: request.trackId,\n seq: request.seq,\n url: request.url,\n })),\n live:\n state.live === null\n ? null\n : {\n start: state.live.span.start,\n end: state.live.span.end,\n edge: state.live.edge,\n latency: optional.live?.latency ?? null,\n },\n tracks: {\n active: Object.fromEntries(\n (['video', 'audio', 'text'] as const).map((type) => [\n type,\n engine.tracks.active(type)?.id ?? null,\n ]),\n ),\n available: engine.tracks.available.map((track) => ({\n id: track.id,\n contentType: track.contentType,\n mimeType: track.mimeType,\n lang: track.lang ?? null,\n role: track.role ?? null,\n renditions: track.renditions.length,\n })),\n },\n quality: {\n playing: engine.quality.playing?.id ?? null,\n active: engine.quality.active?.id ?? null,\n pinned: engine.quality.pinned,\n allowed: engine.quality.allowed.map((r) => r.id),\n renditions: engine.quality.renditions.map((r) => ({\n id: r.id,\n bitrate: r.bitrate,\n width: r.width ?? null,\n height: r.height ?? null,\n frameRate: r.frameRate ?? null,\n codecs: r.codecs,\n })),\n },\n drm:\n optional.drm === undefined\n ? null\n : { keySystem: optional.drm.keySystem, sessions: [...optional.drm.sessions] },\n qoe:\n optional.qoe === undefined\n ? null\n : {\n startupTime: optional.qoe.startupTime,\n rebuffers: optional.qoe.rebuffers,\n rebufferDuration: optional.qoe.rebufferDuration,\n switches: optional.qoe.switches,\n },\n error:\n error === null\n ? null\n : {\n category: error.category,\n code: error.code,\n fatal: error.fatal,\n recoverable: error.recoverable,\n context: error.context ?? null,\n },\n };\n}\n\n/** Two minutes of samples at two a second, and the marks of the same two minutes. */\nconst KEEP_SAMPLES = 240;\nconst KEEP_MS = 120_000;\n\nexport interface ReportSources {\n readonly player: PlayerHost;\n readonly samples: readonly Sample[];\n readonly marks: readonly Mark[];\n readonly counters: Counters;\n /** The trace entries kept, slimmed, oldest first. */\n readonly history: readonly unknown[];\n readonly support: Support | null;\n}\n\nexport function buildReport(sources: ReportSources): DiagnosticsReport {\n const { player } = sources;\n const engine = player.engine;\n const samples = sources.samples.slice(-KEEP_SAMPLES);\n const since = performance.now() - KEEP_MS;\n return {\n at: new Date().toISOString(),\n userAgent: navigator.userAgent,\n source: {\n url: player.getAttribute('src'),\n type: player.getAttribute('type'),\n handler: player.player?.session?.handler ?? null,\n },\n playback: playbackFacts(player.video),\n error: player.error,\n engine: engine === null ? null : engineFacts(engine),\n counters: sources.counters,\n samples,\n marks: sources.marks.filter((mark) => mark.t >= since),\n support: sources.support,\n trace: engine === null ? null : sources.history,\n trackers: trackersOf(player),\n };\n}\n"],"mappings":"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"}
package/dist/sampler.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { slimEntry } from "./trace.js";
2
- //#region src/sampler.ts
2
+ // src/sampler.ts
3
3
  /** Twenty minutes at two samples a second. */
4
4
  const MAX_SAMPLES = 2400;
5
5
  /** Trace entries kept, the engine's own default for a ring. */
@@ -190,7 +190,6 @@ function createSampler() {
190
190
  }
191
191
  };
192
192
  }
193
- //#endregion
194
193
  export { createSampler };
195
194
 
196
195
  //# sourceMappingURL=sampler.js.map
package/dist/style.js CHANGED
@@ -1,5 +1,4 @@
1
1
  const STYLE = ":host{--mbx-chart-1:#5aa9e0;--mbx-chart-2:#6fbf8f;--mbx-chart-3:#d9a83f;--mbx-chart-4:#e05a6e;--mbx-chart-5:#a98fe0;display:inline-flex;position:relative}:host([hidden]){display:none}:host([inline]){display:block}[part~=button]{width:2.5em;height:2.5em;font:inherit;color:inherit;border-radius:var(--mbx-radius);cursor:pointer;opacity:.9;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}[part~=button]:hover{opacity:1}[part~=button]:focus{outline:2px solid var(--mbx-accent);outline-offset:-2px}[part~=button]:focus:not(:focus-visible){outline:none}[part~=icon],::slotted(*){fill:currentColor;width:1.75em;height:1.75em}:host([inline]) [part~=button]{display:none}[part~=panel]{box-sizing:border-box;width:46.6667em;color:var(--mbx-text,#f3ede4);border-radius:var(--mbx-radius,4px);font:400 .75em / 1.5 var(--mbx-mono,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);text-align:left;white-space:normal;background:#1c1c20f2;flex-direction:column;margin-bottom:.6667em;display:flex;position:absolute;bottom:100%;right:0;overflow:hidden;box-shadow:0 4px 16px #00000080}[part~=panel][hidden]{display:none}:host([inline]) [part~=panel]{width:auto;max-height:none;box-shadow:none;border-radius:0;margin:0;position:static}[part~=head]{border-bottom:1px solid #ffffff1f;align-items:center;padding:.5em;display:flex}[part~=tab],[part~=chart-tab]{font:inherit;color:var(--mbx-muted,#aaa49a);border-radius:var(--mbx-radius,4px);cursor:pointer;background:0 0;border:0;padding:.25em .6667em}[part~=tab][aria-selected=true],[part~=chart-tab][aria-selected=true]{color:var(--mbx-text,#f3ede4);background:#ffffff1f}[part~=copy],[part~=close],[part~=window]{font:inherit;color:inherit;border-radius:var(--mbx-radius,4px);cursor:pointer;background:0 0;border:1px solid #ffffff40;padding:.1667em .6667em}[part~=head]>*,[part~=tabs]>*{margin:0 .1667em}[part~=tabs]{align-items:center;margin:0;display:flex}[part~=head]>[part~=copy],[part~=chart-tabs]>[part~=window]{margin-left:auto}[part~=window] option{color:#000}[part~=tab]:focus,[part~=chart-tab]:focus,[part~=copy]:focus,[part~=close]:focus,[part~=window]:focus{outline:2px solid var(--mbx-accent,#e0543c);outline-offset:-2px}[part~=tab]:focus:not(:focus-visible){outline:none}[part~=chart-tab]:focus:not(:focus-visible){outline:none}[part~=copy]:focus:not(:focus-visible){outline:none}[part~=close]:focus:not(:focus-visible){outline:none}[part~=window]:focus:not(:focus-visible){outline:none}[part~=body]{overscroll-behavior:contain;min-height:0;padding:.6667em;overflow:auto}[part~=body]:focus{outline:2px solid var(--mbx-accent,#e0543c);outline-offset:-2px}[part~=body]:focus:not(:focus-visible){outline:none}[part~=page][hidden]{display:none}[part~=rows]{grid-template-columns:max-content 1fr;gap:.1667em 1em;margin:0;display:grid}[part~=key]{color:var(--mbx-muted,#aaa49a);white-space:nowrap}[part~=value]{overflow-wrap:anywhere;margin:0}[part~=heading]{letter-spacing:.06em;text-transform:uppercase;color:var(--mbx-muted,#aaa49a);margin:.9091em 0 .3636em;font-size:.9167em;font-weight:600}[part~=heading]:first-child{margin-top:0}[part~=note]{color:var(--mbx-muted,#aaa49a);margin:0}[part~=chart-tabs]{flex-wrap:wrap;align-items:center;margin:-.1667em -.1667em .3333em;display:flex}[part~=chart-tabs]>*,[part~=chart-tablist]>*{margin:.1667em}[part~=chart-tabs]>[part~=chart-tablist]{flex-wrap:wrap;margin:0;display:flex}[part~=chart]{width:100%;height:13.3333em;display:block}[part~=legend]{color:var(--mbx-muted,#aaa49a);flex-wrap:wrap;margin:.25em -.5em -1px;display:flex}[part~=legend]>*{margin:1px .5em}[part~=swatch]{vertical-align:middle;border-radius:2px;width:.8333em;height:.8333em;margin-right:.3333em;display:inline-block}[part~=readout]{margin-top:.3333em}[part~=table]{border-collapse:collapse;width:100%;margin-bottom:.3333em}[part~=cell]{text-align:left;white-space:nowrap;border-bottom:1px solid #ffffff14;padding:.1667em .5em;font-weight:400}[part~=label]{color:var(--mbx-muted,#aaa49a)}[part~=ok]{color:var(--mbx-chart-2)}[part~=bad]{color:var(--mbx-chart-4)}[part~=na]{color:var(--mbx-muted,#aaa49a)}[part~=ok],[part~=bad],[part~=na],[part~=maybe]{font-weight:600}";
2
- //#endregion
3
2
  export { STYLE };
4
3
 
5
4
  //# sourceMappingURL=style.js.map
package/dist/support.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/support.ts
1
+ // src/support.ts
2
2
  const CODECS = [
3
3
  {
4
4
  label: "H.264 High 4.0",
@@ -330,7 +330,6 @@ function probeSupport() {
330
330
  }))();
331
331
  return cached;
332
332
  }
333
- //#endregion
334
333
  export { probeSupport };
335
334
 
336
335
  //# sourceMappingURL=support.js.map
package/dist/trace.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/trace.ts
1
+ // src/trace.ts
2
2
  /** Segments as a count, whatever their addressing. */
3
3
  function segmentCount(segments) {
4
4
  if (Array.isArray(segments)) return segments.length;
@@ -93,7 +93,6 @@ function slimEntry(entry) {
93
93
  };
94
94
  return JSON.parse(JSON.stringify(slim, serializable));
95
95
  }
96
- //#endregion
97
96
  export { slimEntry };
98
97
 
99
98
  //# sourceMappingURL=trace.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mattebox/player-diagnostics",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "<mbx-diagnostics>: playback stats, charts, engine state and browser support inside <mattebox-player>, and a report to send.",
5
5
  "author": "Josep Boix Requesens",
6
6
  "repository": {
@@ -34,6 +34,11 @@
34
34
  "modern": "./dist/index.js",
35
35
  "default": "./dist/es2015/index.js"
36
36
  },
37
+ "./locales/*": {
38
+ "types": "./dist/locales/*.d.ts",
39
+ "modern": "./dist/locales/*.js",
40
+ "default": "./dist/es2015/locales/*.js"
41
+ },
37
42
  "./package.json": "./package.json"
38
43
  },
39
44
  "files": [
@@ -49,10 +54,10 @@
49
54
  "release:ci": "semantic-release"
50
55
  },
51
56
  "devDependencies": {
52
- "@mattebox/player-core": "^0.7.0"
57
+ "@mattebox/player-core": "^0.9.0"
53
58
  },
54
59
  "peerDependencies": {
55
- "@mattebox/player": ">=0.11.0",
56
- "mattebox": "^0.16.0"
60
+ "@mattebox/player": ">=0.13.0",
61
+ "mattebox": "^0.17.0"
57
62
  }
58
63
  }