@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,316 @@
1
+ import { j as RoomAdapter, C as CameraDeviceInfo, V as RoomConnection, W as RoomEvent, a as CaptureOrientation, X as EngineDependencies, p as SdkNetwork, r as SdkRuntime, u as SdkStorage, T as TelemetrySink, Q as LivestreamEngine, B as BootstrapInput, g as LivestreamSnapshot, S as StartLivestreamInput, c as EndReason, L as LivestreamSessionProvider, i as PickleballExpoError } from './engine-CCSSqPbZ.cjs';
2
+ import React, { ReactNode } from 'react';
3
+
4
+ interface LocalTrackLike {
5
+ kind: string;
6
+ stop(): void;
7
+ mute?(): Promise<unknown>;
8
+ unmute?(): Promise<unknown>;
9
+ /** livekit-client LocalVideoTrack restart; deterministic facing switch. */
10
+ restartTrack?(options: {
11
+ facingMode?: "user" | "environment";
12
+ deviceId?: string;
13
+ resolution?: {
14
+ width: number;
15
+ height: number;
16
+ frameRate: number;
17
+ };
18
+ }): Promise<unknown>;
19
+ mediaStreamTrack?: {
20
+ readyState?: string;
21
+ /**
22
+ * react-native-webrtc: đổi thiết bị/facing TẠI CHỖ trên cùng track native
23
+ * (mediaStreamTrackApplyConstraints) — preview và sender giữ nguyên.
24
+ */
25
+ applyConstraints?(constraints: {
26
+ facingMode?: "user" | "environment";
27
+ deviceId?: string;
28
+ width?: number;
29
+ height?: number;
30
+ frameRate?: number;
31
+ }): Promise<void>;
32
+ /** react-native-webrtc native camera flip; blind front/back toggle. */
33
+ _switchCamera?(): void;
34
+ };
35
+ }
36
+ interface RoomLike {
37
+ state: string;
38
+ localParticipant: {
39
+ publishTrack(track: LocalTrackLike, options?: unknown): Promise<unknown>;
40
+ unpublishTrack?(track: LocalTrackLike, stopOnUnpublish?: boolean): Promise<unknown> | unknown;
41
+ };
42
+ connect(serverUrl: string, token: string, options?: unknown): Promise<void>;
43
+ disconnect(stopTracks?: boolean): Promise<void>;
44
+ on(event: string, listener: (...args: unknown[]) => void): unknown;
45
+ off(event: string, listener: (...args: unknown[]) => void): unknown;
46
+ }
47
+ interface NativeLiveKitBindings {
48
+ registerGlobals(): void;
49
+ createRoom(): RoomLike;
50
+ createLocalTracks(options: {
51
+ audio: true;
52
+ video: {
53
+ facingMode?: "user" | "environment";
54
+ deviceId?: string;
55
+ resolution: {
56
+ width: number;
57
+ height: number;
58
+ frameRate: number;
59
+ };
60
+ };
61
+ }): Promise<LocalTrackLike[]>;
62
+ startAudioSession(): Promise<void> | void;
63
+ stopAudioSession(): Promise<void> | void;
64
+ /** Current window orientation; capture dimensions follow it. */
65
+ isLandscape?(): boolean;
66
+ /** Physical/virtual cameras reported by the platform. */
67
+ listCameras?(): Promise<CameraDeviceInfo[]>;
68
+ cameraSource?: unknown;
69
+ events: {
70
+ reconnecting: string;
71
+ reconnected: string;
72
+ disconnected: string;
73
+ mediaDevicesError: string;
74
+ /** LiveKit RoomEvent.DataReceived — nhận lệnh điều khiển từ dashboard. */
75
+ dataReceived?: string;
76
+ };
77
+ }
78
+ interface LocalPreviewReference {
79
+ videoTrack: unknown;
80
+ trackRef?: {
81
+ participant: RoomLike["localParticipant"];
82
+ publication: unknown;
83
+ source?: unknown;
84
+ };
85
+ }
86
+ declare class LiveKitRoomAdapter implements RoomAdapter {
87
+ private readonly bindings;
88
+ private readonly room;
89
+ private readonly listeners;
90
+ private tracks;
91
+ private videoTrack?;
92
+ private audioTrack?;
93
+ private preview?;
94
+ private isFront;
95
+ private orientationOverride;
96
+ private deviceOverride;
97
+ private published;
98
+ private disposed;
99
+ private quality;
100
+ private readonly nativeListeners;
101
+ constructor(bindings: NativeLiveKitBindings);
102
+ preparePreview(quality: 720 | 1080): Promise<LocalPreviewReference | undefined>;
103
+ connect(input: RoomConnection): Promise<void>;
104
+ /** Bật/tắt publish track khi đã trong phòng — standby ↔ live. */
105
+ setPublishing(enabled: boolean): Promise<void>;
106
+ disconnect(stopTracks?: boolean): Promise<void>;
107
+ private captureResolution;
108
+ /**
109
+ * Tùy chọn publish video. Mặc định của livekit-client (VP8, không encoding,
110
+ * không degradation preference) khiến uplink yếu bóp bitrate xuống ~600kbps
111
+ * mà VẪN giữ 1080 @ ~10fps → khối bể nát, tệ hơn 720p sạch.
112
+ *
113
+ * - videoCodec H.264: HW-encode trên Android, hiệu quả hơn VP8 ở bitrate thấp,
114
+ * trùng preset egress (H264_*) nên bỏ được 1 lần transcode phía egress.
115
+ * - simulcast tắt: viewer chỉ xem HLS do egress xuất; egress subscribe đúng
116
+ * 1 lớp đã publish, nên simulcast chỉ thêm tải/bất ổn encoder (H.264 simulcast
117
+ * kém tin cậy trên Android) mà không lợi gì cho người xem ở kiến trúc này.
118
+ * - maintain-framerate: pickleball chuyển động nhanh; khi uplink không gánh nổi
119
+ * mức đích thì HẠ ĐỘ PHÂN GIẢI (giữ nét-trên-điểm-ảnh) thay vì đóng băng fps.
120
+ * - maxBitrate: trần theo mức chất lượng; BWE vẫn tự hạ dưới trần khi mạng yếu.
121
+ */
122
+ private videoPublishOptions;
123
+ setCaptureOrientation(orientation: "portrait" | "landscape"): Promise<void>;
124
+ /**
125
+ * livekit-client restart() chỉ giữ deviceId/facingMode khi gọi getUserMedia
126
+ * (vứt width/height/frameRate) nên track mới rơi về format mặc định
127
+ * 640x480. Native applyConstraints thì ngược lại: chỉ xử lý
128
+ * width/height/frameRate. Sau mỗi restartTrack phải nắn lại format trên
129
+ * track mới bằng applyConstraints.
130
+ */
131
+ private reapplyCaptureFormat;
132
+ switchCamera(): Promise<void>;
133
+ listCameras(): Promise<CameraDeviceInfo[]>;
134
+ selectCamera(deviceId: string, facing: CameraDeviceInfo["facing"]): Promise<void>;
135
+ setMicrophoneEnabled(enabled: boolean): Promise<void>;
136
+ subscribe(listener: (event: RoomEvent) => void): () => boolean;
137
+ dispose(): Promise<void>;
138
+ private releaseTracks;
139
+ private ensurePreparedTracks;
140
+ private emit;
141
+ private ensureNotDisposed;
142
+ }
143
+
144
+ /**
145
+ * Trạng thái từ tầng RTMP native (trùng NativeRtmpStatus của @pickleball/rtmp-native).
146
+ */
147
+ type RtmpStatus = {
148
+ readonly status: "idle" | "connecting" | "connected" | "publishing";
149
+ } | {
150
+ readonly status: "disconnected";
151
+ readonly reason?: string;
152
+ } | {
153
+ readonly status: "error";
154
+ readonly code: string;
155
+ readonly message: string;
156
+ };
157
+ /**
158
+ * Dấu hiệu để UI biết render nguồn nào. LiveKit trả về một track object; RTMP
159
+ * không có "track" ở JS (khung hình đi thẳng trong native), nên trả marker này
160
+ * — nếu trả undefined thì UI tưởng chưa có preview và vẽ màn TỐI ĐEN.
161
+ */
162
+ interface RtmpPreviewMarker {
163
+ readonly kind: "rtmp";
164
+ }
165
+ /** Bề mặt native mà adapter cần — tiêm vào để test được không cần thiết bị thật. */
166
+ interface NativeRtmpBindings {
167
+ prepare(options: {
168
+ quality: 720 | 1080;
169
+ landscape: boolean;
170
+ }): Promise<void>;
171
+ /** Hướng cầm máy hiện tại — cùng nguồn mà LiveKitRoomAdapter dùng. */
172
+ isLandscape?(): boolean;
173
+ connect(options: {
174
+ url: string;
175
+ videoBitrate: number;
176
+ publish: boolean;
177
+ }): Promise<void>;
178
+ setPublishing(enabled: boolean): Promise<void>;
179
+ disconnect(): Promise<void>;
180
+ switchCamera(): Promise<void>;
181
+ listCameras(): Array<{
182
+ deviceId: string;
183
+ label: string;
184
+ facing: string;
185
+ }>;
186
+ selectCamera(deviceId: string, facing: string): Promise<void>;
187
+ setMicrophoneEnabled(enabled: boolean): Promise<void>;
188
+ setVideoBitrate(bitsPerSecond: number): Promise<void>;
189
+ dispose(): Promise<void>;
190
+ addStatusListener(listener: (event: RtmpStatus) => void): {
191
+ remove(): void;
192
+ };
193
+ }
194
+ /**
195
+ * Adapter cho mode deliveryMode="device-rtmp".
196
+ *
197
+ * Thiết bị mã hoá H.264 bằng phần cứng MỘT lần rồi đẩy thẳng RTMP; server chỉ
198
+ * remux sang HLS. Không có phòng LiveKit, không egress → $0 transcode.
199
+ *
200
+ * Khác LiveKitRoomAdapter ở một điểm quan trọng: RTMP **không có kênh dữ liệu**,
201
+ * nên adapter này không bao giờ phát RoomEvent "command". Lệnh điều khiển từ
202
+ * dashboard đi đường khác (deviceControl trên Convex) — xem device-agent.
203
+ */
204
+ declare class RtmpRoomAdapter implements RoomAdapter {
205
+ private readonly bindings;
206
+ private readonly listeners;
207
+ private nativeSubscription?;
208
+ private quality;
209
+ private connected;
210
+ constructor(bindings: NativeRtmpBindings);
211
+ preparePreview(quality: 720 | 1080): Promise<RtmpPreviewMarker>;
212
+ connect(input: RoomConnection): Promise<void>;
213
+ setPublishing(enabled: boolean): Promise<void>;
214
+ disconnect(_stopTracks?: boolean): Promise<void>;
215
+ switchCamera(): Promise<void>;
216
+ /** Ống kính vật lý (0.5x siêu rộng · 1x · tele) — không có thì UI kẹt ở mặc định. */
217
+ listCameras(): Promise<CameraDeviceInfo[]>;
218
+ selectCamera(deviceId: string, facing: CameraDeviceInfo["facing"]): Promise<void>;
219
+ setMicrophoneEnabled(enabled: boolean): Promise<void>;
220
+ /** Hạ chất lượng khi mạng yếu — thay cho BWE mà WebRTC cho sẵn. */
221
+ setVideoBitrate(bitsPerSecond: number): Promise<void>;
222
+ setCaptureOrientation(_orientation: CaptureOrientation): Promise<void>;
223
+ subscribe(listener: (event: RoomEvent) => void): () => void;
224
+ dispose(): Promise<void>;
225
+ private emit;
226
+ }
227
+
228
+ declare function createNativeLiveKitBindings(): NativeLiveKitBindings;
229
+ declare function createDefaultRuntime(): SdkRuntime;
230
+ declare function createDefaultStorage(): SdkStorage;
231
+ declare function createDefaultNetwork(): SdkNetwork;
232
+ declare function createDefaultTelemetry(fetchImplementation?: typeof fetch, timeoutMs?: number): TelemetrySink;
233
+ declare function createDefaultRoomFactory(): EngineDependencies["roomFactory"];
234
+ /**
235
+ * Bindings cho mode device-rtmp. `require` động giống LiveKit ở trên: app nào
236
+ * không cài @pickleball/rtmp-native thì chỉ lỗi khi thật sự chọn mode này,
237
+ * không gãy lúc import SDK.
238
+ */
239
+ declare function createNativeRtmpBindings(): NativeRtmpBindings;
240
+ /** roomFactory cho mode device-rtmp (thiết bị đẩy RTMP, không dùng LiveKit). */
241
+ declare function createRtmpRoomFactory(): EngineDependencies["roomFactory"];
242
+ /**
243
+ * Thu chỉ số thiết bị cho heartbeat. Mỗi nguồn là optional — thiếu package
244
+ * (expo-battery/expo-device/expo-file-system) thì bỏ qua trường đó thay vì lỗi.
245
+ */
246
+ declare function createDefaultDeviceMetrics(): NonNullable<EngineDependencies["deviceMetrics"]>;
247
+
248
+ interface LivestreamTheme {
249
+ background: string;
250
+ foreground: string;
251
+ accent: string;
252
+ danger: string;
253
+ /** Chữ phụ mờ nhất (labels, chú thích). */
254
+ muted: string;
255
+ overlay: string;
256
+ radius: number;
257
+ /** Token FintechX — đồng bộ với dashboard web. */
258
+ surface: string;
259
+ elevated: string;
260
+ hairline: string;
261
+ /** Màu chữ đặt trên nền accent. */
262
+ ink: string;
263
+ textSecondary: string;
264
+ radiusSm: number;
265
+ fontFamily?: string;
266
+ fontFamilyBold?: string;
267
+ displayFontFamily?: string;
268
+ }
269
+ /** FintechX design tokens — trùng bộ token trong apps/web/globals.css. */
270
+ declare const defaultLivestreamTheme: LivestreamTheme;
271
+ interface PickleballLiveProviderProps {
272
+ children?: ReactNode;
273
+ sessionProvider: LivestreamSessionProvider;
274
+ bootstrapInput: BootstrapInput;
275
+ runtime?: SdkRuntime;
276
+ storage?: SdkStorage;
277
+ network?: SdkNetwork;
278
+ telemetry?: TelemetrySink;
279
+ roomFactory?: () => RoomAdapter;
280
+ deviceMetrics?: EngineDependencies["deviceMetrics"];
281
+ theme?: Partial<LivestreamTheme>;
282
+ locale?: "vi" | "en";
283
+ onError?: (error: PickleballExpoError) => void;
284
+ }
285
+ /**
286
+ * Context nội bộ cho các module opt-in (VD PickleballDeviceAgent) cần truy cập
287
+ * engine trực tiếp — export qua "./advanced", không thuộc API tích hợp cơ bản.
288
+ */
289
+ interface LivestreamHostContextValue {
290
+ engine: LivestreamEngine;
291
+ bootstrapInput: BootstrapInput;
292
+ deviceMetrics: NonNullable<EngineDependencies["deviceMetrics"]>;
293
+ }
294
+ declare function useLivestreamHost(): LivestreamHostContextValue;
295
+ interface LivestreamContextValue extends LivestreamSnapshot {
296
+ locale: "vi" | "en";
297
+ theme: LivestreamTheme;
298
+ prepare(): Promise<void>;
299
+ start(input: StartLivestreamInput, options?: {
300
+ autoPublish?: boolean;
301
+ }): Promise<void>;
302
+ /** Bắt đầu phát khi đang standby. */
303
+ startPublishing(): Promise<void>;
304
+ /** Tạm dừng phát về standby (không kết thúc phiên). */
305
+ stopPublishing(): Promise<void>;
306
+ stop(reason?: EndReason): Promise<void>;
307
+ retry(): Promise<void>;
308
+ switchCamera(): Promise<void>;
309
+ setMicrophoneEnabled(enabled: boolean): Promise<void>;
310
+ setCaptureOrientation(orientation: "portrait" | "landscape"): Promise<void>;
311
+ selectCamera(deviceId: string): Promise<void>;
312
+ }
313
+ declare function PickleballLiveProvider(props: PickleballLiveProviderProps): React.JSX.Element;
314
+ declare function useLivestream(): LivestreamContextValue;
315
+
316
+ export { type LivestreamContextValue as L, type NativeLiveKitBindings as N, PickleballLiveProvider as P, RtmpRoomAdapter as R, type LivestreamTheme as a, type PickleballLiveProviderProps as b, createDefaultStorage as c, defaultLivestreamTheme as d, LiveKitRoomAdapter as e, type LivestreamHostContextValue as f, type LocalPreviewReference as g, type NativeRtmpBindings as h, type RtmpStatus as i, createDefaultDeviceMetrics as j, createDefaultNetwork as k, createDefaultRoomFactory as l, createDefaultRuntime as m, createDefaultTelemetry as n, createNativeLiveKitBindings as o, createNativeRtmpBindings as p, createRtmpRoomFactory as q, useLivestreamHost as r, useLivestream as u };
@@ -0,0 +1,35 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+ var _chunkTBPR2QNDcjs = require('./chunk-TBPR2QND.cjs');
18
+ require('./chunk-7OX2DSKI.cjs');
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+ exports.LEGAL_LIVESTREAM_TRANSITIONS = _chunkTBPR2QNDcjs.LEGAL_LIVESTREAM_TRANSITIONS; exports.LiveKitRoomAdapter = _chunkTBPR2QNDcjs.LiveKitRoomAdapter; exports.LivestreamEngine = _chunkTBPR2QNDcjs.LivestreamEngine; exports.PENDING_END_KEY = _chunkTBPR2QNDcjs.PENDING_END_KEY; exports.RtmpRoomAdapter = _chunkTBPR2QNDcjs.RtmpRoomAdapter; exports.createDefaultDeviceMetrics = _chunkTBPR2QNDcjs.createDefaultDeviceMetrics; exports.createDefaultNetwork = _chunkTBPR2QNDcjs.createDefaultNetwork; exports.createDefaultRoomFactory = _chunkTBPR2QNDcjs.createDefaultRoomFactory; exports.createDefaultRuntime = _chunkTBPR2QNDcjs.createDefaultRuntime; exports.createDefaultStorage = _chunkTBPR2QNDcjs.createDefaultStorage; exports.createDefaultTelemetry = _chunkTBPR2QNDcjs.createDefaultTelemetry; exports.createNativeLiveKitBindings = _chunkTBPR2QNDcjs.createNativeLiveKitBindings; exports.createNativeRtmpBindings = _chunkTBPR2QNDcjs.createNativeRtmpBindings; exports.createRtmpRoomFactory = _chunkTBPR2QNDcjs.createRtmpRoomFactory; exports.useLivestreamHost = _chunkTBPR2QNDcjs.useLivestreamHost;
@@ -0,0 +1,3 @@
1
+ export { C as CameraDeviceInfo, a as CaptureOrientation, D as DeviceMetricsSample, X as EngineDependencies, Y as LEGAL_LIVESTREAM_TRANSITIONS, Q as LivestreamEngine, g as LivestreamSnapshot, Z as PENDING_END_KEY, j as RoomAdapter, V as RoomConnection, W as RoomEvent, p as SdkNetwork, r as SdkRuntime, u as SdkStorage, T as TelemetrySink } from './engine-CCSSqPbZ.cjs';
2
+ export { e as LiveKitRoomAdapter, f as LivestreamHostContextValue, g as LocalPreviewReference, N as NativeLiveKitBindings, h as NativeRtmpBindings, R as RtmpRoomAdapter, i as RtmpStatus, j as createDefaultDeviceMetrics, k as createDefaultNetwork, l as createDefaultRoomFactory, m as createDefaultRuntime, c as createDefaultStorage, n as createDefaultTelemetry, o as createNativeLiveKitBindings, p as createNativeRtmpBindings, q as createRtmpRoomFactory, r as useLivestreamHost } from './advanced-BdAa2Erv.cjs';
3
+ import 'react';
@@ -0,0 +1,3 @@
1
+ export { C as CameraDeviceInfo, a as CaptureOrientation, D as DeviceMetricsSample, X as EngineDependencies, Y as LEGAL_LIVESTREAM_TRANSITIONS, Q as LivestreamEngine, g as LivestreamSnapshot, Z as PENDING_END_KEY, j as RoomAdapter, V as RoomConnection, W as RoomEvent, p as SdkNetwork, r as SdkRuntime, u as SdkStorage, T as TelemetrySink } from './engine-CCSSqPbZ.js';
2
+ export { e as LiveKitRoomAdapter, f as LivestreamHostContextValue, g as LocalPreviewReference, N as NativeLiveKitBindings, h as NativeRtmpBindings, R as RtmpRoomAdapter, i as RtmpStatus, j as createDefaultDeviceMetrics, k as createDefaultNetwork, l as createDefaultRoomFactory, m as createDefaultRuntime, c as createDefaultStorage, n as createDefaultTelemetry, o as createNativeLiveKitBindings, p as createNativeRtmpBindings, q as createRtmpRoomFactory, r as useLivestreamHost } from './advanced-BXDrDl1h.js';
3
+ import 'react';
@@ -0,0 +1,35 @@
1
+ import {
2
+ LEGAL_LIVESTREAM_TRANSITIONS,
3
+ LiveKitRoomAdapter,
4
+ LivestreamEngine,
5
+ PENDING_END_KEY,
6
+ RtmpRoomAdapter,
7
+ createDefaultDeviceMetrics,
8
+ createDefaultNetwork,
9
+ createDefaultRoomFactory,
10
+ createDefaultRuntime,
11
+ createDefaultStorage,
12
+ createDefaultTelemetry,
13
+ createNativeLiveKitBindings,
14
+ createNativeRtmpBindings,
15
+ createRtmpRoomFactory,
16
+ useLivestreamHost
17
+ } from "./chunk-FODE2W2H.js";
18
+ import "./chunk-KFQGP6VL.js";
19
+ export {
20
+ LEGAL_LIVESTREAM_TRANSITIONS,
21
+ LiveKitRoomAdapter,
22
+ LivestreamEngine,
23
+ PENDING_END_KEY,
24
+ RtmpRoomAdapter,
25
+ createDefaultDeviceMetrics,
26
+ createDefaultNetwork,
27
+ createDefaultRoomFactory,
28
+ createDefaultRuntime,
29
+ createDefaultStorage,
30
+ createDefaultTelemetry,
31
+ createNativeLiveKitBindings,
32
+ createNativeRtmpBindings,
33
+ createRtmpRoomFactory,
34
+ useLivestreamHost
35
+ };
@@ -0,0 +1,265 @@
1
+ // src/match/remote/deduplicator.ts
2
+ var BTHomeRemoteDeduplicator = class {
3
+ devices = /* @__PURE__ */ new Map();
4
+ fingerprintWindowMs;
5
+ constructor(options = {}) {
6
+ this.fingerprintWindowMs = options.fingerprintWindowMs ?? 300;
7
+ }
8
+ get trackedDeviceCount() {
9
+ return this.devices.size;
10
+ }
11
+ accept(deviceId, key, now = Date.now()) {
12
+ const previous = this.devices.get(deviceId);
13
+ if (key.packetId !== void 0) {
14
+ if (previous?.packetId === key.packetId) return false;
15
+ this.devices.set(deviceId, { packetId: key.packetId });
16
+ return true;
17
+ }
18
+ if (previous?.fingerprint === key.fingerprint && previous.fingerprintSeenAt !== void 0 && now - previous.fingerprintSeenAt <= this.fingerprintWindowMs) {
19
+ return false;
20
+ }
21
+ this.devices.set(deviceId, { fingerprint: key.fingerprint, fingerprintSeenAt: now });
22
+ return true;
23
+ }
24
+ forget(deviceId) {
25
+ this.devices.delete(deviceId);
26
+ }
27
+ clear() {
28
+ this.devices.clear();
29
+ }
30
+ };
31
+
32
+ // src/match/remote/encoding.ts
33
+ function decodeBase64Bytes(value) {
34
+ if (typeof globalThis.atob !== "function") {
35
+ throw new Error("Base64 decoding is unavailable in this runtime");
36
+ }
37
+ const binary = globalThis.atob(value);
38
+ const bytes = new Uint8Array(binary.length);
39
+ for (let index = 0; index < binary.length; index += 1) {
40
+ bytes[index] = binary.charCodeAt(index);
41
+ }
42
+ return bytes;
43
+ }
44
+
45
+ // src/match/remote/hid-gesture.ts
46
+ var HidVolumeGestureRecognizer = class {
47
+ constructor(options) {
48
+ this.options = options;
49
+ }
50
+ count = 0;
51
+ resolved = false;
52
+ lastTimestamp = null;
53
+ timer = null;
54
+ push(event) {
55
+ if (this.options.direction !== "any" && event.direction !== this.options.direction) return;
56
+ if (this.lastTimestamp !== null && event.timestamp - this.lastTimestamp > this.options.settleMs) {
57
+ this.finishBurst();
58
+ }
59
+ this.lastTimestamp = event.timestamp;
60
+ this.clearTimer();
61
+ if (!this.resolved) {
62
+ this.count += 1;
63
+ if (event.longPress || this.count >= this.options.holdEventCount) {
64
+ this.resolved = true;
65
+ this.options.onGesture("hold");
66
+ }
67
+ }
68
+ this.timer = setTimeout(() => this.finishBurst(), this.options.settleMs);
69
+ }
70
+ dispose() {
71
+ this.clearTimer();
72
+ this.reset();
73
+ }
74
+ finishBurst() {
75
+ this.clearTimer();
76
+ if (!this.resolved && this.count > 0) {
77
+ this.options.onGesture(
78
+ this.count === 1 ? "single" : this.count === 2 ? "double" : this.count === 3 ? "triple" : "quadruple"
79
+ );
80
+ }
81
+ this.reset();
82
+ }
83
+ clearTimer() {
84
+ if (this.timer) clearTimeout(this.timer);
85
+ this.timer = null;
86
+ }
87
+ reset() {
88
+ this.count = 0;
89
+ this.resolved = false;
90
+ this.lastTimestamp = null;
91
+ }
92
+ };
93
+
94
+ // src/match/remote/types.ts
95
+ var BTHOME_SERVICE_UUID = "FCD2";
96
+ var DEFAULT_REMOTE_ACTION_MAPPING = {
97
+ volumeUp: "left",
98
+ volumeDown: "right",
99
+ longPress: "undo"
100
+ };
101
+ var RemoteError = class extends Error {
102
+ constructor(code, message, options) {
103
+ super(message, options);
104
+ this.code = code;
105
+ }
106
+ name = "RemoteError";
107
+ };
108
+
109
+ // src/match/remote/parser.ts
110
+ var BTHomeRemoteParseError = class extends Error {
111
+ constructor(code, message) {
112
+ super(message);
113
+ this.code = code;
114
+ }
115
+ name = "BTHomeRemoteParseError";
116
+ };
117
+ var OBJECT_LENGTHS = Object.freeze({
118
+ 0: 1,
119
+ 1: 1,
120
+ 2: 2,
121
+ 3: 2,
122
+ 4: 3,
123
+ 5: 3,
124
+ 6: 2,
125
+ 7: 2,
126
+ 8: 2,
127
+ 9: 1,
128
+ 10: 3,
129
+ 11: 3,
130
+ 12: 2,
131
+ 13: 2,
132
+ 14: 2,
133
+ 15: 1,
134
+ 16: 1,
135
+ 17: 1,
136
+ 18: 2,
137
+ 19: 2,
138
+ 20: 2,
139
+ 21: 1,
140
+ 22: 1,
141
+ 23: 1,
142
+ 24: 1,
143
+ 25: 1,
144
+ 26: 1,
145
+ 27: 1,
146
+ 28: 1,
147
+ 29: 1,
148
+ 30: 1,
149
+ 31: 1,
150
+ 32: 1,
151
+ 33: 1,
152
+ 34: 1,
153
+ 35: 1,
154
+ 36: 1,
155
+ 37: 1,
156
+ 38: 1,
157
+ 39: 1,
158
+ 40: 1,
159
+ 41: 1,
160
+ 42: 1,
161
+ 43: 1,
162
+ 44: 1,
163
+ 45: 1,
164
+ 46: 1,
165
+ 47: 1,
166
+ 58: 1,
167
+ 60: 2,
168
+ 61: 2,
169
+ 62: 4,
170
+ 63: 2,
171
+ 64: 1,
172
+ 65: 1,
173
+ 66: 1,
174
+ 67: 1,
175
+ 68: 2,
176
+ 69: 2,
177
+ 70: 4,
178
+ 71: 4,
179
+ 72: 4,
180
+ 73: 2,
181
+ 74: 2,
182
+ 75: 2,
183
+ 76: 4,
184
+ 77: 4,
185
+ 78: 4,
186
+ 79: 4
187
+ });
188
+ function isBTHomeUuid(uuid) {
189
+ const normalized = uuid.toLowerCase().replaceAll("-", "");
190
+ return normalized === "fcd2" || normalized === "0000fcd200001000800000805f9b34fb";
191
+ }
192
+ function fingerprint(bytes) {
193
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
194
+ }
195
+ function mapButtonEvent(value) {
196
+ if (value === 1) return "single";
197
+ if (value === 2) return "double";
198
+ if (value === 4 || value === 128) return "long";
199
+ if (value === 0 || value === 3 || value === 5 || value === 6) return null;
200
+ return void 0;
201
+ }
202
+ function parseBTHomeV2Advertisement(input) {
203
+ if (!isBTHomeUuid(input.serviceUuid)) {
204
+ throw new BTHomeRemoteParseError("wrong_uuid", `Expected ${BTHOME_SERVICE_UUID} service data`);
205
+ }
206
+ if (input.serviceData.length < 1) {
207
+ throw new BTHomeRemoteParseError("truncated", "BTHome device-info byte is missing");
208
+ }
209
+ const info = input.serviceData[0];
210
+ const version = info >> 5 & 7;
211
+ if (version !== 2) {
212
+ throw new BTHomeRemoteParseError("unsupported_version", `Unsupported BTHome version ${version}`);
213
+ }
214
+ if ((info & 1) !== 0) {
215
+ throw new BTHomeRemoteParseError("encrypted", "Encrypted BTHome advertisements are unsupported");
216
+ }
217
+ let offset = 1;
218
+ let objectIndex = 0;
219
+ let packetId;
220
+ let button;
221
+ while (offset < input.serviceData.length) {
222
+ const objectId = input.serviceData[offset++];
223
+ const length = OBJECT_LENGTHS[objectId];
224
+ if (length === void 0) {
225
+ throw new BTHomeRemoteParseError("unknown_object", `Unknown BTHome object 0x${objectId.toString(16)}`);
226
+ }
227
+ if (offset + length > input.serviceData.length) {
228
+ throw new BTHomeRemoteParseError("truncated", `BTHome object 0x${objectId.toString(16)} is truncated`);
229
+ }
230
+ if (objectId === 0 && packetId === void 0) packetId = input.serviceData[offset];
231
+ if (objectId === 58 && !button) {
232
+ const rawEvent = input.serviceData[offset];
233
+ const action = mapButtonEvent(rawEvent);
234
+ if (action === void 0) {
235
+ throw new BTHomeRemoteParseError("invalid_button_event", `Reserved button event 0x${rawEvent.toString(16)}`);
236
+ }
237
+ if (action) button = { action, objectIndex, rawEvent };
238
+ }
239
+ offset += length;
240
+ objectIndex += 1;
241
+ }
242
+ if (!button) {
243
+ throw new BTHomeRemoteParseError("no_button", "No actionable BTHome button event was found");
244
+ }
245
+ return {
246
+ deviceId: input.deviceId,
247
+ version: 2,
248
+ encrypted: false,
249
+ triggerBased: (info & 4) !== 0,
250
+ packetId,
251
+ button,
252
+ fingerprint: fingerprint(input.serviceData)
253
+ };
254
+ }
255
+
256
+ export {
257
+ BTHomeRemoteDeduplicator,
258
+ decodeBase64Bytes,
259
+ HidVolumeGestureRecognizer,
260
+ BTHOME_SERVICE_UUID,
261
+ DEFAULT_REMOTE_ACTION_MAPPING,
262
+ RemoteError,
263
+ BTHomeRemoteParseError,
264
+ parseBTHomeV2Advertisement
265
+ };
@@ -0,0 +1,9 @@
1
+ // package.json
2
+ var version = "0.2.0";
3
+
4
+ // src/version.ts
5
+ var PICKLEBALL_EXPO_SDK_VERSION = version;
6
+
7
+ export {
8
+ PICKLEBALL_EXPO_SDK_VERSION
9
+ };