@pickleball/expo-sdk 0.1.1 → 1.0.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/CHANGELOG.md +65 -0
- package/README.md +163 -40
- package/dist/advanced-DcbHBCGb.d.ts +300 -0
- package/dist/advanced-DeQwg7MK.d.cts +300 -0
- package/dist/advanced.cjs +47 -0
- package/dist/advanced.d.cts +3 -0
- package/dist/advanced.d.ts +3 -0
- package/dist/advanced.js +47 -0
- package/dist/camera-controls-By8tHigY.d.cts +97 -0
- package/dist/camera-controls-rCBUGGPC.d.ts +97 -0
- package/dist/chunk-2JHULJZ7.js +265 -0
- package/dist/chunk-62YV3PCD.cjs +139 -0
- package/dist/chunk-6F3HN6US.js +50 -0
- package/dist/chunk-6YE5BL3A.cjs +50 -0
- package/dist/chunk-7OX2DSKI.cjs +33 -0
- package/dist/chunk-7Z7TN5N3.js +318 -0
- package/dist/chunk-DHDX3ZOO.js +800 -0
- package/dist/chunk-GXQYMPHE.cjs +9 -0
- package/dist/chunk-IUIRVKJI.cjs +2290 -0
- package/dist/chunk-KFQGP6VL.js +33 -0
- package/dist/chunk-LCWGNGEN.cjs +265 -0
- package/dist/chunk-TBUEXRFQ.cjs +318 -0
- package/dist/chunk-XGP2MN5R.js +2290 -0
- package/dist/chunk-XL4CISVQ.js +9 -0
- package/dist/chunk-YGSQ25UA.cjs +800 -0
- package/dist/chunk-ZSKSXOCZ.js +139 -0
- package/dist/convex-command-subscription-Cabh9tND.d.ts +41 -0
- package/dist/convex-command-subscription-DUgpu75l.d.cts +41 -0
- package/dist/device-agent/index.cjs +1427 -0
- package/dist/device-agent/index.d.cts +493 -0
- package/dist/device-agent/index.d.ts +493 -0
- package/dist/device-agent/index.js +1427 -0
- package/dist/engine-BSvSdCSE.d.cts +741 -0
- package/dist/engine-BSvSdCSE.d.ts +741 -0
- package/dist/index.cjs +426 -6174
- package/dist/index.d.cts +299 -1400
- package/dist/index.d.ts +299 -1400
- package/dist/index.js +413 -6063
- package/dist/match/index.cjs +2456 -0
- package/dist/match/index.d.cts +253 -0
- package/dist/match/index.d.ts +253 -0
- package/dist/match/index.js +2456 -0
- package/dist/match/remote/index.cjs +21 -0
- package/dist/match/remote/index.d.cts +67 -0
- package/dist/match/remote/index.d.ts +67 -0
- package/dist/match/remote/index.js +21 -0
- package/dist/match/voice/index.cjs +23 -0
- package/dist/match/voice/index.d.cts +114 -0
- package/dist/match/voice/index.d.ts +114 -0
- package/dist/match/voice/index.js +23 -0
- package/dist/plugin.cjs +52 -71
- package/dist/plugin.d.cts +28 -1
- package/dist/plugin.d.ts +28 -1
- package/dist/plugin.js +26 -23
- package/dist/realtime/index.cjs +31 -0
- package/dist/realtime/index.d.cts +15 -0
- package/dist/realtime/index.d.ts +15 -0
- package/dist/realtime/index.js +31 -0
- package/dist/types-CrmcX408.d.cts +176 -0
- package/dist/types-CrmcX408.d.ts +176 -0
- package/dist/types-DiKWjwvN.d.cts +96 -0
- package/dist/types-DiKWjwvN.d.ts +96 -0
- package/dist/ui/index.cjs +1297 -0
- package/dist/ui/index.d.cts +493 -0
- package/dist/ui/index.d.ts +493 -0
- package/dist/ui/index.js +1297 -0
- package/dist/version.cjs +4 -32
- package/dist/version.js +2 -1
- package/package.json +95 -15
- package/src/advanced.ts +49 -0
- package/src/auto-resume.tsx +259 -0
- package/src/camera-controls.ts +99 -0
- package/src/camera-grant-provider.ts +392 -0
- package/src/camera-settings.ts +133 -0
- package/src/contracts.ts +73 -0
- package/src/device-agent/agent.ts +696 -0
- package/src/device-agent/beat-policy.ts +46 -0
- package/src/device-agent/component.tsx +60 -0
- package/src/device-agent/convex-beat-transport.ts +140 -0
- package/src/device-agent/convex-command-subscription.ts +101 -0
- package/src/device-agent/convex-control-channel.ts +88 -0
- package/src/device-agent/http-transport.ts +164 -0
- package/src/device-agent/index.ts +26 -0
- package/src/device-agent/mqtt-channel.ts +379 -0
- package/src/device-agent/mqtt-codec.ts +347 -0
- package/src/device-agent/tournament.ts +352 -0
- package/src/engine.ts +601 -20
- package/src/errors.ts +16 -0
- package/src/http-session-provider.ts +21 -183
- package/src/index.ts +117 -14
- package/src/local-video-quality.ts +43 -0
- package/src/match/index.ts +29 -0
- package/src/match/provider.tsx +4 -2
- package/src/match/remote/hid-gesture.ts +10 -2
- package/src/match/remote/types.ts +6 -4
- package/src/match/voice/scheduler.ts +6 -1
- package/src/match/voice/service.ts +16 -4
- package/src/native-runtime.ts +283 -77
- package/src/plugin.ts +54 -20
- package/src/provider.tsx +129 -22
- package/src/realtime/index.ts +56 -0
- package/src/resume-policy.ts +85 -0
- package/src/resume.ts +132 -0
- package/src/rtmp-room-adapter.ts +348 -0
- package/src/session-grant.ts +256 -0
- package/src/ui/camera-screen.tsx +484 -0
- package/src/ui/controls-sheet.tsx +445 -0
- package/src/ui/copy.ts +326 -0
- package/src/ui/helpers.ts +105 -0
- package/src/ui/hooks.ts +59 -0
- package/src/ui/index.ts +42 -0
- package/src/ui/preview-view.tsx +39 -0
- package/src/ui/primitives.tsx +304 -0
- package/src/uplink-check.ts +173 -0
- package/dist/chunk-VHLUJQG5.js +0 -17
- package/src/livekit-room-adapter.ts +0 -353
- package/src/livestream-screen.tsx +0 -980
package/dist/plugin.d.cts
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { ConfigPlugin } from 'expo/config-plugins';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Version của SCHEMA plugin — tách khỏi version package có chủ ý. Giá trị này
|
|
5
|
+
* được inline vào dist/plugin.cjs, mà @expo/fingerprint băm file đó làm
|
|
6
|
+
* runtimeVersion của app fleet: gắn theo version package là MỖI lần bump SDK
|
|
7
|
+
* (kể cả patch JS-only) đổi fingerprint và toàn bộ máy ngoài sân mất OTA. Chỉ
|
|
8
|
+
* nâng khi plugin đổi hành vi native (permission, mod).
|
|
9
|
+
*/
|
|
10
|
+
declare const PLUGIN_SCHEMA_VERSION = "1";
|
|
3
11
|
interface PickleballLivePluginProps {
|
|
4
12
|
cameraPermission?: string;
|
|
5
13
|
microphonePermission?: string;
|
|
6
14
|
bluetoothPermission?: string;
|
|
7
15
|
consumeHidVolumeKeys?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Tắt phần cấu hình native của module không dùng để app gọn hơn:
|
|
18
|
+
* - remote: false → bỏ permission Bluetooth (Android + iOS usage string) và
|
|
19
|
+
* không patch MainActivity nhận phím HID. Dùng khi app không import
|
|
20
|
+
* "@pickleball/expo-sdk/match/remote".
|
|
21
|
+
* - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
|
|
22
|
+
* nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
|
|
23
|
+
* expo.autolinking.exclude trong package.json của app (xem README).
|
|
24
|
+
* - livekit: KHÔNG còn tác dụng từ 1.0 (SDK RTMP-only, không compose plugin
|
|
25
|
+
* LiveKit nữa). Vẫn nhận để app.config cũ của fleet không phải sửa — sửa
|
|
26
|
+
* là đổi fingerprint OTA.
|
|
27
|
+
*/
|
|
28
|
+
modules?: {
|
|
29
|
+
remote?: boolean;
|
|
30
|
+
voice?: boolean;
|
|
31
|
+
/** @deprecated bị bỏ qua từ 1.0 */
|
|
32
|
+
livekit?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** @deprecated bị bỏ qua từ 1.0 (SDK không còn LiveKit). */
|
|
8
35
|
liveKit?: {
|
|
9
36
|
android?: {
|
|
10
37
|
audioType?: string;
|
|
@@ -18,4 +45,4 @@ interface PickleballLivePluginProps {
|
|
|
18
45
|
declare function injectHidVolumeMainActivity(source: string): string;
|
|
19
46
|
declare const _default: ConfigPlugin<PickleballLivePluginProps | undefined>;
|
|
20
47
|
|
|
21
|
-
export { type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
|
|
48
|
+
export { PLUGIN_SCHEMA_VERSION, type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { ConfigPlugin } from 'expo/config-plugins';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Version của SCHEMA plugin — tách khỏi version package có chủ ý. Giá trị này
|
|
5
|
+
* được inline vào dist/plugin.cjs, mà @expo/fingerprint băm file đó làm
|
|
6
|
+
* runtimeVersion của app fleet: gắn theo version package là MỖI lần bump SDK
|
|
7
|
+
* (kể cả patch JS-only) đổi fingerprint và toàn bộ máy ngoài sân mất OTA. Chỉ
|
|
8
|
+
* nâng khi plugin đổi hành vi native (permission, mod).
|
|
9
|
+
*/
|
|
10
|
+
declare const PLUGIN_SCHEMA_VERSION = "1";
|
|
3
11
|
interface PickleballLivePluginProps {
|
|
4
12
|
cameraPermission?: string;
|
|
5
13
|
microphonePermission?: string;
|
|
6
14
|
bluetoothPermission?: string;
|
|
7
15
|
consumeHidVolumeKeys?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Tắt phần cấu hình native của module không dùng để app gọn hơn:
|
|
18
|
+
* - remote: false → bỏ permission Bluetooth (Android + iOS usage string) và
|
|
19
|
+
* không patch MainActivity nhận phím HID. Dùng khi app không import
|
|
20
|
+
* "@pickleball/expo-sdk/match/remote".
|
|
21
|
+
* - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
|
|
22
|
+
* nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
|
|
23
|
+
* expo.autolinking.exclude trong package.json của app (xem README).
|
|
24
|
+
* - livekit: KHÔNG còn tác dụng từ 1.0 (SDK RTMP-only, không compose plugin
|
|
25
|
+
* LiveKit nữa). Vẫn nhận để app.config cũ của fleet không phải sửa — sửa
|
|
26
|
+
* là đổi fingerprint OTA.
|
|
27
|
+
*/
|
|
28
|
+
modules?: {
|
|
29
|
+
remote?: boolean;
|
|
30
|
+
voice?: boolean;
|
|
31
|
+
/** @deprecated bị bỏ qua từ 1.0 */
|
|
32
|
+
livekit?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** @deprecated bị bỏ qua từ 1.0 (SDK không còn LiveKit). */
|
|
8
35
|
liveKit?: {
|
|
9
36
|
android?: {
|
|
10
37
|
audioType?: string;
|
|
@@ -18,4 +45,4 @@ interface PickleballLivePluginProps {
|
|
|
18
45
|
declare function injectHidVolumeMainActivity(source: string): string;
|
|
19
46
|
declare const _default: ConfigPlugin<PickleballLivePluginProps | undefined>;
|
|
20
47
|
|
|
21
|
-
export { type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
|
|
48
|
+
export { PLUGIN_SCHEMA_VERSION, type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
PICKLEBALL_EXPO_SDK_VERSION
|
|
3
|
-
} from "./chunk-VHLUJQG5.js";
|
|
1
|
+
import "./chunk-KFQGP6VL.js";
|
|
4
2
|
|
|
5
3
|
// src/plugin.ts
|
|
6
4
|
import {
|
|
@@ -8,24 +6,29 @@ import {
|
|
|
8
6
|
createRunOncePlugin,
|
|
9
7
|
withAndroidManifest,
|
|
10
8
|
withDangerousMod,
|
|
11
|
-
withInfoPlist
|
|
12
|
-
withPlugins
|
|
9
|
+
withInfoPlist
|
|
13
10
|
} from "expo/config-plugins";
|
|
14
11
|
import { readdir, readFile, writeFile } from "fs/promises";
|
|
15
12
|
import { join } from "path";
|
|
16
|
-
var
|
|
13
|
+
var PLUGIN_SCHEMA_VERSION = "1";
|
|
14
|
+
var CORE_ANDROID_PERMISSIONS = [
|
|
17
15
|
"android.permission.ACCESS_NETWORK_STATE",
|
|
18
|
-
"android.permission.BLUETOOTH",
|
|
19
|
-
"android.permission.BLUETOOTH_ADMIN",
|
|
20
|
-
"android.permission.BLUETOOTH_SCAN",
|
|
21
|
-
"android.permission.BLUETOOTH_CONNECT",
|
|
22
|
-
"android.permission.ACCESS_FINE_LOCATION",
|
|
23
16
|
"android.permission.CAMERA",
|
|
17
|
+
"android.permission.FOREGROUND_SERVICE",
|
|
18
|
+
"android.permission.FOREGROUND_SERVICE_CAMERA",
|
|
19
|
+
"android.permission.FOREGROUND_SERVICE_MICROPHONE",
|
|
24
20
|
"android.permission.INTERNET",
|
|
25
21
|
"android.permission.MODIFY_AUDIO_SETTINGS",
|
|
26
22
|
"android.permission.RECORD_AUDIO",
|
|
27
23
|
"android.permission.WAKE_LOCK"
|
|
28
24
|
];
|
|
25
|
+
var REMOTE_ANDROID_PERMISSIONS = [
|
|
26
|
+
"android.permission.BLUETOOTH",
|
|
27
|
+
"android.permission.BLUETOOTH_ADMIN",
|
|
28
|
+
"android.permission.BLUETOOTH_SCAN",
|
|
29
|
+
"android.permission.BLUETOOTH_CONNECT",
|
|
30
|
+
"android.permission.ACCESS_FINE_LOCATION"
|
|
31
|
+
];
|
|
29
32
|
function injectHidVolumeMainActivity(source) {
|
|
30
33
|
if (source.includes("PickleballRemoteHidDispatcher.dispatch(event)")) return source;
|
|
31
34
|
if (!/class\s+MainActivity\s*:\s*ReactActivity\(\)\s*\{/.test(source)) {
|
|
@@ -60,19 +63,18 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
60
63
|
const cameraPermission = props?.cameraPermission ?? "Allow $(PRODUCT_NAME) to use the camera for livestreaming.";
|
|
61
64
|
const microphonePermission = props?.microphonePermission ?? "Allow $(PRODUCT_NAME) to use the microphone for livestreaming.";
|
|
62
65
|
const bluetoothPermission = props?.bluetoothPermission ?? "Cho ph\xE9p $(PRODUCT_NAME) d\xF9ng Bluetooth \u0111\u1EC3 nh\u1EADn thao t\xE1c t\u1EEB n\xFAt \u0111i\u1EC1u khi\u1EC3n tr\xEAn s\xE2n.";
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
]);
|
|
66
|
+
const remoteEnabled = props?.modules?.remote !== false;
|
|
67
|
+
const androidPermissions = remoteEnabled ? [...CORE_ANDROID_PERMISSIONS, ...REMOTE_ANDROID_PERMISSIONS] : [...CORE_ANDROID_PERMISSIONS];
|
|
66
68
|
config.ios = { ...config.ios, bitcode: false };
|
|
67
69
|
config = withInfoPlist(config, (mod) => {
|
|
68
70
|
mod.modResults.NSCameraUsageDescription = cameraPermission;
|
|
69
71
|
mod.modResults.NSMicrophoneUsageDescription = microphonePermission;
|
|
70
|
-
|
|
72
|
+
if (remoteEnabled) {
|
|
73
|
+
mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
|
|
74
|
+
}
|
|
71
75
|
return mod;
|
|
72
76
|
});
|
|
73
|
-
config = AndroidConfig.Permissions.withPermissions(config,
|
|
74
|
-
...ANDROID_PERMISSIONS
|
|
75
|
-
]);
|
|
77
|
+
config = AndroidConfig.Permissions.withPermissions(config, androidPermissions);
|
|
76
78
|
config = withAndroidManifest(config, (mod) => {
|
|
77
79
|
const manifest = mod.modResults.manifest;
|
|
78
80
|
const existing = manifest["uses-permission"] ?? [];
|
|
@@ -89,7 +91,7 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
89
91
|
const name = entry.$?.["android:name"];
|
|
90
92
|
if (name && !byName.has(name)) byName.set(name, entry);
|
|
91
93
|
}
|
|
92
|
-
for (const permission of
|
|
94
|
+
for (const permission of androidPermissions) {
|
|
93
95
|
const entry = byName.get(permission) ?? { $: { "android:name": permission } };
|
|
94
96
|
entry.$ = {
|
|
95
97
|
"android:name": permission,
|
|
@@ -97,17 +99,17 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
97
99
|
};
|
|
98
100
|
byName.set(permission, entry);
|
|
99
101
|
}
|
|
100
|
-
const requiredNames = new Set(
|
|
102
|
+
const requiredNames = new Set(androidPermissions);
|
|
101
103
|
manifest["uses-permission"] = [
|
|
102
104
|
...existing.filter((entry) => {
|
|
103
105
|
const name = entry.$?.["android:name"];
|
|
104
106
|
return !name || !requiredNames.has(name);
|
|
105
107
|
}),
|
|
106
|
-
...
|
|
108
|
+
...androidPermissions.map((name) => byName.get(name))
|
|
107
109
|
];
|
|
108
110
|
return mod;
|
|
109
111
|
});
|
|
110
|
-
if (props?.consumeHidVolumeKeys !== false) {
|
|
112
|
+
if (remoteEnabled && props?.consumeHidVolumeKeys !== false) {
|
|
111
113
|
config = withDangerousMod(config, ["android", async (mod) => {
|
|
112
114
|
const root = join(mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
|
|
113
115
|
const path = await findMainActivity(root);
|
|
@@ -123,9 +125,10 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
123
125
|
var plugin_default = createRunOncePlugin(
|
|
124
126
|
withPickleballLive,
|
|
125
127
|
"@pickleball/expo-sdk",
|
|
126
|
-
|
|
128
|
+
PLUGIN_SCHEMA_VERSION
|
|
127
129
|
);
|
|
128
130
|
export {
|
|
131
|
+
PLUGIN_SCHEMA_VERSION,
|
|
129
132
|
plugin_default as default,
|
|
130
133
|
injectHidVolumeMainActivity
|
|
131
134
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunk6YE5BL3Acjs = require('../chunk-6YE5BL3A.cjs');
|
|
5
|
+
require('../chunk-7OX2DSKI.cjs');
|
|
6
|
+
|
|
7
|
+
// src/realtime/index.ts
|
|
8
|
+
function createGrantCommandSubscription(getConvexUrl) {
|
|
9
|
+
const clients = /* @__PURE__ */ new Map();
|
|
10
|
+
return {
|
|
11
|
+
subscribe(credentials, sessionId, onCommands, onError) {
|
|
12
|
+
const url = getConvexUrl();
|
|
13
|
+
if (!url) return () => void 0;
|
|
14
|
+
let realtime = clients.get(url);
|
|
15
|
+
if (!realtime) {
|
|
16
|
+
realtime = _chunk6YE5BL3Acjs.createConvexDeviceRealtime.call(void 0, url);
|
|
17
|
+
clients.set(url, realtime);
|
|
18
|
+
}
|
|
19
|
+
return realtime.commandSubscription.subscribe(credentials, sessionId, onCommands, onError);
|
|
20
|
+
},
|
|
21
|
+
dispose() {
|
|
22
|
+
for (const realtime of clients.values()) realtime.dispose();
|
|
23
|
+
clients.clear();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
exports.createConvexCommandSubscription = _chunk6YE5BL3Acjs.createConvexCommandSubscription; exports.createConvexDeviceRealtime = _chunk6YE5BL3Acjs.createConvexDeviceRealtime; exports.createGrantCommandSubscription = createGrantCommandSubscription;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { C as ConvexDeviceRealtime, c as createConvexCommandSubscription, a as createConvexDeviceRealtime } from '../convex-command-subscription-DUgpu75l.cjs';
|
|
2
|
+
import { S as SessionCommandSubscription } from '../engine-BSvSdCSE.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subscription cho app dùng camera grant: URL Convex nằm TRONG grant
|
|
6
|
+
* (`grant.convexUrl`) nên chỉ biết sau khi start — đọc URL lúc engine subscribe
|
|
7
|
+
* (ngay sau khi vào phiên), dựng MỘT client mỗi origin và tái dùng qua các
|
|
8
|
+
* phiên. Không có URL (deployment không lộ origin chuẩn) → không subscribe,
|
|
9
|
+
* engine giữ poll HTTP như cũ.
|
|
10
|
+
*
|
|
11
|
+
* Dùng với createCameraGrantProvider: `() => provider.getActiveGrant()?.convexUrl`.
|
|
12
|
+
*/
|
|
13
|
+
declare function createGrantCommandSubscription(getConvexUrl: () => string | null | undefined): SessionCommandSubscription;
|
|
14
|
+
|
|
15
|
+
export { createGrantCommandSubscription };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { C as ConvexDeviceRealtime, c as createConvexCommandSubscription, a as createConvexDeviceRealtime } from '../convex-command-subscription-Cabh9tND.js';
|
|
2
|
+
import { S as SessionCommandSubscription } from '../engine-BSvSdCSE.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subscription cho app dùng camera grant: URL Convex nằm TRONG grant
|
|
6
|
+
* (`grant.convexUrl`) nên chỉ biết sau khi start — đọc URL lúc engine subscribe
|
|
7
|
+
* (ngay sau khi vào phiên), dựng MỘT client mỗi origin và tái dùng qua các
|
|
8
|
+
* phiên. Không có URL (deployment không lộ origin chuẩn) → không subscribe,
|
|
9
|
+
* engine giữ poll HTTP như cũ.
|
|
10
|
+
*
|
|
11
|
+
* Dùng với createCameraGrantProvider: `() => provider.getActiveGrant()?.convexUrl`.
|
|
12
|
+
*/
|
|
13
|
+
declare function createGrantCommandSubscription(getConvexUrl: () => string | null | undefined): SessionCommandSubscription;
|
|
14
|
+
|
|
15
|
+
export { createGrantCommandSubscription };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createConvexCommandSubscription,
|
|
3
|
+
createConvexDeviceRealtime
|
|
4
|
+
} from "../chunk-6F3HN6US.js";
|
|
5
|
+
import "../chunk-KFQGP6VL.js";
|
|
6
|
+
|
|
7
|
+
// src/realtime/index.ts
|
|
8
|
+
function createGrantCommandSubscription(getConvexUrl) {
|
|
9
|
+
const clients = /* @__PURE__ */ new Map();
|
|
10
|
+
return {
|
|
11
|
+
subscribe(credentials, sessionId, onCommands, onError) {
|
|
12
|
+
const url = getConvexUrl();
|
|
13
|
+
if (!url) return () => void 0;
|
|
14
|
+
let realtime = clients.get(url);
|
|
15
|
+
if (!realtime) {
|
|
16
|
+
realtime = createConvexDeviceRealtime(url);
|
|
17
|
+
clients.set(url, realtime);
|
|
18
|
+
}
|
|
19
|
+
return realtime.commandSubscription.subscribe(credentials, sessionId, onCommands, onError);
|
|
20
|
+
},
|
|
21
|
+
dispose() {
|
|
22
|
+
for (const realtime of clients.values()) realtime.dispose();
|
|
23
|
+
clients.clear();
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
createConvexCommandSubscription,
|
|
29
|
+
createConvexDeviceRealtime,
|
|
30
|
+
createGrantCommandSubscription
|
|
31
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
type MatchFormat = "singles" | "doubles";
|
|
2
|
+
type MatchScoringMode = "rally" | "sideOut";
|
|
3
|
+
type MatchTeamId = "A" | "B";
|
|
4
|
+
type CourtSide = "left" | "right";
|
|
5
|
+
type MatchInputSource = "local" | "remote" | "voice" | "ble" | "system";
|
|
6
|
+
interface MatchPlayer {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly name: string;
|
|
9
|
+
}
|
|
10
|
+
interface MatchTeam {
|
|
11
|
+
readonly id: MatchTeamId;
|
|
12
|
+
readonly name?: string;
|
|
13
|
+
/** Defaults to the first player in the roster. */
|
|
14
|
+
readonly initialServerId?: string;
|
|
15
|
+
readonly players: readonly MatchPlayer[];
|
|
16
|
+
}
|
|
17
|
+
interface MatchCreateInput {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly format: MatchFormat;
|
|
20
|
+
readonly scoringMode: MatchScoringMode;
|
|
21
|
+
readonly targetScore?: number;
|
|
22
|
+
readonly initialServingTeam?: MatchTeamId;
|
|
23
|
+
readonly teams: Readonly<Record<MatchTeamId, MatchTeam>>;
|
|
24
|
+
}
|
|
25
|
+
interface TeamScore {
|
|
26
|
+
readonly A: number;
|
|
27
|
+
readonly B: number;
|
|
28
|
+
}
|
|
29
|
+
interface ServeState {
|
|
30
|
+
readonly teamId: MatchTeamId;
|
|
31
|
+
readonly playerId: string;
|
|
32
|
+
readonly serverNumber: 1 | 2;
|
|
33
|
+
readonly court: CourtSide;
|
|
34
|
+
}
|
|
35
|
+
interface GameSnapshot {
|
|
36
|
+
readonly number: 1 | 2 | 3;
|
|
37
|
+
readonly score: TeamScore;
|
|
38
|
+
readonly startingServingTeam: MatchTeamId;
|
|
39
|
+
readonly winner: MatchTeamId | null;
|
|
40
|
+
readonly midGameSwitchCompleted: boolean;
|
|
41
|
+
}
|
|
42
|
+
type PendingCourtSwitch = {
|
|
43
|
+
readonly reason: "gameEnd";
|
|
44
|
+
readonly game: 1 | 2;
|
|
45
|
+
} | {
|
|
46
|
+
readonly reason: "gameThreeMidpoint";
|
|
47
|
+
readonly game: 3;
|
|
48
|
+
};
|
|
49
|
+
interface MatchSnapshot {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly format: MatchFormat;
|
|
52
|
+
readonly scoringMode: MatchScoringMode;
|
|
53
|
+
readonly targetScore: number;
|
|
54
|
+
readonly bestOf: 3;
|
|
55
|
+
readonly teams: Readonly<Record<MatchTeamId, MatchTeam>>;
|
|
56
|
+
readonly designatedServerByTeam: Readonly<Record<MatchTeamId, string>>;
|
|
57
|
+
readonly initialServingTeam: MatchTeamId;
|
|
58
|
+
readonly courtSides: Readonly<Record<CourtSide, MatchTeamId>>;
|
|
59
|
+
readonly playerCourts: Readonly<Record<string, CourtSide>>;
|
|
60
|
+
readonly games: readonly GameSnapshot[];
|
|
61
|
+
readonly currentGame: 1 | 2 | 3;
|
|
62
|
+
readonly gamesWon: TeamScore;
|
|
63
|
+
readonly serve: ServeState;
|
|
64
|
+
readonly pendingCourtSwitch: PendingCourtSwitch | null;
|
|
65
|
+
readonly status: "inProgress" | "completed" | "ended";
|
|
66
|
+
readonly winner: MatchTeamId | null;
|
|
67
|
+
readonly endReason: string | null;
|
|
68
|
+
readonly sequence: number;
|
|
69
|
+
}
|
|
70
|
+
interface MatchCorrection {
|
|
71
|
+
readonly score?: Partial<TeamScore>;
|
|
72
|
+
readonly serve?: ServeState;
|
|
73
|
+
readonly playerCourts?: Readonly<Record<string, CourtSide>>;
|
|
74
|
+
}
|
|
75
|
+
interface MatchEventBase {
|
|
76
|
+
readonly schemaVersion: 1;
|
|
77
|
+
readonly id: string;
|
|
78
|
+
readonly sequence: number;
|
|
79
|
+
readonly source: MatchInputSource;
|
|
80
|
+
}
|
|
81
|
+
interface MatchCreatedEvent extends MatchEventBase {
|
|
82
|
+
readonly type: "matchCreated";
|
|
83
|
+
readonly input: MatchCreateInput;
|
|
84
|
+
readonly snapshot: MatchSnapshot;
|
|
85
|
+
}
|
|
86
|
+
interface RallyAwardedEvent extends MatchEventBase {
|
|
87
|
+
readonly type: "rallyAwarded";
|
|
88
|
+
readonly displaySide: CourtSide;
|
|
89
|
+
readonly winnerTeamId: MatchTeamId;
|
|
90
|
+
}
|
|
91
|
+
interface CourtSwitchConfirmedEvent extends MatchEventBase {
|
|
92
|
+
readonly type: "courtSwitchConfirmed";
|
|
93
|
+
readonly pending: PendingCourtSwitch;
|
|
94
|
+
}
|
|
95
|
+
interface MatchCorrectedEvent extends MatchEventBase {
|
|
96
|
+
readonly type: "matchCorrected";
|
|
97
|
+
readonly correction: MatchCorrection;
|
|
98
|
+
}
|
|
99
|
+
interface MatchEndedEvent extends MatchEventBase {
|
|
100
|
+
readonly type: "matchEnded";
|
|
101
|
+
readonly reason: string;
|
|
102
|
+
}
|
|
103
|
+
interface MatchEventUndoneEvent extends MatchEventBase {
|
|
104
|
+
readonly type: "matchEventUndone";
|
|
105
|
+
readonly targetEventId: string;
|
|
106
|
+
readonly restoredSnapshot: MatchSnapshot;
|
|
107
|
+
}
|
|
108
|
+
type MatchEvent = MatchCreatedEvent | RallyAwardedEvent | CourtSwitchConfirmedEvent | MatchCorrectedEvent | MatchEndedEvent | MatchEventUndoneEvent;
|
|
109
|
+
interface MatchCreation {
|
|
110
|
+
readonly snapshot: MatchSnapshot;
|
|
111
|
+
readonly events: readonly [MatchCreatedEvent];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type AnnouncementKind = "score" | "serviceChange" | "gamePoint" | "gameWon" | "courtSwitch" | "matchWon";
|
|
115
|
+
type FallbackVoiceToken = `number-${number}` | "number-mot" | "number-lam" | `score-deu-${number}` | "score-deu-mot" | "score-deu-lam" | "server-1" | "server-2" | "court-left" | "court-right" | "service-change" | "game-point" | "game-won" | "court-switch" | "match-won" | "test-speaker";
|
|
116
|
+
interface AnnouncementPlan {
|
|
117
|
+
readonly kind: AnnouncementKind;
|
|
118
|
+
readonly text: string;
|
|
119
|
+
readonly score?: readonly [number, number];
|
|
120
|
+
readonly fallbackTokens: readonly FallbackVoiceToken[];
|
|
121
|
+
}
|
|
122
|
+
type VoiceAudioRoute = "system" | "bluetoothA2DP" | "bluetoothHFP" | "speaker" | "headphones" | "unknown";
|
|
123
|
+
type VoiceDisconnectReason = "oldDeviceUnavailable" | "becomingNoisy" | "unknown";
|
|
124
|
+
interface VoiceRouteState {
|
|
125
|
+
readonly route: VoiceAudioRoute;
|
|
126
|
+
readonly interrupted: boolean;
|
|
127
|
+
readonly disconnectedReason: VoiceDisconnectReason | null;
|
|
128
|
+
}
|
|
129
|
+
type VoiceAudioMode = "offline" | "live";
|
|
130
|
+
interface AudioPlayback {
|
|
131
|
+
configure(mode: VoiceAudioMode): Promise<void>;
|
|
132
|
+
play(source: string): Promise<void>;
|
|
133
|
+
stop(): Promise<void>;
|
|
134
|
+
dispose(): Promise<void>;
|
|
135
|
+
getRouteState(): VoiceRouteState;
|
|
136
|
+
subscribeToRouteChanges?(listener: (state: VoiceRouteState) => void): () => void;
|
|
137
|
+
}
|
|
138
|
+
type NeuralVoiceAvailability = "available" | "unavailable";
|
|
139
|
+
interface NeuralVoiceEngine {
|
|
140
|
+
availability(): Promise<NeuralVoiceAvailability>;
|
|
141
|
+
prewarm(commonPhrases: readonly string[]): Promise<void>;
|
|
142
|
+
synthesize(text: string, signal: AbortSignal): Promise<string>;
|
|
143
|
+
cancel(): Promise<void>;
|
|
144
|
+
release?(filePath: string): Promise<void>;
|
|
145
|
+
dispose(): Promise<void>;
|
|
146
|
+
}
|
|
147
|
+
/** Cloud TTS endpoint the SDK posts announcement text to (see apps/proxy /voice/tts). */
|
|
148
|
+
interface VoiceTtsOptions {
|
|
149
|
+
readonly url: string;
|
|
150
|
+
/** Extra request headers, e.g. partner bearer tokens. Re-evaluated per request. */
|
|
151
|
+
readonly headers?: () => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;
|
|
152
|
+
readonly voiceName?: string;
|
|
153
|
+
readonly languageCode?: string;
|
|
154
|
+
readonly requestTimeoutMs?: number;
|
|
155
|
+
}
|
|
156
|
+
type VoiceErrorCode = "engine_unavailable" | "network_unavailable" | "synthesis_failed" | "storage_failure" | "playback_failed";
|
|
157
|
+
declare class VoiceError extends Error {
|
|
158
|
+
readonly code: VoiceErrorCode;
|
|
159
|
+
readonly name = "VoiceError";
|
|
160
|
+
constructor(code: VoiceErrorCode, message: string, options?: {
|
|
161
|
+
cause?: unknown;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
interface MatchVoiceService {
|
|
165
|
+
readonly audioState: VoiceRouteState;
|
|
166
|
+
readonly lastError?: Error | null;
|
|
167
|
+
initialize(): Promise<void>;
|
|
168
|
+
subscribe(listener: () => void): () => void;
|
|
169
|
+
announce(previous: MatchSnapshot, current: MatchSnapshot, event: MatchEvent): void;
|
|
170
|
+
replayAnnouncement(): Promise<void>;
|
|
171
|
+
testSpeaker(): Promise<void>;
|
|
172
|
+
configureAudioMode?(mode: VoiceAudioMode): Promise<void>;
|
|
173
|
+
dispose(): Promise<void>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { type AnnouncementPlan as A, type CourtSide as C, type FallbackVoiceToken as F, type GameSnapshot as G, type MatchSnapshot as M, type NeuralVoiceEngine as N, type PendingCourtSwitch as P, type RallyAwardedEvent as R, type ServeState as S, type TeamScore as T, type VoiceAudioMode as V, type MatchEvent as a, type AudioPlayback as b, type VoiceRouteState as c, type VoiceTtsOptions as d, type MatchVoiceService as e, type AnnouncementKind as f, type NeuralVoiceAvailability as g, type VoiceAudioRoute as h, type VoiceDisconnectReason as i, VoiceError as j, type VoiceErrorCode as k, type MatchInputSource as l, type CourtSwitchConfirmedEvent as m, type MatchCorrection as n, type MatchCorrectedEvent as o, type MatchCreateInput as p, type MatchCreation as q, type MatchEndedEvent as r, type MatchEventUndoneEvent as s, type MatchCreatedEvent as t, type MatchFormat as u, type MatchPlayer as v, type MatchScoringMode as w, type MatchTeam as x, type MatchTeamId as y };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
type MatchFormat = "singles" | "doubles";
|
|
2
|
+
type MatchScoringMode = "rally" | "sideOut";
|
|
3
|
+
type MatchTeamId = "A" | "B";
|
|
4
|
+
type CourtSide = "left" | "right";
|
|
5
|
+
type MatchInputSource = "local" | "remote" | "voice" | "ble" | "system";
|
|
6
|
+
interface MatchPlayer {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly name: string;
|
|
9
|
+
}
|
|
10
|
+
interface MatchTeam {
|
|
11
|
+
readonly id: MatchTeamId;
|
|
12
|
+
readonly name?: string;
|
|
13
|
+
/** Defaults to the first player in the roster. */
|
|
14
|
+
readonly initialServerId?: string;
|
|
15
|
+
readonly players: readonly MatchPlayer[];
|
|
16
|
+
}
|
|
17
|
+
interface MatchCreateInput {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly format: MatchFormat;
|
|
20
|
+
readonly scoringMode: MatchScoringMode;
|
|
21
|
+
readonly targetScore?: number;
|
|
22
|
+
readonly initialServingTeam?: MatchTeamId;
|
|
23
|
+
readonly teams: Readonly<Record<MatchTeamId, MatchTeam>>;
|
|
24
|
+
}
|
|
25
|
+
interface TeamScore {
|
|
26
|
+
readonly A: number;
|
|
27
|
+
readonly B: number;
|
|
28
|
+
}
|
|
29
|
+
interface ServeState {
|
|
30
|
+
readonly teamId: MatchTeamId;
|
|
31
|
+
readonly playerId: string;
|
|
32
|
+
readonly serverNumber: 1 | 2;
|
|
33
|
+
readonly court: CourtSide;
|
|
34
|
+
}
|
|
35
|
+
interface GameSnapshot {
|
|
36
|
+
readonly number: 1 | 2 | 3;
|
|
37
|
+
readonly score: TeamScore;
|
|
38
|
+
readonly startingServingTeam: MatchTeamId;
|
|
39
|
+
readonly winner: MatchTeamId | null;
|
|
40
|
+
readonly midGameSwitchCompleted: boolean;
|
|
41
|
+
}
|
|
42
|
+
type PendingCourtSwitch = {
|
|
43
|
+
readonly reason: "gameEnd";
|
|
44
|
+
readonly game: 1 | 2;
|
|
45
|
+
} | {
|
|
46
|
+
readonly reason: "gameThreeMidpoint";
|
|
47
|
+
readonly game: 3;
|
|
48
|
+
};
|
|
49
|
+
interface MatchSnapshot {
|
|
50
|
+
readonly id: string;
|
|
51
|
+
readonly format: MatchFormat;
|
|
52
|
+
readonly scoringMode: MatchScoringMode;
|
|
53
|
+
readonly targetScore: number;
|
|
54
|
+
readonly bestOf: 3;
|
|
55
|
+
readonly teams: Readonly<Record<MatchTeamId, MatchTeam>>;
|
|
56
|
+
readonly designatedServerByTeam: Readonly<Record<MatchTeamId, string>>;
|
|
57
|
+
readonly initialServingTeam: MatchTeamId;
|
|
58
|
+
readonly courtSides: Readonly<Record<CourtSide, MatchTeamId>>;
|
|
59
|
+
readonly playerCourts: Readonly<Record<string, CourtSide>>;
|
|
60
|
+
readonly games: readonly GameSnapshot[];
|
|
61
|
+
readonly currentGame: 1 | 2 | 3;
|
|
62
|
+
readonly gamesWon: TeamScore;
|
|
63
|
+
readonly serve: ServeState;
|
|
64
|
+
readonly pendingCourtSwitch: PendingCourtSwitch | null;
|
|
65
|
+
readonly status: "inProgress" | "completed" | "ended";
|
|
66
|
+
readonly winner: MatchTeamId | null;
|
|
67
|
+
readonly endReason: string | null;
|
|
68
|
+
readonly sequence: number;
|
|
69
|
+
}
|
|
70
|
+
interface MatchCorrection {
|
|
71
|
+
readonly score?: Partial<TeamScore>;
|
|
72
|
+
readonly serve?: ServeState;
|
|
73
|
+
readonly playerCourts?: Readonly<Record<string, CourtSide>>;
|
|
74
|
+
}
|
|
75
|
+
interface MatchEventBase {
|
|
76
|
+
readonly schemaVersion: 1;
|
|
77
|
+
readonly id: string;
|
|
78
|
+
readonly sequence: number;
|
|
79
|
+
readonly source: MatchInputSource;
|
|
80
|
+
}
|
|
81
|
+
interface MatchCreatedEvent extends MatchEventBase {
|
|
82
|
+
readonly type: "matchCreated";
|
|
83
|
+
readonly input: MatchCreateInput;
|
|
84
|
+
readonly snapshot: MatchSnapshot;
|
|
85
|
+
}
|
|
86
|
+
interface RallyAwardedEvent extends MatchEventBase {
|
|
87
|
+
readonly type: "rallyAwarded";
|
|
88
|
+
readonly displaySide: CourtSide;
|
|
89
|
+
readonly winnerTeamId: MatchTeamId;
|
|
90
|
+
}
|
|
91
|
+
interface CourtSwitchConfirmedEvent extends MatchEventBase {
|
|
92
|
+
readonly type: "courtSwitchConfirmed";
|
|
93
|
+
readonly pending: PendingCourtSwitch;
|
|
94
|
+
}
|
|
95
|
+
interface MatchCorrectedEvent extends MatchEventBase {
|
|
96
|
+
readonly type: "matchCorrected";
|
|
97
|
+
readonly correction: MatchCorrection;
|
|
98
|
+
}
|
|
99
|
+
interface MatchEndedEvent extends MatchEventBase {
|
|
100
|
+
readonly type: "matchEnded";
|
|
101
|
+
readonly reason: string;
|
|
102
|
+
}
|
|
103
|
+
interface MatchEventUndoneEvent extends MatchEventBase {
|
|
104
|
+
readonly type: "matchEventUndone";
|
|
105
|
+
readonly targetEventId: string;
|
|
106
|
+
readonly restoredSnapshot: MatchSnapshot;
|
|
107
|
+
}
|
|
108
|
+
type MatchEvent = MatchCreatedEvent | RallyAwardedEvent | CourtSwitchConfirmedEvent | MatchCorrectedEvent | MatchEndedEvent | MatchEventUndoneEvent;
|
|
109
|
+
interface MatchCreation {
|
|
110
|
+
readonly snapshot: MatchSnapshot;
|
|
111
|
+
readonly events: readonly [MatchCreatedEvent];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type AnnouncementKind = "score" | "serviceChange" | "gamePoint" | "gameWon" | "courtSwitch" | "matchWon";
|
|
115
|
+
type FallbackVoiceToken = `number-${number}` | "number-mot" | "number-lam" | `score-deu-${number}` | "score-deu-mot" | "score-deu-lam" | "server-1" | "server-2" | "court-left" | "court-right" | "service-change" | "game-point" | "game-won" | "court-switch" | "match-won" | "test-speaker";
|
|
116
|
+
interface AnnouncementPlan {
|
|
117
|
+
readonly kind: AnnouncementKind;
|
|
118
|
+
readonly text: string;
|
|
119
|
+
readonly score?: readonly [number, number];
|
|
120
|
+
readonly fallbackTokens: readonly FallbackVoiceToken[];
|
|
121
|
+
}
|
|
122
|
+
type VoiceAudioRoute = "system" | "bluetoothA2DP" | "bluetoothHFP" | "speaker" | "headphones" | "unknown";
|
|
123
|
+
type VoiceDisconnectReason = "oldDeviceUnavailable" | "becomingNoisy" | "unknown";
|
|
124
|
+
interface VoiceRouteState {
|
|
125
|
+
readonly route: VoiceAudioRoute;
|
|
126
|
+
readonly interrupted: boolean;
|
|
127
|
+
readonly disconnectedReason: VoiceDisconnectReason | null;
|
|
128
|
+
}
|
|
129
|
+
type VoiceAudioMode = "offline" | "live";
|
|
130
|
+
interface AudioPlayback {
|
|
131
|
+
configure(mode: VoiceAudioMode): Promise<void>;
|
|
132
|
+
play(source: string): Promise<void>;
|
|
133
|
+
stop(): Promise<void>;
|
|
134
|
+
dispose(): Promise<void>;
|
|
135
|
+
getRouteState(): VoiceRouteState;
|
|
136
|
+
subscribeToRouteChanges?(listener: (state: VoiceRouteState) => void): () => void;
|
|
137
|
+
}
|
|
138
|
+
type NeuralVoiceAvailability = "available" | "unavailable";
|
|
139
|
+
interface NeuralVoiceEngine {
|
|
140
|
+
availability(): Promise<NeuralVoiceAvailability>;
|
|
141
|
+
prewarm(commonPhrases: readonly string[]): Promise<void>;
|
|
142
|
+
synthesize(text: string, signal: AbortSignal): Promise<string>;
|
|
143
|
+
cancel(): Promise<void>;
|
|
144
|
+
release?(filePath: string): Promise<void>;
|
|
145
|
+
dispose(): Promise<void>;
|
|
146
|
+
}
|
|
147
|
+
/** Cloud TTS endpoint the SDK posts announcement text to (see apps/proxy /voice/tts). */
|
|
148
|
+
interface VoiceTtsOptions {
|
|
149
|
+
readonly url: string;
|
|
150
|
+
/** Extra request headers, e.g. partner bearer tokens. Re-evaluated per request. */
|
|
151
|
+
readonly headers?: () => Readonly<Record<string, string>> | Promise<Readonly<Record<string, string>>>;
|
|
152
|
+
readonly voiceName?: string;
|
|
153
|
+
readonly languageCode?: string;
|
|
154
|
+
readonly requestTimeoutMs?: number;
|
|
155
|
+
}
|
|
156
|
+
type VoiceErrorCode = "engine_unavailable" | "network_unavailable" | "synthesis_failed" | "storage_failure" | "playback_failed";
|
|
157
|
+
declare class VoiceError extends Error {
|
|
158
|
+
readonly code: VoiceErrorCode;
|
|
159
|
+
readonly name = "VoiceError";
|
|
160
|
+
constructor(code: VoiceErrorCode, message: string, options?: {
|
|
161
|
+
cause?: unknown;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
interface MatchVoiceService {
|
|
165
|
+
readonly audioState: VoiceRouteState;
|
|
166
|
+
readonly lastError?: Error | null;
|
|
167
|
+
initialize(): Promise<void>;
|
|
168
|
+
subscribe(listener: () => void): () => void;
|
|
169
|
+
announce(previous: MatchSnapshot, current: MatchSnapshot, event: MatchEvent): void;
|
|
170
|
+
replayAnnouncement(): Promise<void>;
|
|
171
|
+
testSpeaker(): Promise<void>;
|
|
172
|
+
configureAudioMode?(mode: VoiceAudioMode): Promise<void>;
|
|
173
|
+
dispose(): Promise<void>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { type AnnouncementPlan as A, type CourtSide as C, type FallbackVoiceToken as F, type GameSnapshot as G, type MatchSnapshot as M, type NeuralVoiceEngine as N, type PendingCourtSwitch as P, type RallyAwardedEvent as R, type ServeState as S, type TeamScore as T, type VoiceAudioMode as V, type MatchEvent as a, type AudioPlayback as b, type VoiceRouteState as c, type VoiceTtsOptions as d, type MatchVoiceService as e, type AnnouncementKind as f, type NeuralVoiceAvailability as g, type VoiceAudioRoute as h, type VoiceDisconnectReason as i, VoiceError as j, type VoiceErrorCode as k, type MatchInputSource as l, type CourtSwitchConfirmedEvent as m, type MatchCorrection as n, type MatchCorrectedEvent as o, type MatchCreateInput as p, type MatchCreation as q, type MatchEndedEvent as r, type MatchEventUndoneEvent as s, type MatchCreatedEvent as t, type MatchFormat as u, type MatchPlayer as v, type MatchScoringMode as w, type MatchTeam as x, type MatchTeamId as y };
|