@pickleball/expo-sdk 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/app.plugin.js +6 -0
- package/dist/chunk-VHLUJQG5.js +17 -0
- package/dist/index.cjs +6284 -0
- package/dist/index.d.cts +1436 -0
- package/dist/index.d.ts +1436 -0
- package/dist/index.js +6186 -0
- package/dist/plugin.cjs +153 -0
- package/dist/plugin.d.cts +21 -0
- package/dist/plugin.d.ts +21 -0
- package/dist/plugin.js +131 -0
- package/dist/version.cjs +35 -0
- package/dist/version.d.cts +4 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +6 -0
- package/package.json +126 -0
- package/src/contracts.ts +211 -0
- package/src/engine.ts +1332 -0
- package/src/errors.ts +128 -0
- package/src/http-session-provider.ts +259 -0
- package/src/index.ts +16 -0
- package/src/livekit-room-adapter.ts +353 -0
- package/src/livestream-screen.tsx +980 -0
- package/src/match/contracts.ts +137 -0
- package/src/match/engine.ts +702 -0
- package/src/match/persistence/default-store.native.ts +20 -0
- package/src/match/persistence/default-store.ts +11 -0
- package/src/match/persistence/index.ts +6 -0
- package/src/match/persistence/memory-driver.ts +255 -0
- package/src/match/persistence/migrations.ts +40 -0
- package/src/match/persistence/sqlite-driver.ts +348 -0
- package/src/match/persistence/store.ts +497 -0
- package/src/match/persistence/types.ts +98 -0
- package/src/match/provider.tsx +728 -0
- package/src/match/remote/deduplicator.ts +54 -0
- package/src/match/remote/encoding.ts +12 -0
- package/src/match/remote/hid-gesture.ts +61 -0
- package/src/match/remote/index.ts +5 -0
- package/src/match/remote/native-service.ts +62 -0
- package/src/match/remote/parser.ts +134 -0
- package/src/match/remote/types.ts +116 -0
- package/src/match/replay.ts +102 -0
- package/src/match/state.ts +72 -0
- package/src/match/validation.ts +375 -0
- package/src/match/voice/assets/court-left.wav +0 -0
- package/src/match/voice/assets/court-right.wav +0 -0
- package/src/match/voice/assets/court-switch.wav +0 -0
- package/src/match/voice/assets/game-point.wav +0 -0
- package/src/match/voice/assets/game-won.wav +0 -0
- package/src/match/voice/assets/match-won.wav +0 -0
- package/src/match/voice/assets/number-0.wav +0 -0
- package/src/match/voice/assets/number-1.wav +0 -0
- package/src/match/voice/assets/number-10.wav +0 -0
- package/src/match/voice/assets/number-11.wav +0 -0
- package/src/match/voice/assets/number-12.wav +0 -0
- package/src/match/voice/assets/number-13.wav +0 -0
- package/src/match/voice/assets/number-14.wav +0 -0
- package/src/match/voice/assets/number-15.wav +0 -0
- package/src/match/voice/assets/number-16.wav +0 -0
- package/src/match/voice/assets/number-17.wav +0 -0
- package/src/match/voice/assets/number-18.wav +0 -0
- package/src/match/voice/assets/number-19.wav +0 -0
- package/src/match/voice/assets/number-2.wav +0 -0
- package/src/match/voice/assets/number-20.wav +0 -0
- package/src/match/voice/assets/number-3.wav +0 -0
- package/src/match/voice/assets/number-30.wav +0 -0
- package/src/match/voice/assets/number-4.wav +0 -0
- package/src/match/voice/assets/number-40.wav +0 -0
- package/src/match/voice/assets/number-5.wav +0 -0
- package/src/match/voice/assets/number-50.wav +0 -0
- package/src/match/voice/assets/number-6.wav +0 -0
- package/src/match/voice/assets/number-60.wav +0 -0
- package/src/match/voice/assets/number-7.wav +0 -0
- package/src/match/voice/assets/number-70.wav +0 -0
- package/src/match/voice/assets/number-8.wav +0 -0
- package/src/match/voice/assets/number-80.wav +0 -0
- package/src/match/voice/assets/number-9.wav +0 -0
- package/src/match/voice/assets/number-90.wav +0 -0
- package/src/match/voice/assets/number-lam.wav +0 -0
- package/src/match/voice/assets/number-mot.wav +0 -0
- package/src/match/voice/assets/score-deu-0.wav +0 -0
- package/src/match/voice/assets/score-deu-1.wav +0 -0
- package/src/match/voice/assets/score-deu-10.wav +0 -0
- package/src/match/voice/assets/score-deu-11.wav +0 -0
- package/src/match/voice/assets/score-deu-12.wav +0 -0
- package/src/match/voice/assets/score-deu-13.wav +0 -0
- package/src/match/voice/assets/score-deu-14.wav +0 -0
- package/src/match/voice/assets/score-deu-15.wav +0 -0
- package/src/match/voice/assets/score-deu-16.wav +0 -0
- package/src/match/voice/assets/score-deu-17.wav +0 -0
- package/src/match/voice/assets/score-deu-18.wav +0 -0
- package/src/match/voice/assets/score-deu-19.wav +0 -0
- package/src/match/voice/assets/score-deu-2.wav +0 -0
- package/src/match/voice/assets/score-deu-20.wav +0 -0
- package/src/match/voice/assets/score-deu-3.wav +0 -0
- package/src/match/voice/assets/score-deu-30.wav +0 -0
- package/src/match/voice/assets/score-deu-4.wav +0 -0
- package/src/match/voice/assets/score-deu-40.wav +0 -0
- package/src/match/voice/assets/score-deu-5.wav +0 -0
- package/src/match/voice/assets/score-deu-50.wav +0 -0
- package/src/match/voice/assets/score-deu-6.wav +0 -0
- package/src/match/voice/assets/score-deu-60.wav +0 -0
- package/src/match/voice/assets/score-deu-7.wav +0 -0
- package/src/match/voice/assets/score-deu-70.wav +0 -0
- package/src/match/voice/assets/score-deu-8.wav +0 -0
- package/src/match/voice/assets/score-deu-80.wav +0 -0
- package/src/match/voice/assets/score-deu-9.wav +0 -0
- package/src/match/voice/assets/score-deu-90.wav +0 -0
- package/src/match/voice/assets/score-deu-lam.wav +0 -0
- package/src/match/voice/assets/score-deu-mot.wav +0 -0
- package/src/match/voice/assets/server-1.wav +0 -0
- package/src/match/voice/assets/server-2.wav +0 -0
- package/src/match/voice/assets/service-change.wav +0 -0
- package/src/match/voice/assets/test-speaker.wav +0 -0
- package/src/match/voice/audio.ts +231 -0
- package/src/match/voice/bundled-assets.native.ts +47 -0
- package/src/match/voice/bundled-assets.ts +3 -0
- package/src/match/voice/gemini-engine.ts +167 -0
- package/src/match/voice/index.ts +7 -0
- package/src/match/voice/phrases.ts +185 -0
- package/src/match/voice/scheduler.ts +205 -0
- package/src/match/voice/service.ts +147 -0
- package/src/match/voice/types.ts +118 -0
- package/src/native-runtime.ts +241 -0
- package/src/plugin.ts +145 -0
- package/src/provider.tsx +176 -0
- package/src/version.ts +4 -0
package/src/contracts.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
export type LivestreamState =
|
|
2
|
+
| "idle"
|
|
3
|
+
| "preparing"
|
|
4
|
+
| "preview"
|
|
5
|
+
| "connecting"
|
|
6
|
+
/** Đã vào phòng, chưa phát — chờ lệnh phát từ app hoặc dashboard. */
|
|
7
|
+
| "standby"
|
|
8
|
+
| "live"
|
|
9
|
+
| "reconnecting"
|
|
10
|
+
| "ending"
|
|
11
|
+
| "ended"
|
|
12
|
+
| "error";
|
|
13
|
+
|
|
14
|
+
export type SdkErrorCode =
|
|
15
|
+
| "PERMISSION_DENIED"
|
|
16
|
+
| "NETWORK_UNAVAILABLE"
|
|
17
|
+
| "TOKEN_EXPIRED"
|
|
18
|
+
| "SDK_UPGRADE_REQUIRED"
|
|
19
|
+
| "SESSION_CONFLICT"
|
|
20
|
+
| "RECORDING_FAILED"
|
|
21
|
+
| "CONSENT_REQUIRED"
|
|
22
|
+
| "SDK_DISABLED"
|
|
23
|
+
| "UNKNOWN";
|
|
24
|
+
|
|
25
|
+
export interface SdkError {
|
|
26
|
+
code: SdkErrorCode;
|
|
27
|
+
message: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface BootstrapInput {
|
|
31
|
+
sdkVersion: string;
|
|
32
|
+
platform: "ios" | "android";
|
|
33
|
+
bundleId: string;
|
|
34
|
+
installationId: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SdkRemoteConfig {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
protocolVersion: 1;
|
|
40
|
+
minSdkVersion: string;
|
|
41
|
+
recommendedSdkVersion: string;
|
|
42
|
+
videoQuality: 720 | 1080;
|
|
43
|
+
reconnectTimeoutMs: number;
|
|
44
|
+
backgroundGraceMs: number;
|
|
45
|
+
telemetryIntervalMs: number;
|
|
46
|
+
maxSessionDurationMs: number;
|
|
47
|
+
/** Tự kết thúc phiên nếu ngồi standby quá lâu không phát (mặc định 15 phút). */
|
|
48
|
+
standbyTimeoutMs?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SdkBootstrap {
|
|
52
|
+
config: SdkRemoteConfig;
|
|
53
|
+
serverTime: number;
|
|
54
|
+
rolloutEnabled: boolean;
|
|
55
|
+
message?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface StartLivestreamInput {
|
|
59
|
+
externalSessionId: string;
|
|
60
|
+
title: string;
|
|
61
|
+
visibility?: "public" | "private";
|
|
62
|
+
consentVersion: string;
|
|
63
|
+
metadata?: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* true: vào phòng ở chế độ chờ (không publish) — server giữ status
|
|
66
|
+
* "scheduled" và KHÔNG khởi động recording egress cho tới khi publish.
|
|
67
|
+
* Engine tự đặt cờ này theo options.autoPublish; app không cần truyền.
|
|
68
|
+
*/
|
|
69
|
+
standby?: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface SdkTelemetryCredentials {
|
|
73
|
+
endpoint: string;
|
|
74
|
+
token: string;
|
|
75
|
+
expiresAt: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface SdkSessionGrant {
|
|
79
|
+
sessionId: string;
|
|
80
|
+
serverUrl: string;
|
|
81
|
+
participantToken: string;
|
|
82
|
+
playbackUrl: string | null;
|
|
83
|
+
tokenExpiresAt: number;
|
|
84
|
+
telemetry: SdkTelemetryCredentials;
|
|
85
|
+
config: SdkRemoteConfig;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SdkSessionRefresh {
|
|
89
|
+
participantToken?: string;
|
|
90
|
+
tokenExpiresAt?: number;
|
|
91
|
+
telemetry?: SdkTelemetryCredentials;
|
|
92
|
+
config: SdkRemoteConfig;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface EndLivestreamInput {
|
|
96
|
+
sessionId: string;
|
|
97
|
+
reason:
|
|
98
|
+
| "user"
|
|
99
|
+
| "background_timeout"
|
|
100
|
+
| "network_timeout"
|
|
101
|
+
| "standby_timeout"
|
|
102
|
+
| "error";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type EndReason = EndLivestreamInput["reason"];
|
|
106
|
+
|
|
107
|
+
export const SDK_TELEMETRY_EVENT_NAMES = [
|
|
108
|
+
"state_changed",
|
|
109
|
+
"connection_quality",
|
|
110
|
+
"reconnect",
|
|
111
|
+
"error",
|
|
112
|
+
"heartbeat",
|
|
113
|
+
"session_ended",
|
|
114
|
+
] as const;
|
|
115
|
+
|
|
116
|
+
export type SdkTelemetryEventName =
|
|
117
|
+
(typeof SDK_TELEMETRY_EVENT_NAMES)[number];
|
|
118
|
+
|
|
119
|
+
export interface SdkTelemetryEvent {
|
|
120
|
+
sessionId: string;
|
|
121
|
+
at: number;
|
|
122
|
+
name: SdkTelemetryEventName;
|
|
123
|
+
data?: Record<string, unknown>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface LivestreamSessionProvider {
|
|
127
|
+
bootstrap(input: BootstrapInput): Promise<SdkBootstrap>;
|
|
128
|
+
start(input: StartLivestreamInput): Promise<SdkSessionGrant>;
|
|
129
|
+
refresh(sessionId: string): Promise<SdkSessionRefresh>;
|
|
130
|
+
end(input: EndLivestreamInput): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Báo server bắt đầu phát thật (standby → live): server bật recording
|
|
133
|
+
* egress + chuyển status live TRƯỚC khi engine publish track. Optional để
|
|
134
|
+
* giữ tương thích provider cũ — thiếu thì engine bỏ qua bước server.
|
|
135
|
+
*/
|
|
136
|
+
publish?(sessionId: string): Promise<void>;
|
|
137
|
+
/** Báo server tạm dừng phát (live → standby): dừng egress, status về chờ. */
|
|
138
|
+
unpublish?(sessionId: string): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
142
|
+
|
|
143
|
+
const CONFIG_DURATION_LIMITS = {
|
|
144
|
+
reconnectTimeoutMs: 10 * 60_000,
|
|
145
|
+
backgroundGraceMs: 10 * 60_000,
|
|
146
|
+
telemetryIntervalMs: 60 * 60_000,
|
|
147
|
+
maxSessionDurationMs: 24 * 60 * 60_000,
|
|
148
|
+
} as const;
|
|
149
|
+
|
|
150
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
151
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function isPositiveDuration(value: unknown, maximum: number) {
|
|
155
|
+
return (
|
|
156
|
+
typeof value === "number" &&
|
|
157
|
+
Number.isFinite(value) &&
|
|
158
|
+
value > 0 &&
|
|
159
|
+
value <= maximum
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function isSdkRemoteConfig(value: unknown): value is SdkRemoteConfig {
|
|
164
|
+
return (
|
|
165
|
+
isRecord(value) &&
|
|
166
|
+
typeof value.enabled === "boolean" &&
|
|
167
|
+
value.protocolVersion === 1 &&
|
|
168
|
+
typeof value.minSdkVersion === "string" &&
|
|
169
|
+
SEMVER.test(value.minSdkVersion) &&
|
|
170
|
+
typeof value.recommendedSdkVersion === "string" &&
|
|
171
|
+
SEMVER.test(value.recommendedSdkVersion) &&
|
|
172
|
+
(value.videoQuality === 720 || value.videoQuality === 1080) &&
|
|
173
|
+
isPositiveDuration(
|
|
174
|
+
value.reconnectTimeoutMs,
|
|
175
|
+
CONFIG_DURATION_LIMITS.reconnectTimeoutMs,
|
|
176
|
+
) &&
|
|
177
|
+
isPositiveDuration(
|
|
178
|
+
value.backgroundGraceMs,
|
|
179
|
+
CONFIG_DURATION_LIMITS.backgroundGraceMs,
|
|
180
|
+
) &&
|
|
181
|
+
isPositiveDuration(
|
|
182
|
+
value.telemetryIntervalMs,
|
|
183
|
+
CONFIG_DURATION_LIMITS.telemetryIntervalMs,
|
|
184
|
+
) &&
|
|
185
|
+
isPositiveDuration(
|
|
186
|
+
value.maxSessionDurationMs,
|
|
187
|
+
CONFIG_DURATION_LIMITS.maxSessionDurationMs,
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function compareSemver(left: string, right: string): -1 | 0 | 1 {
|
|
193
|
+
const a = SEMVER.exec(left);
|
|
194
|
+
const b = SEMVER.exec(right);
|
|
195
|
+
if (!a || !b) throw new TypeError("Invalid semantic version");
|
|
196
|
+
for (let index = 1; index < 4; index += 1) {
|
|
197
|
+
const av = BigInt(a[index]);
|
|
198
|
+
const bv = BigInt(b[index]);
|
|
199
|
+
if (av < bv) return -1;
|
|
200
|
+
if (av > bv) return 1;
|
|
201
|
+
}
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function isSdkVersionSupported(version: string, minimum: string) {
|
|
206
|
+
try {
|
|
207
|
+
return compareSemver(version, minimum) >= 0;
|
|
208
|
+
} catch {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|