@chunkify/analytics 0.1.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.
- package/LICENSE +21 -0
- package/README.md +413 -0
- package/dist/core.d.ts +144 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +660 -0
- package/dist/core.js.map +1 -0
- package/dist/datadog.d.ts +8 -0
- package/dist/datadog.d.ts.map +1 -0
- package/dist/datadog.js +15 -0
- package/dist/datadog.js.map +1 -0
- package/dist/event-types.d.ts +3 -0
- package/dist/event-types.d.ts.map +1 -0
- package/dist/event-types.js +5 -0
- package/dist/event-types.js.map +1 -0
- package/dist/hlsjs.d.ts +10 -0
- package/dist/hlsjs.d.ts.map +1 -0
- package/dist/hlsjs.js +185 -0
- package/dist/hlsjs.js.map +1 -0
- package/dist/http.d.ts +4 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +43 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/mapper.d.ts +11 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +11 -0
- package/dist/mapper.js.map +1 -0
- package/dist/monitor.d.ts +6 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +14 -0
- package/dist/monitor.js.map +1 -0
- package/dist/options.d.ts +4 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +26 -0
- package/dist/options.js.map +1 -0
- package/dist/otlp.d.ts +4 -0
- package/dist/otlp.d.ts.map +1 -0
- package/dist/otlp.js +56 -0
- package/dist/otlp.js.map +1 -0
- package/dist/player.d.ts +8 -0
- package/dist/player.d.ts.map +1 -0
- package/dist/player.js +93 -0
- package/dist/player.js.map +1 -0
- package/dist/posthog.d.ts +8 -0
- package/dist/posthog.d.ts.map +1 -0
- package/dist/posthog.js +15 -0
- package/dist/posthog.js.map +1 -0
- package/dist/shaka.d.ts +26 -0
- package/dist/shaka.d.ts.map +1 -0
- package/dist/shaka.js +164 -0
- package/dist/shaka.js.map +1 -0
- package/dist/videojs.d.ts +11 -0
- package/dist/videojs.d.ts.map +1 -0
- package/dist/videojs.js +77 -0
- package/dist/videojs.js.map +1 -0
- package/package.json +75 -0
- package/src/core.ts +774 -0
- package/src/datadog.ts +24 -0
- package/src/event-types.ts +6 -0
- package/src/hlsjs.ts +192 -0
- package/src/http.ts +43 -0
- package/src/index.ts +11 -0
- package/src/mapper.ts +22 -0
- package/src/monitor.ts +15 -0
- package/src/options.ts +28 -0
- package/src/otlp.ts +70 -0
- package/src/player.ts +96 -0
- package/src/posthog.ts +24 -0
- package/src/shaka.ts +181 -0
- package/src/videojs.ts +89 -0
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["import { analyticsEventTypes, type AnalyticsEventType } from \"./event-types.js\";\nimport { assertAnalyticsOptions } from \"./options.js\";\n\nexport type { AnalyticsEventType } from \"./event-types.js\";\n\nconst sdkVersion = \"0.1.0\"; // x-release-please-version\n\nexport type AnalyticsEndReason = \"ended\" | \"destroyed\" | \"source_changed\" | \"page_exit\";\nexport type AnalyticsErrorCategory = \"aborted\" | \"network\" | \"decode\" | \"unsupported\" | \"unknown\";\nexport type AnalyticsStartupOutcome = \"started\" | \"failed_before_start\" | \"ended_before_start\";\nexport type AnalyticsPlaybackState = \"startup\" | \"resuming\" | \"playing\" | \"paused\" | \"buffering\" |\n \"seeking\" | \"error\" | \"ended\" | \"stopped\";\nexport interface RenditionPlayingTime {\n width: number | null;\n height: number | null;\n codec: string | null;\n bitrate_bps: number | null;\n frame_rate: number | null;\n playing_time_ms: number;\n}\nexport type AnalyticsRendition = Omit<RenditionPlayingTime, \"playing_time_ms\">;\nexport interface ViewMetrics {\n media_duration_seconds: number | null;\n startup_time_ms: number | null;\n first_video_frame_time_ms: number | null;\n playing_time_ms: number;\n rebuffer_count: number;\n rebuffer_duration_ms: number;\n rebuffer_ratio: number | null;\n seek_count: number;\n seek_duration_ms: number;\n maximum_playhead_seconds: number;\n furthest_progress_ratio: number | null;\n video_intrinsic_width_css_px: number | null;\n video_intrinsic_height_css_px: number | null;\n dropped_video_frames: number | null;\n total_video_frames: number | null;\n selected_rendition_width: number | null;\n selected_rendition_height: number | null;\n selected_rendition_codec: string | null;\n selected_rendition_bitrate_bps: number | null;\n rendition_switch_count: number | null;\n rendition_playing_time: RenditionPlayingTime[] | null;\n delivery_request_count: number | null;\n delivery_transferred_bytes: number | null;\n delivery_throughput_bps: number | null;\n}\nexport interface AnalyticsEventEnvelope {\n schema_version: 1;\n event_name: `chunkify.video.${AnalyticsEventType}`;\n event_id: string;\n sequence: number;\n occurred_at: string;\n view_id: string;\n video_id: string;\n sdk_name: \"@chunkify/analytics\";\n sdk_version: string;\n connector_name: string;\n connector_version: string | null;\n player_name: string | null;\n player_version: string | null;\n delivery_hostname: string | null;\n environment: string | null;\n viewer_id: string | null;\n reason: AnalyticsEndReason | null;\n startup_outcome: AnalyticsStartupOutcome | null;\n error_category: AnalyticsErrorCategory | null;\n error_code: string | number | null;\n error_fatal: boolean | null;\n error_playhead_seconds: number | null;\n}\nexport interface AnalyticsViewEvent extends AnalyticsEventEnvelope, ViewMetrics {\n event_name: \"chunkify.video.view_started\" | \"chunkify.video.view_snapshot\" |\n \"chunkify.video.playback_error\" | \"chunkify.video.view_ended\";\n}\nexport interface AnalyticsPlaybackStateEvent extends AnalyticsEventEnvelope, Partial<ViewMetrics> {\n event_name: \"chunkify.video.playback_state_changed\";\n playhead_seconds: number | null;\n from_state: AnalyticsPlaybackState;\n to_state: AnalyticsPlaybackState;\n previous_state_duration_ms: number;\n}\nexport interface AnalyticsRenditionEvent extends AnalyticsEventEnvelope, Partial<ViewMetrics> {\n event_name: \"chunkify.video.rendition_changed\";\n playhead_seconds: number | null;\n previous_rendition_width: number | null;\n previous_rendition_height: number | null;\n previous_rendition_codec: string | null;\n previous_rendition_bitrate_bps: number | null;\n previous_rendition_frame_rate: number | null;\n selected_rendition_width: number | null;\n selected_rendition_height: number | null;\n selected_rendition_codec: string | null;\n selected_rendition_bitrate_bps: number | null;\n selected_rendition_frame_rate: number | null;\n}\nexport type ChunkifyPlayerAnalyticsEvent = AnalyticsViewEvent | AnalyticsPlaybackStateEvent | AnalyticsRenditionEvent;\nexport interface AnalyticsDestination {\n send(event: ChunkifyPlayerAnalyticsEvent): void | Promise<void>;\n}\nexport interface AnalyticsConfig {\n destinations: readonly AnalyticsDestination[];\n environment?: string | undefined;\n viewerId?: string | undefined;\n /** Active playing time between cumulative snapshots. Defaults to 30,000 ms. */\n snapshotIntervalMs?: number | undefined;\n /** Event types passed to destinations. Defaults to all six types. */\n includeEvents?: readonly AnalyticsEventType[] | undefined;\n}\nexport interface AnalyticsOptions extends AnalyticsConfig {\n videoId: string;\n}\nexport interface AnalyticsConnectorSnapshot {\n renditionWidth: number | null;\n renditionHeight: number | null;\n renditionCodec: string | null;\n renditionBitrate: number | null;\n renditionSwitchCount: number | null;\n deliveryRequestCount: number | null;\n deliveryTransferredBytes: number | null;\n deliveryDurationMs: number | null;\n}\nexport interface AnalyticsConnectorError {\n category: AnalyticsErrorCategory;\n code: string | number | null;\n fatal: boolean;\n}\nexport interface AnalyticsConnector {\n name: string;\n version: string | null;\n playerName: string | null;\n playerVersion: string | null;\n snapshot(): AnalyticsConnectorSnapshot;\n subscribeToErrors(listener: (error: AnalyticsConnectorError) => void): () => void;\n /** Fires with the rendition currently reaching playback, including the initial selection. */\n subscribeToRenditions?(listener: (rendition: AnalyticsRendition | null) => void): () => void;\n}\nexport interface AnalyticsSession {\n /** Call immediately before play() to include attempts that reject before a play event. */\n startAttempt(): void;\n /** Finish the current view before its media source or playback engine is replaced. */\n sourceChanged(): void;\n /** Add or replace optional engine-specific measurements for subsequent records. */\n setConnector(connector: AnalyticsConnector | null): void;\n /** End the current view, if any, and remove all analytics listeners. Idempotent. */\n destroy(): void;\n}\n\ninterface View {\n id: string;\n sequence: number;\n startedAt: number;\n startup: number | null;\n firstVideoFrame: number | null;\n frameCallbackId: number | null;\n playing: number;\n playingSince: number | null;\n rebufferCount: number;\n rebufferDuration: number;\n rebufferSince: number | null;\n seekCount: number;\n seekDuration: number;\n seekSince: number | null;\n maximumPlayhead: number;\n nextSnapshotAt: number;\n duration: number | null;\n intrinsicVideoWidth: number | null;\n intrinsicVideoHeight: number | null;\n hostname: string | null;\n source: string;\n resourceStarted: boolean;\n errorEmitted: boolean;\n fatalErrorBeforeStart: boolean;\n frameBaseline: FrameCounts | null;\n framePrevious: FrameCounts | null;\n frameMetricsValid: boolean;\n connectorBaseline: AnalyticsConnectorSnapshot | null;\n renditionTrackingAvailable: boolean;\n renditionTimes: Map<string, RenditionPlayingTime>;\n activeRendition: AnalyticsRendition | null;\n activeRenditionSince: number | null;\n playbackState: AnalyticsPlaybackState;\n playbackStateSince: number;\n}\n\ninterface FrameCounts {\n dropped: number;\n total: number;\n}\n\ninterface NormalizedError {\n category: AnalyticsErrorCategory;\n code: string | number | null;\n fatal: boolean;\n playhead: number | null;\n}\n\nfunction finiteNonNegative(value: number | null): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nfunction nonNegativeDelta(current: number | null, baseline: number | null): number | null {\n return current === null || baseline === null ? null : finiteNonNegative(current - baseline);\n}\n\nfunction finitePositive(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : null;\n}\n\nfunction intrinsicVideoSize(media: HTMLMediaElement): { width: number | null; height: number | null } {\n try {\n const customMedia = media as HTMLMediaElement & { nativeEl?: Element | null };\n const video = (customMedia.nativeEl?.localName === \"video\" ? customMedia.nativeEl : media) as\n HTMLMediaElement & Partial<Pick<HTMLVideoElement, \"videoWidth\" | \"videoHeight\">>;\n const width = finitePositive(video.videoWidth);\n const height = finitePositive(video.videoHeight);\n return width !== null && height !== null ? { width, height } : { width: null, height: null };\n } catch {\n return { width: null, height: null };\n }\n}\n\nfunction normalizedRendition(rendition: AnalyticsRendition | null): AnalyticsRendition | null {\n if (!rendition) return null;\n const result = {\n width: finiteNonNegative(rendition.width),\n height: finiteNonNegative(rendition.height),\n codec: typeof rendition.codec === \"string\" && rendition.codec ? rendition.codec : null,\n bitrate_bps: finiteNonNegative(rendition.bitrate_bps),\n frame_rate: finiteNonNegative(rendition.frame_rate),\n };\n return Object.values(result).every((value) => value === null) ? null : result;\n}\n\nfunction renditionKey(rendition: AnalyticsRendition): string {\n return JSON.stringify([rendition.width, rendition.height, rendition.codec, rendition.bitrate_bps, rendition.frame_rate]);\n}\n\nfunction renditionPlayingTime(current: View, now: number): RenditionPlayingTime[] | null {\n if (!current.renditionTrackingAvailable) return null;\n const times = new Map([...current.renditionTimes].map(([key, value]) => [key, { ...value }]));\n if (current.activeRendition && current.activeRenditionSince !== null) {\n const key = renditionKey(current.activeRendition);\n const entry = times.get(key) ?? { ...current.activeRendition, playing_time_ms: 0 };\n entry.playing_time_ms += Math.max(0, now - current.activeRenditionSince);\n times.set(key, entry);\n }\n return [...times.values()];\n}\n\nconst emptyConnectorMetrics = {\n selected_rendition_width: null,\n selected_rendition_height: null,\n selected_rendition_codec: null,\n selected_rendition_bitrate_bps: null,\n rendition_switch_count: null,\n delivery_request_count: null,\n delivery_transferred_bytes: null,\n delivery_throughput_bps: null,\n};\n\nfunction connectorMetrics(connector: AnalyticsConnector | null, baseline: AnalyticsConnectorSnapshot | null): Pick<ViewMetrics,\n \"selected_rendition_width\" | \"selected_rendition_height\" | \"selected_rendition_codec\" |\n \"selected_rendition_bitrate_bps\" | \"rendition_switch_count\" | \"delivery_request_count\" |\n \"delivery_transferred_bytes\" | \"delivery_throughput_bps\"> {\n if (!connector || !baseline) return { ...emptyConnectorMetrics };\n let current: AnalyticsConnectorSnapshot;\n try {\n current = connector.snapshot();\n } catch {\n return { ...emptyConnectorMetrics };\n }\n const switches = nonNegativeDelta(current.renditionSwitchCount, baseline.renditionSwitchCount);\n const requests = nonNegativeDelta(current.deliveryRequestCount, baseline.deliveryRequestCount);\n const bytes = nonNegativeDelta(current.deliveryTransferredBytes, baseline.deliveryTransferredBytes);\n const deliveryDuration = nonNegativeDelta(current.deliveryDurationMs, baseline.deliveryDurationMs);\n return {\n selected_rendition_width: finiteNonNegative(current.renditionWidth),\n selected_rendition_height: finiteNonNegative(current.renditionHeight),\n selected_rendition_codec: typeof current.renditionCodec === \"string\" && current.renditionCodec ? current.renditionCodec : null,\n selected_rendition_bitrate_bps: finiteNonNegative(current.renditionBitrate),\n rendition_switch_count: switches,\n delivery_request_count: requests,\n delivery_transferred_bytes: bytes,\n delivery_throughput_bps: bytes !== null && deliveryDuration !== null && deliveryDuration > 0\n ? bytes * 8 * 1000 / deliveryDuration : null,\n };\n}\n\nfunction deliveryHostname(media: HTMLMediaElement): string | null {\n try {\n const url = new URL(media.currentSrc || media.src);\n return url.protocol === \"http:\" || url.protocol === \"https:\" ? url.hostname : null;\n } catch {\n return null;\n }\n}\nfunction duration(media: HTMLMediaElement): number | null {\n return Number.isFinite(media.duration) && media.duration >= 0 ? media.duration : null;\n}\nfunction mediaErrorCategory(code: number | null): AnalyticsErrorCategory {\n return code === 1 ? \"aborted\" : code === 2 ? \"network\" : code === 3 ? \"decode\"\n : code === 4 ? \"unsupported\" : \"unknown\";\n}\nfunction frameCounts(media: HTMLMediaElement): FrameCounts | null {\n const video = media as HTMLMediaElement & Partial<Pick<HTMLVideoElement, \"getVideoPlaybackQuality\">>;\n if (typeof video.getVideoPlaybackQuality === \"function\") {\n try {\n const quality = video.getVideoPlaybackQuality();\n if (Number.isInteger(quality.droppedVideoFrames) && quality.droppedVideoFrames >= 0 &&\n Number.isInteger(quality.totalVideoFrames) && quality.totalVideoFrames >= 0) {\n return { dropped: quality.droppedVideoFrames, total: quality.totalVideoFrames };\n }\n } catch {\n // Treat an inaccessible browser counter like an unavailable measurement.\n }\n }\n const webkit = media as HTMLMediaElement & {\n webkitDecodedFrameCount?: number;\n webkitDroppedFrameCount?: number;\n };\n if (!Number.isInteger(webkit.webkitDecodedFrameCount) || (webkit.webkitDecodedFrameCount ?? -1) < 0 ||\n !Number.isInteger(webkit.webkitDroppedFrameCount) || (webkit.webkitDroppedFrameCount ?? -1) < 0) return null;\n return { dropped: webkit.webkitDroppedFrameCount!, total: webkit.webkitDecodedFrameCount! };\n}\n\nexport function attachAnalytics(media: HTMLMediaElement, options: AnalyticsOptions): AnalyticsSession {\n return createAnalyticsSession(media, options, false);\n}\n\n/** Engine adapters call this when they own source-change events. */\nexport function attachAnalyticsWithManagedSource(media: HTMLMediaElement, options: AnalyticsOptions): AnalyticsSession {\n return createAnalyticsSession(media, options, true);\n}\n\nfunction createAnalyticsSession(media: HTMLMediaElement, options: AnalyticsOptions,\n sourceManagedByEngine: boolean): AnalyticsSession {\n assertAnalyticsOptions(options);\n const frameVideo = media as HTMLMediaElement & Partial<Pick<HTMLVideoElement,\n \"requestVideoFrameCallback\" | \"cancelVideoFrameCallback\">>;\n const { videoId, environment = null, viewerId = null, snapshotIntervalMs = 30000 } = options;\n const destinations = [...options.destinations];\n const includedEvents = new Set((options.includeEvents ?? analyticsEventTypes)\n .map((event) => `chunkify.video.${event}`));\n let view: View | null = null;\n let destroyed = false;\n let wantsPlay = false;\n let seeking = false;\n let snapshotTimer: ReturnType<typeof setTimeout> | null = null;\n let connector: AnalyticsConnector | null = null;\n let unsubscribeConnector: (() => void) | null = null;\n let unsubscribeRenditions: (() => void) | null = null;\n let selectedRendition: AnalyticsRendition | null = null;\n\n function refreshIntrinsicVideoSize(current: View) {\n const size = intrinsicVideoSize(media);\n if (size.width === null || size.height === null) return;\n current.intrinsicVideoWidth = size.width;\n current.intrinsicVideoHeight = size.height;\n }\n\n function cancelFirstVideoFrame(current: View) {\n if (current.frameCallbackId === null) return;\n const callbackId = current.frameCallbackId;\n current.frameCallbackId = null;\n try { frameVideo.cancelVideoFrameCallback?.(callbackId); } catch {}\n }\n\n function observeFirstVideoFrame(current: View) {\n if (typeof frameVideo.requestVideoFrameCallback !== \"function\" ||\n typeof frameVideo.cancelVideoFrameCallback !== \"function\") return;\n try {\n current.frameCallbackId = frameVideo.requestVideoFrameCallback((observedAt) => {\n if (current.frameCallbackId === null) return;\n current.frameCallbackId = null;\n if (view !== current) return;\n // WebKit can report a presentationTime outside performance.now()'s clock.\n if (!Number.isFinite(observedAt) || observedAt < current.startedAt) return;\n current.firstVideoFrame = observedAt - current.startedAt;\n });\n } catch {\n // Frame timing is optional; an inaccessible browser API leaves it unavailable.\n }\n }\n\n function closeActiveRendition(now: number) {\n if (!view || !view.activeRendition || view.activeRenditionSince === null) return;\n const key = renditionKey(view.activeRendition);\n const entry = view.renditionTimes.get(key) ?? { ...view.activeRendition, playing_time_ms: 0 };\n entry.playing_time_ms += Math.max(0, now - view.activeRenditionSince);\n view.renditionTimes.set(key, entry);\n view.activeRendition = null;\n view.activeRenditionSince = null;\n }\n\n function onRenditionChanged(rendition: AnalyticsRendition | null) {\n const next = normalizedRendition(rendition);\n const previous = selectedRendition;\n if (previous && next && renditionKey(previous) === renditionKey(next)) return;\n const now = performance.now();\n closeActiveRendition(now);\n selectedRendition = next;\n if (view && view.playingSince !== null && selectedRendition) {\n view.activeRendition = selectedRendition;\n view.activeRenditionSince = now;\n }\n if (view && previous && next) emitRenditionChange(view, previous, next);\n }\n\n function playheadSeconds(): number | null {\n return Number.isFinite(media.currentTime) && media.currentTime >= 0 ? media.currentTime : null;\n }\n\n function envelope(current: View, event_name: ChunkifyPlayerAnalyticsEvent[\"event_name\"]): AnalyticsEventEnvelope {\n return {\n schema_version: 1, event_name, event_id: crypto.randomUUID(), sequence: ++current.sequence,\n occurred_at: new Date().toISOString(), view_id: current.id, video_id: videoId,\n sdk_name: \"@chunkify/analytics\", sdk_version: sdkVersion,\n connector_name: connector?.name ?? \"html-media\", connector_version: connector?.version ?? sdkVersion,\n player_name: connector?.playerName ?? null, player_version: connector?.playerVersion ?? null,\n delivery_hostname: current.hostname, environment, viewer_id: viewerId,\n reason: null, startup_outcome: null, error_category: null, error_code: null,\n error_fatal: null, error_playhead_seconds: null,\n };\n }\n\n function deliver(event: ChunkifyPlayerAnalyticsEvent) {\n for (const destination of destinations) {\n try {\n // A failing destination must not interrupt playback or another destination.\n void Promise.resolve(destination.send(event)).catch(() => {});\n } catch {\n // Synchronous delivery failures are isolated for the same reason.\n }\n }\n }\n\n function changePlaybackState(next: AnalyticsPlaybackState, current = view) {\n if (!current || current.playbackState === next) return;\n if (current.playbackState === \"ended\" || current.playbackState === \"stopped\" ||\n (current.playbackState === \"error\" && next !== \"ended\" && next !== \"stopped\")) return;\n const now = performance.now();\n const previous = current.playbackState;\n const elapsed = Math.max(0, now - current.playbackStateSince);\n current.playbackState = next;\n current.playbackStateSince = now;\n if (!includedEvents.has(\"chunkify.video.playback_state_changed\")) return;\n deliver({ ...envelope(current, \"chunkify.video.playback_state_changed\"),\n event_name: \"chunkify.video.playback_state_changed\", playhead_seconds: playheadSeconds(),\n from_state: previous, to_state: next, previous_state_duration_ms: elapsed });\n }\n\n function emitRenditionChange(current: View, previous: AnalyticsRendition, selected: AnalyticsRendition) {\n if (!includedEvents.has(\"chunkify.video.rendition_changed\")) return;\n deliver({ ...envelope(current, \"chunkify.video.rendition_changed\"),\n event_name: \"chunkify.video.rendition_changed\", playhead_seconds: playheadSeconds(),\n previous_rendition_width: previous.width, previous_rendition_height: previous.height,\n previous_rendition_codec: previous.codec, previous_rendition_bitrate_bps: previous.bitrate_bps,\n previous_rendition_frame_rate: previous.frame_rate,\n selected_rendition_width: selected.width, selected_rendition_height: selected.height,\n selected_rendition_codec: selected.codec, selected_rendition_bitrate_bps: selected.bitrate_bps,\n selected_rendition_frame_rate: selected.frame_rate });\n }\n\n function emit(current: View, event_name: AnalyticsViewEvent[\"event_name\"], reason: AnalyticsEndReason | null = null,\n error: NormalizedError | null = null) {\n if (!includedEvents.has(event_name)) return;\n const now = performance.now();\n const playingTime = current.playing + (current.playingSince === null ? 0 : now - current.playingSince);\n const rebufferDuration = current.rebufferDuration + (current.rebufferSince === null ? 0 : now - current.rebufferSince);\n const seekDuration = current.seekDuration + (current.seekSince === null ? 0 : now - current.seekSince);\n const rebufferDenominator = playingTime + rebufferDuration;\n const frames = frameCounts(media);\n let viewFrames: FrameCounts | null = null;\n if (frames && current.frameBaseline && current.framePrevious && current.frameMetricsValid) {\n if (frames.dropped < current.framePrevious.dropped || frames.total < current.framePrevious.total) {\n current.frameMetricsValid = false;\n } else {\n viewFrames = {\n dropped: frames.dropped - current.frameBaseline.dropped,\n total: frames.total - current.frameBaseline.total,\n };\n }\n }\n if (frames) current.framePrevious = frames;\n const engineMetrics = connectorMetrics(connector, current.connectorBaseline);\n let startupOutcome: AnalyticsStartupOutcome | null = null;\n if (event_name === \"chunkify.video.view_ended\") {\n if (current.startup !== null) startupOutcome = \"started\";\n else if (current.fatalErrorBeforeStart) startupOutcome = \"failed_before_start\";\n else startupOutcome = \"ended_before_start\";\n }\n refreshIntrinsicVideoSize(current);\n const event: AnalyticsViewEvent = {\n ...envelope(current, event_name), event_name, reason, startup_outcome: startupOutcome,\n error_category: error?.category ?? null,\n error_code: error?.code ?? null,\n error_fatal: error?.fatal ?? null,\n error_playhead_seconds: error?.playhead ?? null,\n media_duration_seconds: current.duration,\n startup_time_ms: current.startup,\n first_video_frame_time_ms: current.firstVideoFrame,\n playing_time_ms: playingTime,\n rebuffer_count: current.rebufferCount,\n rebuffer_duration_ms: rebufferDuration,\n rebuffer_ratio: rebufferDenominator > 0 ? rebufferDuration / rebufferDenominator : null,\n seek_count: current.seekCount,\n seek_duration_ms: seekDuration,\n maximum_playhead_seconds: current.maximumPlayhead,\n furthest_progress_ratio: current.duration === null || current.duration === 0 ? null : Math.min(1, current.maximumPlayhead / current.duration),\n video_intrinsic_width_css_px: current.intrinsicVideoWidth,\n video_intrinsic_height_css_px: current.intrinsicVideoHeight,\n dropped_video_frames: viewFrames?.dropped ?? null,\n total_video_frames: viewFrames?.total ?? null,\n ...engineMetrics,\n rendition_playing_time: renditionPlayingTime(current, now),\n };\n deliver(event);\n }\n function startAttempt() {\n if (destroyed) return;\n wantsPlay = true;\n if (view) {\n if (view.playbackState === \"paused\") changePlaybackState(\"resuming\");\n return;\n }\n const initialFrames = frameCounts(media);\n const initialVideoSize = intrinsicVideoSize(media);\n const startedAt = performance.now();\n const current: View = { id: crypto.randomUUID(), sequence: 0, startedAt,\n startup: null, firstVideoFrame: null, frameCallbackId: null,\n playing: 0, playingSince: null,\n rebufferCount: 0, rebufferDuration: 0, rebufferSince: null,\n seekCount: 0, seekDuration: 0, seekSince: null,\n maximumPlayhead: Number.isFinite(media.currentTime) ? Math.max(0, media.currentTime) : 0,\n nextSnapshotAt: snapshotIntervalMs,\n duration: duration(media),\n intrinsicVideoWidth: initialVideoSize.width, intrinsicVideoHeight: initialVideoSize.height,\n hostname: deliveryHostname(media), source: media.src || media.currentSrc,\n // NETWORK_IDLE (1) and NETWORK_LOADING (2) already have a selected resource.\n resourceStarted: media.readyState > 0 || media.networkState === 1 || media.networkState === 2,\n errorEmitted: false, fatalErrorBeforeStart: false,\n frameBaseline: initialFrames, framePrevious: initialFrames,\n frameMetricsValid: initialFrames !== null,\n connectorBaseline: connector ? safeConnectorSnapshot(connector) : null,\n renditionTrackingAvailable: Boolean(connector?.subscribeToRenditions),\n renditionTimes: new Map(), activeRendition: null, activeRenditionSince: null,\n playbackState: \"startup\", playbackStateSince: startedAt };\n view = current;\n if (includedEvents.size > 0) observeFirstVideoFrame(current);\n emit(current, \"chunkify.video.view_started\");\n if (view !== current) return;\n if (media.error) reportMediaError();\n }\n function stopPlaying() {\n if (snapshotTimer !== null) {\n clearTimeout(snapshotTimer);\n snapshotTimer = null;\n }\n if (!view || view.playingSince === null) return;\n const now = performance.now();\n closeActiveRendition(now);\n view.playing += now - view.playingSince;\n view.playingSince = null;\n }\n function stopRebuffering() {\n if (!view || view.rebufferSince === null) return;\n view.rebufferDuration += performance.now() - view.rebufferSince;\n view.rebufferSince = null;\n }\n function stopSeeking() {\n if (!view || view.seekSince === null) return;\n view.seekDuration += performance.now() - view.seekSince;\n view.seekSince = null;\n }\n function updatePlaybackPosition() {\n if (!view) return;\n refreshIntrinsicVideoSize(view);\n if (!Number.isFinite(media.currentTime)) return;\n view.maximumPlayhead = Math.max(view.maximumPlayhead, media.currentTime);\n }\n function reportMediaError() {\n if (!view) return;\n const current = view;\n cancelFirstVideoFrame(current);\n if (current.startup === null) current.fatalErrorBeforeStart = true;\n if (current.errorEmitted) return;\n updatePlaybackPosition();\n current.errorEmitted = true;\n const code = media.error && Number.isFinite(media.error.code) ? media.error.code : null;\n emit(current, \"chunkify.video.playback_error\", null, {\n category: mediaErrorCategory(code), code, fatal: true,\n playhead: Number.isFinite(media.currentTime) ? Math.max(0, media.currentTime) : null,\n });\n if (view === current) changePlaybackState(\"error\");\n }\n function reportConnectorError(error: AnalyticsConnectorError) {\n if (!view) return;\n const current = view;\n if (error.fatal) cancelFirstVideoFrame(current);\n if (error.fatal && current.startup === null) current.fatalErrorBeforeStart = true;\n if (current.errorEmitted) return;\n if (error.fatal) {\n stopPlaying();\n stopRebuffering();\n stopSeeking();\n seeking = false;\n wantsPlay = false;\n }\n updatePlaybackPosition();\n current.errorEmitted = true;\n emit(current, \"chunkify.video.playback_error\", null, {\n category: error.category,\n code: typeof error.code === \"string\" || typeof error.code === \"number\" ? error.code : null,\n fatal: Boolean(error.fatal),\n playhead: Number.isFinite(media.currentTime) ? Math.max(0, media.currentTime) : null,\n });\n if (error.fatal && view === current) changePlaybackState(\"error\");\n }\n function setConnector(next: AnalyticsConnector | null) {\n if (destroyed) return;\n const previousUnsubscribe = unsubscribeConnector;\n const previousRenditionUnsubscribe = unsubscribeRenditions;\n unsubscribeConnector = null;\n unsubscribeRenditions = null;\n try { previousUnsubscribe?.(); } catch {}\n try { previousRenditionUnsubscribe?.(); } catch {}\n if (destroyed) return;\n onRenditionChanged(null);\n connector = next;\n if (view) view.connectorBaseline = connector ? safeConnectorSnapshot(connector) : null;\n if (view && connector?.subscribeToRenditions) view.renditionTrackingAvailable = true;\n if (connector) {\n let unsubscribe: (() => void) | null = null;\n try { unsubscribe = connector.subscribeToErrors(reportConnectorError); } catch {}\n let unsubscribeRendition: (() => void) | null = null;\n try { unsubscribeRendition = connector.subscribeToRenditions?.(onRenditionChanged) ?? null; } catch {}\n if (destroyed) {\n try { unsubscribe?.(); } catch {}\n try { unsubscribeRendition?.(); } catch {}\n return;\n }\n unsubscribeConnector = unsubscribe;\n unsubscribeRenditions = unsubscribeRendition;\n }\n }\n function scheduleSnapshot() {\n if (!view || !includedEvents.has(\"chunkify.video.view_snapshot\") || snapshotTimer !== null) return;\n const playingSince = view.playingSince;\n if (playingSince === null) return;\n const current = view;\n const playingTime = current.playing + performance.now() - playingSince;\n snapshotTimer = globalThis.setTimeout(() => {\n snapshotTimer = null;\n if (view !== current || current.playingSince === null) return;\n updatePlaybackPosition();\n metadata();\n emit(current, \"chunkify.video.view_snapshot\");\n const currentPlayingTime = current.playing + performance.now() - current.playingSince;\n const nextFutureInterval = (Math.floor(currentPlayingTime / snapshotIntervalMs) + 1) * snapshotIntervalMs;\n current.nextSnapshotAt = Math.max(current.nextSnapshotAt + snapshotIntervalMs, nextFutureInterval);\n if (view === current) scheduleSnapshot();\n }, Math.max(0, current.nextSnapshotAt - playingTime));\n }\n function playing() {\n if (!view || !wantsPlay || seeking) return;\n refreshIntrinsicVideoSize(view);\n const now = performance.now();\n view.resourceStarted = true;\n view.startup ??= now - view.startedAt;\n stopRebuffering();\n view.playingSince ??= now;\n if (view.activeRenditionSince === null && selectedRendition) {\n view.activeRendition = selectedRendition;\n view.activeRenditionSince = now;\n }\n changePlaybackState(\"playing\");\n scheduleSnapshot();\n }\n function finish(reason: AnalyticsEndReason) {\n if (!view) return;\n const current = view;\n cancelFirstVideoFrame(current);\n stopPlaying();\n stopRebuffering();\n stopSeeking();\n updatePlaybackPosition();\n view = null;\n wantsPlay = false;\n seeking = false;\n changePlaybackState(reason === \"ended\" ? \"ended\" : \"stopped\", current);\n emit(current, \"chunkify.video.view_ended\", reason);\n }\n function metadata() {\n if (!view) return;\n view.duration = duration(media);\n refreshIntrinsicVideoSize(view);\n view.hostname = deliveryHostname(media);\n }\n const listeners: Record<string, () => void> = {\n play: startAttempt, playing,\n waiting() {\n stopPlaying();\n if (view && view.startup !== null && wantsPlay && !seeking && view.rebufferSince === null) {\n view.rebufferCount++;\n view.rebufferSince = performance.now();\n changePlaybackState(\"buffering\");\n }\n },\n error() {\n stopPlaying(); stopRebuffering(); stopSeeking(); seeking = false; wantsPlay = false;\n reportMediaError();\n },\n ended() { finish(\"ended\"); },\n emptied() {\n if (sourceManagedByEngine) return;\n if (!view) return;\n // A new attempt can begin after src changes but before the old resource's\n // queued emptied event arrives. That reset does not belong to the new view.\n if (view.resourceStarted || (view.source && view.source !== (media.src || media.currentSrc))) finish(\"source_changed\");\n },\n loadstart() {\n if (!view) return;\n const source = media.src || media.currentSrc;\n if (!sourceManagedByEngine && view.source && view.source !== source) { finish(\"source_changed\"); return; }\n // <source> selection can first expose the URL after the initial attempt.\n view.source = source;\n view.resourceStarted = true;\n },\n pause() {\n stopPlaying(); stopRebuffering(); wantsPlay = false;\n if (view && !media.ended) changePlaybackState(\"paused\");\n },\n seeking() {\n stopPlaying();\n stopRebuffering();\n updatePlaybackPosition();\n if (view && !seeking) { view.seekCount++; view.seekSince = performance.now(); }\n seeking = true;\n changePlaybackState(\"seeking\");\n },\n seeked() {\n updatePlaybackPosition(); stopSeeking(); seeking = false;\n changePlaybackState(wantsPlay ? \"resuming\" : \"paused\");\n },\n timeupdate: updatePlaybackPosition,\n loadedmetadata: metadata, durationchange: metadata,\n };\n for (const [name, listener] of Object.entries(listeners)) media.addEventListener(name, listener);\n const page = media.ownerDocument.defaultView;\n const pagehide = () => finish(\"page_exit\");\n page?.addEventListener(\"pagehide\", pagehide);\n return {\n startAttempt,\n sourceChanged() { finish(\"source_changed\"); },\n setConnector,\n destroy() {\n if (destroyed) return;\n destroyed = true;\n for (const [name, listener] of Object.entries(listeners)) media.removeEventListener(name, listener);\n page?.removeEventListener(\"pagehide\", pagehide);\n finish(\"destroyed\");\n try { unsubscribeConnector?.(); } catch {}\n try { unsubscribeRenditions?.(); } catch {}\n unsubscribeConnector = null;\n unsubscribeRenditions = null;\n connector = null;\n },\n };\n}\n\nfunction safeConnectorSnapshot(connector: AnalyticsConnector): AnalyticsConnectorSnapshot | null {\n try { return connector.snapshot(); } catch { return null; }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AnalyticsDestination, ChunkifyPlayerAnalyticsEvent } from "./core.js";
|
|
2
|
+
/** The small part of an initialized Datadog RUM client needed by this adapter. */
|
|
3
|
+
export interface DatadogRumCompatibleClient {
|
|
4
|
+
addAction(name: string, context: Record<string, unknown>): void;
|
|
5
|
+
}
|
|
6
|
+
/** Send one action per event, optionally mapping its Datadog context. */
|
|
7
|
+
export declare function createDatadogAdapter(client: DatadogRumCompatibleClient, mapEvent?: (event: ChunkifyPlayerAnalyticsEvent) => Record<string, unknown>): AnalyticsDestination;
|
|
8
|
+
//# sourceMappingURL=datadog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datadog.d.ts","sourceRoot":"","sources":["../src/datadog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAEpF,kFAAkF;AAClF,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACjE;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,0BAA0B,EAClC,QAAQ,GAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAA6B,GACrG,oBAAoB,CAYtB"}
|
package/dist/datadog.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Send one action per event, optionally mapping its Datadog context. */
|
|
2
|
+
export function createDatadogAdapter(client, mapEvent = (event) => ({ ...event })) {
|
|
3
|
+
if (!client || typeof client.addAction !== "function") {
|
|
4
|
+
throw new TypeError("Datadog adapter requires an initialized client with addAction().");
|
|
5
|
+
}
|
|
6
|
+
if (typeof mapEvent !== "function") {
|
|
7
|
+
throw new TypeError("Datadog event mapper must be a function.");
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
send(event) {
|
|
11
|
+
client.addAction(event.event_name, mapEvent(event));
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=datadog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datadog.js","sourceRoot":"","sources":["../src/datadog.ts"],"names":[],"mappings":"AAOA,yEAAyE;AACzE,MAAM,UAAU,oBAAoB,CAClC,MAAkC,EAClC,QAAQ,GAAqE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;IAEtG,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;QACtD,MAAM,IAAI,SAAS,CAAC,kEAAkE,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO;QACL,IAAI,CAAC,KAAmC;YACtC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { AnalyticsDestination, ChunkifyPlayerAnalyticsEvent } from \"./core.js\";\n\n/** The small part of an initialized Datadog RUM client needed by this adapter. */\nexport interface DatadogRumCompatibleClient {\n addAction(name: string, context: Record<string, unknown>): void;\n}\n\n/** Send one action per event, optionally mapping its Datadog context. */\nexport function createDatadogAdapter(\n client: DatadogRumCompatibleClient,\n mapEvent: (event: ChunkifyPlayerAnalyticsEvent) => Record<string, unknown> = (event) => ({ ...event }),\n): AnalyticsDestination {\n if (!client || typeof client.addAction !== \"function\") {\n throw new TypeError(\"Datadog adapter requires an initialized client with addAction().\");\n }\n if (typeof mapEvent !== \"function\") {\n throw new TypeError(\"Datadog event mapper must be a function.\");\n }\n return {\n send(event: ChunkifyPlayerAnalyticsEvent) {\n client.addAction(event.event_name, mapEvent(event));\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const analyticsEventTypes: readonly ["view_started", "view_snapshot", "playback_error", "view_ended", "playback_state_changed", "rendition_changed"];
|
|
2
|
+
export type AnalyticsEventType = (typeof analyticsEventTypes)[number];
|
|
3
|
+
//# sourceMappingURL=event-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../src/event-types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,YAC9B,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAC/D,wBAAwB,EAAE,mBAAmB,CACrC,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-types.js","sourceRoot":"","sources":["../src/event-types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY;IAC/D,wBAAwB,EAAE,mBAAmB;CACrC,CAAC","sourcesContent":["export const analyticsEventTypes = [\n \"view_started\", \"view_snapshot\", \"playback_error\", \"view_ended\",\n \"playback_state_changed\", \"rendition_changed\",\n] as const;\n\nexport type AnalyticsEventType = (typeof analyticsEventTypes)[number];\n"]}
|
package/dist/hlsjs.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Hls from "hls.js";
|
|
2
|
+
import { type AnalyticsConnector, type AnalyticsOptions, type AnalyticsSession } from "./core.js";
|
|
3
|
+
export interface HlsJsAnalyticsConnector extends AnalyticsConnector {
|
|
4
|
+
destroy(): void;
|
|
5
|
+
}
|
|
6
|
+
/** Observe an hls.js instance without changing its playback configuration. */
|
|
7
|
+
export declare function createHlsJsConnector(hls: Hls): HlsJsAnalyticsConnector;
|
|
8
|
+
/** Follow an hls.js instance as it attaches to or detaches from media. */
|
|
9
|
+
export declare function monitorHlsJs(hls: Hls, options: AnalyticsOptions): Pick<AnalyticsSession, "startAttempt" | "sourceChanged" | "destroy">;
|
|
10
|
+
//# sourceMappingURL=hlsjs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hlsjs.d.ts","sourceRoot":"","sources":["../src/hlsjs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,QAAQ,CAAC;AAK9B,OAAO,EAAoC,KAAK,kBAAkB,EAC/B,KAAK,gBAAgB,EACtD,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG3C,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,OAAO,IAAI,IAAI,CAAC;CACjB;AASD,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,GAAG,uBAAuB,CA4FtE;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB,GAC9D,IAAI,CAAC,gBAAgB,EAAE,cAAc,GAAG,eAAe,GAAG,SAAS,CAAC,CAyErE"}
|
package/dist/hlsjs.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { attachAnalyticsWithManagedSource } from "./core.js";
|
|
2
|
+
import { assertAnalyticsOptions } from "./options.js";
|
|
3
|
+
/** Observe an hls.js instance without changing its playback configuration. */
|
|
4
|
+
export function createHlsJsConnector(hls) {
|
|
5
|
+
const HlsClass = hls.constructor;
|
|
6
|
+
const snapshot = {
|
|
7
|
+
renditionWidth: null, renditionHeight: null, renditionCodec: null, renditionBitrate: null,
|
|
8
|
+
renditionSwitchCount: 0, deliveryRequestCount: 0, deliveryTransferredBytes: 0,
|
|
9
|
+
deliveryDurationMs: 0,
|
|
10
|
+
};
|
|
11
|
+
const seenStats = new WeakSet();
|
|
12
|
+
const errorListeners = new Set();
|
|
13
|
+
const renditionListeners = new Set();
|
|
14
|
+
let selectedLevel = null;
|
|
15
|
+
let currentRendition = null;
|
|
16
|
+
let destroyed = false;
|
|
17
|
+
const selectLevel = (level) => {
|
|
18
|
+
const rendition = hls.levels[level];
|
|
19
|
+
if (!rendition)
|
|
20
|
+
return;
|
|
21
|
+
if (selectedLevel !== null && selectedLevel !== level)
|
|
22
|
+
snapshot.renditionSwitchCount++;
|
|
23
|
+
selectedLevel = level;
|
|
24
|
+
snapshot.renditionWidth = rendition.width || null;
|
|
25
|
+
snapshot.renditionHeight = rendition.height || null;
|
|
26
|
+
snapshot.renditionCodec = rendition.videoCodec || rendition.codecSet || null;
|
|
27
|
+
snapshot.renditionBitrate = rendition.bitrate || null;
|
|
28
|
+
currentRendition = {
|
|
29
|
+
width: snapshot.renditionWidth,
|
|
30
|
+
height: snapshot.renditionHeight,
|
|
31
|
+
codec: snapshot.renditionCodec,
|
|
32
|
+
bitrate_bps: snapshot.renditionBitrate,
|
|
33
|
+
frame_rate: rendition.frameRate || null,
|
|
34
|
+
};
|
|
35
|
+
for (const listener of renditionListeners)
|
|
36
|
+
listener(currentRendition);
|
|
37
|
+
};
|
|
38
|
+
if (hls.currentLevel >= 0)
|
|
39
|
+
selectLevel(hls.currentLevel);
|
|
40
|
+
const recordStats = (stats) => {
|
|
41
|
+
if (!stats || seenStats.has(stats))
|
|
42
|
+
return;
|
|
43
|
+
seenStats.add(stats);
|
|
44
|
+
const bytes = Number.isFinite(stats.loaded) && stats.loaded >= 0 ? stats.loaded : 0;
|
|
45
|
+
const elapsed = stats.loading.end - stats.loading.start;
|
|
46
|
+
snapshot.deliveryRequestCount++;
|
|
47
|
+
snapshot.deliveryTransferredBytes += bytes;
|
|
48
|
+
if (Number.isFinite(elapsed) && elapsed > 0)
|
|
49
|
+
snapshot.deliveryDurationMs += elapsed;
|
|
50
|
+
};
|
|
51
|
+
const onManifestLoaded = (_event, data) => recordStats(data.stats);
|
|
52
|
+
const onLevelLoaded = (_event, data) => recordStats(data.stats);
|
|
53
|
+
const onAudioTrackLoaded = (_event, data) => recordStats(data.stats);
|
|
54
|
+
const onSubtitleTrackLoaded = (_event, data) => recordStats(data.stats);
|
|
55
|
+
const onFragLoaded = (_event, data) => recordStats(data.part?.stats ?? data.frag.stats);
|
|
56
|
+
const onLevelSwitched = (_event, data) => selectLevel(data.level);
|
|
57
|
+
const onError = (_event, data) => {
|
|
58
|
+
if (!data.fatal)
|
|
59
|
+
return;
|
|
60
|
+
const category = data.type === HlsClass.ErrorTypes.NETWORK_ERROR ? "network"
|
|
61
|
+
: data.type === HlsClass.ErrorTypes.MEDIA_ERROR || data.type === HlsClass.ErrorTypes.MUX_ERROR ? "decode"
|
|
62
|
+
: data.type === HlsClass.ErrorTypes.KEY_SYSTEM_ERROR ? "unsupported" : "unknown";
|
|
63
|
+
for (const listener of errorListeners)
|
|
64
|
+
listener({ category, code: data.details, fatal: true });
|
|
65
|
+
};
|
|
66
|
+
hls.on(HlsClass.Events.MANIFEST_LOADED, onManifestLoaded);
|
|
67
|
+
hls.on(HlsClass.Events.LEVEL_LOADED, onLevelLoaded);
|
|
68
|
+
hls.on(HlsClass.Events.AUDIO_TRACK_LOADED, onAudioTrackLoaded);
|
|
69
|
+
hls.on(HlsClass.Events.SUBTITLE_TRACK_LOADED, onSubtitleTrackLoaded);
|
|
70
|
+
hls.on(HlsClass.Events.FRAG_LOADED, onFragLoaded);
|
|
71
|
+
hls.on(HlsClass.Events.LEVEL_SWITCHED, onLevelSwitched);
|
|
72
|
+
hls.on(HlsClass.Events.ERROR, onError);
|
|
73
|
+
return {
|
|
74
|
+
name: "hls.js", version: HlsClass.version,
|
|
75
|
+
playerName: "hls.js", playerVersion: HlsClass.version,
|
|
76
|
+
snapshot: () => ({ ...snapshot }),
|
|
77
|
+
subscribeToErrors(listener) {
|
|
78
|
+
errorListeners.add(listener);
|
|
79
|
+
return () => { errorListeners.delete(listener); };
|
|
80
|
+
},
|
|
81
|
+
subscribeToRenditions(listener) {
|
|
82
|
+
renditionListeners.add(listener);
|
|
83
|
+
listener(currentRendition);
|
|
84
|
+
return () => { renditionListeners.delete(listener); };
|
|
85
|
+
},
|
|
86
|
+
destroy() {
|
|
87
|
+
if (destroyed)
|
|
88
|
+
return;
|
|
89
|
+
destroyed = true;
|
|
90
|
+
hls.off(HlsClass.Events.MANIFEST_LOADED, onManifestLoaded);
|
|
91
|
+
hls.off(HlsClass.Events.LEVEL_LOADED, onLevelLoaded);
|
|
92
|
+
hls.off(HlsClass.Events.AUDIO_TRACK_LOADED, onAudioTrackLoaded);
|
|
93
|
+
hls.off(HlsClass.Events.SUBTITLE_TRACK_LOADED, onSubtitleTrackLoaded);
|
|
94
|
+
hls.off(HlsClass.Events.FRAG_LOADED, onFragLoaded);
|
|
95
|
+
hls.off(HlsClass.Events.LEVEL_SWITCHED, onLevelSwitched);
|
|
96
|
+
hls.off(HlsClass.Events.ERROR, onError);
|
|
97
|
+
errorListeners.clear();
|
|
98
|
+
renditionListeners.clear();
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Follow an hls.js instance as it attaches to or detaches from media. */
|
|
103
|
+
export function monitorHlsJs(hls, options) {
|
|
104
|
+
assertAnalyticsOptions(options);
|
|
105
|
+
const HlsClass = hls.constructor;
|
|
106
|
+
let media = null;
|
|
107
|
+
let session = null;
|
|
108
|
+
let connector = null;
|
|
109
|
+
let pendingAttempt = false;
|
|
110
|
+
let destroyed = false;
|
|
111
|
+
const releaseMedia = (sourceChanged) => {
|
|
112
|
+
const previousSession = session;
|
|
113
|
+
const previousConnector = connector;
|
|
114
|
+
media = null;
|
|
115
|
+
session = null;
|
|
116
|
+
connector = null;
|
|
117
|
+
if (sourceChanged)
|
|
118
|
+
previousSession?.sourceChanged();
|
|
119
|
+
previousSession?.destroy();
|
|
120
|
+
previousConnector?.destroy();
|
|
121
|
+
};
|
|
122
|
+
const attachMedia = () => {
|
|
123
|
+
const nextMedia = hls.media;
|
|
124
|
+
if (destroyed || !nextMedia || nextMedia === media)
|
|
125
|
+
return;
|
|
126
|
+
if (media)
|
|
127
|
+
releaseMedia(true);
|
|
128
|
+
const nextSession = attachAnalyticsWithManagedSource(nextMedia, options);
|
|
129
|
+
media = nextMedia;
|
|
130
|
+
session = nextSession;
|
|
131
|
+
try {
|
|
132
|
+
connector = createHlsJsConnector(hls);
|
|
133
|
+
nextSession.setConnector(connector);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// An engine measurement failure must not prevent media playback analytics.
|
|
137
|
+
}
|
|
138
|
+
if (pendingAttempt) {
|
|
139
|
+
pendingAttempt = false;
|
|
140
|
+
nextSession.startAttempt();
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const onMediaAttaching = () => attachMedia();
|
|
144
|
+
const onMediaDetaching = () => {
|
|
145
|
+
// hls.js can detach and reattach the same media synchronously while
|
|
146
|
+
// recovering an error or recreating its MediaSource. That is one view.
|
|
147
|
+
queueMicrotask(() => {
|
|
148
|
+
if (!destroyed && !hls.media)
|
|
149
|
+
releaseMedia(true);
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
const onDestroying = () => destroy();
|
|
153
|
+
function destroy() {
|
|
154
|
+
if (destroyed)
|
|
155
|
+
return;
|
|
156
|
+
destroyed = true;
|
|
157
|
+
hls.off(HlsClass.Events.MEDIA_ATTACHING, onMediaAttaching);
|
|
158
|
+
hls.off(HlsClass.Events.MEDIA_DETACHING, onMediaDetaching);
|
|
159
|
+
hls.off(HlsClass.Events.DESTROYING, onDestroying);
|
|
160
|
+
releaseMedia(false);
|
|
161
|
+
pendingAttempt = false;
|
|
162
|
+
}
|
|
163
|
+
hls.on(HlsClass.Events.MEDIA_ATTACHING, onMediaAttaching);
|
|
164
|
+
hls.on(HlsClass.Events.MEDIA_DETACHING, onMediaDetaching);
|
|
165
|
+
hls.on(HlsClass.Events.DESTROYING, onDestroying);
|
|
166
|
+
attachMedia();
|
|
167
|
+
return {
|
|
168
|
+
startAttempt() {
|
|
169
|
+
if (destroyed)
|
|
170
|
+
return;
|
|
171
|
+
if (session)
|
|
172
|
+
session.startAttempt();
|
|
173
|
+
else
|
|
174
|
+
pendingAttempt = true;
|
|
175
|
+
},
|
|
176
|
+
sourceChanged() {
|
|
177
|
+
if (destroyed)
|
|
178
|
+
return;
|
|
179
|
+
pendingAttempt = false;
|
|
180
|
+
session?.sourceChanged();
|
|
181
|
+
},
|
|
182
|
+
destroy,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=hlsjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hlsjs.js","sourceRoot":"","sources":["../src/hlsjs.ts"],"names":[],"mappings":"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","sourcesContent":["import type Hls from \"hls.js\";\nimport type {\n AudioTrackLoadedData, ErrorData, FragLoadedData, LevelLoadedData,\n LevelSwitchedData, LoaderStats, ManifestLoadedData, SubtitleTrackLoadedData,\n} from \"hls.js\";\nimport { attachAnalyticsWithManagedSource, type AnalyticsConnector, type AnalyticsConnectorError,\n type AnalyticsConnectorSnapshot, type AnalyticsOptions, type AnalyticsRendition,\n type AnalyticsSession } from \"./core.js\";\nimport { assertAnalyticsOptions } from \"./options.js\";\n\nexport interface HlsJsAnalyticsConnector extends AnalyticsConnector {\n destroy(): void;\n}\n\ntype HlsJsSnapshot = AnalyticsConnectorSnapshot & {\n renditionSwitchCount: number;\n deliveryRequestCount: number;\n deliveryTransferredBytes: number;\n deliveryDurationMs: number;\n};\n\n/** Observe an hls.js instance without changing its playback configuration. */\nexport function createHlsJsConnector(hls: Hls): HlsJsAnalyticsConnector {\n const HlsClass = hls.constructor as typeof Hls;\n const snapshot: HlsJsSnapshot = {\n renditionWidth: null, renditionHeight: null, renditionCodec: null, renditionBitrate: null,\n renditionSwitchCount: 0, deliveryRequestCount: 0, deliveryTransferredBytes: 0,\n deliveryDurationMs: 0,\n };\n const seenStats = new WeakSet<object>();\n const errorListeners = new Set<(error: AnalyticsConnectorError) => void>();\n const renditionListeners = new Set<(rendition: AnalyticsRendition | null) => void>();\n let selectedLevel: number | null = null;\n let currentRendition: AnalyticsRendition | null = null;\n let destroyed = false;\n\n const selectLevel = (level: number) => {\n const rendition = hls.levels[level];\n if (!rendition) return;\n if (selectedLevel !== null && selectedLevel !== level) snapshot.renditionSwitchCount++;\n selectedLevel = level;\n snapshot.renditionWidth = rendition.width || null;\n snapshot.renditionHeight = rendition.height || null;\n snapshot.renditionCodec = rendition.videoCodec || rendition.codecSet || null;\n snapshot.renditionBitrate = rendition.bitrate || null;\n currentRendition = {\n width: snapshot.renditionWidth,\n height: snapshot.renditionHeight,\n codec: snapshot.renditionCodec,\n bitrate_bps: snapshot.renditionBitrate,\n frame_rate: rendition.frameRate || null,\n };\n for (const listener of renditionListeners) listener(currentRendition);\n };\n if (hls.currentLevel >= 0) selectLevel(hls.currentLevel);\n\n const recordStats = (stats: LoaderStats | null | undefined) => {\n if (!stats || seenStats.has(stats)) return;\n seenStats.add(stats);\n const bytes = Number.isFinite(stats.loaded) && stats.loaded >= 0 ? stats.loaded : 0;\n const elapsed = stats.loading.end - stats.loading.start;\n snapshot.deliveryRequestCount++;\n snapshot.deliveryTransferredBytes += bytes;\n if (Number.isFinite(elapsed) && elapsed > 0) snapshot.deliveryDurationMs += elapsed;\n };\n const onManifestLoaded = (_event: unknown, data: ManifestLoadedData) => recordStats(data.stats);\n const onLevelLoaded = (_event: unknown, data: LevelLoadedData) => recordStats(data.stats);\n const onAudioTrackLoaded = (_event: unknown, data: AudioTrackLoadedData) => recordStats(data.stats);\n const onSubtitleTrackLoaded = (_event: unknown, data: SubtitleTrackLoadedData) => recordStats(data.stats);\n const onFragLoaded = (_event: unknown, data: FragLoadedData) => recordStats(data.part?.stats ?? data.frag.stats);\n const onLevelSwitched = (_event: unknown, data: LevelSwitchedData) => selectLevel(data.level);\n const onError = (_event: unknown, data: ErrorData) => {\n if (!data.fatal) return;\n const category = data.type === HlsClass.ErrorTypes.NETWORK_ERROR ? \"network\"\n : data.type === HlsClass.ErrorTypes.MEDIA_ERROR || data.type === HlsClass.ErrorTypes.MUX_ERROR ? \"decode\"\n : data.type === HlsClass.ErrorTypes.KEY_SYSTEM_ERROR ? \"unsupported\" : \"unknown\";\n for (const listener of errorListeners) listener({ category, code: data.details, fatal: true });\n };\n\n hls.on(HlsClass.Events.MANIFEST_LOADED, onManifestLoaded);\n hls.on(HlsClass.Events.LEVEL_LOADED, onLevelLoaded);\n hls.on(HlsClass.Events.AUDIO_TRACK_LOADED, onAudioTrackLoaded);\n hls.on(HlsClass.Events.SUBTITLE_TRACK_LOADED, onSubtitleTrackLoaded);\n hls.on(HlsClass.Events.FRAG_LOADED, onFragLoaded);\n hls.on(HlsClass.Events.LEVEL_SWITCHED, onLevelSwitched);\n hls.on(HlsClass.Events.ERROR, onError);\n\n return {\n name: \"hls.js\", version: HlsClass.version,\n playerName: \"hls.js\", playerVersion: HlsClass.version,\n snapshot: () => ({ ...snapshot }),\n subscribeToErrors(listener) {\n errorListeners.add(listener);\n return () => { errorListeners.delete(listener); };\n },\n subscribeToRenditions(listener) {\n renditionListeners.add(listener);\n listener(currentRendition);\n return () => { renditionListeners.delete(listener); };\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n hls.off(HlsClass.Events.MANIFEST_LOADED, onManifestLoaded);\n hls.off(HlsClass.Events.LEVEL_LOADED, onLevelLoaded);\n hls.off(HlsClass.Events.AUDIO_TRACK_LOADED, onAudioTrackLoaded);\n hls.off(HlsClass.Events.SUBTITLE_TRACK_LOADED, onSubtitleTrackLoaded);\n hls.off(HlsClass.Events.FRAG_LOADED, onFragLoaded);\n hls.off(HlsClass.Events.LEVEL_SWITCHED, onLevelSwitched);\n hls.off(HlsClass.Events.ERROR, onError);\n errorListeners.clear();\n renditionListeners.clear();\n },\n };\n}\n\n/** Follow an hls.js instance as it attaches to or detaches from media. */\nexport function monitorHlsJs(hls: Hls, options: AnalyticsOptions):\n Pick<AnalyticsSession, \"startAttempt\" | \"sourceChanged\" | \"destroy\"> {\n assertAnalyticsOptions(options);\n const HlsClass = hls.constructor as typeof Hls;\n let media: HTMLMediaElement | null = null;\n let session: AnalyticsSession | null = null;\n let connector: HlsJsAnalyticsConnector | null = null;\n let pendingAttempt = false;\n let destroyed = false;\n\n const releaseMedia = (sourceChanged: boolean) => {\n const previousSession = session;\n const previousConnector = connector;\n media = null;\n session = null;\n connector = null;\n if (sourceChanged) previousSession?.sourceChanged();\n previousSession?.destroy();\n previousConnector?.destroy();\n };\n const attachMedia = () => {\n const nextMedia = hls.media;\n if (destroyed || !nextMedia || nextMedia === media) return;\n if (media) releaseMedia(true);\n const nextSession = attachAnalyticsWithManagedSource(nextMedia, options);\n media = nextMedia;\n session = nextSession;\n try {\n connector = createHlsJsConnector(hls);\n nextSession.setConnector(connector);\n } catch {\n // An engine measurement failure must not prevent media playback analytics.\n }\n if (pendingAttempt) {\n pendingAttempt = false;\n nextSession.startAttempt();\n }\n };\n const onMediaAttaching = () => attachMedia();\n const onMediaDetaching = () => {\n // hls.js can detach and reattach the same media synchronously while\n // recovering an error or recreating its MediaSource. That is one view.\n queueMicrotask(() => {\n if (!destroyed && !hls.media) releaseMedia(true);\n });\n };\n const onDestroying = () => destroy();\n function destroy() {\n if (destroyed) return;\n destroyed = true;\n hls.off(HlsClass.Events.MEDIA_ATTACHING, onMediaAttaching);\n hls.off(HlsClass.Events.MEDIA_DETACHING, onMediaDetaching);\n hls.off(HlsClass.Events.DESTROYING, onDestroying);\n releaseMedia(false);\n pendingAttempt = false;\n }\n\n hls.on(HlsClass.Events.MEDIA_ATTACHING, onMediaAttaching);\n hls.on(HlsClass.Events.MEDIA_DETACHING, onMediaDetaching);\n hls.on(HlsClass.Events.DESTROYING, onDestroying);\n attachMedia();\n return {\n startAttempt() {\n if (destroyed) return;\n if (session) session.startAttempt();\n else pendingAttempt = true;\n },\n sourceChanged() {\n if (destroyed) return;\n pendingAttempt = false;\n session?.sourceChanged();\n },\n destroy,\n };\n}\n"]}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AnalyticsDestination, ChunkifyPlayerAnalyticsEvent } from "./core.js";
|
|
2
|
+
/** POST each event as JSON to a customer endpoint. No credentials or custom headers are accepted. */
|
|
3
|
+
export declare function createHttpAdapter(endpoint: string, mapEvent?: (event: ChunkifyPlayerAnalyticsEvent) => unknown): AnalyticsDestination;
|
|
4
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAEpF,qGAAqG;AACrG,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,OAA0B,GAC5E,oBAAoB,CAoCtB"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** POST each event as JSON to a customer endpoint. No credentials or custom headers are accepted. */
|
|
2
|
+
export function createHttpAdapter(endpoint, mapEvent = (event) => event) {
|
|
3
|
+
if (typeof mapEvent !== "function")
|
|
4
|
+
throw new TypeError("HTTP adapter mapper must be a function.");
|
|
5
|
+
if (typeof endpoint !== "string" || !endpoint || endpoint.startsWith("//")) {
|
|
6
|
+
throw new TypeError("HTTP adapter requires an HTTPS URL or a root-relative path.");
|
|
7
|
+
}
|
|
8
|
+
const rootRelative = endpoint.startsWith("/");
|
|
9
|
+
const absolute = /^[a-z][a-z\d+.-]*:/i.test(endpoint);
|
|
10
|
+
let url;
|
|
11
|
+
try {
|
|
12
|
+
url = new URL(endpoint, "https://chunkify.invalid");
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new TypeError("HTTP adapter requires a valid endpoint URL.");
|
|
16
|
+
}
|
|
17
|
+
const localHttp = url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
18
|
+
if ((!rootRelative && !absolute) ||
|
|
19
|
+
(rootRelative && url.origin !== "https://chunkify.invalid") ||
|
|
20
|
+
(!rootRelative && url.protocol !== "https:" && !localHttp) ||
|
|
21
|
+
url.username || url.password || url.search || url.hash) {
|
|
22
|
+
throw new TypeError("HTTP adapter requires a root-relative path or HTTPS URL without credentials or query parameters (HTTP is allowed on loopback).");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
async send(event) {
|
|
26
|
+
const body = JSON.stringify(mapEvent(event));
|
|
27
|
+
if (body === undefined)
|
|
28
|
+
throw new TypeError("HTTP adapter mapper must return a JSON value.");
|
|
29
|
+
const response = await fetch(endpoint, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "Content-Type": "application/json" },
|
|
32
|
+
body,
|
|
33
|
+
credentials: "omit",
|
|
34
|
+
referrerPolicy: "no-referrer",
|
|
35
|
+
redirect: "error",
|
|
36
|
+
keepalive: event.event_name === "chunkify.video.view_ended",
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok)
|
|
39
|
+
throw new Error(`Analytics endpoint returned HTTP ${response.status}.`);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAEA,qGAAqG;AACrG,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,QAAQ,GAAqD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;IAE7E,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACnG,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,SAAS,CAAC,6DAA6D,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzG,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC;QAC5B,CAAC,YAAY,IAAI,GAAG,CAAC,MAAM,KAAK,0BAA0B,CAAC;QAC3D,CAAC,CAAC,YAAY,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC;QAC1D,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CAAC,gIAAgI,CAAC,CAAC;IACxJ,CAAC;IACD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,KAAmC;YAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7C,IAAI,IAAI,KAAK,SAAS;gBAAE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;YAC7F,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI;gBACJ,WAAW,EAAE,MAAM;gBACnB,cAAc,EAAE,aAAa;gBAC7B,QAAQ,EAAE,OAAO;gBACjB,SAAS,EAAE,KAAK,CAAC,UAAU,KAAK,2BAA2B;aAC5D,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5F,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { AnalyticsDestination, ChunkifyPlayerAnalyticsEvent } from \"./core.js\";\n\n/** POST each event as JSON to a customer endpoint. No credentials or custom headers are accepted. */\nexport function createHttpAdapter(\n endpoint: string,\n mapEvent: (event: ChunkifyPlayerAnalyticsEvent) => unknown = (event) => event,\n): AnalyticsDestination {\n if (typeof mapEvent !== \"function\") throw new TypeError(\"HTTP adapter mapper must be a function.\");\n if (typeof endpoint !== \"string\" || !endpoint || endpoint.startsWith(\"//\")) {\n throw new TypeError(\"HTTP adapter requires an HTTPS URL or a root-relative path.\");\n }\n const rootRelative = endpoint.startsWith(\"/\");\n const absolute = /^[a-z][a-z\\d+.-]*:/i.test(endpoint);\n let url: URL;\n try {\n url = new URL(endpoint, \"https://chunkify.invalid\");\n } catch {\n throw new TypeError(\"HTTP adapter requires a valid endpoint URL.\");\n }\n const localHttp = url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname);\n if ((!rootRelative && !absolute) ||\n (rootRelative && url.origin !== \"https://chunkify.invalid\") ||\n (!rootRelative && url.protocol !== \"https:\" && !localHttp) ||\n url.username || url.password || url.search || url.hash) {\n throw new TypeError(\"HTTP adapter requires a root-relative path or HTTPS URL without credentials or query parameters (HTTP is allowed on loopback).\");\n }\n return {\n async send(event: ChunkifyPlayerAnalyticsEvent) {\n const body = JSON.stringify(mapEvent(event));\n if (body === undefined) throw new TypeError(\"HTTP adapter mapper must return a JSON value.\");\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body,\n credentials: \"omit\",\n referrerPolicy: \"no-referrer\",\n redirect: \"error\",\n keepalive: event.event_name === \"chunkify.video.view_ended\",\n });\n if (!response.ok) throw new Error(`Analytics endpoint returned HTTP ${response.status}.`);\n },\n };\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { attachAnalytics } from "./core.js";
|
|
2
|
+
export type { AnalyticsEventType, AnalyticsEndReason, AnalyticsErrorCategory, AnalyticsStartupOutcome, AnalyticsPlaybackState, AnalyticsEventEnvelope, AnalyticsViewEvent, AnalyticsPlaybackStateEvent, AnalyticsRenditionEvent, RenditionPlayingTime, AnalyticsRendition, ViewMetrics, ChunkifyPlayerAnalyticsEvent, AnalyticsDestination, AnalyticsConfig, AnalyticsOptions, AnalyticsConnectorSnapshot, AnalyticsConnectorError, AnalyticsConnector, AnalyticsSession } from "./core.js";
|
|
3
|
+
export { createEventMapper } from "./mapper.js";
|
|
4
|
+
export { monitor, type MonitorSession } from "./monitor.js";
|
|
5
|
+
export { monitorHlsJs } from "./hlsjs.js";
|
|
6
|
+
export { monitorVideoJs } from "./videojs.js";
|
|
7
|
+
export { monitorShaka } from "./shaka.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,uBAAuB,EACnG,sBAAsB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,2BAA2B,EAC/F,uBAAuB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,WAAW,EAAE,4BAA4B,EAC5G,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,0BAA0B,EACnF,uBAAuB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { attachAnalytics } from "./core.js";
|
|
2
|
+
export { createEventMapper } from "./mapper.js";
|
|
3
|
+
export { monitor } from "./monitor.js";
|
|
4
|
+
export { monitorHlsJs } from "./hlsjs.js";
|
|
5
|
+
export { monitorVideoJs } from "./videojs.js";
|
|
6
|
+
export { monitorShaka } from "./shaka.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAM5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { attachAnalytics } from \"./core.js\";\nexport type { AnalyticsEventType, AnalyticsEndReason, AnalyticsErrorCategory, AnalyticsStartupOutcome,\n AnalyticsPlaybackState, AnalyticsEventEnvelope, AnalyticsViewEvent, AnalyticsPlaybackStateEvent,\n AnalyticsRenditionEvent, RenditionPlayingTime, AnalyticsRendition, ViewMetrics, ChunkifyPlayerAnalyticsEvent,\n AnalyticsDestination, AnalyticsConfig, AnalyticsOptions, AnalyticsConnectorSnapshot,\n AnalyticsConnectorError, AnalyticsConnector, AnalyticsSession } from \"./core.js\";\nexport { createEventMapper } from \"./mapper.js\";\nexport { monitor, type MonitorSession } from \"./monitor.js\";\nexport { monitorHlsJs } from \"./hlsjs.js\";\nexport { monitorVideoJs } from \"./videojs.js\";\nexport { monitorShaka } from \"./shaka.js\";\n"]}
|
package/dist/mapper.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AnalyticsPlaybackStateEvent, AnalyticsRenditionEvent, AnalyticsViewEvent, ChunkifyPlayerAnalyticsEvent } from "./core.js";
|
|
2
|
+
type EventField = keyof AnalyticsViewEvent | keyof AnalyticsPlaybackStateEvent | keyof AnalyticsRenditionEvent;
|
|
3
|
+
type FieldSelector = EventField | ((event: ChunkifyPlayerAnalyticsEvent) => unknown);
|
|
4
|
+
type EventFieldValue<Key extends EventField> = ChunkifyPlayerAnalyticsEvent extends infer Event ? Event extends unknown ? Key extends keyof Event ? Event[Key] : undefined : never : never;
|
|
5
|
+
type SelectedValue<Selector> = Selector extends EventField ? EventFieldValue<Selector> : Selector extends (event: ChunkifyPlayerAnalyticsEvent) => infer Value ? Value : never;
|
|
6
|
+
/** Select, rename, or calculate fields for a destination without changing the source event. */
|
|
7
|
+
export declare function createEventMapper<const Fields extends Record<string, FieldSelector>>(fields: Fields): (event: ChunkifyPlayerAnalyticsEvent) => {
|
|
8
|
+
[Name in keyof Fields]: SelectedValue<Fields[Name]>;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,kBAAkB,EACpF,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAElD,KAAK,UAAU,GAAG,MAAM,kBAAkB,GAAG,MAAM,2BAA2B,GAAG,MAAM,uBAAuB,CAAC;AAC/G,KAAK,aAAa,GAAG,UAAU,GAAG,CAAC,CAAC,KAAK,EAAE,4BAA4B,KAAK,OAAO,CAAC,CAAC;AACrF,KAAK,eAAe,CAAC,GAAG,SAAS,UAAU,IAAI,4BAA4B,SAAS,MAAM,KAAK,GAC3F,KAAK,SAAS,OAAO,GAAG,GAAG,SAAS,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,KAAK,GAChF,KAAK,CAAC;AACV,KAAK,aAAa,CAAC,QAAQ,IAAI,QAAQ,SAAS,UAAU,GACtD,eAAe,CAAC,QAAQ,CAAC,GACzB,QAAQ,SAAS,CAAC,KAAK,EAAE,4BAA4B,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1F,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,GAClG,CAAC,KAAK,EAAE,4BAA4B,KAAK;KAAG,IAAI,IAAI,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CAAE,CAOjG"}
|
package/dist/mapper.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Select, rename, or calculate fields for a destination without changing the source event. */
|
|
2
|
+
export function createEventMapper(fields) {
|
|
3
|
+
const entries = Object.entries(fields);
|
|
4
|
+
return (event) => Object.fromEntries(entries.flatMap(([name, source]) => {
|
|
5
|
+
if (typeof source !== "function" && !(source in event))
|
|
6
|
+
return [];
|
|
7
|
+
const value = typeof source === "function" ? source(event) : event[source];
|
|
8
|
+
return value === undefined ? [] : [[name, value]];
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.js","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAYA,+FAA+F;AAC/F,MAAM,UAAU,iBAAiB,CAAqD,MAAc;IAElG,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE;QACtE,IAAI,OAAO,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClE,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAA4B,CAAC,CAAC;QACjG,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAA4D,CAAC;AACjE,CAAC","sourcesContent":["import type { AnalyticsPlaybackStateEvent, AnalyticsRenditionEvent, AnalyticsViewEvent,\n ChunkifyPlayerAnalyticsEvent } from \"./core.js\";\n\ntype EventField = keyof AnalyticsViewEvent | keyof AnalyticsPlaybackStateEvent | keyof AnalyticsRenditionEvent;\ntype FieldSelector = EventField | ((event: ChunkifyPlayerAnalyticsEvent) => unknown);\ntype EventFieldValue<Key extends EventField> = ChunkifyPlayerAnalyticsEvent extends infer Event\n ? Event extends unknown ? Key extends keyof Event ? Event[Key] : undefined : never\n : never;\ntype SelectedValue<Selector> = Selector extends EventField\n ? EventFieldValue<Selector>\n : Selector extends (event: ChunkifyPlayerAnalyticsEvent) => infer Value ? Value : never;\n\n/** Select, rename, or calculate fields for a destination without changing the source event. */\nexport function createEventMapper<const Fields extends Record<string, FieldSelector>>(fields: Fields):\n (event: ChunkifyPlayerAnalyticsEvent) => { [Name in keyof Fields]: SelectedValue<Fields[Name]> } {\n const entries = Object.entries(fields);\n return (event) => Object.fromEntries(entries.flatMap(([name, source]) => {\n if (typeof source !== \"function\" && !(source in event)) return [];\n const value = typeof source === \"function\" ? source(event) : event[source as keyof typeof event];\n return value === undefined ? [] : [[name, value]];\n })) as { [Name in keyof Fields]: SelectedValue<Fields[Name]> };\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type AnalyticsOptions, type AnalyticsSession } from "./core.js";
|
|
2
|
+
import { type MediaPlayerHost } from "./player.js";
|
|
3
|
+
export type MonitorSession = Pick<AnalyticsSession, "startAttempt" | "sourceChanged" | "destroy">;
|
|
4
|
+
/** Start analytics for a video element or a Chunkify Player. */
|
|
5
|
+
export declare function monitor(target: HTMLVideoElement | MediaPlayerHost, options: AnalyticsOptions): MonitorSession;
|
|
6
|
+
//# sourceMappingURL=monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC1F,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1E,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,GAAG,eAAe,GAAG,SAAS,CAAC,CAAC;AAElG,gEAAgE;AAChE,wBAAgB,OAAO,CAAC,MAAM,EAAE,gBAAgB,GAAG,eAAe,EAAE,OAAO,EAAE,gBAAgB,GAAG,cAAc,CAQ7G"}
|
package/dist/monitor.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { attachAnalytics } from "./core.js";
|
|
2
|
+
import { attachPlayerAnalytics } from "./player.js";
|
|
3
|
+
/** Start analytics for a video element or a Chunkify Player. */
|
|
4
|
+
export function monitor(target, options) {
|
|
5
|
+
const view = target?.ownerDocument?.defaultView;
|
|
6
|
+
if (view && target instanceof view.HTMLVideoElement)
|
|
7
|
+
return attachAnalytics(target, options);
|
|
8
|
+
if (view && target instanceof view.HTMLElement
|
|
9
|
+
&& target.localName === "chunkify-player" && "media" in target) {
|
|
10
|
+
return attachPlayerAnalytics(target, options);
|
|
11
|
+
}
|
|
12
|
+
throw new TypeError("Analytics supports a <video> or <chunkify-player> element.");
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor.js","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgD,MAAM,WAAW,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAwB,MAAM,aAAa,CAAC;AAI1E,gEAAgE;AAChE,MAAM,UAAU,OAAO,CAAC,MAA0C,EAAE,OAAyB;IAC3F,MAAM,IAAI,GAAG,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC;IAChD,IAAI,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,gBAAgB;QAAE,OAAO,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7F,IAAI,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,WAAW;WACzC,MAAM,CAAC,SAAS,KAAK,iBAAiB,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;QACjE,OAAO,qBAAqB,CAAC,MAAyB,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,4DAA4D,CAAC,CAAC;AACpF,CAAC","sourcesContent":["import { attachAnalytics, type AnalyticsOptions, type AnalyticsSession } from \"./core.js\";\nimport { attachPlayerAnalytics, type MediaPlayerHost } from \"./player.js\";\n\nexport type MonitorSession = Pick<AnalyticsSession, \"startAttempt\" | \"sourceChanged\" | \"destroy\">;\n\n/** Start analytics for a video element or a Chunkify Player. */\nexport function monitor(target: HTMLVideoElement | MediaPlayerHost, options: AnalyticsOptions): MonitorSession {\n const view = target?.ownerDocument?.defaultView;\n if (view && target instanceof view.HTMLVideoElement) return attachAnalytics(target, options);\n if (view && target instanceof view.HTMLElement\n && target.localName === \"chunkify-player\" && \"media\" in target) {\n return attachPlayerAnalytics(target as MediaPlayerHost, options);\n }\n throw new TypeError(\"Analytics supports a <video> or <chunkify-player> element.\");\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAKlD,wEAAwE;AACxE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAqBtE"}
|