@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.
Files changed (74) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +69 -0
  3. package/dist/advanced-BXDrDl1h.d.ts +316 -0
  4. package/dist/advanced-BdAa2Erv.d.cts +316 -0
  5. package/dist/advanced.cjs +35 -0
  6. package/dist/advanced.d.cts +3 -0
  7. package/dist/advanced.d.ts +3 -0
  8. package/dist/advanced.js +35 -0
  9. package/dist/chunk-2JHULJZ7.js +265 -0
  10. package/dist/chunk-6JOMESNT.js +9 -0
  11. package/dist/chunk-7OX2DSKI.cjs +33 -0
  12. package/dist/chunk-DHDX3ZOO.js +800 -0
  13. package/dist/chunk-FODE2W2H.js +1953 -0
  14. package/dist/chunk-KFQGP6VL.js +33 -0
  15. package/dist/chunk-LCWGNGEN.cjs +265 -0
  16. package/dist/chunk-TBPR2QND.cjs +1953 -0
  17. package/dist/chunk-TRLASNPQ.cjs +9 -0
  18. package/dist/chunk-YGSQ25UA.cjs +800 -0
  19. package/dist/device-agent/index.cjs +498 -0
  20. package/dist/device-agent/index.d.cts +157 -0
  21. package/dist/device-agent/index.d.ts +157 -0
  22. package/dist/device-agent/index.js +498 -0
  23. package/dist/engine-CCSSqPbZ.d.cts +516 -0
  24. package/dist/engine-CCSSqPbZ.d.ts +516 -0
  25. package/dist/index.cjs +339 -5569
  26. package/dist/index.d.cts +22 -1406
  27. package/dist/index.d.ts +22 -1406
  28. package/dist/index.js +269 -5401
  29. package/dist/match/index.cjs +2456 -0
  30. package/dist/match/index.d.cts +253 -0
  31. package/dist/match/index.d.ts +253 -0
  32. package/dist/match/index.js +2456 -0
  33. package/dist/match/remote/index.cjs +21 -0
  34. package/dist/match/remote/index.d.cts +67 -0
  35. package/dist/match/remote/index.d.ts +67 -0
  36. package/dist/match/remote/index.js +21 -0
  37. package/dist/match/voice/index.cjs +23 -0
  38. package/dist/match/voice/index.d.cts +114 -0
  39. package/dist/match/voice/index.d.ts +114 -0
  40. package/dist/match/voice/index.js +23 -0
  41. package/dist/plugin.cjs +53 -70
  42. package/dist/plugin.d.cts +13 -0
  43. package/dist/plugin.d.ts +13 -0
  44. package/dist/plugin.js +20 -15
  45. package/dist/types-CrmcX408.d.cts +176 -0
  46. package/dist/types-CrmcX408.d.ts +176 -0
  47. package/dist/types-DiKWjwvN.d.cts +96 -0
  48. package/dist/types-DiKWjwvN.d.ts +96 -0
  49. package/dist/version.cjs +4 -32
  50. package/dist/version.js +2 -1
  51. package/package.json +68 -4
  52. package/src/advanced.ts +47 -0
  53. package/src/device-agent/agent.ts +443 -0
  54. package/src/device-agent/component.tsx +49 -0
  55. package/src/device-agent/convex-control-channel.ts +82 -0
  56. package/src/device-agent/http-transport.ts +143 -0
  57. package/src/device-agent/index.ts +4 -0
  58. package/src/engine.ts +21 -5
  59. package/src/errors.ts +16 -0
  60. package/src/http-session-provider.ts +19 -13
  61. package/src/index.ts +38 -14
  62. package/src/livekit-room-adapter.ts +39 -2
  63. package/src/livestream-screen.tsx +26 -4
  64. package/src/match/index.ts +29 -0
  65. package/src/match/provider.tsx +4 -2
  66. package/src/match/remote/hid-gesture.ts +10 -2
  67. package/src/match/remote/types.ts +6 -4
  68. package/src/match/voice/scheduler.ts +6 -1
  69. package/src/match/voice/service.ts +16 -4
  70. package/src/native-runtime.ts +54 -4
  71. package/src/plugin.ts +35 -14
  72. package/src/provider.tsx +35 -4
  73. package/src/rtmp-room-adapter.ts +196 -0
  74. package/dist/chunk-VHLUJQG5.js +0 -17
@@ -0,0 +1,21 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+ var _chunkLCWGNGENcjs = require('../../chunk-LCWGNGEN.cjs');
11
+ require('../../chunk-7OX2DSKI.cjs');
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ exports.BTHOME_SERVICE_UUID = _chunkLCWGNGENcjs.BTHOME_SERVICE_UUID; exports.BTHomeRemoteDeduplicator = _chunkLCWGNGENcjs.BTHomeRemoteDeduplicator; exports.BTHomeRemoteParseError = _chunkLCWGNGENcjs.BTHomeRemoteParseError; exports.DEFAULT_REMOTE_ACTION_MAPPING = _chunkLCWGNGENcjs.DEFAULT_REMOTE_ACTION_MAPPING; exports.HidVolumeGestureRecognizer = _chunkLCWGNGENcjs.HidVolumeGestureRecognizer; exports.RemoteError = _chunkLCWGNGENcjs.RemoteError; exports.decodeBase64Bytes = _chunkLCWGNGENcjs.decodeBase64Bytes; exports.parseBTHomeV2Advertisement = _chunkLCWGNGENcjs.parseBTHomeV2Advertisement;
@@ -0,0 +1,67 @@
1
+ import { R as RemoteButtonAction, a as RemoteHidGestureMapping, b as RemoteHidGesture, c as RemoteHidVolumeEvent } from '../../types-DiKWjwvN.cjs';
2
+ export { B as BTHOME_SERVICE_UUID, D as DEFAULT_REMOTE_ACTION_MAPPING, d as RemoteActionMapping, e as RemoteBinding, f as RemoteCandidate, g as RemoteError, h as RemoteErrorCode, i as RemoteInputMode, j as RemoteMappedAction, k as RemoteNativeState, l as RemotePermissionStatus, m as RemoteScanAdvertisement, n as RemoteService, o as RemoteState, p as RemoteStatus } from '../../types-DiKWjwvN.cjs';
3
+
4
+ type BTHomeRemoteParseErrorCode = "wrong_uuid" | "unsupported_version" | "encrypted" | "truncated" | "unknown_object" | "invalid_button_event" | "no_button";
5
+ declare class BTHomeRemoteParseError extends Error {
6
+ readonly code: BTHomeRemoteParseErrorCode;
7
+ readonly name = "BTHomeRemoteParseError";
8
+ constructor(code: BTHomeRemoteParseErrorCode, message: string);
9
+ }
10
+ interface BTHomeAdvertisementInput {
11
+ readonly deviceId: string;
12
+ readonly serviceUuid: string;
13
+ /** FCD2 service data only. The first byte must be BTHome device-info, not UUID bytes. */
14
+ readonly serviceData: Uint8Array;
15
+ }
16
+ interface ParsedBTHomeRemoteAdvertisement {
17
+ readonly deviceId: string;
18
+ readonly version: 2;
19
+ readonly encrypted: false;
20
+ readonly triggerBased: boolean;
21
+ readonly packetId?: number;
22
+ readonly button: {
23
+ readonly action: RemoteButtonAction;
24
+ readonly objectIndex: number;
25
+ readonly rawEvent: number;
26
+ };
27
+ readonly fingerprint: string;
28
+ }
29
+ declare function parseBTHomeV2Advertisement(input: BTHomeAdvertisementInput): ParsedBTHomeRemoteAdvertisement;
30
+
31
+ interface RemoteDeduplicationKey {
32
+ readonly packetId?: number;
33
+ readonly fingerprint: string;
34
+ }
35
+ interface BTHomeRemoteDeduplicatorOptions {
36
+ readonly fingerprintWindowMs?: number;
37
+ }
38
+ declare class BTHomeRemoteDeduplicator {
39
+ private readonly devices;
40
+ private readonly fingerprintWindowMs;
41
+ constructor(options?: BTHomeRemoteDeduplicatorOptions);
42
+ get trackedDeviceCount(): number;
43
+ accept(deviceId: string, key: RemoteDeduplicationKey, now?: number): boolean;
44
+ forget(deviceId: string): void;
45
+ clear(): void;
46
+ }
47
+
48
+ declare function decodeBase64Bytes(value: string): Uint8Array;
49
+
50
+ interface HidVolumeGestureRecognizerOptions extends Pick<RemoteHidGestureMapping, "direction" | "settleMs" | "holdEventCount"> {
51
+ readonly onGesture: (gesture: RemoteHidGesture) => void;
52
+ }
53
+ declare class HidVolumeGestureRecognizer {
54
+ private readonly options;
55
+ private count;
56
+ private resolved;
57
+ private lastTimestamp;
58
+ private timer;
59
+ constructor(options: HidVolumeGestureRecognizerOptions);
60
+ push(event: RemoteHidVolumeEvent): void;
61
+ dispose(): void;
62
+ private finishBurst;
63
+ private clearTimer;
64
+ private reset;
65
+ }
66
+
67
+ export { type BTHomeAdvertisementInput, BTHomeRemoteDeduplicator, type BTHomeRemoteDeduplicatorOptions, BTHomeRemoteParseError, type BTHomeRemoteParseErrorCode, HidVolumeGestureRecognizer, type HidVolumeGestureRecognizerOptions, type ParsedBTHomeRemoteAdvertisement, RemoteButtonAction, type RemoteDeduplicationKey, RemoteHidGesture, RemoteHidGestureMapping, RemoteHidVolumeEvent, decodeBase64Bytes, parseBTHomeV2Advertisement };
@@ -0,0 +1,67 @@
1
+ import { R as RemoteButtonAction, a as RemoteHidGestureMapping, b as RemoteHidGesture, c as RemoteHidVolumeEvent } from '../../types-DiKWjwvN.js';
2
+ export { B as BTHOME_SERVICE_UUID, D as DEFAULT_REMOTE_ACTION_MAPPING, d as RemoteActionMapping, e as RemoteBinding, f as RemoteCandidate, g as RemoteError, h as RemoteErrorCode, i as RemoteInputMode, j as RemoteMappedAction, k as RemoteNativeState, l as RemotePermissionStatus, m as RemoteScanAdvertisement, n as RemoteService, o as RemoteState, p as RemoteStatus } from '../../types-DiKWjwvN.js';
3
+
4
+ type BTHomeRemoteParseErrorCode = "wrong_uuid" | "unsupported_version" | "encrypted" | "truncated" | "unknown_object" | "invalid_button_event" | "no_button";
5
+ declare class BTHomeRemoteParseError extends Error {
6
+ readonly code: BTHomeRemoteParseErrorCode;
7
+ readonly name = "BTHomeRemoteParseError";
8
+ constructor(code: BTHomeRemoteParseErrorCode, message: string);
9
+ }
10
+ interface BTHomeAdvertisementInput {
11
+ readonly deviceId: string;
12
+ readonly serviceUuid: string;
13
+ /** FCD2 service data only. The first byte must be BTHome device-info, not UUID bytes. */
14
+ readonly serviceData: Uint8Array;
15
+ }
16
+ interface ParsedBTHomeRemoteAdvertisement {
17
+ readonly deviceId: string;
18
+ readonly version: 2;
19
+ readonly encrypted: false;
20
+ readonly triggerBased: boolean;
21
+ readonly packetId?: number;
22
+ readonly button: {
23
+ readonly action: RemoteButtonAction;
24
+ readonly objectIndex: number;
25
+ readonly rawEvent: number;
26
+ };
27
+ readonly fingerprint: string;
28
+ }
29
+ declare function parseBTHomeV2Advertisement(input: BTHomeAdvertisementInput): ParsedBTHomeRemoteAdvertisement;
30
+
31
+ interface RemoteDeduplicationKey {
32
+ readonly packetId?: number;
33
+ readonly fingerprint: string;
34
+ }
35
+ interface BTHomeRemoteDeduplicatorOptions {
36
+ readonly fingerprintWindowMs?: number;
37
+ }
38
+ declare class BTHomeRemoteDeduplicator {
39
+ private readonly devices;
40
+ private readonly fingerprintWindowMs;
41
+ constructor(options?: BTHomeRemoteDeduplicatorOptions);
42
+ get trackedDeviceCount(): number;
43
+ accept(deviceId: string, key: RemoteDeduplicationKey, now?: number): boolean;
44
+ forget(deviceId: string): void;
45
+ clear(): void;
46
+ }
47
+
48
+ declare function decodeBase64Bytes(value: string): Uint8Array;
49
+
50
+ interface HidVolumeGestureRecognizerOptions extends Pick<RemoteHidGestureMapping, "direction" | "settleMs" | "holdEventCount"> {
51
+ readonly onGesture: (gesture: RemoteHidGesture) => void;
52
+ }
53
+ declare class HidVolumeGestureRecognizer {
54
+ private readonly options;
55
+ private count;
56
+ private resolved;
57
+ private lastTimestamp;
58
+ private timer;
59
+ constructor(options: HidVolumeGestureRecognizerOptions);
60
+ push(event: RemoteHidVolumeEvent): void;
61
+ dispose(): void;
62
+ private finishBurst;
63
+ private clearTimer;
64
+ private reset;
65
+ }
66
+
67
+ export { type BTHomeAdvertisementInput, BTHomeRemoteDeduplicator, type BTHomeRemoteDeduplicatorOptions, BTHomeRemoteParseError, type BTHomeRemoteParseErrorCode, HidVolumeGestureRecognizer, type HidVolumeGestureRecognizerOptions, type ParsedBTHomeRemoteAdvertisement, RemoteButtonAction, type RemoteDeduplicationKey, RemoteHidGesture, RemoteHidGestureMapping, RemoteHidVolumeEvent, decodeBase64Bytes, parseBTHomeV2Advertisement };
@@ -0,0 +1,21 @@
1
+ import {
2
+ BTHOME_SERVICE_UUID,
3
+ BTHomeRemoteDeduplicator,
4
+ BTHomeRemoteParseError,
5
+ DEFAULT_REMOTE_ACTION_MAPPING,
6
+ HidVolumeGestureRecognizer,
7
+ RemoteError,
8
+ decodeBase64Bytes,
9
+ parseBTHomeV2Advertisement
10
+ } from "../../chunk-2JHULJZ7.js";
11
+ import "../../chunk-KFQGP6VL.js";
12
+ export {
13
+ BTHOME_SERVICE_UUID,
14
+ BTHomeRemoteDeduplicator,
15
+ BTHomeRemoteParseError,
16
+ DEFAULT_REMOTE_ACTION_MAPPING,
17
+ HidVolumeGestureRecognizer,
18
+ RemoteError,
19
+ decodeBase64Bytes,
20
+ parseBTHomeV2Advertisement
21
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ var _chunkYGSQ25UAcjs = require('../../chunk-YGSQ25UA.cjs');
12
+ require('../../chunk-7OX2DSKI.cjs');
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+ exports.LatestAnnouncementScheduler = _chunkYGSQ25UAcjs.LatestAnnouncementScheduler; exports.VoiceError = _chunkYGSQ25UAcjs.VoiceError; exports.buildVietnameseAnnouncement = _chunkYGSQ25UAcjs.buildVietnameseAnnouncement; exports.createDefaultMatchVoiceService = _chunkYGSQ25UAcjs.createDefaultMatchVoiceService; exports.createExpoAudioPlayback = _chunkYGSQ25UAcjs.createExpoAudioPlayback; exports.createGeminiVoiceEngine = _chunkYGSQ25UAcjs.createGeminiVoiceEngine; exports.createUnavailableVoiceEngine = _chunkYGSQ25UAcjs.createUnavailableVoiceEngine; exports.planBundledFallback = _chunkYGSQ25UAcjs.planBundledFallback; exports.resolveBundledVoiceAsset = _chunkYGSQ25UAcjs.resolveBundledVoiceAsset;
@@ -0,0 +1,114 @@
1
+ import { M as MatchSnapshot, a as MatchEvent, A as AnnouncementPlan, N as NeuralVoiceEngine, b as AudioPlayback, V as VoiceAudioMode, c as VoiceRouteState, d as VoiceTtsOptions, e as MatchVoiceService } from '../../types-CrmcX408.cjs';
2
+ export { f as AnnouncementKind, F as FallbackVoiceToken, g as NeuralVoiceAvailability, h as VoiceAudioRoute, i as VoiceDisconnectReason, j as VoiceError, k as VoiceErrorCode } from '../../types-CrmcX408.cjs';
3
+
4
+ /** Pure phrase selection from the state before and after one committed event. */
5
+ declare function buildVietnameseAnnouncement(previous: MatchSnapshot, current: MatchSnapshot, event: MatchEvent): AnnouncementPlan;
6
+ declare function planBundledFallback(plan: AnnouncementPlan): readonly string[];
7
+
8
+ interface LatestAnnouncementSchedulerOptions {
9
+ readonly engine: NeuralVoiceEngine;
10
+ readonly audio: AudioPlayback;
11
+ readonly onError?: (error: Error) => void;
12
+ }
13
+ declare class LatestAnnouncementScheduler {
14
+ private readonly options;
15
+ private static readonly MAX_CACHE_ENTRIES;
16
+ private generation;
17
+ private activeController;
18
+ private lastPlan;
19
+ private readonly neuralCache;
20
+ private readonly operations;
21
+ private readonly prewarmControllers;
22
+ private lifecycle;
23
+ private disposePromise;
24
+ constructor(options: LatestAnnouncementSchedulerOptions);
25
+ prewarm(commonPhrases?: readonly string[]): Promise<void>;
26
+ enqueue(plan: AnnouncementPlan): Promise<void>;
27
+ private performEnqueue;
28
+ replayLast(): Promise<void>;
29
+ testSpeaker(): Promise<void>;
30
+ private performSpeakerTest;
31
+ dispose(): Promise<void>;
32
+ clearCache(): Promise<void>;
33
+ private cacheFile;
34
+ private touchCachedFile;
35
+ private track;
36
+ private report;
37
+ }
38
+
39
+ interface ExpoAudioPlayer {
40
+ play(): void;
41
+ pause(): void;
42
+ remove(): void;
43
+ addListener(event: "playbackStatusUpdate", listener: (status: {
44
+ readonly didJustFinish?: boolean;
45
+ readonly isLoaded?: boolean;
46
+ readonly isBuffering?: boolean;
47
+ readonly error?: unknown;
48
+ readonly playbackState?: string;
49
+ }) => void): {
50
+ remove(): void;
51
+ };
52
+ }
53
+ interface ExpoAudioBindings {
54
+ setAudioModeAsync(options: {
55
+ readonly allowsRecording: boolean;
56
+ readonly playsInSilentMode: boolean;
57
+ }): Promise<void>;
58
+ createAudioPlayer(source: unknown): ExpoAudioPlayer;
59
+ }
60
+ interface ExpoAudioPlaybackOptions {
61
+ readonly load?: () => ExpoAudioBindings;
62
+ readonly loadNativeAudio?: () => NativeAudioSessionBindings;
63
+ readonly resolveSource?: (source: string) => unknown;
64
+ readonly playbackTimeoutMs?: number;
65
+ }
66
+ interface NativeAudioSessionBindings {
67
+ captureAudioSessionState(): Promise<void>;
68
+ configureAudioSession(mode: VoiceAudioMode): Promise<VoiceRouteState>;
69
+ getAudioRouteState(): VoiceRouteState | Promise<VoiceRouteState>;
70
+ addListener(event: "onAudioRouteChanged", listener: (state: VoiceRouteState) => void): {
71
+ remove(): void;
72
+ };
73
+ disposeAudioSession(): Promise<void>;
74
+ }
75
+ declare function createExpoAudioPlayback(options?: ExpoAudioPlaybackOptions): AudioPlayback;
76
+
77
+ /** Minimal file operations the engine needs; defaults to expo-file-system. */
78
+ interface GeneratedAudioFileSystem {
79
+ writeFile(path: string, bytes: Uint8Array): Promise<void>;
80
+ removeFile(path: string): Promise<void>;
81
+ }
82
+ interface GeminiVoiceEngineOptions extends VoiceTtsOptions {
83
+ /** Directory that receives generated WAV files. */
84
+ readonly generatedRoot: string;
85
+ readonly fetch?: typeof globalThis.fetch;
86
+ readonly fileSystem?: GeneratedAudioFileSystem;
87
+ }
88
+ /**
89
+ * Cloud announcement voice: posts the phrase to the partner proxy, which calls
90
+ * Vertex AI Gemini TTS and returns a WAV body. Failures surface as VoiceError
91
+ * so the scheduler drops to the bundled WAV fallback.
92
+ */
93
+ declare function createGeminiVoiceEngine(options: GeminiVoiceEngineOptions): NeuralVoiceEngine;
94
+ /** Placeholder engine used when no TTS endpoint is configured: always falls back. */
95
+ declare function createUnavailableVoiceEngine(): NeuralVoiceEngine;
96
+
97
+ declare function resolveBundledVoiceAsset(source: string): string;
98
+
99
+ interface DefaultMatchVoiceServiceOptions {
100
+ /** Cloud TTS endpoint. Without it, announcements always use the bundled WAVs. */
101
+ readonly tts?: VoiceTtsOptions;
102
+ readonly audioMode?: VoiceAudioMode;
103
+ /** Exact cache directory for generated WAVs. Primarily useful for tests. */
104
+ readonly generatedRoot?: string;
105
+ /** Primarily useful for tests. Defaults to expo-file-system removal. */
106
+ readonly removeGeneratedDirectory?: (path: string) => Promise<void>;
107
+ /** Primarily useful for native integration tests. */
108
+ readonly audio?: AudioPlayback;
109
+ /** Primarily useful for native integration tests. */
110
+ readonly engine?: NeuralVoiceEngine;
111
+ }
112
+ declare function createDefaultMatchVoiceService(options?: DefaultMatchVoiceServiceOptions): MatchVoiceService;
113
+
114
+ export { AnnouncementPlan, AudioPlayback, type DefaultMatchVoiceServiceOptions, type ExpoAudioBindings, type ExpoAudioPlaybackOptions, type ExpoAudioPlayer, type GeminiVoiceEngineOptions, type GeneratedAudioFileSystem, LatestAnnouncementScheduler, type LatestAnnouncementSchedulerOptions, MatchVoiceService, type NativeAudioSessionBindings, NeuralVoiceEngine, VoiceAudioMode, VoiceRouteState, VoiceTtsOptions, buildVietnameseAnnouncement, createDefaultMatchVoiceService, createExpoAudioPlayback, createGeminiVoiceEngine, createUnavailableVoiceEngine, planBundledFallback, resolveBundledVoiceAsset };
@@ -0,0 +1,114 @@
1
+ import { M as MatchSnapshot, a as MatchEvent, A as AnnouncementPlan, N as NeuralVoiceEngine, b as AudioPlayback, V as VoiceAudioMode, c as VoiceRouteState, d as VoiceTtsOptions, e as MatchVoiceService } from '../../types-CrmcX408.js';
2
+ export { f as AnnouncementKind, F as FallbackVoiceToken, g as NeuralVoiceAvailability, h as VoiceAudioRoute, i as VoiceDisconnectReason, j as VoiceError, k as VoiceErrorCode } from '../../types-CrmcX408.js';
3
+
4
+ /** Pure phrase selection from the state before and after one committed event. */
5
+ declare function buildVietnameseAnnouncement(previous: MatchSnapshot, current: MatchSnapshot, event: MatchEvent): AnnouncementPlan;
6
+ declare function planBundledFallback(plan: AnnouncementPlan): readonly string[];
7
+
8
+ interface LatestAnnouncementSchedulerOptions {
9
+ readonly engine: NeuralVoiceEngine;
10
+ readonly audio: AudioPlayback;
11
+ readonly onError?: (error: Error) => void;
12
+ }
13
+ declare class LatestAnnouncementScheduler {
14
+ private readonly options;
15
+ private static readonly MAX_CACHE_ENTRIES;
16
+ private generation;
17
+ private activeController;
18
+ private lastPlan;
19
+ private readonly neuralCache;
20
+ private readonly operations;
21
+ private readonly prewarmControllers;
22
+ private lifecycle;
23
+ private disposePromise;
24
+ constructor(options: LatestAnnouncementSchedulerOptions);
25
+ prewarm(commonPhrases?: readonly string[]): Promise<void>;
26
+ enqueue(plan: AnnouncementPlan): Promise<void>;
27
+ private performEnqueue;
28
+ replayLast(): Promise<void>;
29
+ testSpeaker(): Promise<void>;
30
+ private performSpeakerTest;
31
+ dispose(): Promise<void>;
32
+ clearCache(): Promise<void>;
33
+ private cacheFile;
34
+ private touchCachedFile;
35
+ private track;
36
+ private report;
37
+ }
38
+
39
+ interface ExpoAudioPlayer {
40
+ play(): void;
41
+ pause(): void;
42
+ remove(): void;
43
+ addListener(event: "playbackStatusUpdate", listener: (status: {
44
+ readonly didJustFinish?: boolean;
45
+ readonly isLoaded?: boolean;
46
+ readonly isBuffering?: boolean;
47
+ readonly error?: unknown;
48
+ readonly playbackState?: string;
49
+ }) => void): {
50
+ remove(): void;
51
+ };
52
+ }
53
+ interface ExpoAudioBindings {
54
+ setAudioModeAsync(options: {
55
+ readonly allowsRecording: boolean;
56
+ readonly playsInSilentMode: boolean;
57
+ }): Promise<void>;
58
+ createAudioPlayer(source: unknown): ExpoAudioPlayer;
59
+ }
60
+ interface ExpoAudioPlaybackOptions {
61
+ readonly load?: () => ExpoAudioBindings;
62
+ readonly loadNativeAudio?: () => NativeAudioSessionBindings;
63
+ readonly resolveSource?: (source: string) => unknown;
64
+ readonly playbackTimeoutMs?: number;
65
+ }
66
+ interface NativeAudioSessionBindings {
67
+ captureAudioSessionState(): Promise<void>;
68
+ configureAudioSession(mode: VoiceAudioMode): Promise<VoiceRouteState>;
69
+ getAudioRouteState(): VoiceRouteState | Promise<VoiceRouteState>;
70
+ addListener(event: "onAudioRouteChanged", listener: (state: VoiceRouteState) => void): {
71
+ remove(): void;
72
+ };
73
+ disposeAudioSession(): Promise<void>;
74
+ }
75
+ declare function createExpoAudioPlayback(options?: ExpoAudioPlaybackOptions): AudioPlayback;
76
+
77
+ /** Minimal file operations the engine needs; defaults to expo-file-system. */
78
+ interface GeneratedAudioFileSystem {
79
+ writeFile(path: string, bytes: Uint8Array): Promise<void>;
80
+ removeFile(path: string): Promise<void>;
81
+ }
82
+ interface GeminiVoiceEngineOptions extends VoiceTtsOptions {
83
+ /** Directory that receives generated WAV files. */
84
+ readonly generatedRoot: string;
85
+ readonly fetch?: typeof globalThis.fetch;
86
+ readonly fileSystem?: GeneratedAudioFileSystem;
87
+ }
88
+ /**
89
+ * Cloud announcement voice: posts the phrase to the partner proxy, which calls
90
+ * Vertex AI Gemini TTS and returns a WAV body. Failures surface as VoiceError
91
+ * so the scheduler drops to the bundled WAV fallback.
92
+ */
93
+ declare function createGeminiVoiceEngine(options: GeminiVoiceEngineOptions): NeuralVoiceEngine;
94
+ /** Placeholder engine used when no TTS endpoint is configured: always falls back. */
95
+ declare function createUnavailableVoiceEngine(): NeuralVoiceEngine;
96
+
97
+ declare function resolveBundledVoiceAsset(source: string): string;
98
+
99
+ interface DefaultMatchVoiceServiceOptions {
100
+ /** Cloud TTS endpoint. Without it, announcements always use the bundled WAVs. */
101
+ readonly tts?: VoiceTtsOptions;
102
+ readonly audioMode?: VoiceAudioMode;
103
+ /** Exact cache directory for generated WAVs. Primarily useful for tests. */
104
+ readonly generatedRoot?: string;
105
+ /** Primarily useful for tests. Defaults to expo-file-system removal. */
106
+ readonly removeGeneratedDirectory?: (path: string) => Promise<void>;
107
+ /** Primarily useful for native integration tests. */
108
+ readonly audio?: AudioPlayback;
109
+ /** Primarily useful for native integration tests. */
110
+ readonly engine?: NeuralVoiceEngine;
111
+ }
112
+ declare function createDefaultMatchVoiceService(options?: DefaultMatchVoiceServiceOptions): MatchVoiceService;
113
+
114
+ export { AnnouncementPlan, AudioPlayback, type DefaultMatchVoiceServiceOptions, type ExpoAudioBindings, type ExpoAudioPlaybackOptions, type ExpoAudioPlayer, type GeminiVoiceEngineOptions, type GeneratedAudioFileSystem, LatestAnnouncementScheduler, type LatestAnnouncementSchedulerOptions, MatchVoiceService, type NativeAudioSessionBindings, NeuralVoiceEngine, VoiceAudioMode, VoiceRouteState, VoiceTtsOptions, buildVietnameseAnnouncement, createDefaultMatchVoiceService, createExpoAudioPlayback, createGeminiVoiceEngine, createUnavailableVoiceEngine, planBundledFallback, resolveBundledVoiceAsset };
@@ -0,0 +1,23 @@
1
+ import {
2
+ LatestAnnouncementScheduler,
3
+ VoiceError,
4
+ buildVietnameseAnnouncement,
5
+ createDefaultMatchVoiceService,
6
+ createExpoAudioPlayback,
7
+ createGeminiVoiceEngine,
8
+ createUnavailableVoiceEngine,
9
+ planBundledFallback,
10
+ resolveBundledVoiceAsset
11
+ } from "../../chunk-DHDX3ZOO.js";
12
+ import "../../chunk-KFQGP6VL.js";
13
+ export {
14
+ LatestAnnouncementScheduler,
15
+ VoiceError,
16
+ buildVietnameseAnnouncement,
17
+ createDefaultMatchVoiceService,
18
+ createExpoAudioPlayback,
19
+ createGeminiVoiceEngine,
20
+ createUnavailableVoiceEngine,
21
+ planBundledFallback,
22
+ resolveBundledVoiceAsset
23
+ };
package/dist/plugin.cjs CHANGED
@@ -1,53 +1,34 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+ var _chunkTRLASNPQcjs = require('./chunk-TRLASNPQ.cjs');
4
+ require('./chunk-7OX2DSKI.cjs');
19
5
 
20
6
  // src/plugin.ts
21
- var plugin_exports = {};
22
- __export(plugin_exports, {
23
- default: () => plugin_default,
24
- injectHidVolumeMainActivity: () => injectHidVolumeMainActivity
25
- });
26
- module.exports = __toCommonJS(plugin_exports);
27
- var import_config_plugins = require("expo/config-plugins");
28
- var import_promises = require("fs/promises");
29
- var import_node_path = require("path");
30
7
 
31
- // package.json
32
- var version = "0.1.1";
33
8
 
34
- // src/version.ts
35
- var PICKLEBALL_EXPO_SDK_VERSION = version;
36
9
 
37
- // src/plugin.ts
38
- var ANDROID_PERMISSIONS = [
10
+
11
+
12
+
13
+
14
+ var _configplugins = require('expo/config-plugins');
15
+ var _promises = require('fs/promises');
16
+ var _path = require('path');
17
+ var CORE_ANDROID_PERMISSIONS = [
39
18
  "android.permission.ACCESS_NETWORK_STATE",
40
- "android.permission.BLUETOOTH",
41
- "android.permission.BLUETOOTH_ADMIN",
42
- "android.permission.BLUETOOTH_SCAN",
43
- "android.permission.BLUETOOTH_CONNECT",
44
- "android.permission.ACCESS_FINE_LOCATION",
45
19
  "android.permission.CAMERA",
46
20
  "android.permission.INTERNET",
47
21
  "android.permission.MODIFY_AUDIO_SETTINGS",
48
22
  "android.permission.RECORD_AUDIO",
49
23
  "android.permission.WAKE_LOCK"
50
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
+ ];
51
32
  function injectHidVolumeMainActivity(source) {
52
33
  if (source.includes("PickleballRemoteHidDispatcher.dispatch(event)")) return source;
53
34
  if (!/class\s+MainActivity\s*:\s*ReactActivity\(\)\s*\{/.test(source)) {
@@ -69,8 +50,8 @@ function injectHidVolumeMainActivity(source) {
69
50
  ${updated.slice(closing)}`;
70
51
  }
71
52
  async function findMainActivity(directory) {
72
- for (const entry of await (0, import_promises.readdir)(directory, { withFileTypes: true })) {
73
- const path = (0, import_node_path.join)(directory, entry.name);
53
+ for (const entry of await _promises.readdir.call(void 0, directory, { withFileTypes: true })) {
54
+ const path = _path.join.call(void 0, directory, entry.name);
74
55
  if (entry.isDirectory()) {
75
56
  const found = await findMainActivity(path);
76
57
  if (found) return found;
@@ -79,25 +60,27 @@ async function findMainActivity(directory) {
79
60
  return null;
80
61
  }
81
62
  var withPickleballLive = (config, props = {}) => {
82
- const cameraPermission = props?.cameraPermission ?? "Allow $(PRODUCT_NAME) to use the camera for livestreaming.";
83
- const microphonePermission = props?.microphonePermission ?? "Allow $(PRODUCT_NAME) to use the microphone for livestreaming.";
84
- 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.";
85
- config = (0, import_config_plugins.withPlugins)(config, [
86
- ["@livekit/react-native-expo-plugin", props?.liveKit]
63
+ const cameraPermission = _nullishCoalesce(_optionalChain([props, 'optionalAccess', _ => _.cameraPermission]), () => ( "Allow $(PRODUCT_NAME) to use the camera for livestreaming."));
64
+ const microphonePermission = _nullishCoalesce(_optionalChain([props, 'optionalAccess', _2 => _2.microphonePermission]), () => ( "Allow $(PRODUCT_NAME) to use the microphone for livestreaming."));
65
+ const bluetoothPermission = _nullishCoalesce(_optionalChain([props, 'optionalAccess', _3 => _3.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 = _optionalChain([props, 'optionalAccess', _4 => _4.modules, 'optionalAccess', _5 => _5.remote]) !== false;
67
+ const androidPermissions = remoteEnabled ? [...CORE_ANDROID_PERMISSIONS, ...REMOTE_ANDROID_PERMISSIONS] : [...CORE_ANDROID_PERMISSIONS];
68
+ config = _configplugins.withPlugins.call(void 0, config, [
69
+ ["@livekit/react-native-expo-plugin", _optionalChain([props, 'optionalAccess', _6 => _6.liveKit])]
87
70
  ]);
88
71
  config.ios = { ...config.ios, bitcode: false };
89
- config = (0, import_config_plugins.withInfoPlist)(config, (mod) => {
72
+ config = _configplugins.withInfoPlist.call(void 0, config, (mod) => {
90
73
  mod.modResults.NSCameraUsageDescription = cameraPermission;
91
74
  mod.modResults.NSMicrophoneUsageDescription = microphonePermission;
92
- mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
75
+ if (remoteEnabled) {
76
+ mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
77
+ }
93
78
  return mod;
94
79
  });
95
- config = import_config_plugins.AndroidConfig.Permissions.withPermissions(config, [
96
- ...ANDROID_PERMISSIONS
97
- ]);
98
- config = (0, import_config_plugins.withAndroidManifest)(config, (mod) => {
80
+ config = _configplugins.AndroidConfig.Permissions.withPermissions(config, androidPermissions);
81
+ config = _configplugins.withAndroidManifest.call(void 0, config, (mod) => {
99
82
  const manifest = mod.modResults.manifest;
100
- const existing = manifest["uses-permission"] ?? [];
83
+ const existing = _nullishCoalesce(manifest["uses-permission"], () => ( []));
101
84
  const requiredAttributes = {
102
85
  "android.permission.BLUETOOTH": { "android:maxSdkVersion": "30" },
103
86
  "android.permission.BLUETOOTH_ADMIN": { "android:maxSdkVersion": "30" },
@@ -108,46 +91,46 @@ var withPickleballLive = (config, props = {}) => {
108
91
  };
109
92
  const byName = /* @__PURE__ */ new Map();
110
93
  for (const entry of existing) {
111
- const name = entry.$?.["android:name"];
94
+ const name = _optionalChain([entry, 'access', _7 => _7.$, 'optionalAccess', _8 => _8["android:name"]]);
112
95
  if (name && !byName.has(name)) byName.set(name, entry);
113
96
  }
114
- for (const permission of ANDROID_PERMISSIONS) {
115
- const entry = byName.get(permission) ?? { $: { "android:name": permission } };
97
+ for (const permission of androidPermissions) {
98
+ const entry = _nullishCoalesce(byName.get(permission), () => ( { $: { "android:name": permission } }));
116
99
  entry.$ = {
117
100
  "android:name": permission,
118
- ...requiredAttributes[permission] ?? {}
101
+ ..._nullishCoalesce(requiredAttributes[permission], () => ( {}))
119
102
  };
120
103
  byName.set(permission, entry);
121
104
  }
122
- const requiredNames = new Set(ANDROID_PERMISSIONS);
105
+ const requiredNames = new Set(androidPermissions);
123
106
  manifest["uses-permission"] = [
124
107
  ...existing.filter((entry) => {
125
- const name = entry.$?.["android:name"];
108
+ const name = _optionalChain([entry, 'access', _9 => _9.$, 'optionalAccess', _10 => _10["android:name"]]);
126
109
  return !name || !requiredNames.has(name);
127
110
  }),
128
- ...ANDROID_PERMISSIONS.map((name) => byName.get(name))
111
+ ...androidPermissions.map((name) => byName.get(name))
129
112
  ];
130
113
  return mod;
131
114
  });
132
- if (props?.consumeHidVolumeKeys !== false) {
133
- config = (0, import_config_plugins.withDangerousMod)(config, ["android", async (mod) => {
134
- const root = (0, import_node_path.join)(mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
115
+ if (remoteEnabled && _optionalChain([props, 'optionalAccess', _11 => _11.consumeHidVolumeKeys]) !== false) {
116
+ config = _configplugins.withDangerousMod.call(void 0, config, ["android", async (mod) => {
117
+ const root = _path.join.call(void 0, mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
135
118
  const path = await findMainActivity(root);
136
119
  if (!path) throw new Error("Generated Android MainActivity.kt was not found");
137
- const source = await (0, import_promises.readFile)(path, "utf8");
120
+ const source = await _promises.readFile.call(void 0, path, "utf8");
138
121
  const updated = injectHidVolumeMainActivity(source);
139
- if (updated !== source) await (0, import_promises.writeFile)(path, updated);
122
+ if (updated !== source) await _promises.writeFile.call(void 0, path, updated);
140
123
  return mod;
141
124
  }]);
142
125
  }
143
126
  return config;
144
127
  };
145
- var plugin_default = (0, import_config_plugins.createRunOncePlugin)(
128
+ var plugin_default = _configplugins.createRunOncePlugin.call(void 0,
146
129
  withPickleballLive,
147
130
  "@pickleball/expo-sdk",
148
- PICKLEBALL_EXPO_SDK_VERSION
131
+ _chunkTRLASNPQcjs.PICKLEBALL_EXPO_SDK_VERSION
149
132
  );
150
- // Annotate the CommonJS export names for ESM import in node:
151
- 0 && (module.exports = {
152
- injectHidVolumeMainActivity
153
- });
133
+
134
+
135
+
136
+ exports.default = plugin_default; exports.injectHidVolumeMainActivity = injectHidVolumeMainActivity;