@videojs/spf 10.0.0-beta.11 → 10.0.0-beta.13
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/dist/default/core/abr/bandwidth-estimator.js +2 -3
- package/dist/default/core/abr/bandwidth-estimator.js.map +1 -1
- package/dist/default/core/abr/ewma.js +1 -1
- package/dist/default/core/abr/quality-selection.js +2 -2
- package/dist/default/core/abr/quality-selection.js.map +1 -1
- package/dist/default/core/buffer/back-buffer.js +2 -2
- package/dist/default/core/buffer/forward-buffer.js +1 -1
- package/dist/default/core/features/calculate-presentation-duration.js +11 -9
- package/dist/default/core/features/calculate-presentation-duration.js.map +1 -1
- package/dist/default/core/features/quality-switching.js +7 -6
- package/dist/default/core/features/quality-switching.js.map +1 -1
- package/dist/default/core/features/resolve-presentation.js +30 -52
- package/dist/default/core/features/resolve-presentation.js.map +1 -1
- package/dist/default/core/features/resolve-track.js +17 -28
- package/dist/default/core/features/resolve-track.js.map +1 -1
- package/dist/default/core/features/select-tracks.js +18 -35
- package/dist/default/core/features/select-tracks.js.map +1 -1
- package/dist/default/core/features/sync-preload-attribute.js +26 -0
- package/dist/default/core/features/sync-preload-attribute.js.map +1 -0
- package/dist/default/core/hls/parse-attributes.js +1 -1
- package/dist/default/core/hls/parse-attributes.js.map +1 -1
- package/dist/default/core/hls/parse-media-playlist.js +1 -2
- package/dist/default/core/hls/parse-media-playlist.js.map +1 -1
- package/dist/default/core/hls/parse-multivariant.js +2 -3
- package/dist/default/core/hls/parse-multivariant.js.map +1 -1
- package/dist/default/core/hls/resolve-url.js +1 -1
- package/dist/default/core/signals/effect.js +41 -0
- package/dist/default/core/signals/effect.js.map +1 -0
- package/dist/default/core/signals/primitives.js +32 -0
- package/dist/default/core/signals/primitives.js.map +1 -0
- package/dist/default/core/task.js +3 -3
- package/dist/default/core/task.js.map +1 -1
- package/dist/default/core/types/index.js +1 -1
- package/dist/default/core/types/index.js.map +1 -1
- package/dist/default/core/utils/generate-id.js +1 -1
- package/dist/default/core/utils/track-selection.js +10 -2
- package/dist/default/core/utils/track-selection.js.map +1 -1
- package/dist/default/dom/features/end-of-stream.js +24 -48
- package/dist/default/dom/features/end-of-stream.js.map +1 -1
- package/dist/default/dom/features/load-segments.js +40 -36
- package/dist/default/dom/features/load-segments.js.map +1 -1
- package/dist/default/dom/features/load-text-track-cues.js +36 -26
- package/dist/default/dom/features/load-text-track-cues.js.map +1 -1
- package/dist/default/dom/features/segment-loader-actor.js +4 -5
- package/dist/default/dom/features/segment-loader-actor.js.map +1 -1
- package/dist/default/dom/features/setup-mediasource.js +29 -36
- package/dist/default/dom/features/setup-mediasource.js.map +1 -1
- package/dist/default/dom/features/setup-sourcebuffer.js +43 -35
- package/dist/default/dom/features/setup-sourcebuffer.js.map +1 -1
- package/dist/default/dom/features/setup-text-tracks.js +25 -46
- package/dist/default/dom/features/setup-text-tracks.js.map +1 -1
- package/dist/default/dom/features/sync-selected-text-track-from-dom.js +14 -23
- package/dist/default/dom/features/sync-selected-text-track-from-dom.js.map +1 -1
- package/dist/default/dom/features/sync-text-track-modes.js +12 -17
- package/dist/default/dom/features/sync-text-track-modes.js.map +1 -1
- package/dist/default/dom/features/track-current-time.js +10 -7
- package/dist/default/dom/features/track-current-time.js.map +1 -1
- package/dist/default/dom/features/track-playback-initiated.js +34 -36
- package/dist/default/dom/features/track-playback-initiated.js.map +1 -1
- package/dist/default/dom/features/track-playback-rate.js +12 -16
- package/dist/default/dom/features/track-playback-rate.js.map +1 -1
- package/dist/default/dom/features/update-duration.js +19 -13
- package/dist/default/dom/features/update-duration.js.map +1 -1
- package/dist/default/dom/media/append-segment.js +1 -1
- package/dist/default/dom/media/buffer-flusher.js +1 -1
- package/dist/default/dom/media/mediasource-setup.js +32 -40
- package/dist/default/dom/media/mediasource-setup.js.map +1 -1
- package/dist/default/dom/media/source-buffer-actor.js +16 -26
- package/dist/default/dom/media/source-buffer-actor.js.map +1 -1
- package/dist/default/dom/network/chunked-stream-iterable.js +1 -1
- package/dist/default/dom/network/chunked-stream-iterable.js.map +1 -1
- package/dist/default/dom/network/fetch.js +1 -2
- package/dist/default/dom/network/fetch.js.map +1 -1
- package/dist/default/dom/playback-engine/adapter.js +13 -13
- package/dist/default/dom/playback-engine/adapter.js.map +1 -1
- package/dist/default/dom/playback-engine/engine.js +24 -49
- package/dist/default/dom/playback-engine/engine.js.map +1 -1
- package/dist/default/dom/playback-engine.js +2 -2
- package/dist/default/dom/text/parse-vtt-segment.js +1 -1
- package/dist/default/dom.js +1 -2
- package/dist/default/index.js +1 -1
- package/dist/dev/core/abr/bandwidth-estimator.js +2 -3
- package/dist/dev/core/abr/bandwidth-estimator.js.map +1 -1
- package/dist/dev/core/abr/ewma.js +1 -1
- package/dist/dev/core/abr/quality-selection.js +2 -2
- package/dist/dev/core/abr/quality-selection.js.map +1 -1
- package/dist/dev/core/actor.d.ts +6 -19
- package/dist/dev/core/actor.d.ts.map +1 -1
- package/dist/dev/core/buffer/back-buffer.js +2 -2
- package/dist/dev/core/buffer/forward-buffer.js +1 -1
- package/dist/dev/core/features/calculate-presentation-duration.js +11 -9
- package/dist/dev/core/features/calculate-presentation-duration.js.map +1 -1
- package/dist/dev/core/features/quality-switching.js +7 -6
- package/dist/dev/core/features/quality-switching.js.map +1 -1
- package/dist/dev/core/features/resolve-presentation.js +30 -52
- package/dist/dev/core/features/resolve-presentation.js.map +1 -1
- package/dist/dev/core/features/resolve-track.js +17 -28
- package/dist/dev/core/features/resolve-track.js.map +1 -1
- package/dist/dev/core/features/select-tracks.js +18 -35
- package/dist/dev/core/features/select-tracks.js.map +1 -1
- package/dist/dev/core/features/sync-preload-attribute.js +26 -0
- package/dist/dev/core/features/sync-preload-attribute.js.map +1 -0
- package/dist/dev/core/hls/parse-attributes.js +1 -1
- package/dist/dev/core/hls/parse-attributes.js.map +1 -1
- package/dist/dev/core/hls/parse-media-playlist.js +1 -2
- package/dist/dev/core/hls/parse-media-playlist.js.map +1 -1
- package/dist/dev/core/hls/parse-multivariant.js +2 -3
- package/dist/dev/core/hls/parse-multivariant.js.map +1 -1
- package/dist/dev/core/hls/resolve-url.js +1 -1
- package/dist/dev/core/signals/effect.d.ts +15 -0
- package/dist/dev/core/signals/effect.d.ts.map +1 -0
- package/dist/dev/core/signals/effect.js +41 -0
- package/dist/dev/core/signals/effect.js.map +1 -0
- package/dist/dev/core/signals/primitives.d.ts +10 -0
- package/dist/dev/core/signals/primitives.d.ts.map +1 -0
- package/dist/dev/core/signals/primitives.js +32 -0
- package/dist/dev/core/signals/primitives.js.map +1 -0
- package/dist/dev/core/task.js +3 -3
- package/dist/dev/core/task.js.map +1 -1
- package/dist/dev/core/types/index.js +1 -1
- package/dist/dev/core/types/index.js.map +1 -1
- package/dist/dev/core/utils/generate-id.js +1 -1
- package/dist/dev/core/utils/track-selection.js +10 -2
- package/dist/dev/core/utils/track-selection.js.map +1 -1
- package/dist/dev/dom/features/end-of-stream.js +24 -48
- package/dist/dev/dom/features/end-of-stream.js.map +1 -1
- package/dist/dev/dom/features/load-segments.d.ts +4 -4
- package/dist/dev/dom/features/load-segments.d.ts.map +1 -1
- package/dist/dev/dom/features/load-segments.js +40 -36
- package/dist/dev/dom/features/load-segments.js.map +1 -1
- package/dist/dev/dom/features/load-text-track-cues.d.ts +4 -4
- package/dist/dev/dom/features/load-text-track-cues.d.ts.map +1 -1
- package/dist/dev/dom/features/load-text-track-cues.js +36 -26
- package/dist/dev/dom/features/load-text-track-cues.js.map +1 -1
- package/dist/dev/dom/features/segment-loader-actor.d.ts +1 -0
- package/dist/dev/dom/features/segment-loader-actor.js +4 -5
- package/dist/dev/dom/features/segment-loader-actor.js.map +1 -1
- package/dist/dev/dom/features/setup-mediasource.js +29 -36
- package/dist/dev/dom/features/setup-mediasource.js.map +1 -1
- package/dist/dev/dom/features/setup-sourcebuffer.d.ts.map +1 -1
- package/dist/dev/dom/features/setup-sourcebuffer.js +43 -35
- package/dist/dev/dom/features/setup-sourcebuffer.js.map +1 -1
- package/dist/dev/dom/features/setup-text-tracks.js +25 -46
- package/dist/dev/dom/features/setup-text-tracks.js.map +1 -1
- package/dist/dev/dom/features/sync-selected-text-track-from-dom.js +14 -23
- package/dist/dev/dom/features/sync-selected-text-track-from-dom.js.map +1 -1
- package/dist/dev/dom/features/sync-text-track-modes.js +12 -17
- package/dist/dev/dom/features/sync-text-track-modes.js.map +1 -1
- package/dist/dev/dom/features/track-current-time.d.ts +4 -4
- package/dist/dev/dom/features/track-current-time.d.ts.map +1 -1
- package/dist/dev/dom/features/track-current-time.js +10 -7
- package/dist/dev/dom/features/track-current-time.js.map +1 -1
- package/dist/dev/dom/features/track-playback-initiated.d.ts +14 -23
- package/dist/dev/dom/features/track-playback-initiated.d.ts.map +1 -1
- package/dist/dev/dom/features/track-playback-initiated.js +34 -36
- package/dist/dev/dom/features/track-playback-initiated.js.map +1 -1
- package/dist/dev/dom/features/track-playback-rate.d.ts +4 -4
- package/dist/dev/dom/features/track-playback-rate.d.ts.map +1 -1
- package/dist/dev/dom/features/track-playback-rate.js +12 -16
- package/dist/dev/dom/features/track-playback-rate.js.map +1 -1
- package/dist/dev/dom/features/update-duration.js +19 -13
- package/dist/dev/dom/features/update-duration.js.map +1 -1
- package/dist/dev/dom/media/append-segment.js +1 -1
- package/dist/dev/dom/media/buffer-flusher.js +1 -1
- package/dist/dev/dom/media/mediasource-setup.js +32 -40
- package/dist/dev/dom/media/mediasource-setup.js.map +1 -1
- package/dist/dev/dom/media/source-buffer-actor.d.ts +2 -2
- package/dist/dev/dom/media/source-buffer-actor.d.ts.map +1 -1
- package/dist/dev/dom/media/source-buffer-actor.js +16 -26
- package/dist/dev/dom/media/source-buffer-actor.js.map +1 -1
- package/dist/dev/dom/network/chunked-stream-iterable.js +1 -1
- package/dist/dev/dom/network/chunked-stream-iterable.js.map +1 -1
- package/dist/dev/dom/network/fetch.js +1 -2
- package/dist/dev/dom/network/fetch.js.map +1 -1
- package/dist/dev/dom/playback-engine/adapter.d.ts.map +1 -1
- package/dist/dev/dom/playback-engine/adapter.js +13 -13
- package/dist/dev/dom/playback-engine/adapter.js.map +1 -1
- package/dist/dev/dom/playback-engine/engine.d.ts +14 -26
- package/dist/dev/dom/playback-engine/engine.d.ts.map +1 -1
- package/dist/dev/dom/playback-engine/engine.js +24 -49
- package/dist/dev/dom/playback-engine/engine.js.map +1 -1
- package/dist/dev/dom/playback-engine.d.ts +3 -2
- package/dist/dev/dom/playback-engine.js +2 -2
- package/dist/dev/dom/text/parse-vtt-segment.js +1 -1
- package/dist/dev/dom.js +1 -2
- package/dist/dev/index.js +1 -1
- package/package.json +5 -4
- package/dist/default/all.js +0 -16
- package/dist/default/core/events/create-event-stream.js +0 -48
- package/dist/default/core/events/create-event-stream.js.map +0 -1
- package/dist/default/core/reactive/combine-latest.js +0 -72
- package/dist/default/core/reactive/combine-latest.js.map +0 -1
- package/dist/default/core/state/create-state.js +0 -143
- package/dist/default/core/state/create-state.js.map +0 -1
- package/dist/dev/all.js +0 -16
- package/dist/dev/core/events/create-event-stream.d.ts +0 -48
- package/dist/dev/core/events/create-event-stream.d.ts.map +0 -1
- package/dist/dev/core/events/create-event-stream.js +0 -48
- package/dist/dev/core/events/create-event-stream.js.map +0 -1
- package/dist/dev/core/features/resolve-presentation.d.ts +0 -16
- package/dist/dev/core/features/resolve-presentation.d.ts.map +0 -1
- package/dist/dev/core/features/resolve-track.d.ts +0 -13
- package/dist/dev/core/features/resolve-track.d.ts.map +0 -1
- package/dist/dev/core/features/select-tracks.d.ts +0 -11
- package/dist/dev/core/features/select-tracks.d.ts.map +0 -1
- package/dist/dev/core/reactive/combine-latest.js +0 -72
- package/dist/dev/core/reactive/combine-latest.js.map +0 -1
- package/dist/dev/core/state/create-state.d.ts +0 -104
- package/dist/dev/core/state/create-state.d.ts.map +0 -1
- package/dist/dev/core/state/create-state.js +0 -143
- package/dist/dev/core/state/create-state.js.map +0 -1
package/dist/dev/dom.js
CHANGED
|
@@ -7,5 +7,4 @@ import { trackPlaybackRate } from "./dom/features/track-playback-rate.js";
|
|
|
7
7
|
import { appendSegment } from "./dom/media/append-segment.js";
|
|
8
8
|
import { flushBuffer } from "./dom/media/buffer-flusher.js";
|
|
9
9
|
import { SpfMedia } from "./dom/playback-engine/adapter.js";
|
|
10
|
-
|
|
11
|
-
export { SpfMedia, appendSegment, destroyVttParser, flushBuffer, loadSegments, loadTextTrackCues, parseVttSegment, trackCurrentTime, trackPlaybackInitiated, trackPlaybackRate };
|
|
10
|
+
export { SpfMedia, appendSegment, destroyVttParser, flushBuffer, loadSegments, loadTextTrackCues, parseVttSegment, trackCurrentTime, trackPlaybackInitiated, trackPlaybackRate };
|
package/dist/dev/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@videojs/spf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "10.0.0-beta.
|
|
4
|
+
"version": "10.0.0-beta.13",
|
|
5
5
|
"description": "Stream Processing Framework for Video.js 10",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"dist"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"
|
|
43
|
+
"signal-polyfill": "^0.2.2",
|
|
44
|
+
"@videojs/utils": "10.0.0-beta.13"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@vitest/browser": "^4.1.0",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@vitest/coverage-v8": "^4.1.0",
|
|
49
50
|
"jsdom": "^26.1.0",
|
|
50
51
|
"playwright": "^1.58.1",
|
|
51
|
-
"tsdown": "^0.
|
|
52
|
+
"tsdown": "^0.21.4",
|
|
52
53
|
"typescript": "^6.0.2",
|
|
53
54
|
"vitest": "^4.1.0"
|
|
54
55
|
},
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
"dev": "pnpm run build:watch",
|
|
62
63
|
"test": "vitest run",
|
|
63
64
|
"test:watch": "vitest",
|
|
64
|
-
"clean": "
|
|
65
|
+
"clean": "rimraf --glob dist types '*.tsbuildinfo'",
|
|
65
66
|
"size": "node scripts/measure-size.js --playback-engine",
|
|
66
67
|
"size:all": "node scripts/measure-size.js --all"
|
|
67
68
|
}
|
package/dist/default/all.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { VERSION } from "./index.js";
|
|
2
|
-
import { createState } from "./core/state/create-state.js";
|
|
3
|
-
import { resolveUrl } from "./core/hls/resolve-url.js";
|
|
4
|
-
import { parseMediaPlaylist } from "./core/hls/parse-media-playlist.js";
|
|
5
|
-
import { parseMultivariantPlaylist } from "./core/hls/parse-multivariant.js";
|
|
6
|
-
import { DEFAULT_BANDWIDTH_CONFIG, getBandwidthEstimate, sampleBandwidth } from "./core/abr/bandwidth-estimator.js";
|
|
7
|
-
import { DEFAULT_QUALITY_CONFIG, selectQuality } from "./core/abr/quality-selection.js";
|
|
8
|
-
import { DEFAULT_BACK_BUFFER_CONFIG, calculateBackBufferFlushPoint } from "./core/buffer/back-buffer.js";
|
|
9
|
-
import { DEFAULT_FORWARD_BUFFER_CONFIG, getSegmentsToLoad } from "./core/buffer/forward-buffer.js";
|
|
10
|
-
import { hasPresentationDuration, isResolvedTrack } from "./core/types/index.js";
|
|
11
|
-
import { attachMediaSource, createMediaSource, createSourceBuffer, isCodecSupported, supportsManagedMediaSource, supportsMediaSource, waitForSourceOpen } from "./dom/media/mediasource-setup.js";
|
|
12
|
-
import { fetchResolvable, getResponseText } from "./dom/network/fetch.js";
|
|
13
|
-
import { createEventStream } from "./core/events/create-event-stream.js";
|
|
14
|
-
import { combineLatest } from "./core/reactive/combine-latest.js";
|
|
15
|
-
import { canResolve, isUnresolved, resolvePresentation, shouldResolve, syncPreloadAttribute } from "./core/features/resolve-presentation.js";
|
|
16
|
-
import { DEFAULT_SWITCHING_CONFIG, switchQuality } from "./core/features/quality-switching.js";
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
//#region src/core/events/create-event-stream.ts
|
|
2
|
-
/**
|
|
3
|
-
* Minimal event stream with Observable-like shape.
|
|
4
|
-
*
|
|
5
|
-
* Simple Subject/Observable-like implementation for dispatching discrete events.
|
|
6
|
-
* Events are dispatched synchronously to all subscribers.
|
|
7
|
-
*/
|
|
8
|
-
const EVENT_STREAM_SYMBOL = Symbol("@videojs/event-stream");
|
|
9
|
-
/**
|
|
10
|
-
* Creates a minimal event stream for dispatching discrete events.
|
|
11
|
-
*
|
|
12
|
-
* Events are dispatched synchronously to all subscribers.
|
|
13
|
-
* Conforms to Observable-like shape for future compatibility.
|
|
14
|
-
*
|
|
15
|
-
* Events must have a 'type' property for discriminated union type narrowing.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```ts
|
|
19
|
-
* type Action = { type: 'PLAY' } | { type: 'PAUSE' };
|
|
20
|
-
* const events = createEventStream<Action>();
|
|
21
|
-
*
|
|
22
|
-
* events.subscribe((action) => {
|
|
23
|
-
* if (action.type === 'PLAY') {
|
|
24
|
-
* // Type narrowed to { type: 'PLAY' }
|
|
25
|
-
* }
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* events.dispatch({ type: 'PLAY' });
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
function createEventStream() {
|
|
32
|
-
const subscribers = /* @__PURE__ */ new Set();
|
|
33
|
-
return {
|
|
34
|
-
[EVENT_STREAM_SYMBOL]: true,
|
|
35
|
-
dispatch(event) {
|
|
36
|
-
const current = Array.from(subscribers);
|
|
37
|
-
for (const listener of current) listener(event);
|
|
38
|
-
},
|
|
39
|
-
subscribe(listener) {
|
|
40
|
-
subscribers.add(listener);
|
|
41
|
-
return () => subscribers.delete(listener);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//#endregion
|
|
47
|
-
export { createEventStream };
|
|
48
|
-
//# sourceMappingURL=create-event-stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-event-stream.js","names":[],"sources":["../../../../src/core/events/create-event-stream.ts"],"sourcesContent":["/**\n * Minimal event stream with Observable-like shape.\n *\n * Simple Subject/Observable-like implementation for dispatching discrete events.\n * Events are dispatched synchronously to all subscribers.\n */\n\nconst EVENT_STREAM_SYMBOL = Symbol('@videojs/event-stream');\n\n/**\n * Event listener function.\n */\nexport type EventListener<T extends Pick<Event, 'type'>> = (event: T) => void;\n\n/**\n * Event stream interface.\n */\nexport interface EventStream<T extends Pick<Event, 'type'> = { type: string }> {\n [EVENT_STREAM_SYMBOL]: true;\n dispatch(event: T): void;\n subscribe(listener: EventListener<T>): () => void;\n}\n\n/**\n * Creates a minimal event stream for dispatching discrete events.\n *\n * Events are dispatched synchronously to all subscribers.\n * Conforms to Observable-like shape for future compatibility.\n *\n * Events must have a 'type' property for discriminated union type narrowing.\n *\n * @example\n * ```ts\n * type Action = { type: 'PLAY' } | { type: 'PAUSE' };\n * const events = createEventStream<Action>();\n *\n * events.subscribe((action) => {\n * if (action.type === 'PLAY') {\n * // Type narrowed to { type: 'PLAY' }\n * }\n * });\n *\n * events.dispatch({ type: 'PLAY' });\n * ```\n */\nexport function createEventStream<T extends Pick<Event, 'type'>>(): EventStream<T> {\n const subscribers = new Set<EventListener<T>>();\n\n return {\n [EVENT_STREAM_SYMBOL]: true,\n\n dispatch(event: T): void {\n // Snapshot subscribers to avoid notifying those added during dispatch\n const current = Array.from(subscribers);\n for (const listener of current) {\n listener(event);\n }\n },\n\n subscribe(listener: EventListener<T>): () => void {\n subscribers.add(listener);\n return () => subscribers.delete(listener);\n },\n };\n}\n\n/**\n * Type guard to check if value is an EventStream.\n */\nexport function isEventStream(value: unknown): value is EventStream {\n return typeof value === 'object' && value !== null && EVENT_STREAM_SYMBOL in value;\n}\n"],"mappings":";;;;;;;AAOA,MAAM,sBAAsB,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;AAsC3D,SAAgB,oBAAmE;CACjF,MAAM,8BAAc,IAAI,KAAuB;AAE/C,QAAO;GACJ,sBAAsB;EAEvB,SAAS,OAAgB;GAEvB,MAAM,UAAU,MAAM,KAAK,YAAY;AACvC,QAAK,MAAM,YAAY,QACrB,UAAS,MAAM;;EAInB,UAAU,UAAwC;AAChD,eAAY,IAAI,SAAS;AACzB,gBAAa,YAAY,OAAO,SAAS;;EAE5C"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
//#region src/core/reactive/combine-latest.ts
|
|
2
|
-
/**
|
|
3
|
-
* Combines multiple Observable sources into a single Observable.
|
|
4
|
-
*
|
|
5
|
-
* Emits an array of latest values whenever any source emits.
|
|
6
|
-
* Only emits after all sources have emitted at least once.
|
|
7
|
-
*
|
|
8
|
-
* Supports selector-based subscriptions (fires only when the selected value
|
|
9
|
-
* changes, per the optional equalityFn) mirroring the createState API.
|
|
10
|
-
*
|
|
11
|
-
* @param sources - Array of Observable sources
|
|
12
|
-
* @returns Combined Observable
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* const state = createState({ count: 0 });
|
|
17
|
-
* const events = createEventStream<Action>();
|
|
18
|
-
*
|
|
19
|
-
* combineLatest([state, events]).subscribe(([state, event]) => {
|
|
20
|
-
* if (event.type === 'PLAY' && state.count > 0) {
|
|
21
|
-
* // React to event + state condition
|
|
22
|
-
* }
|
|
23
|
-
* });
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @example Selector subscription
|
|
27
|
-
* ```ts
|
|
28
|
-
* combineLatest([state, owners]).subscribe(
|
|
29
|
-
* ([s, o]) => deriveKey(s, o),
|
|
30
|
-
* (key) => { ... },
|
|
31
|
-
* { equalityFn: keyEq }
|
|
32
|
-
* );
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
function combineLatest(sources) {
|
|
36
|
-
const subscribeToSources = (listener) => {
|
|
37
|
-
const latest = new Array(sources.length);
|
|
38
|
-
const hasValue = new Array(sources.length).fill(false);
|
|
39
|
-
const unsubscribers = [];
|
|
40
|
-
for (let i = 0; i < sources.length; i++) {
|
|
41
|
-
const unsubscribe = sources[i].subscribe((value) => {
|
|
42
|
-
latest[i] = value;
|
|
43
|
-
hasValue[i] = true;
|
|
44
|
-
if (hasValue.every((has) => has)) listener([...latest]);
|
|
45
|
-
});
|
|
46
|
-
unsubscribers.push(unsubscribe);
|
|
47
|
-
}
|
|
48
|
-
return () => {
|
|
49
|
-
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
return { subscribe(listenerOrSelector, maybeListener, options) {
|
|
53
|
-
if (maybeListener === void 0) return subscribeToSources(listenerOrSelector);
|
|
54
|
-
const selector = listenerOrSelector;
|
|
55
|
-
const listener = maybeListener;
|
|
56
|
-
const equalityFn = options?.equalityFn ?? Object.is;
|
|
57
|
-
let prevSelected;
|
|
58
|
-
let initialized = false;
|
|
59
|
-
return subscribeToSources((values) => {
|
|
60
|
-
const nextSelected = selector(values);
|
|
61
|
-
if (!initialized || !equalityFn(prevSelected, nextSelected)) {
|
|
62
|
-
prevSelected = nextSelected;
|
|
63
|
-
initialized = true;
|
|
64
|
-
listener(nextSelected);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
} };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
//#endregion
|
|
71
|
-
export { combineLatest };
|
|
72
|
-
//# sourceMappingURL=combine-latest.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"combine-latest.js","names":[],"sources":["../../../../src/core/reactive/combine-latest.ts"],"sourcesContent":["/**\n * Minimal combineLatest operator for reactive composition.\n *\n * Combines multiple Observable-like sources and emits an array of their latest values\n * whenever any source emits.\n */\n\n/**\n * Observable-like interface.\n * Both State and EventStream conform to this shape.\n */\nexport interface Observable<T> {\n subscribe(listener: (value: T) => void): () => void;\n}\n\n/**\n * Infer value types from array of Observables.\n */\nexport type InferObservableValues<T extends readonly Observable<unknown>[]> = {\n [K in keyof T]: T[K] extends Observable<infer V> ? V : never;\n};\n\n/**\n * Options for selector-based subscriptions on a combined observable.\n */\nexport interface SelectorOptions<R> {\n equalityFn?: (a: R, b: R) => boolean;\n}\n\n/**\n * Observable returned by combineLatest — supports both plain and\n * selector-based subscriptions.\n */\nexport interface CombinedObservable<T> extends Observable<T> {\n subscribe(listener: (value: T) => void): () => void;\n subscribe<R>(selector: (value: T) => R, listener: (value: R) => void, options?: SelectorOptions<R>): () => void;\n}\n\n/**\n * Combines multiple Observable sources into a single Observable.\n *\n * Emits an array of latest values whenever any source emits.\n * Only emits after all sources have emitted at least once.\n *\n * Supports selector-based subscriptions (fires only when the selected value\n * changes, per the optional equalityFn) mirroring the createState API.\n *\n * @param sources - Array of Observable sources\n * @returns Combined Observable\n *\n * @example\n * ```ts\n * const state = createState({ count: 0 });\n * const events = createEventStream<Action>();\n *\n * combineLatest([state, events]).subscribe(([state, event]) => {\n * if (event.type === 'PLAY' && state.count > 0) {\n * // React to event + state condition\n * }\n * });\n * ```\n *\n * @example Selector subscription\n * ```ts\n * combineLatest([state, owners]).subscribe(\n * ([s, o]) => deriveKey(s, o),\n * (key) => { ... },\n * { equalityFn: keyEq }\n * );\n * ```\n */\nexport function combineLatest<T extends readonly Observable<unknown>[]>(\n sources: [...T]\n): CombinedObservable<InferObservableValues<T>> {\n type Values = InferObservableValues<T>;\n\n const subscribeToSources = (listener: (values: Values) => void): (() => void) => {\n const latest: unknown[] = new Array(sources.length);\n const hasValue: boolean[] = new Array(sources.length).fill(false);\n const unsubscribers: Array<() => void> = [];\n\n for (let i = 0; i < sources.length; i++) {\n const unsubscribe = sources[i]!.subscribe((value) => {\n latest[i] = value;\n hasValue[i] = true;\n if (hasValue.every((has) => has)) {\n listener([...latest] as Values);\n }\n });\n unsubscribers.push(unsubscribe);\n }\n\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n };\n\n return {\n subscribe<R>(\n listenerOrSelector: ((values: Values) => void) | ((values: Values) => R),\n maybeListener?: (value: R) => void,\n options?: SelectorOptions<R>\n ): () => void {\n if (maybeListener === undefined) {\n return subscribeToSources(listenerOrSelector as (values: Values) => void);\n }\n\n const selector = listenerOrSelector as (values: Values) => R;\n const listener = maybeListener;\n const equalityFn = options?.equalityFn ?? Object.is;\n\n let prevSelected: R | undefined;\n let initialized = false;\n\n return subscribeToSources((values) => {\n const nextSelected = selector(values);\n if (!initialized || !equalityFn(prevSelected as R, nextSelected)) {\n prevSelected = nextSelected;\n initialized = true;\n listener(nextSelected);\n }\n });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,SAAgB,cACd,SAC8C;CAG9C,MAAM,sBAAsB,aAAqD;EAC/E,MAAM,SAAoB,IAAI,MAAM,QAAQ,OAAO;EACnD,MAAM,WAAsB,IAAI,MAAM,QAAQ,OAAO,CAAC,KAAK,MAAM;EACjE,MAAM,gBAAmC,EAAE;AAE3C,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,MAAM,cAAc,QAAQ,GAAI,WAAW,UAAU;AACnD,WAAO,KAAK;AACZ,aAAS,KAAK;AACd,QAAI,SAAS,OAAO,QAAQ,IAAI,CAC9B,UAAS,CAAC,GAAG,OAAO,CAAW;KAEjC;AACF,iBAAc,KAAK,YAAY;;AAGjC,eAAa;AACX,QAAK,MAAM,eAAe,cACxB,cAAa;;;AAKnB,QAAO,EACL,UACE,oBACA,eACA,SACY;AACZ,MAAI,kBAAkB,OACpB,QAAO,mBAAmB,mBAA+C;EAG3E,MAAM,WAAW;EACjB,MAAM,WAAW;EACjB,MAAM,aAAa,SAAS,cAAc,OAAO;EAEjD,IAAI;EACJ,IAAI,cAAc;AAElB,SAAO,oBAAoB,WAAW;GACpC,MAAM,eAAe,SAAS,OAAO;AACrC,OAAI,CAAC,eAAe,CAAC,WAAW,cAAmB,aAAa,EAAE;AAChE,mBAAe;AACf,kBAAc;AACd,aAAS,aAAa;;IAExB;IAEL"}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
//#region src/core/state/create-state.ts
|
|
2
|
-
/**
|
|
3
|
-
* Reactive state container with selectors, custom equality, and batched updates.
|
|
4
|
-
*
|
|
5
|
-
* Manages both immutable state values and mutable object references (e.g., HTMLMediaElement).
|
|
6
|
-
*/
|
|
7
|
-
const STATE_SYMBOL = Symbol("@videojs/spf/state");
|
|
8
|
-
/**
|
|
9
|
-
* Default equality function using Object.is.
|
|
10
|
-
*/
|
|
11
|
-
function defaultEquality(a, b) {
|
|
12
|
-
return Object.is(a, b);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* State container implementation.
|
|
16
|
-
*/
|
|
17
|
-
var StateContainer = class {
|
|
18
|
-
[STATE_SYMBOL] = true;
|
|
19
|
-
#current;
|
|
20
|
-
#pending = null;
|
|
21
|
-
#pendingFlush = false;
|
|
22
|
-
#equalityFn;
|
|
23
|
-
#listeners = /* @__PURE__ */ new Set();
|
|
24
|
-
#selectorListeners = /* @__PURE__ */ new Set();
|
|
25
|
-
constructor(initial, config) {
|
|
26
|
-
this.#current = typeof initial === "object" && initial !== null ? { ...initial } : initial;
|
|
27
|
-
this.#equalityFn = config?.equalityFn ?? defaultEquality;
|
|
28
|
-
}
|
|
29
|
-
get current() {
|
|
30
|
-
return this.#pending ?? this.#current;
|
|
31
|
-
}
|
|
32
|
-
patch(partial) {
|
|
33
|
-
const base = this.#pending ?? this.#current;
|
|
34
|
-
if (typeof base !== "object" || base === null) {
|
|
35
|
-
const value = partial;
|
|
36
|
-
if (!Object.is(base, value)) {
|
|
37
|
-
this.#pending = value;
|
|
38
|
-
this.#scheduleFlush();
|
|
39
|
-
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const next = { ...base };
|
|
43
|
-
let changed = false;
|
|
44
|
-
for (const key in partial) {
|
|
45
|
-
if (!Object.hasOwn(partial, key)) continue;
|
|
46
|
-
const value = partial[key];
|
|
47
|
-
if (!Object.is(base[key], value)) {
|
|
48
|
-
next[key] = value;
|
|
49
|
-
changed = true;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (changed) {
|
|
53
|
-
this.#pending = next;
|
|
54
|
-
this.#scheduleFlush();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
subscribe(selectorOrListener, maybeListener, options) {
|
|
58
|
-
if (maybeListener === void 0) {
|
|
59
|
-
const listener = selectorOrListener;
|
|
60
|
-
this.#listeners.add(listener);
|
|
61
|
-
listener(this.current);
|
|
62
|
-
return () => {
|
|
63
|
-
this.#listeners.delete(listener);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
const selector = selectorOrListener;
|
|
67
|
-
const listener = maybeListener;
|
|
68
|
-
const entry = {
|
|
69
|
-
selector,
|
|
70
|
-
listener,
|
|
71
|
-
options: options ?? {}
|
|
72
|
-
};
|
|
73
|
-
this.#selectorListeners.add(entry);
|
|
74
|
-
listener(selector(this.current));
|
|
75
|
-
return () => {
|
|
76
|
-
this.#selectorListeners.delete(entry);
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
flush() {
|
|
80
|
-
if (this.#pending === null) return;
|
|
81
|
-
const prev = this.#current;
|
|
82
|
-
const next = this.#pending;
|
|
83
|
-
this.#pending = null;
|
|
84
|
-
this.#pendingFlush = false;
|
|
85
|
-
if (this.#equalityFn(prev, next)) return;
|
|
86
|
-
this.#current = next;
|
|
87
|
-
for (const listener of this.#listeners) listener(this.#current);
|
|
88
|
-
for (const entry of this.#selectorListeners) {
|
|
89
|
-
const prevSelected = entry.selector(prev);
|
|
90
|
-
const nextSelected = entry.selector(this.#current);
|
|
91
|
-
if (!(entry.options.equalityFn ?? Object.is)(prevSelected, nextSelected)) entry.listener(nextSelected);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
#scheduleFlush() {
|
|
95
|
-
if (this.#pendingFlush) return;
|
|
96
|
-
this.#pendingFlush = true;
|
|
97
|
-
queueMicrotask(() => this.flush());
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Create a reactive state container.
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```typescript
|
|
105
|
-
* const state = createState({ count: 0 });
|
|
106
|
-
*
|
|
107
|
-
* // Subscribe to changes
|
|
108
|
-
* state.subscribe((current, prev) => {
|
|
109
|
-
* console.log('Changed:', prev, '->', current);
|
|
110
|
-
* });
|
|
111
|
-
*
|
|
112
|
-
* // Updates are batched
|
|
113
|
-
* state.patch({ count: 1 });
|
|
114
|
-
* state.patch({ count: 2 });
|
|
115
|
-
* // Only one notification fires (with count: 2)
|
|
116
|
-
* ```
|
|
117
|
-
*
|
|
118
|
-
* @example Selector subscriptions
|
|
119
|
-
* ```typescript
|
|
120
|
-
* const state = createState({ count: 0, name: 'test' });
|
|
121
|
-
*
|
|
122
|
-
* // Only notified when count changes
|
|
123
|
-
* state.subscribe(
|
|
124
|
-
* s => s.count,
|
|
125
|
-
* (current, prev) => console.log(current, prev)
|
|
126
|
-
* );
|
|
127
|
-
* ```
|
|
128
|
-
*
|
|
129
|
-
* @example Custom equality
|
|
130
|
-
* ```typescript
|
|
131
|
-
* const state = createState(
|
|
132
|
-
* { count: 0, name: 'test' },
|
|
133
|
-
* { equalityFn: (a, b) => a.count === b.count }
|
|
134
|
-
* );
|
|
135
|
-
* ```
|
|
136
|
-
*/
|
|
137
|
-
function createState(initial, config) {
|
|
138
|
-
return new StateContainer(initial, config);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
//#endregion
|
|
142
|
-
export { createState };
|
|
143
|
-
//# sourceMappingURL=create-state.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-state.js","names":["#current","#equalityFn","#pending","#scheduleFlush","#listeners","#selectorListeners","#pendingFlush"],"sources":["../../../../src/core/state/create-state.ts"],"sourcesContent":["/**\n * Reactive state container with selectors, custom equality, and batched updates.\n *\n * Manages both immutable state values and mutable object references (e.g., HTMLMediaElement).\n */\n\n// =============================================================================\n// Symbol for type identification\n// =============================================================================\n\nconst STATE_SYMBOL = Symbol('@videojs/spf/state');\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * State change listener for full-state subscriptions.\n */\nexport type StateListener<T> = (current: T) => void;\n\n/**\n * Selector function to derive a value from state.\n */\nexport type StateSelector<T, R> = (state: T) => R;\n\n/**\n * Listener for selector-based subscriptions.\n */\nexport type SelectorListener<R> = (current: R) => void;\n\n/**\n * Options for selector subscriptions.\n */\nexport interface SelectorOptions<R> {\n /**\n * Custom equality function for selected value.\n * Defaults to Object.is\n */\n equalityFn?: (a: R, b: R) => boolean;\n}\n\n/**\n * Configuration for creating a state container.\n */\nexport interface StateConfig<T> {\n /**\n * Custom equality function for change detection.\n * Defaults to Object.is for top-level comparison.\n */\n equalityFn?: (a: T, b: T) => boolean;\n}\n\n/**\n * Read-only state interface.\n */\nexport interface State<T> {\n /** Symbol for type identification */\n readonly [STATE_SYMBOL]: true;\n\n /** Current state snapshot */\n readonly current: T;\n\n /** Subscribe to state changes */\n subscribe(listener: StateListener<T>): () => void;\n}\n\n/**\n * Writable state interface with patch capability.\n */\nexport interface WritableState<T> extends State<T> {\n /** Update state with partial object (for object state) or full value (for primitive state) */\n patch(partial: T extends object ? Partial<T> : T): void;\n\n /** Subscribe to full-state changes */\n subscribe(listener: StateListener<T>): () => void;\n\n /** Subscribe to selected value changes */\n subscribe<R>(selector: StateSelector<T, R>, listener: SelectorListener<R>, options?: SelectorOptions<R>): () => void;\n\n /** Manually flush pending updates */\n flush(): void;\n}\n\n/**\n * Entry for selector subscriptions.\n */\ninterface SelectorEntry<T, R> {\n selector: StateSelector<T, R>;\n listener: SelectorListener<R>;\n options: SelectorOptions<R>;\n}\n\n// =============================================================================\n// Default equality function\n// =============================================================================\n\n/**\n * Default equality function using Object.is.\n */\nfunction defaultEquality<T>(a: T, b: T): boolean {\n return Object.is(a, b);\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * State container implementation.\n */\nclass StateContainer<T> implements WritableState<T> {\n [STATE_SYMBOL] = true as const;\n\n #current: T;\n #pending: T | null = null;\n #pendingFlush = false;\n #equalityFn: (a: T, b: T) => boolean;\n\n // Full-state listeners\n #listeners = new Set<StateListener<T>>();\n\n // Selector-based listeners\n #selectorListeners = new Set<SelectorEntry<T, unknown>>();\n\n constructor(initial: T, config?: StateConfig<T>) {\n this.#current = typeof initial === 'object' && initial !== null ? ({ ...initial } as T) : initial;\n this.#equalityFn = config?.equalityFn ?? defaultEquality;\n }\n\n get current(): T {\n // Return pending state if available (for chained patches)\n return this.#pending ?? this.#current;\n }\n\n patch(partial: T extends object ? Partial<T> : T): void {\n const base = this.#pending ?? this.#current;\n\n if (typeof base !== 'object' || base === null) {\n // Primitive state: replace the whole value\n const value = partial as T;\n if (!Object.is(base, value)) {\n this.#pending = value;\n this.#scheduleFlush();\n }\n return;\n }\n\n const next = { ...base } as T;\n let changed = false;\n\n // Apply partial updates with change detection\n for (const key in partial) {\n if (!Object.hasOwn(partial as any, key)) continue;\n\n const value = (partial as Partial<T>)[key as keyof T];\n\n if (!Object.is((base as Partial<T>)[key as keyof T], value)) {\n (next as Partial<T>)[key as keyof T] = value;\n changed = true;\n }\n }\n\n if (changed) {\n this.#pending = next;\n this.#scheduleFlush();\n }\n }\n\n subscribe(listener: StateListener<T>): () => void;\n subscribe<R>(selector: StateSelector<T, R>, listener: SelectorListener<R>, options?: SelectorOptions<R>): () => void;\n subscribe<R>(\n selectorOrListener: StateListener<T> | StateSelector<T, R>,\n maybeListener?: SelectorListener<R>,\n options?: SelectorOptions<R>\n ): () => void {\n // Overload 1: Full-state subscription\n if (maybeListener === undefined) {\n const listener = selectorOrListener as StateListener<T>;\n this.#listeners.add(listener);\n\n // Fire immediately with current state\n listener(this.current);\n\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n // Overload 2: Selector subscription\n const selector = selectorOrListener as StateSelector<T, R>;\n const listener = maybeListener;\n const opts = options ?? {};\n\n const entry: SelectorEntry<T, unknown> = {\n selector: selector as StateSelector<T, unknown>,\n listener: listener as SelectorListener<unknown>,\n options: opts as SelectorOptions<unknown>,\n };\n\n this.#selectorListeners.add(entry);\n\n // Fire immediately with current selected value\n const selected = selector(this.current);\n listener(selected);\n\n return () => {\n this.#selectorListeners.delete(entry);\n };\n }\n\n flush(): void {\n if (this.#pending === null) return;\n\n const prev = this.#current;\n const next = this.#pending;\n this.#pending = null;\n this.#pendingFlush = false;\n\n // Check if state actually changed using custom equality\n if (this.#equalityFn(prev, next)) return;\n\n this.#current = next;\n\n // Notify full-state listeners\n for (const listener of this.#listeners) {\n listener(this.#current);\n }\n\n // Notify selector listeners\n for (const entry of this.#selectorListeners) {\n const prevSelected = entry.selector(prev);\n const nextSelected = entry.selector(this.#current);\n\n const equalityFn = entry.options.equalityFn ?? Object.is;\n\n if (!equalityFn(prevSelected, nextSelected)) {\n entry.listener(nextSelected);\n }\n }\n }\n\n #scheduleFlush(): void {\n if (this.#pendingFlush) return;\n this.#pendingFlush = true;\n queueMicrotask(() => this.flush());\n }\n}\n\n// =============================================================================\n// Factory function\n// =============================================================================\n\n/**\n * Create a reactive state container.\n *\n * @example\n * ```typescript\n * const state = createState({ count: 0 });\n *\n * // Subscribe to changes\n * state.subscribe((current, prev) => {\n * console.log('Changed:', prev, '->', current);\n * });\n *\n * // Updates are batched\n * state.patch({ count: 1 });\n * state.patch({ count: 2 });\n * // Only one notification fires (with count: 2)\n * ```\n *\n * @example Selector subscriptions\n * ```typescript\n * const state = createState({ count: 0, name: 'test' });\n *\n * // Only notified when count changes\n * state.subscribe(\n * s => s.count,\n * (current, prev) => console.log(current, prev)\n * );\n * ```\n *\n * @example Custom equality\n * ```typescript\n * const state = createState(\n * { count: 0, name: 'test' },\n * { equalityFn: (a, b) => a.count === b.count }\n * );\n * ```\n */\nexport function createState<T>(initial: T, config?: StateConfig<T>): WritableState<T> {\n return new StateContainer(initial, config);\n}\n\n// =============================================================================\n// Type guard\n// =============================================================================\n\n/**\n * Check if a value is a State container.\n */\nexport function isState(value: unknown): value is State<object> {\n return typeof value === 'object' && value !== null && STATE_SYMBOL in value;\n}\n"],"mappings":";;;;;;AAUA,MAAM,eAAe,OAAO,qBAAqB;;;;AA0FjD,SAAS,gBAAmB,GAAM,GAAe;AAC/C,QAAO,OAAO,GAAG,GAAG,EAAE;;;;;AAUxB,IAAM,iBAAN,MAAoD;CAClD,CAAC,gBAAgB;CAEjB;CACA,WAAqB;CACrB,gBAAgB;CAChB;CAGA,6BAAa,IAAI,KAAuB;CAGxC,qCAAqB,IAAI,KAAgC;CAEzD,YAAY,SAAY,QAAyB;AAC/C,QAAKA,UAAW,OAAO,YAAY,YAAY,YAAY,OAAQ,EAAE,GAAG,SAAS,GAAS;AAC1F,QAAKC,aAAc,QAAQ,cAAc;;CAG3C,IAAI,UAAa;AAEf,SAAO,MAAKC,WAAY,MAAKF;;CAG/B,MAAM,SAAkD;EACtD,MAAM,OAAO,MAAKE,WAAY,MAAKF;AAEnC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;GAE7C,MAAM,QAAQ;AACd,OAAI,CAAC,OAAO,GAAG,MAAM,MAAM,EAAE;AAC3B,UAAKE,UAAW;AAChB,UAAKC,eAAgB;;AAEvB;;EAGF,MAAM,OAAO,EAAE,GAAG,MAAM;EACxB,IAAI,UAAU;AAGd,OAAK,MAAM,OAAO,SAAS;AACzB,OAAI,CAAC,OAAO,OAAO,SAAgB,IAAI,CAAE;GAEzC,MAAM,QAAS,QAAuB;AAEtC,OAAI,CAAC,OAAO,GAAI,KAAoB,MAAiB,MAAM,EAAE;AAC3D,IAAC,KAAoB,OAAkB;AACvC,cAAU;;;AAId,MAAI,SAAS;AACX,SAAKD,UAAW;AAChB,SAAKC,eAAgB;;;CAMzB,UACE,oBACA,eACA,SACY;AAEZ,MAAI,kBAAkB,QAAW;GAC/B,MAAM,WAAW;AACjB,SAAKC,UAAW,IAAI,SAAS;AAG7B,YAAS,KAAK,QAAQ;AAEtB,gBAAa;AACX,UAAKA,UAAW,OAAO,SAAS;;;EAKpC,MAAM,WAAW;EACjB,MAAM,WAAW;EAGjB,MAAM,QAAmC;GAC7B;GACA;GACV,SALW,WAAW,EAAE;GAMzB;AAED,QAAKC,kBAAmB,IAAI,MAAM;AAIlC,WADiB,SAAS,KAAK,QAAQ,CACrB;AAElB,eAAa;AACX,SAAKA,kBAAmB,OAAO,MAAM;;;CAIzC,QAAc;AACZ,MAAI,MAAKH,YAAa,KAAM;EAE5B,MAAM,OAAO,MAAKF;EAClB,MAAM,OAAO,MAAKE;AAClB,QAAKA,UAAW;AAChB,QAAKI,eAAgB;AAGrB,MAAI,MAAKL,WAAY,MAAM,KAAK,CAAE;AAElC,QAAKD,UAAW;AAGhB,OAAK,MAAM,YAAY,MAAKI,UAC1B,UAAS,MAAKJ,QAAS;AAIzB,OAAK,MAAM,SAAS,MAAKK,mBAAoB;GAC3C,MAAM,eAAe,MAAM,SAAS,KAAK;GACzC,MAAM,eAAe,MAAM,SAAS,MAAKL,QAAS;AAIlD,OAAI,EAFe,MAAM,QAAQ,cAAc,OAAO,IAEtC,cAAc,aAAa,CACzC,OAAM,SAAS,aAAa;;;CAKlC,iBAAuB;AACrB,MAAI,MAAKM,aAAe;AACxB,QAAKA,eAAgB;AACrB,uBAAqB,KAAK,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CtC,SAAgB,YAAe,SAAY,QAA2C;AACpF,QAAO,IAAI,eAAe,SAAS,OAAO"}
|
package/dist/dev/all.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { VERSION } from "./index.js";
|
|
2
|
-
import { createState } from "./core/state/create-state.js";
|
|
3
|
-
import { resolveUrl } from "./core/hls/resolve-url.js";
|
|
4
|
-
import { parseMediaPlaylist } from "./core/hls/parse-media-playlist.js";
|
|
5
|
-
import { parseMultivariantPlaylist } from "./core/hls/parse-multivariant.js";
|
|
6
|
-
import { DEFAULT_BANDWIDTH_CONFIG, getBandwidthEstimate, sampleBandwidth } from "./core/abr/bandwidth-estimator.js";
|
|
7
|
-
import { DEFAULT_QUALITY_CONFIG, selectQuality } from "./core/abr/quality-selection.js";
|
|
8
|
-
import { DEFAULT_BACK_BUFFER_CONFIG, calculateBackBufferFlushPoint } from "./core/buffer/back-buffer.js";
|
|
9
|
-
import { DEFAULT_FORWARD_BUFFER_CONFIG, getSegmentsToLoad } from "./core/buffer/forward-buffer.js";
|
|
10
|
-
import { hasPresentationDuration, isResolvedTrack } from "./core/types/index.js";
|
|
11
|
-
import { attachMediaSource, createMediaSource, createSourceBuffer, isCodecSupported, supportsManagedMediaSource, supportsMediaSource, waitForSourceOpen } from "./dom/media/mediasource-setup.js";
|
|
12
|
-
import { fetchResolvable, getResponseText } from "./dom/network/fetch.js";
|
|
13
|
-
import { createEventStream } from "./core/events/create-event-stream.js";
|
|
14
|
-
import { combineLatest } from "./core/reactive/combine-latest.js";
|
|
15
|
-
import { canResolve, isUnresolved, resolvePresentation, shouldResolve, syncPreloadAttribute } from "./core/features/resolve-presentation.js";
|
|
16
|
-
import { DEFAULT_SWITCHING_CONFIG, switchQuality } from "./core/features/quality-switching.js";
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
//#region src/core/events/create-event-stream.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Minimal event stream with Observable-like shape.
|
|
4
|
-
*
|
|
5
|
-
* Simple Subject/Observable-like implementation for dispatching discrete events.
|
|
6
|
-
* Events are dispatched synchronously to all subscribers.
|
|
7
|
-
*/
|
|
8
|
-
declare const EVENT_STREAM_SYMBOL: unique symbol;
|
|
9
|
-
/**
|
|
10
|
-
* Event listener function.
|
|
11
|
-
*/
|
|
12
|
-
type EventListener<T extends Pick<Event, 'type'>> = (event: T) => void;
|
|
13
|
-
/**
|
|
14
|
-
* Event stream interface.
|
|
15
|
-
*/
|
|
16
|
-
interface EventStream<T extends Pick<Event, 'type'> = {
|
|
17
|
-
type: string;
|
|
18
|
-
}> {
|
|
19
|
-
[EVENT_STREAM_SYMBOL]: true;
|
|
20
|
-
dispatch(event: T): void;
|
|
21
|
-
subscribe(listener: EventListener<T>): () => void;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Creates a minimal event stream for dispatching discrete events.
|
|
25
|
-
*
|
|
26
|
-
* Events are dispatched synchronously to all subscribers.
|
|
27
|
-
* Conforms to Observable-like shape for future compatibility.
|
|
28
|
-
*
|
|
29
|
-
* Events must have a 'type' property for discriminated union type narrowing.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* type Action = { type: 'PLAY' } | { type: 'PAUSE' };
|
|
34
|
-
* const events = createEventStream<Action>();
|
|
35
|
-
*
|
|
36
|
-
* events.subscribe((action) => {
|
|
37
|
-
* if (action.type === 'PLAY') {
|
|
38
|
-
* // Type narrowed to { type: 'PLAY' }
|
|
39
|
-
* }
|
|
40
|
-
* });
|
|
41
|
-
*
|
|
42
|
-
* events.dispatch({ type: 'PLAY' });
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
declare function createEventStream<T extends Pick<Event, 'type'>>(): EventStream<T>;
|
|
46
|
-
//#endregion
|
|
47
|
-
export { EventStream, createEventStream };
|
|
48
|
-
//# sourceMappingURL=create-event-stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-event-stream.d.ts","names":[],"sources":["../../../../src/core/events/create-event-stream.ts"],"mappings":";;;;;;;cAOM,mBAAA;;;;KAKM,aAAA,WAAwB,IAAA,CAAK,KAAA,cAAmB,KAAA,EAAO,CAAA;;;;UAKlD,WAAA,WAAsB,IAAA,CAAK,KAAA;EAAmB,IAAA;AAAA;EAAA,CAC5D,mBAAA;EACD,QAAA,CAAS,KAAA,EAAO,CAAA;EAChB,SAAA,CAAU,QAAA,EAAU,aAAA,CAAc,CAAA;AAAA;AAHpC;;;;;;;;;;;;;;;;;;;;;;AAAA,iBA4BgB,iBAAA,WAA4B,IAAA,CAAK,KAAA,UAAA,CAAA,GAAmB,WAAA,CAAY,CAAA"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
//#region src/core/events/create-event-stream.ts
|
|
2
|
-
/**
|
|
3
|
-
* Minimal event stream with Observable-like shape.
|
|
4
|
-
*
|
|
5
|
-
* Simple Subject/Observable-like implementation for dispatching discrete events.
|
|
6
|
-
* Events are dispatched synchronously to all subscribers.
|
|
7
|
-
*/
|
|
8
|
-
const EVENT_STREAM_SYMBOL = Symbol("@videojs/event-stream");
|
|
9
|
-
/**
|
|
10
|
-
* Creates a minimal event stream for dispatching discrete events.
|
|
11
|
-
*
|
|
12
|
-
* Events are dispatched synchronously to all subscribers.
|
|
13
|
-
* Conforms to Observable-like shape for future compatibility.
|
|
14
|
-
*
|
|
15
|
-
* Events must have a 'type' property for discriminated union type narrowing.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```ts
|
|
19
|
-
* type Action = { type: 'PLAY' } | { type: 'PAUSE' };
|
|
20
|
-
* const events = createEventStream<Action>();
|
|
21
|
-
*
|
|
22
|
-
* events.subscribe((action) => {
|
|
23
|
-
* if (action.type === 'PLAY') {
|
|
24
|
-
* // Type narrowed to { type: 'PLAY' }
|
|
25
|
-
* }
|
|
26
|
-
* });
|
|
27
|
-
*
|
|
28
|
-
* events.dispatch({ type: 'PLAY' });
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
function createEventStream() {
|
|
32
|
-
const subscribers = /* @__PURE__ */ new Set();
|
|
33
|
-
return {
|
|
34
|
-
[EVENT_STREAM_SYMBOL]: true,
|
|
35
|
-
dispatch(event) {
|
|
36
|
-
const current = Array.from(subscribers);
|
|
37
|
-
for (const listener of current) listener(event);
|
|
38
|
-
},
|
|
39
|
-
subscribe(listener) {
|
|
40
|
-
subscribers.add(listener);
|
|
41
|
-
return () => subscribers.delete(listener);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
//#endregion
|
|
47
|
-
export { createEventStream };
|
|
48
|
-
//# sourceMappingURL=create-event-stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-event-stream.js","names":[],"sources":["../../../../src/core/events/create-event-stream.ts"],"sourcesContent":["/**\n * Minimal event stream with Observable-like shape.\n *\n * Simple Subject/Observable-like implementation for dispatching discrete events.\n * Events are dispatched synchronously to all subscribers.\n */\n\nconst EVENT_STREAM_SYMBOL = Symbol('@videojs/event-stream');\n\n/**\n * Event listener function.\n */\nexport type EventListener<T extends Pick<Event, 'type'>> = (event: T) => void;\n\n/**\n * Event stream interface.\n */\nexport interface EventStream<T extends Pick<Event, 'type'> = { type: string }> {\n [EVENT_STREAM_SYMBOL]: true;\n dispatch(event: T): void;\n subscribe(listener: EventListener<T>): () => void;\n}\n\n/**\n * Creates a minimal event stream for dispatching discrete events.\n *\n * Events are dispatched synchronously to all subscribers.\n * Conforms to Observable-like shape for future compatibility.\n *\n * Events must have a 'type' property for discriminated union type narrowing.\n *\n * @example\n * ```ts\n * type Action = { type: 'PLAY' } | { type: 'PAUSE' };\n * const events = createEventStream<Action>();\n *\n * events.subscribe((action) => {\n * if (action.type === 'PLAY') {\n * // Type narrowed to { type: 'PLAY' }\n * }\n * });\n *\n * events.dispatch({ type: 'PLAY' });\n * ```\n */\nexport function createEventStream<T extends Pick<Event, 'type'>>(): EventStream<T> {\n const subscribers = new Set<EventListener<T>>();\n\n return {\n [EVENT_STREAM_SYMBOL]: true,\n\n dispatch(event: T): void {\n // Snapshot subscribers to avoid notifying those added during dispatch\n const current = Array.from(subscribers);\n for (const listener of current) {\n listener(event);\n }\n },\n\n subscribe(listener: EventListener<T>): () => void {\n subscribers.add(listener);\n return () => subscribers.delete(listener);\n },\n };\n}\n\n/**\n * Type guard to check if value is an EventStream.\n */\nexport function isEventStream(value: unknown): value is EventStream {\n return typeof value === 'object' && value !== null && EVENT_STREAM_SYMBOL in value;\n}\n"],"mappings":";;;;;;;AAOA,MAAM,sBAAsB,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;AAsC3D,SAAgB,oBAAmE;CACjF,MAAM,8BAAc,IAAI,KAAuB;AAE/C,QAAO;GACJ,sBAAsB;EAEvB,SAAS,OAAgB;GAEvB,MAAM,UAAU,MAAM,KAAK,YAAY;AACvC,QAAK,MAAM,YAAY,QACrB,UAAS,MAAM;;EAInB,UAAU,UAAwC;AAChD,eAAY,IAAI,SAAS;AACzB,gBAAa,YAAY,OAAO,SAAS;;EAE5C"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
//#region src/core/features/resolve-presentation.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Action types for presentation resolution.
|
|
4
|
-
* Event names match HTMLMediaElement events (lowercase).
|
|
5
|
-
*/
|
|
6
|
-
type PresentationAction = {
|
|
7
|
-
type: 'play';
|
|
8
|
-
} | {
|
|
9
|
-
type: 'pause';
|
|
10
|
-
} | {
|
|
11
|
-
type: 'load';
|
|
12
|
-
url: string;
|
|
13
|
-
};
|
|
14
|
-
//#endregion
|
|
15
|
-
export { PresentationAction };
|
|
16
|
-
//# sourceMappingURL=resolve-presentation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-presentation.d.ts","names":[],"sources":["../../../../src/core/features/resolve-presentation.ts"],"mappings":";;;;;KA2FY,kBAAA;EAAuB,IAAA;AAAA;EAAmB,IAAA;AAAA;EAAoB,IAAA;EAAc,GAAA;AAAA"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
//#region src/core/features/resolve-track.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Action types for track resolution.
|
|
4
|
-
* Event names match HTMLMediaElement events (lowercase).
|
|
5
|
-
*/
|
|
6
|
-
type TrackResolutionAction = {
|
|
7
|
-
type: 'play';
|
|
8
|
-
} | {
|
|
9
|
-
type: 'pause';
|
|
10
|
-
};
|
|
11
|
-
//#endregion
|
|
12
|
-
export { TrackResolutionAction };
|
|
13
|
-
//# sourceMappingURL=resolve-track.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-track.d.ts","names":[],"sources":["../../../../src/core/features/resolve-track.ts"],"mappings":";;;;;KAyEY,qBAAA;EAA0B,IAAA;AAAA;EAAmB,IAAA;AAAA"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//#region src/core/features/select-tracks.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Action types for track selection.
|
|
4
|
-
* Reserved for future event-driven selection triggers.
|
|
5
|
-
*/
|
|
6
|
-
type TrackSelectionAction = {
|
|
7
|
-
type: 'presentation-loaded';
|
|
8
|
-
};
|
|
9
|
-
//#endregion
|
|
10
|
-
export { TrackSelectionAction };
|
|
11
|
-
//# sourceMappingURL=select-tracks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"select-tracks.d.ts","names":[],"sources":["../../../../src/core/features/select-tracks.ts"],"mappings":";;;;;KAgCY,oBAAA;EAAyB,IAAA;AAAA"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
//#region src/core/reactive/combine-latest.ts
|
|
2
|
-
/**
|
|
3
|
-
* Combines multiple Observable sources into a single Observable.
|
|
4
|
-
*
|
|
5
|
-
* Emits an array of latest values whenever any source emits.
|
|
6
|
-
* Only emits after all sources have emitted at least once.
|
|
7
|
-
*
|
|
8
|
-
* Supports selector-based subscriptions (fires only when the selected value
|
|
9
|
-
* changes, per the optional equalityFn) mirroring the createState API.
|
|
10
|
-
*
|
|
11
|
-
* @param sources - Array of Observable sources
|
|
12
|
-
* @returns Combined Observable
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* const state = createState({ count: 0 });
|
|
17
|
-
* const events = createEventStream<Action>();
|
|
18
|
-
*
|
|
19
|
-
* combineLatest([state, events]).subscribe(([state, event]) => {
|
|
20
|
-
* if (event.type === 'PLAY' && state.count > 0) {
|
|
21
|
-
* // React to event + state condition
|
|
22
|
-
* }
|
|
23
|
-
* });
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @example Selector subscription
|
|
27
|
-
* ```ts
|
|
28
|
-
* combineLatest([state, owners]).subscribe(
|
|
29
|
-
* ([s, o]) => deriveKey(s, o),
|
|
30
|
-
* (key) => { ... },
|
|
31
|
-
* { equalityFn: keyEq }
|
|
32
|
-
* );
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
function combineLatest(sources) {
|
|
36
|
-
const subscribeToSources = (listener) => {
|
|
37
|
-
const latest = new Array(sources.length);
|
|
38
|
-
const hasValue = new Array(sources.length).fill(false);
|
|
39
|
-
const unsubscribers = [];
|
|
40
|
-
for (let i = 0; i < sources.length; i++) {
|
|
41
|
-
const unsubscribe = sources[i].subscribe((value) => {
|
|
42
|
-
latest[i] = value;
|
|
43
|
-
hasValue[i] = true;
|
|
44
|
-
if (hasValue.every((has) => has)) listener([...latest]);
|
|
45
|
-
});
|
|
46
|
-
unsubscribers.push(unsubscribe);
|
|
47
|
-
}
|
|
48
|
-
return () => {
|
|
49
|
-
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
50
|
-
};
|
|
51
|
-
};
|
|
52
|
-
return { subscribe(listenerOrSelector, maybeListener, options) {
|
|
53
|
-
if (maybeListener === void 0) return subscribeToSources(listenerOrSelector);
|
|
54
|
-
const selector = listenerOrSelector;
|
|
55
|
-
const listener = maybeListener;
|
|
56
|
-
const equalityFn = options?.equalityFn ?? Object.is;
|
|
57
|
-
let prevSelected;
|
|
58
|
-
let initialized = false;
|
|
59
|
-
return subscribeToSources((values) => {
|
|
60
|
-
const nextSelected = selector(values);
|
|
61
|
-
if (!initialized || !equalityFn(prevSelected, nextSelected)) {
|
|
62
|
-
prevSelected = nextSelected;
|
|
63
|
-
initialized = true;
|
|
64
|
-
listener(nextSelected);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
} };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
//#endregion
|
|
71
|
-
export { combineLatest };
|
|
72
|
-
//# sourceMappingURL=combine-latest.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"combine-latest.js","names":[],"sources":["../../../../src/core/reactive/combine-latest.ts"],"sourcesContent":["/**\n * Minimal combineLatest operator for reactive composition.\n *\n * Combines multiple Observable-like sources and emits an array of their latest values\n * whenever any source emits.\n */\n\n/**\n * Observable-like interface.\n * Both State and EventStream conform to this shape.\n */\nexport interface Observable<T> {\n subscribe(listener: (value: T) => void): () => void;\n}\n\n/**\n * Infer value types from array of Observables.\n */\nexport type InferObservableValues<T extends readonly Observable<unknown>[]> = {\n [K in keyof T]: T[K] extends Observable<infer V> ? V : never;\n};\n\n/**\n * Options for selector-based subscriptions on a combined observable.\n */\nexport interface SelectorOptions<R> {\n equalityFn?: (a: R, b: R) => boolean;\n}\n\n/**\n * Observable returned by combineLatest — supports both plain and\n * selector-based subscriptions.\n */\nexport interface CombinedObservable<T> extends Observable<T> {\n subscribe(listener: (value: T) => void): () => void;\n subscribe<R>(selector: (value: T) => R, listener: (value: R) => void, options?: SelectorOptions<R>): () => void;\n}\n\n/**\n * Combines multiple Observable sources into a single Observable.\n *\n * Emits an array of latest values whenever any source emits.\n * Only emits after all sources have emitted at least once.\n *\n * Supports selector-based subscriptions (fires only when the selected value\n * changes, per the optional equalityFn) mirroring the createState API.\n *\n * @param sources - Array of Observable sources\n * @returns Combined Observable\n *\n * @example\n * ```ts\n * const state = createState({ count: 0 });\n * const events = createEventStream<Action>();\n *\n * combineLatest([state, events]).subscribe(([state, event]) => {\n * if (event.type === 'PLAY' && state.count > 0) {\n * // React to event + state condition\n * }\n * });\n * ```\n *\n * @example Selector subscription\n * ```ts\n * combineLatest([state, owners]).subscribe(\n * ([s, o]) => deriveKey(s, o),\n * (key) => { ... },\n * { equalityFn: keyEq }\n * );\n * ```\n */\nexport function combineLatest<T extends readonly Observable<unknown>[]>(\n sources: [...T]\n): CombinedObservable<InferObservableValues<T>> {\n type Values = InferObservableValues<T>;\n\n const subscribeToSources = (listener: (values: Values) => void): (() => void) => {\n const latest: unknown[] = new Array(sources.length);\n const hasValue: boolean[] = new Array(sources.length).fill(false);\n const unsubscribers: Array<() => void> = [];\n\n for (let i = 0; i < sources.length; i++) {\n const unsubscribe = sources[i]!.subscribe((value) => {\n latest[i] = value;\n hasValue[i] = true;\n if (hasValue.every((has) => has)) {\n listener([...latest] as Values);\n }\n });\n unsubscribers.push(unsubscribe);\n }\n\n return () => {\n for (const unsubscribe of unsubscribers) {\n unsubscribe();\n }\n };\n };\n\n return {\n subscribe<R>(\n listenerOrSelector: ((values: Values) => void) | ((values: Values) => R),\n maybeListener?: (value: R) => void,\n options?: SelectorOptions<R>\n ): () => void {\n if (maybeListener === undefined) {\n return subscribeToSources(listenerOrSelector as (values: Values) => void);\n }\n\n const selector = listenerOrSelector as (values: Values) => R;\n const listener = maybeListener;\n const equalityFn = options?.equalityFn ?? Object.is;\n\n let prevSelected: R | undefined;\n let initialized = false;\n\n return subscribeToSources((values) => {\n const nextSelected = selector(values);\n if (!initialized || !equalityFn(prevSelected as R, nextSelected)) {\n prevSelected = nextSelected;\n initialized = true;\n listener(nextSelected);\n }\n });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,SAAgB,cACd,SAC8C;CAG9C,MAAM,sBAAsB,aAAqD;EAC/E,MAAM,SAAoB,IAAI,MAAM,QAAQ,OAAO;EACnD,MAAM,WAAsB,IAAI,MAAM,QAAQ,OAAO,CAAC,KAAK,MAAM;EACjE,MAAM,gBAAmC,EAAE;AAE3C,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,MAAM,cAAc,QAAQ,GAAI,WAAW,UAAU;AACnD,WAAO,KAAK;AACZ,aAAS,KAAK;AACd,QAAI,SAAS,OAAO,QAAQ,IAAI,CAC9B,UAAS,CAAC,GAAG,OAAO,CAAW;KAEjC;AACF,iBAAc,KAAK,YAAY;;AAGjC,eAAa;AACX,QAAK,MAAM,eAAe,cACxB,cAAa;;;AAKnB,QAAO,EACL,UACE,oBACA,eACA,SACY;AACZ,MAAI,kBAAkB,OACpB,QAAO,mBAAmB,mBAA+C;EAG3E,MAAM,WAAW;EACjB,MAAM,WAAW;EACjB,MAAM,aAAa,SAAS,cAAc,OAAO;EAEjD,IAAI;EACJ,IAAI,cAAc;AAElB,SAAO,oBAAoB,WAAW;GACpC,MAAM,eAAe,SAAS,OAAO;AACrC,OAAI,CAAC,eAAe,CAAC,WAAW,cAAmB,aAAa,EAAE;AAChE,mBAAe;AACf,kBAAc;AACd,aAAS,aAAa;;IAExB;IAEL"}
|