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/README.md +699 -0
- package/dist/index.cjs +202 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +144 -0
- package/dist/index.d.ts +144 -0
- package/dist/index.js +199 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 };
|