@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.
Files changed (117) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +163 -40
  3. package/dist/advanced-DcbHBCGb.d.ts +300 -0
  4. package/dist/advanced-DeQwg7MK.d.cts +300 -0
  5. package/dist/advanced.cjs +47 -0
  6. package/dist/advanced.d.cts +3 -0
  7. package/dist/advanced.d.ts +3 -0
  8. package/dist/advanced.js +47 -0
  9. package/dist/camera-controls-By8tHigY.d.cts +97 -0
  10. package/dist/camera-controls-rCBUGGPC.d.ts +97 -0
  11. package/dist/chunk-2JHULJZ7.js +265 -0
  12. package/dist/chunk-62YV3PCD.cjs +139 -0
  13. package/dist/chunk-6F3HN6US.js +50 -0
  14. package/dist/chunk-6YE5BL3A.cjs +50 -0
  15. package/dist/chunk-7OX2DSKI.cjs +33 -0
  16. package/dist/chunk-7Z7TN5N3.js +318 -0
  17. package/dist/chunk-DHDX3ZOO.js +800 -0
  18. package/dist/chunk-GXQYMPHE.cjs +9 -0
  19. package/dist/chunk-IUIRVKJI.cjs +2290 -0
  20. package/dist/chunk-KFQGP6VL.js +33 -0
  21. package/dist/chunk-LCWGNGEN.cjs +265 -0
  22. package/dist/chunk-TBUEXRFQ.cjs +318 -0
  23. package/dist/chunk-XGP2MN5R.js +2290 -0
  24. package/dist/chunk-XL4CISVQ.js +9 -0
  25. package/dist/chunk-YGSQ25UA.cjs +800 -0
  26. package/dist/chunk-ZSKSXOCZ.js +139 -0
  27. package/dist/convex-command-subscription-Cabh9tND.d.ts +41 -0
  28. package/dist/convex-command-subscription-DUgpu75l.d.cts +41 -0
  29. package/dist/device-agent/index.cjs +1427 -0
  30. package/dist/device-agent/index.d.cts +493 -0
  31. package/dist/device-agent/index.d.ts +493 -0
  32. package/dist/device-agent/index.js +1427 -0
  33. package/dist/engine-BSvSdCSE.d.cts +741 -0
  34. package/dist/engine-BSvSdCSE.d.ts +741 -0
  35. package/dist/index.cjs +426 -6174
  36. package/dist/index.d.cts +299 -1400
  37. package/dist/index.d.ts +299 -1400
  38. package/dist/index.js +413 -6063
  39. package/dist/match/index.cjs +2456 -0
  40. package/dist/match/index.d.cts +253 -0
  41. package/dist/match/index.d.ts +253 -0
  42. package/dist/match/index.js +2456 -0
  43. package/dist/match/remote/index.cjs +21 -0
  44. package/dist/match/remote/index.d.cts +67 -0
  45. package/dist/match/remote/index.d.ts +67 -0
  46. package/dist/match/remote/index.js +21 -0
  47. package/dist/match/voice/index.cjs +23 -0
  48. package/dist/match/voice/index.d.cts +114 -0
  49. package/dist/match/voice/index.d.ts +114 -0
  50. package/dist/match/voice/index.js +23 -0
  51. package/dist/plugin.cjs +52 -71
  52. package/dist/plugin.d.cts +28 -1
  53. package/dist/plugin.d.ts +28 -1
  54. package/dist/plugin.js +26 -23
  55. package/dist/realtime/index.cjs +31 -0
  56. package/dist/realtime/index.d.cts +15 -0
  57. package/dist/realtime/index.d.ts +15 -0
  58. package/dist/realtime/index.js +31 -0
  59. package/dist/types-CrmcX408.d.cts +176 -0
  60. package/dist/types-CrmcX408.d.ts +176 -0
  61. package/dist/types-DiKWjwvN.d.cts +96 -0
  62. package/dist/types-DiKWjwvN.d.ts +96 -0
  63. package/dist/ui/index.cjs +1297 -0
  64. package/dist/ui/index.d.cts +493 -0
  65. package/dist/ui/index.d.ts +493 -0
  66. package/dist/ui/index.js +1297 -0
  67. package/dist/version.cjs +4 -32
  68. package/dist/version.js +2 -1
  69. package/package.json +95 -15
  70. package/src/advanced.ts +49 -0
  71. package/src/auto-resume.tsx +259 -0
  72. package/src/camera-controls.ts +99 -0
  73. package/src/camera-grant-provider.ts +392 -0
  74. package/src/camera-settings.ts +133 -0
  75. package/src/contracts.ts +73 -0
  76. package/src/device-agent/agent.ts +696 -0
  77. package/src/device-agent/beat-policy.ts +46 -0
  78. package/src/device-agent/component.tsx +60 -0
  79. package/src/device-agent/convex-beat-transport.ts +140 -0
  80. package/src/device-agent/convex-command-subscription.ts +101 -0
  81. package/src/device-agent/convex-control-channel.ts +88 -0
  82. package/src/device-agent/http-transport.ts +164 -0
  83. package/src/device-agent/index.ts +26 -0
  84. package/src/device-agent/mqtt-channel.ts +379 -0
  85. package/src/device-agent/mqtt-codec.ts +347 -0
  86. package/src/device-agent/tournament.ts +352 -0
  87. package/src/engine.ts +601 -20
  88. package/src/errors.ts +16 -0
  89. package/src/http-session-provider.ts +21 -183
  90. package/src/index.ts +117 -14
  91. package/src/local-video-quality.ts +43 -0
  92. package/src/match/index.ts +29 -0
  93. package/src/match/provider.tsx +4 -2
  94. package/src/match/remote/hid-gesture.ts +10 -2
  95. package/src/match/remote/types.ts +6 -4
  96. package/src/match/voice/scheduler.ts +6 -1
  97. package/src/match/voice/service.ts +16 -4
  98. package/src/native-runtime.ts +283 -77
  99. package/src/plugin.ts +54 -20
  100. package/src/provider.tsx +129 -22
  101. package/src/realtime/index.ts +56 -0
  102. package/src/resume-policy.ts +85 -0
  103. package/src/resume.ts +132 -0
  104. package/src/rtmp-room-adapter.ts +348 -0
  105. package/src/session-grant.ts +256 -0
  106. package/src/ui/camera-screen.tsx +484 -0
  107. package/src/ui/controls-sheet.tsx +445 -0
  108. package/src/ui/copy.ts +326 -0
  109. package/src/ui/helpers.ts +105 -0
  110. package/src/ui/hooks.ts +59 -0
  111. package/src/ui/index.ts +42 -0
  112. package/src/ui/preview-view.tsx +39 -0
  113. package/src/ui/primitives.tsx +304 -0
  114. package/src/uplink-check.ts +173 -0
  115. package/dist/chunk-VHLUJQG5.js +0 -17
  116. package/src/livekit-room-adapter.ts +0 -353
  117. package/src/livestream-screen.tsx +0 -980
@@ -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; }require('./chunk-7OX2DSKI.cjs');
19
2
 
20
3
  // 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
4
 
31
- // package.json
32
- var version = "0.1.1";
33
5
 
34
- // src/version.ts
35
- var PICKLEBALL_EXPO_SDK_VERSION = version;
36
6
 
37
- // src/plugin.ts
38
- var ANDROID_PERMISSIONS = [
7
+
8
+
9
+
10
+ var _configplugins = require('expo/config-plugins');
11
+ var _promises = require('fs/promises');
12
+ var _path = require('path');
13
+ var PLUGIN_SCHEMA_VERSION = "1";
14
+ var CORE_ANDROID_PERMISSIONS = [
39
15
  "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
16
  "android.permission.CAMERA",
17
+ "android.permission.FOREGROUND_SERVICE",
18
+ "android.permission.FOREGROUND_SERVICE_CAMERA",
19
+ "android.permission.FOREGROUND_SERVICE_MICROPHONE",
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,24 @@ 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]
87
- ]);
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];
88
68
  config.ios = { ...config.ios, bitcode: false };
89
- config = (0, import_config_plugins.withInfoPlist)(config, (mod) => {
69
+ config = _configplugins.withInfoPlist.call(void 0, config, (mod) => {
90
70
  mod.modResults.NSCameraUsageDescription = cameraPermission;
91
71
  mod.modResults.NSMicrophoneUsageDescription = microphonePermission;
92
- mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
72
+ if (remoteEnabled) {
73
+ mod.modResults.NSBluetoothAlwaysUsageDescription = bluetoothPermission;
74
+ }
93
75
  return mod;
94
76
  });
95
- config = import_config_plugins.AndroidConfig.Permissions.withPermissions(config, [
96
- ...ANDROID_PERMISSIONS
97
- ]);
98
- config = (0, import_config_plugins.withAndroidManifest)(config, (mod) => {
77
+ config = _configplugins.AndroidConfig.Permissions.withPermissions(config, androidPermissions);
78
+ config = _configplugins.withAndroidManifest.call(void 0, config, (mod) => {
99
79
  const manifest = mod.modResults.manifest;
100
- const existing = manifest["uses-permission"] ?? [];
80
+ const existing = _nullishCoalesce(manifest["uses-permission"], () => ( []));
101
81
  const requiredAttributes = {
102
82
  "android.permission.BLUETOOTH": { "android:maxSdkVersion": "30" },
103
83
  "android.permission.BLUETOOTH_ADMIN": { "android:maxSdkVersion": "30" },
@@ -108,46 +88,47 @@ var withPickleballLive = (config, props = {}) => {
108
88
  };
109
89
  const byName = /* @__PURE__ */ new Map();
110
90
  for (const entry of existing) {
111
- const name = entry.$?.["android:name"];
91
+ const name = _optionalChain([entry, 'access', _6 => _6.$, 'optionalAccess', _7 => _7["android:name"]]);
112
92
  if (name && !byName.has(name)) byName.set(name, entry);
113
93
  }
114
- for (const permission of ANDROID_PERMISSIONS) {
115
- const entry = byName.get(permission) ?? { $: { "android:name": permission } };
94
+ for (const permission of androidPermissions) {
95
+ const entry = _nullishCoalesce(byName.get(permission), () => ( { $: { "android:name": permission } }));
116
96
  entry.$ = {
117
97
  "android:name": permission,
118
- ...requiredAttributes[permission] ?? {}
98
+ ..._nullishCoalesce(requiredAttributes[permission], () => ( {}))
119
99
  };
120
100
  byName.set(permission, entry);
121
101
  }
122
- const requiredNames = new Set(ANDROID_PERMISSIONS);
102
+ const requiredNames = new Set(androidPermissions);
123
103
  manifest["uses-permission"] = [
124
104
  ...existing.filter((entry) => {
125
- const name = entry.$?.["android:name"];
105
+ const name = _optionalChain([entry, 'access', _8 => _8.$, 'optionalAccess', _9 => _9["android:name"]]);
126
106
  return !name || !requiredNames.has(name);
127
107
  }),
128
- ...ANDROID_PERMISSIONS.map((name) => byName.get(name))
108
+ ...androidPermissions.map((name) => byName.get(name))
129
109
  ];
130
110
  return mod;
131
111
  });
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");
112
+ if (remoteEnabled && _optionalChain([props, 'optionalAccess', _10 => _10.consumeHidVolumeKeys]) !== false) {
113
+ config = _configplugins.withDangerousMod.call(void 0, config, ["android", async (mod) => {
114
+ const root = _path.join.call(void 0, mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
135
115
  const path = await findMainActivity(root);
136
116
  if (!path) throw new Error("Generated Android MainActivity.kt was not found");
137
- const source = await (0, import_promises.readFile)(path, "utf8");
117
+ const source = await _promises.readFile.call(void 0, path, "utf8");
138
118
  const updated = injectHidVolumeMainActivity(source);
139
- if (updated !== source) await (0, import_promises.writeFile)(path, updated);
119
+ if (updated !== source) await _promises.writeFile.call(void 0, path, updated);
140
120
  return mod;
141
121
  }]);
142
122
  }
143
123
  return config;
144
124
  };
145
- var plugin_default = (0, import_config_plugins.createRunOncePlugin)(
125
+ var plugin_default = _configplugins.createRunOncePlugin.call(void 0,
146
126
  withPickleballLive,
147
127
  "@pickleball/expo-sdk",
148
- PICKLEBALL_EXPO_SDK_VERSION
128
+ PLUGIN_SCHEMA_VERSION
149
129
  );
150
- // Annotate the CommonJS export names for ESM import in node:
151
- 0 && (module.exports = {
152
- injectHidVolumeMainActivity
153
- });
130
+
131
+
132
+
133
+
134
+ exports.PLUGIN_SCHEMA_VERSION = PLUGIN_SCHEMA_VERSION; exports.default = plugin_default; exports.injectHidVolumeMainActivity = injectHidVolumeMainActivity;