@pickleball/expo-sdk 0.1.1 → 0.2.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 +24 -0
- package/README.md +69 -0
- package/dist/advanced-BXDrDl1h.d.ts +316 -0
- package/dist/advanced-BdAa2Erv.d.cts +316 -0
- package/dist/advanced.cjs +35 -0
- package/dist/advanced.d.cts +3 -0
- package/dist/advanced.d.ts +3 -0
- package/dist/advanced.js +35 -0
- package/dist/chunk-2JHULJZ7.js +265 -0
- package/dist/chunk-6JOMESNT.js +9 -0
- package/dist/chunk-7OX2DSKI.cjs +33 -0
- package/dist/chunk-DHDX3ZOO.js +800 -0
- package/dist/chunk-FODE2W2H.js +1953 -0
- package/dist/chunk-KFQGP6VL.js +33 -0
- package/dist/chunk-LCWGNGEN.cjs +265 -0
- package/dist/chunk-TBPR2QND.cjs +1953 -0
- package/dist/chunk-TRLASNPQ.cjs +9 -0
- package/dist/chunk-YGSQ25UA.cjs +800 -0
- package/dist/device-agent/index.cjs +498 -0
- package/dist/device-agent/index.d.cts +157 -0
- package/dist/device-agent/index.d.ts +157 -0
- package/dist/device-agent/index.js +498 -0
- package/dist/engine-CCSSqPbZ.d.cts +516 -0
- package/dist/engine-CCSSqPbZ.d.ts +516 -0
- package/dist/index.cjs +339 -5569
- package/dist/index.d.cts +22 -1406
- package/dist/index.d.ts +22 -1406
- package/dist/index.js +269 -5401
- 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 +53 -70
- package/dist/plugin.d.cts +13 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.js +20 -15
- 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/version.cjs +4 -32
- package/dist/version.js +2 -1
- package/package.json +68 -4
- package/src/advanced.ts +47 -0
- package/src/device-agent/agent.ts +443 -0
- package/src/device-agent/component.tsx +49 -0
- package/src/device-agent/convex-control-channel.ts +82 -0
- package/src/device-agent/http-transport.ts +143 -0
- package/src/device-agent/index.ts +4 -0
- package/src/engine.ts +21 -5
- package/src/errors.ts +16 -0
- package/src/http-session-provider.ts +19 -13
- package/src/index.ts +38 -14
- package/src/livekit-room-adapter.ts +39 -2
- package/src/livestream-screen.tsx +26 -4
- 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 +54 -4
- package/src/plugin.ts +35 -14
- package/src/provider.tsx +35 -4
- package/src/rtmp-room-adapter.ts +196 -0
- package/dist/chunk-VHLUJQG5.js +0 -17
package/dist/plugin.d.cts
CHANGED
|
@@ -5,6 +5,19 @@ interface PickleballLivePluginProps {
|
|
|
5
5
|
microphonePermission?: string;
|
|
6
6
|
bluetoothPermission?: string;
|
|
7
7
|
consumeHidVolumeKeys?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Tắt phần cấu hình native của module không dùng để app gọn hơn:
|
|
10
|
+
* - remote: false → bỏ permission Bluetooth (Android + iOS usage string) và
|
|
11
|
+
* không patch MainActivity nhận phím HID. Dùng khi app không import
|
|
12
|
+
* "@pickleball/expo-sdk/match/remote".
|
|
13
|
+
* - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
|
|
14
|
+
* nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
|
|
15
|
+
* expo.autolinking.exclude trong package.json của app (xem README).
|
|
16
|
+
*/
|
|
17
|
+
modules?: {
|
|
18
|
+
remote?: boolean;
|
|
19
|
+
voice?: boolean;
|
|
20
|
+
};
|
|
8
21
|
liveKit?: {
|
|
9
22
|
android?: {
|
|
10
23
|
audioType?: string;
|
package/dist/plugin.d.ts
CHANGED
|
@@ -5,6 +5,19 @@ interface PickleballLivePluginProps {
|
|
|
5
5
|
microphonePermission?: string;
|
|
6
6
|
bluetoothPermission?: string;
|
|
7
7
|
consumeHidVolumeKeys?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Tắt phần cấu hình native của module không dùng để app gọn hơn:
|
|
10
|
+
* - remote: false → bỏ permission Bluetooth (Android + iOS usage string) và
|
|
11
|
+
* không patch MainActivity nhận phím HID. Dùng khi app không import
|
|
12
|
+
* "@pickleball/expo-sdk/match/remote".
|
|
13
|
+
* - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
|
|
14
|
+
* nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
|
|
15
|
+
* expo.autolinking.exclude trong package.json của app (xem README).
|
|
16
|
+
*/
|
|
17
|
+
modules?: {
|
|
18
|
+
remote?: boolean;
|
|
19
|
+
voice?: boolean;
|
|
20
|
+
};
|
|
8
21
|
liveKit?: {
|
|
9
22
|
android?: {
|
|
10
23
|
audioType?: string;
|
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PICKLEBALL_EXPO_SDK_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6JOMESNT.js";
|
|
4
|
+
import "./chunk-KFQGP6VL.js";
|
|
4
5
|
|
|
5
6
|
// src/plugin.ts
|
|
6
7
|
import {
|
|
@@ -13,19 +14,21 @@ import {
|
|
|
13
14
|
} from "expo/config-plugins";
|
|
14
15
|
import { readdir, readFile, writeFile } from "fs/promises";
|
|
15
16
|
import { join } from "path";
|
|
16
|
-
var
|
|
17
|
+
var CORE_ANDROID_PERMISSIONS = [
|
|
17
18
|
"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
19
|
"android.permission.CAMERA",
|
|
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,6 +63,8 @@ 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.";
|
|
66
|
+
const remoteEnabled = props?.modules?.remote !== false;
|
|
67
|
+
const androidPermissions = remoteEnabled ? [...CORE_ANDROID_PERMISSIONS, ...REMOTE_ANDROID_PERMISSIONS] : [...CORE_ANDROID_PERMISSIONS];
|
|
63
68
|
config = withPlugins(config, [
|
|
64
69
|
["@livekit/react-native-expo-plugin", props?.liveKit]
|
|
65
70
|
]);
|
|
@@ -67,12 +72,12 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
67
72
|
config = withInfoPlist(config, (mod) => {
|
|
68
73
|
mod.modResults.NSCameraUsageDescription = cameraPermission;
|
|
69
74
|
mod.modResults.NSMicrophoneUsageDescription = microphonePermission;
|
|
70
|
-
|
|
75
|
+
if (remoteEnabled) {
|
|
76
|
+
mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
|
|
77
|
+
}
|
|
71
78
|
return mod;
|
|
72
79
|
});
|
|
73
|
-
config = AndroidConfig.Permissions.withPermissions(config,
|
|
74
|
-
...ANDROID_PERMISSIONS
|
|
75
|
-
]);
|
|
80
|
+
config = AndroidConfig.Permissions.withPermissions(config, androidPermissions);
|
|
76
81
|
config = withAndroidManifest(config, (mod) => {
|
|
77
82
|
const manifest = mod.modResults.manifest;
|
|
78
83
|
const existing = manifest["uses-permission"] ?? [];
|
|
@@ -89,7 +94,7 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
89
94
|
const name = entry.$?.["android:name"];
|
|
90
95
|
if (name && !byName.has(name)) byName.set(name, entry);
|
|
91
96
|
}
|
|
92
|
-
for (const permission of
|
|
97
|
+
for (const permission of androidPermissions) {
|
|
93
98
|
const entry = byName.get(permission) ?? { $: { "android:name": permission } };
|
|
94
99
|
entry.$ = {
|
|
95
100
|
"android:name": permission,
|
|
@@ -97,17 +102,17 @@ var withPickleballLive = (config, props = {}) => {
|
|
|
97
102
|
};
|
|
98
103
|
byName.set(permission, entry);
|
|
99
104
|
}
|
|
100
|
-
const requiredNames = new Set(
|
|
105
|
+
const requiredNames = new Set(androidPermissions);
|
|
101
106
|
manifest["uses-permission"] = [
|
|
102
107
|
...existing.filter((entry) => {
|
|
103
108
|
const name = entry.$?.["android:name"];
|
|
104
109
|
return !name || !requiredNames.has(name);
|
|
105
110
|
}),
|
|
106
|
-
...
|
|
111
|
+
...androidPermissions.map((name) => byName.get(name))
|
|
107
112
|
];
|
|
108
113
|
return mod;
|
|
109
114
|
});
|
|
110
|
-
if (props?.consumeHidVolumeKeys !== false) {
|
|
115
|
+
if (remoteEnabled && props?.consumeHidVolumeKeys !== false) {
|
|
111
116
|
config = withDangerousMod(config, ["android", async (mod) => {
|
|
112
117
|
const root = join(mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
|
|
113
118
|
const path = await findMainActivity(root);
|
|
@@ -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 };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
declare const BTHOME_SERVICE_UUID: "FCD2";
|
|
2
|
+
type RemoteButtonAction = "single" | "double" | "long";
|
|
3
|
+
type RemoteInputMode = "bthome" | "hidVolume" | "both";
|
|
4
|
+
type RemoteMappedAction = "left" | "right" | "undo" | "announce" | "none";
|
|
5
|
+
interface RemoteActionMapping {
|
|
6
|
+
readonly volumeUp: RemoteMappedAction;
|
|
7
|
+
readonly volumeDown: RemoteMappedAction;
|
|
8
|
+
readonly longPress: RemoteMappedAction;
|
|
9
|
+
}
|
|
10
|
+
declare const DEFAULT_REMOTE_ACTION_MAPPING: RemoteActionMapping;
|
|
11
|
+
interface RemoteHidVolumeEvent {
|
|
12
|
+
readonly source: "hidVolume";
|
|
13
|
+
readonly direction: "volumeUp" | "volumeDown";
|
|
14
|
+
readonly repeat: boolean;
|
|
15
|
+
readonly longPress: boolean;
|
|
16
|
+
readonly timestamp: number;
|
|
17
|
+
}
|
|
18
|
+
type RemoteHidGesture = "single" | "double" | "triple" | "quadruple" | "hold";
|
|
19
|
+
interface RemoteHidGestureMapping {
|
|
20
|
+
/** Raw HID direction emitted by the calibrated remote button, or "any" for single-button remotes that alternate directions. */
|
|
21
|
+
readonly direction: RemoteHidVolumeEvent["direction"] | "any";
|
|
22
|
+
/** Quiet window used to close one physical gesture burst. */
|
|
23
|
+
readonly settleMs: number;
|
|
24
|
+
/** Repeated volume changes required to classify a hold before the burst ends. */
|
|
25
|
+
readonly holdEventCount: number;
|
|
26
|
+
readonly single: RemoteMappedAction;
|
|
27
|
+
readonly double: RemoteMappedAction;
|
|
28
|
+
readonly triple?: RemoteMappedAction;
|
|
29
|
+
readonly quadruple?: RemoteMappedAction;
|
|
30
|
+
readonly hold: RemoteMappedAction;
|
|
31
|
+
}
|
|
32
|
+
interface RemoteBinding {
|
|
33
|
+
/** Stable identifier supplied by CoreBluetooth or BluetoothLeScanner. */
|
|
34
|
+
readonly deviceId: string;
|
|
35
|
+
readonly label?: string;
|
|
36
|
+
}
|
|
37
|
+
type RemotePermissionStatus = "unknown" | "granted" | "denied" | "restricted" | "unavailable";
|
|
38
|
+
type RemoteStatus = "unavailable" | "poweredOff" | "idle" | "scanning" | "bound" | "outOfRange";
|
|
39
|
+
interface RemoteCandidate {
|
|
40
|
+
readonly deviceId: string;
|
|
41
|
+
readonly label?: string;
|
|
42
|
+
readonly rssi: number;
|
|
43
|
+
readonly lastSeenAt: number;
|
|
44
|
+
}
|
|
45
|
+
interface RemoteState {
|
|
46
|
+
readonly status: RemoteStatus;
|
|
47
|
+
readonly permission: RemotePermissionStatus;
|
|
48
|
+
readonly binding: RemoteBinding | null;
|
|
49
|
+
readonly candidate: RemoteCandidate | null;
|
|
50
|
+
readonly lastSeenAt: number | null;
|
|
51
|
+
readonly error: RemoteError | null;
|
|
52
|
+
readonly hidCaptureArmed: boolean;
|
|
53
|
+
readonly lastInputSource: "bthome" | "hidVolume" | null;
|
|
54
|
+
readonly lastHidEvent: RemoteHidVolumeEvent | null;
|
|
55
|
+
}
|
|
56
|
+
type RemoteErrorCode = "permission_denied" | "permission_restricted" | "bluetooth_unavailable" | "bluetooth_powered_off" | "scan_failed" | "native_unavailable";
|
|
57
|
+
declare class RemoteError extends Error {
|
|
58
|
+
readonly code: RemoteErrorCode;
|
|
59
|
+
readonly name = "RemoteError";
|
|
60
|
+
constructor(code: RemoteErrorCode, message: string, options?: {
|
|
61
|
+
cause?: unknown;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
interface RemoteScanAdvertisement {
|
|
65
|
+
readonly deviceId: string;
|
|
66
|
+
readonly name?: string;
|
|
67
|
+
readonly rssi: number;
|
|
68
|
+
readonly serviceUuid: string;
|
|
69
|
+
/** Base64 encoded FCD2 service-data payload, beginning with the device-info byte. */
|
|
70
|
+
readonly serviceData: string;
|
|
71
|
+
readonly timestamp: number;
|
|
72
|
+
}
|
|
73
|
+
type RemoteNativeState = {
|
|
74
|
+
readonly status: "permission";
|
|
75
|
+
readonly permission: RemotePermissionStatus;
|
|
76
|
+
} | {
|
|
77
|
+
readonly status: "poweredOff" | "unavailable" | "scanning" | "idle";
|
|
78
|
+
} | {
|
|
79
|
+
readonly status: "error";
|
|
80
|
+
readonly code: string;
|
|
81
|
+
readonly message: string;
|
|
82
|
+
};
|
|
83
|
+
interface RemoteService {
|
|
84
|
+
start(): Promise<void>;
|
|
85
|
+
stop(): Promise<void>;
|
|
86
|
+
dispose(): Promise<void>;
|
|
87
|
+
subscribeAdvertisement(listener: (event: RemoteScanAdvertisement) => void): () => void;
|
|
88
|
+
subscribeState(listener: (event: RemoteNativeState) => void): () => void;
|
|
89
|
+
startHidCapture(options?: {
|
|
90
|
+
consume?: boolean;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
stopHidCapture(): Promise<void>;
|
|
93
|
+
subscribeHidVolume(listener: (event: RemoteHidVolumeEvent) => void): () => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { BTHOME_SERVICE_UUID as B, DEFAULT_REMOTE_ACTION_MAPPING as D, type RemoteButtonAction as R, type RemoteHidGestureMapping as a, type RemoteHidGesture as b, type RemoteHidVolumeEvent as c, type RemoteActionMapping as d, type RemoteBinding as e, type RemoteCandidate as f, RemoteError as g, type RemoteErrorCode as h, type RemoteInputMode as i, type RemoteMappedAction as j, type RemoteNativeState as k, type RemotePermissionStatus as l, type RemoteScanAdvertisement as m, type RemoteService as n, type RemoteState as o, type RemoteStatus as p };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
declare const BTHOME_SERVICE_UUID: "FCD2";
|
|
2
|
+
type RemoteButtonAction = "single" | "double" | "long";
|
|
3
|
+
type RemoteInputMode = "bthome" | "hidVolume" | "both";
|
|
4
|
+
type RemoteMappedAction = "left" | "right" | "undo" | "announce" | "none";
|
|
5
|
+
interface RemoteActionMapping {
|
|
6
|
+
readonly volumeUp: RemoteMappedAction;
|
|
7
|
+
readonly volumeDown: RemoteMappedAction;
|
|
8
|
+
readonly longPress: RemoteMappedAction;
|
|
9
|
+
}
|
|
10
|
+
declare const DEFAULT_REMOTE_ACTION_MAPPING: RemoteActionMapping;
|
|
11
|
+
interface RemoteHidVolumeEvent {
|
|
12
|
+
readonly source: "hidVolume";
|
|
13
|
+
readonly direction: "volumeUp" | "volumeDown";
|
|
14
|
+
readonly repeat: boolean;
|
|
15
|
+
readonly longPress: boolean;
|
|
16
|
+
readonly timestamp: number;
|
|
17
|
+
}
|
|
18
|
+
type RemoteHidGesture = "single" | "double" | "triple" | "quadruple" | "hold";
|
|
19
|
+
interface RemoteHidGestureMapping {
|
|
20
|
+
/** Raw HID direction emitted by the calibrated remote button, or "any" for single-button remotes that alternate directions. */
|
|
21
|
+
readonly direction: RemoteHidVolumeEvent["direction"] | "any";
|
|
22
|
+
/** Quiet window used to close one physical gesture burst. */
|
|
23
|
+
readonly settleMs: number;
|
|
24
|
+
/** Repeated volume changes required to classify a hold before the burst ends. */
|
|
25
|
+
readonly holdEventCount: number;
|
|
26
|
+
readonly single: RemoteMappedAction;
|
|
27
|
+
readonly double: RemoteMappedAction;
|
|
28
|
+
readonly triple?: RemoteMappedAction;
|
|
29
|
+
readonly quadruple?: RemoteMappedAction;
|
|
30
|
+
readonly hold: RemoteMappedAction;
|
|
31
|
+
}
|
|
32
|
+
interface RemoteBinding {
|
|
33
|
+
/** Stable identifier supplied by CoreBluetooth or BluetoothLeScanner. */
|
|
34
|
+
readonly deviceId: string;
|
|
35
|
+
readonly label?: string;
|
|
36
|
+
}
|
|
37
|
+
type RemotePermissionStatus = "unknown" | "granted" | "denied" | "restricted" | "unavailable";
|
|
38
|
+
type RemoteStatus = "unavailable" | "poweredOff" | "idle" | "scanning" | "bound" | "outOfRange";
|
|
39
|
+
interface RemoteCandidate {
|
|
40
|
+
readonly deviceId: string;
|
|
41
|
+
readonly label?: string;
|
|
42
|
+
readonly rssi: number;
|
|
43
|
+
readonly lastSeenAt: number;
|
|
44
|
+
}
|
|
45
|
+
interface RemoteState {
|
|
46
|
+
readonly status: RemoteStatus;
|
|
47
|
+
readonly permission: RemotePermissionStatus;
|
|
48
|
+
readonly binding: RemoteBinding | null;
|
|
49
|
+
readonly candidate: RemoteCandidate | null;
|
|
50
|
+
readonly lastSeenAt: number | null;
|
|
51
|
+
readonly error: RemoteError | null;
|
|
52
|
+
readonly hidCaptureArmed: boolean;
|
|
53
|
+
readonly lastInputSource: "bthome" | "hidVolume" | null;
|
|
54
|
+
readonly lastHidEvent: RemoteHidVolumeEvent | null;
|
|
55
|
+
}
|
|
56
|
+
type RemoteErrorCode = "permission_denied" | "permission_restricted" | "bluetooth_unavailable" | "bluetooth_powered_off" | "scan_failed" | "native_unavailable";
|
|
57
|
+
declare class RemoteError extends Error {
|
|
58
|
+
readonly code: RemoteErrorCode;
|
|
59
|
+
readonly name = "RemoteError";
|
|
60
|
+
constructor(code: RemoteErrorCode, message: string, options?: {
|
|
61
|
+
cause?: unknown;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
interface RemoteScanAdvertisement {
|
|
65
|
+
readonly deviceId: string;
|
|
66
|
+
readonly name?: string;
|
|
67
|
+
readonly rssi: number;
|
|
68
|
+
readonly serviceUuid: string;
|
|
69
|
+
/** Base64 encoded FCD2 service-data payload, beginning with the device-info byte. */
|
|
70
|
+
readonly serviceData: string;
|
|
71
|
+
readonly timestamp: number;
|
|
72
|
+
}
|
|
73
|
+
type RemoteNativeState = {
|
|
74
|
+
readonly status: "permission";
|
|
75
|
+
readonly permission: RemotePermissionStatus;
|
|
76
|
+
} | {
|
|
77
|
+
readonly status: "poweredOff" | "unavailable" | "scanning" | "idle";
|
|
78
|
+
} | {
|
|
79
|
+
readonly status: "error";
|
|
80
|
+
readonly code: string;
|
|
81
|
+
readonly message: string;
|
|
82
|
+
};
|
|
83
|
+
interface RemoteService {
|
|
84
|
+
start(): Promise<void>;
|
|
85
|
+
stop(): Promise<void>;
|
|
86
|
+
dispose(): Promise<void>;
|
|
87
|
+
subscribeAdvertisement(listener: (event: RemoteScanAdvertisement) => void): () => void;
|
|
88
|
+
subscribeState(listener: (event: RemoteNativeState) => void): () => void;
|
|
89
|
+
startHidCapture(options?: {
|
|
90
|
+
consume?: boolean;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
stopHidCapture(): Promise<void>;
|
|
93
|
+
subscribeHidVolume(listener: (event: RemoteHidVolumeEvent) => void): () => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { BTHOME_SERVICE_UUID as B, DEFAULT_REMOTE_ACTION_MAPPING as D, type RemoteButtonAction as R, type RemoteHidGestureMapping as a, type RemoteHidGesture as b, type RemoteHidVolumeEvent as c, type RemoteActionMapping as d, type RemoteBinding as e, type RemoteCandidate as f, RemoteError as g, type RemoteErrorCode as h, type RemoteInputMode as i, type RemoteMappedAction as j, type RemoteNativeState as k, type RemotePermissionStatus as l, type RemoteScanAdvertisement as m, type RemoteService as n, type RemoteState as o, type RemoteStatus as p };
|