vue-streaming 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/dist/index.cjs ADDED
@@ -0,0 +1,202 @@
1
+ 'use strict';
2
+
3
+ var vue = require('vue');
4
+ var jsStreaming = require('js-streaming');
5
+
6
+ // src/components/StreamPlayer.ts
7
+ var StreamPlayer_default = vue.defineComponent({
8
+ name: "StreamPlayer",
9
+ props: {
10
+ type: { type: String, required: true },
11
+ config: { type: Object, required: true },
12
+ autoOpen: { type: Boolean, default: false },
13
+ autoplay: { type: Boolean, default: false },
14
+ controls: { type: Boolean, default: true },
15
+ playsInline: { type: Boolean, default: true },
16
+ muted: { type: Boolean, default: false },
17
+ logLimit: { type: Number, default: 500 },
18
+ videoAttrs: {
19
+ type: Object,
20
+ default: () => ({})
21
+ }
22
+ },
23
+ emits: ["open", "close", "status", "error", "message"],
24
+ setup(props, { emit, slots, expose }) {
25
+ const status = vue.ref("idle");
26
+ const isOpen = vue.ref(false);
27
+ const error = vue.ref(null);
28
+ const messages = vue.shallowRef([]);
29
+ const videoRef = vue.ref(null);
30
+ let api = null;
31
+ let unsubs = [];
32
+ function destroyAPI() {
33
+ try {
34
+ api?.close();
35
+ } catch {
36
+ }
37
+ for (const off of unsubs) off();
38
+ unsubs = [];
39
+ api = null;
40
+ isOpen.value = false;
41
+ }
42
+ function bindAPI(a) {
43
+ const onOpen = () => {
44
+ isOpen.value = true;
45
+ emit("open");
46
+ };
47
+ const onClose = () => {
48
+ isOpen.value = false;
49
+ emit("close");
50
+ };
51
+ const onStatus = (s) => {
52
+ status.value = s;
53
+ emit("status", s);
54
+ };
55
+ const onError = (e) => {
56
+ error.value = e;
57
+ emit("error", e);
58
+ };
59
+ const onMessage = (m) => {
60
+ const next = messages.value.slice();
61
+ next.push(m);
62
+ const limit = props.logLimit ?? 500;
63
+ messages.value = next.length > limit ? next.slice(next.length - limit) : next;
64
+ emit("message", m);
65
+ };
66
+ unsubs.push(a.on("open", onOpen));
67
+ unsubs.push(a.on("close", onClose));
68
+ unsubs.push(a.on("status", onStatus));
69
+ unsubs.push(a.on("error", onError));
70
+ unsubs.push(a.on("message", onMessage));
71
+ if (a.off) {
72
+ unsubs.push(() => {
73
+ a.off("open", onOpen);
74
+ a.off("close", onClose);
75
+ a.off("status", onStatus);
76
+ a.off("error", onError);
77
+ a.off("message", onMessage);
78
+ });
79
+ }
80
+ }
81
+ function buildOptions() {
82
+ const base = { ...props.config };
83
+ if (props.type === "hls") {
84
+ const cfg = base;
85
+ if (videoRef.value) {
86
+ videoRef.value.autoplay = props.autoplay;
87
+ videoRef.value.controls = props.controls;
88
+ videoRef.value.playsInline = props.playsInline;
89
+ videoRef.value.muted = props.muted;
90
+ }
91
+ return { type: "hls", ...cfg, video: videoRef.value };
92
+ }
93
+ if (props.type === "webrtc") {
94
+ const cfg = base;
95
+ const attachVideo = cfg.attachVideo !== false;
96
+ const onTrack = (ms) => {
97
+ if (attachVideo && videoRef.value) {
98
+ videoRef.value.srcObject = ms;
99
+ videoRef.value.autoplay = props.autoplay;
100
+ videoRef.value.controls = props.controls;
101
+ videoRef.value.playsInline = props.playsInline;
102
+ videoRef.value.muted = props.muted;
103
+ }
104
+ };
105
+ return { type: "webrtc", ...cfg, onTrack };
106
+ }
107
+ return { type: props.type, ...base };
108
+ }
109
+ async function instantiate() {
110
+ destroyAPI();
111
+ const opts = buildOptions();
112
+ const newApi = jsStreaming.createStream(opts);
113
+ api = newApi;
114
+ bindAPI(newApi);
115
+ if (props.autoOpen) await newApi.open();
116
+ }
117
+ function open() {
118
+ api?.open();
119
+ }
120
+ function close() {
121
+ api?.close();
122
+ }
123
+ function send(d) {
124
+ api?.send?.(d);
125
+ }
126
+ expose({ open, close, send, status, isOpen, error, messages });
127
+ vue.onMounted(() => {
128
+ void instantiate();
129
+ });
130
+ vue.onBeforeUnmount(() => {
131
+ destroyAPI();
132
+ });
133
+ vue.watch(
134
+ () => [props.type, props.config],
135
+ () => {
136
+ void instantiate();
137
+ },
138
+ { deep: true }
139
+ );
140
+ return () => {
141
+ const children = [];
142
+ if (props.type === "hls" || props.type === "webrtc") {
143
+ children.push(
144
+ vue.h("video", {
145
+ ref: videoRef,
146
+ playsinline: props.playsInline,
147
+ controls: props.controls,
148
+ autoplay: props.autoplay,
149
+ muted: props.muted,
150
+ ...props.videoAttrs,
151
+ style: "width:100%;border-radius:12px;"
152
+ })
153
+ );
154
+ } else {
155
+ const lines = (messages.value || []).map(
156
+ (m, i) => vue.h(
157
+ "div",
158
+ { key: i, style: "white-space:pre-wrap;word-break:break-word;" },
159
+ typeof m === "string" ? m : JSON.stringify(m)
160
+ )
161
+ );
162
+ const logBox = vue.h(
163
+ "div",
164
+ {
165
+ style: "background:#0b1322;color:#e5e7eb;border:1px solid #1f2937;border-radius:10px;padding:8px;max-height:260px;overflow:auto;font:12px/1.5 ui-monospace,monospace;"
166
+ },
167
+ lines
168
+ );
169
+ children.push(
170
+ slots.log ? slots.log({
171
+ messages: messages.value,
172
+ status: status.value,
173
+ error: error.value
174
+ }) : logBox
175
+ );
176
+ }
177
+ children.push(
178
+ vue.h(
179
+ "div",
180
+ { style: "display:flex;gap:8px;flex-wrap:wrap;" },
181
+ slots.actions ? slots.actions({
182
+ open,
183
+ close,
184
+ send,
185
+ isOpen: isOpen.value,
186
+ status: status.value
187
+ }) : []
188
+ )
189
+ );
190
+ return vue.h(
191
+ "div",
192
+ { class: "usp", style: "display:grid;gap:8px;" },
193
+ children
194
+ );
195
+ };
196
+ }
197
+ });
198
+
199
+ exports.StreamPlayer = StreamPlayer_default;
200
+ exports.StreamingPlayer = StreamPlayer_default;
201
+ //# sourceMappingURL=index.cjs.map
202
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/StreamPlayer.ts"],"names":["defineComponent","ref","shallowRef","createStream","onMounted","onBeforeUnmount","watch","h"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\r\n defineComponent,\r\n h,\r\n ref,\r\n shallowRef,\r\n watch,\r\n onMounted,\r\n onBeforeUnmount,\r\n type PropType,\r\n} from \"vue\";\r\n\r\n// Import the core streaming functionality without its types\r\nimport { createStream } from \"js-streaming\";\r\n\r\n// Import local type definitions\r\nimport type {\r\n StreamAPI,\r\n StreamStatus,\r\n StreamType,\r\n AnyConfig,\r\n HLSConfig,\r\n WebRTCConfig,\r\n} from \"../types\";\r\n\r\nexport default defineComponent({\r\n name: \"StreamPlayer\",\r\n props: {\r\n type: { type: String as PropType<StreamType>, required: true },\r\n config: { type: Object as PropType<AnyConfig>, required: true },\r\n autoOpen: { type: Boolean, default: false },\r\n autoplay: { type: Boolean, default: false },\r\n controls: { type: Boolean, default: true },\r\n playsInline: { type: Boolean, default: true },\r\n muted: { type: Boolean, default: false },\r\n logLimit: { type: Number, default: 500 },\r\n videoAttrs: {\r\n type: Object as PropType<Partial<HTMLVideoElement>>,\r\n default: () => ({}),\r\n },\r\n },\r\n emits: [\"open\", \"close\", \"status\", \"error\", \"message\"],\r\n setup(props, { emit, slots, expose }) {\r\n const status = ref<StreamStatus>(\"idle\");\r\n const isOpen = ref(false);\r\n const error = ref<Error | null>(null);\r\n const messages = shallowRef<unknown[]>([]);\r\n const videoRef = ref<HTMLVideoElement | null>(null);\r\n\r\n let api: StreamAPI | null = null;\r\n let unsubs: Array<() => void> = [];\r\n\r\n function destroyAPI() {\r\n try {\r\n api?.close();\r\n } catch {}\r\n for (const off of unsubs) off();\r\n unsubs = [];\r\n api = null;\r\n isOpen.value = false;\r\n }\r\n\r\n function bindAPI(a: StreamAPI & { off?: StreamAPI[\"off\"] }) {\r\n const onOpen = () => {\r\n isOpen.value = true;\r\n emit(\"open\");\r\n };\r\n const onClose = () => {\r\n isOpen.value = false;\r\n emit(\"close\");\r\n };\r\n const onStatus = (s: StreamStatus) => {\r\n status.value = s;\r\n emit(\"status\", s);\r\n };\r\n const onError = (e: Error) => {\r\n error.value = e;\r\n emit(\"error\", e);\r\n };\r\n const onMessage = (m: unknown) => {\r\n const next = messages.value.slice();\r\n next.push(m);\r\n const limit = props.logLimit ?? 500;\r\n messages.value =\r\n next.length > limit ? next.slice(next.length - limit) : next;\r\n emit(\"message\", m);\r\n };\r\n\r\n unsubs.push(a.on(\"open\", onOpen));\r\n unsubs.push(a.on(\"close\", onClose));\r\n unsubs.push(a.on(\"status\", onStatus));\r\n unsubs.push(a.on(\"error\", onError));\r\n unsubs.push(a.on(\"message\", onMessage));\r\n\r\n if (a.off) {\r\n unsubs.push(() => {\r\n a.off!(\"open\", onOpen);\r\n a.off!(\"close\", onClose);\r\n a.off!(\"status\", onStatus);\r\n a.off!(\"error\", onError);\r\n a.off!(\"message\", onMessage);\r\n });\r\n }\r\n }\r\n\r\n function buildOptions(): any {\r\n const base = { ...(props.config as any) };\r\n\r\n if (props.type === \"hls\") {\r\n const cfg = base as HLSConfig;\r\n if (videoRef.value) {\r\n videoRef.value.autoplay = props.autoplay;\r\n videoRef.value.controls = props.controls;\r\n videoRef.value.playsInline = props.playsInline;\r\n videoRef.value.muted = props.muted;\r\n }\r\n return { type: \"hls\", ...cfg, video: videoRef.value! };\r\n }\r\n\r\n if (props.type === \"webrtc\") {\r\n const cfg = base as WebRTCConfig;\r\n const attachVideo = cfg.attachVideo !== false;\r\n const onTrack = (ms: MediaStream) => {\r\n if (attachVideo && videoRef.value) {\r\n videoRef.value.srcObject = ms;\r\n videoRef.value.autoplay = props.autoplay;\r\n videoRef.value.controls = props.controls;\r\n videoRef.value.playsInline = props.playsInline;\r\n videoRef.value.muted = props.muted;\r\n }\r\n };\r\n return { type: \"webrtc\", ...cfg, onTrack };\r\n }\r\n\r\n return { type: props.type, ...base };\r\n }\r\n\r\n async function instantiate() {\r\n destroyAPI();\r\n const opts = buildOptions();\r\n const newApi = createStream(opts) as StreamAPI & {\r\n off?: StreamAPI[\"off\"];\r\n };\r\n api = newApi;\r\n bindAPI(newApi);\r\n if (props.autoOpen) await newApi.open();\r\n }\r\n\r\n function open() {\r\n api?.open();\r\n }\r\n function close() {\r\n api?.close();\r\n }\r\n function send(d: unknown) {\r\n api?.send?.(d);\r\n }\r\n\r\n expose({ open, close, send, status, isOpen, error, messages });\r\n\r\n onMounted(() => {\r\n void instantiate();\r\n });\r\n onBeforeUnmount(() => {\r\n destroyAPI();\r\n });\r\n\r\n watch(\r\n () => [props.type, props.config],\r\n () => {\r\n void instantiate();\r\n },\r\n { deep: true }\r\n );\r\n\r\n // render (بدون SFC)\r\n return () => {\r\n const children: any[] = [];\r\n\r\n if (props.type === \"hls\" || props.type === \"webrtc\") {\r\n children.push(\r\n h(\"video\", {\r\n ref: videoRef,\r\n playsinline: props.playsInline,\r\n controls: props.controls,\r\n autoplay: props.autoplay,\r\n muted: props.muted,\r\n ...props.videoAttrs,\r\n style: \"width:100%;border-radius:12px;\",\r\n })\r\n );\r\n } else {\r\n const lines = (messages.value || []).map((m, i) =>\r\n h(\r\n \"div\",\r\n { key: i, style: \"white-space:pre-wrap;word-break:break-word;\" },\r\n typeof m === \"string\" ? m : JSON.stringify(m)\r\n )\r\n );\r\n const logBox = h(\r\n \"div\",\r\n {\r\n style:\r\n \"background:#0b1322;color:#e5e7eb;border:1px solid #1f2937;border-radius:10px;padding:8px;max-height:260px;overflow:auto;font:12px/1.5 ui-monospace,monospace;\",\r\n },\r\n lines\r\n );\r\n children.push(\r\n slots.log\r\n ? slots.log({\r\n messages: messages.value,\r\n status: status.value,\r\n error: error.value,\r\n })\r\n : logBox\r\n );\r\n }\r\n\r\n children.push(\r\n h(\r\n \"div\",\r\n { style: \"display:flex;gap:8px;flex-wrap:wrap;\" },\r\n slots.actions\r\n ? slots.actions({\r\n open,\r\n close,\r\n send,\r\n isOpen: isOpen.value,\r\n status: status.value,\r\n })\r\n : []\r\n )\r\n );\r\n\r\n return h(\r\n \"div\",\r\n { class: \"usp\", style: \"display:grid;gap:8px;\" },\r\n children\r\n );\r\n };\r\n },\r\n});\r\n"]}
@@ -0,0 +1,144 @@
1
+ import * as vue from 'vue';
2
+ import { PropType } from 'vue';
3
+
4
+ type StreamType = "websocket" | "sse" | "http" | "long-polling" | "hls" | "webrtc";
5
+ type StreamStatus = "idle" | "connecting" | "open" | "closing" | "closed" | "error";
6
+ type AnyConfig = Record<string, unknown>;
7
+ type HLSConfig = Omit<AnyConfig, "type" | "video">;
8
+ type WebRTCConfig = Omit<AnyConfig, "type" | "onTrack"> & {
9
+ attachVideo?: boolean;
10
+ };
11
+ interface BaseOptions {
12
+ type: StreamType;
13
+ bufferLimit?: number;
14
+ autoReconnect?: boolean;
15
+ maxRetries?: number;
16
+ heartbeatMs?: number;
17
+ backoff?: {
18
+ baseMs?: number;
19
+ maxMs?: number;
20
+ factor?: number;
21
+ jitter?: boolean;
22
+ };
23
+ }
24
+ type Message = unknown;
25
+ interface StreamState {
26
+ status: StreamStatus;
27
+ error: Error | null;
28
+ messages: Message[];
29
+ isOpen: boolean;
30
+ }
31
+ interface StreamAdapter {
32
+ open(): Promise<void> | void;
33
+ close(): Promise<void> | void;
34
+ send?(data: unknown): void;
35
+ }
36
+ type ListenerMap = {
37
+ open: (() => void)[];
38
+ close: (() => void)[];
39
+ error: ((err: Error) => void)[];
40
+ message: ((msg: Message) => void)[];
41
+ status: ((s: StreamStatus) => void)[];
42
+ };
43
+ interface StreamAPI {
44
+ open(): Promise<void>;
45
+ close(): Promise<void>;
46
+ send?(data: unknown): void;
47
+ on<T extends keyof ListenerMap>(evt: T, cb: ListenerMap[T][number]): () => void;
48
+ off<T extends keyof ListenerMap>(evt: T, cb: ListenerMap[T][number]): void;
49
+ readonly state: Readonly<StreamState>;
50
+ }
51
+
52
+ declare const _default: vue.DefineComponent<vue.ExtractPropTypes<{
53
+ type: {
54
+ type: PropType<StreamType>;
55
+ required: true;
56
+ };
57
+ config: {
58
+ type: PropType<AnyConfig>;
59
+ required: true;
60
+ };
61
+ autoOpen: {
62
+ type: BooleanConstructor;
63
+ default: boolean;
64
+ };
65
+ autoplay: {
66
+ type: BooleanConstructor;
67
+ default: boolean;
68
+ };
69
+ controls: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ playsInline: {
74
+ type: BooleanConstructor;
75
+ default: boolean;
76
+ };
77
+ muted: {
78
+ type: BooleanConstructor;
79
+ default: boolean;
80
+ };
81
+ logLimit: {
82
+ type: NumberConstructor;
83
+ default: number;
84
+ };
85
+ videoAttrs: {
86
+ type: PropType<Partial<HTMLVideoElement>>;
87
+ default: () => {};
88
+ };
89
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
90
+ [key: string]: any;
91
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("open" | "error" | "close" | "message" | "status")[], "open" | "error" | "close" | "message" | "status", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
92
+ type: {
93
+ type: PropType<StreamType>;
94
+ required: true;
95
+ };
96
+ config: {
97
+ type: PropType<AnyConfig>;
98
+ required: true;
99
+ };
100
+ autoOpen: {
101
+ type: BooleanConstructor;
102
+ default: boolean;
103
+ };
104
+ autoplay: {
105
+ type: BooleanConstructor;
106
+ default: boolean;
107
+ };
108
+ controls: {
109
+ type: BooleanConstructor;
110
+ default: boolean;
111
+ };
112
+ playsInline: {
113
+ type: BooleanConstructor;
114
+ default: boolean;
115
+ };
116
+ muted: {
117
+ type: BooleanConstructor;
118
+ default: boolean;
119
+ };
120
+ logLimit: {
121
+ type: NumberConstructor;
122
+ default: number;
123
+ };
124
+ videoAttrs: {
125
+ type: PropType<Partial<HTMLVideoElement>>;
126
+ default: () => {};
127
+ };
128
+ }>> & Readonly<{
129
+ onOpen?: ((...args: any[]) => any) | undefined;
130
+ onError?: ((...args: any[]) => any) | undefined;
131
+ onClose?: ((...args: any[]) => any) | undefined;
132
+ onMessage?: ((...args: any[]) => any) | undefined;
133
+ onStatus?: ((...args: any[]) => any) | undefined;
134
+ }>, {
135
+ playsInline: boolean;
136
+ autoplay: boolean;
137
+ controls: boolean;
138
+ muted: boolean;
139
+ autoOpen: boolean;
140
+ logLimit: number;
141
+ videoAttrs: Partial<HTMLVideoElement>;
142
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
143
+
144
+ export { type AnyConfig, type BaseOptions, type HLSConfig, type ListenerMap, type Message, type StreamAPI, type StreamAdapter, _default as StreamPlayer, type StreamState, type StreamStatus, type StreamType, _default as StreamingPlayer, type WebRTCConfig };
@@ -0,0 +1,144 @@
1
+ import * as vue from 'vue';
2
+ import { PropType } from 'vue';
3
+
4
+ type StreamType = "websocket" | "sse" | "http" | "long-polling" | "hls" | "webrtc";
5
+ type StreamStatus = "idle" | "connecting" | "open" | "closing" | "closed" | "error";
6
+ type AnyConfig = Record<string, unknown>;
7
+ type HLSConfig = Omit<AnyConfig, "type" | "video">;
8
+ type WebRTCConfig = Omit<AnyConfig, "type" | "onTrack"> & {
9
+ attachVideo?: boolean;
10
+ };
11
+ interface BaseOptions {
12
+ type: StreamType;
13
+ bufferLimit?: number;
14
+ autoReconnect?: boolean;
15
+ maxRetries?: number;
16
+ heartbeatMs?: number;
17
+ backoff?: {
18
+ baseMs?: number;
19
+ maxMs?: number;
20
+ factor?: number;
21
+ jitter?: boolean;
22
+ };
23
+ }
24
+ type Message = unknown;
25
+ interface StreamState {
26
+ status: StreamStatus;
27
+ error: Error | null;
28
+ messages: Message[];
29
+ isOpen: boolean;
30
+ }
31
+ interface StreamAdapter {
32
+ open(): Promise<void> | void;
33
+ close(): Promise<void> | void;
34
+ send?(data: unknown): void;
35
+ }
36
+ type ListenerMap = {
37
+ open: (() => void)[];
38
+ close: (() => void)[];
39
+ error: ((err: Error) => void)[];
40
+ message: ((msg: Message) => void)[];
41
+ status: ((s: StreamStatus) => void)[];
42
+ };
43
+ interface StreamAPI {
44
+ open(): Promise<void>;
45
+ close(): Promise<void>;
46
+ send?(data: unknown): void;
47
+ on<T extends keyof ListenerMap>(evt: T, cb: ListenerMap[T][number]): () => void;
48
+ off<T extends keyof ListenerMap>(evt: T, cb: ListenerMap[T][number]): void;
49
+ readonly state: Readonly<StreamState>;
50
+ }
51
+
52
+ declare const _default: vue.DefineComponent<vue.ExtractPropTypes<{
53
+ type: {
54
+ type: PropType<StreamType>;
55
+ required: true;
56
+ };
57
+ config: {
58
+ type: PropType<AnyConfig>;
59
+ required: true;
60
+ };
61
+ autoOpen: {
62
+ type: BooleanConstructor;
63
+ default: boolean;
64
+ };
65
+ autoplay: {
66
+ type: BooleanConstructor;
67
+ default: boolean;
68
+ };
69
+ controls: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ playsInline: {
74
+ type: BooleanConstructor;
75
+ default: boolean;
76
+ };
77
+ muted: {
78
+ type: BooleanConstructor;
79
+ default: boolean;
80
+ };
81
+ logLimit: {
82
+ type: NumberConstructor;
83
+ default: number;
84
+ };
85
+ videoAttrs: {
86
+ type: PropType<Partial<HTMLVideoElement>>;
87
+ default: () => {};
88
+ };
89
+ }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
90
+ [key: string]: any;
91
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("open" | "error" | "close" | "message" | "status")[], "open" | "error" | "close" | "message" | "status", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
92
+ type: {
93
+ type: PropType<StreamType>;
94
+ required: true;
95
+ };
96
+ config: {
97
+ type: PropType<AnyConfig>;
98
+ required: true;
99
+ };
100
+ autoOpen: {
101
+ type: BooleanConstructor;
102
+ default: boolean;
103
+ };
104
+ autoplay: {
105
+ type: BooleanConstructor;
106
+ default: boolean;
107
+ };
108
+ controls: {
109
+ type: BooleanConstructor;
110
+ default: boolean;
111
+ };
112
+ playsInline: {
113
+ type: BooleanConstructor;
114
+ default: boolean;
115
+ };
116
+ muted: {
117
+ type: BooleanConstructor;
118
+ default: boolean;
119
+ };
120
+ logLimit: {
121
+ type: NumberConstructor;
122
+ default: number;
123
+ };
124
+ videoAttrs: {
125
+ type: PropType<Partial<HTMLVideoElement>>;
126
+ default: () => {};
127
+ };
128
+ }>> & Readonly<{
129
+ onOpen?: ((...args: any[]) => any) | undefined;
130
+ onError?: ((...args: any[]) => any) | undefined;
131
+ onClose?: ((...args: any[]) => any) | undefined;
132
+ onMessage?: ((...args: any[]) => any) | undefined;
133
+ onStatus?: ((...args: any[]) => any) | undefined;
134
+ }>, {
135
+ playsInline: boolean;
136
+ autoplay: boolean;
137
+ controls: boolean;
138
+ muted: boolean;
139
+ autoOpen: boolean;
140
+ logLimit: number;
141
+ videoAttrs: Partial<HTMLVideoElement>;
142
+ }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
143
+
144
+ export { type AnyConfig, type BaseOptions, type HLSConfig, type ListenerMap, type Message, type StreamAPI, type StreamAdapter, _default as StreamPlayer, type StreamState, type StreamStatus, type StreamType, _default as StreamingPlayer, type WebRTCConfig };