@pickleball/expo-sdk 0.2.0 → 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.
- package/CHANGELOG.md +41 -0
- package/README.md +155 -101
- package/dist/advanced-DcbHBCGb.d.ts +300 -0
- package/dist/advanced-DeQwg7MK.d.cts +300 -0
- package/dist/advanced.cjs +14 -2
- package/dist/advanced.d.cts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/advanced.js +17 -5
- package/dist/camera-controls-By8tHigY.d.cts +97 -0
- package/dist/camera-controls-rCBUGGPC.d.ts +97 -0
- package/dist/chunk-62YV3PCD.cjs +139 -0
- package/dist/chunk-6F3HN6US.js +50 -0
- package/dist/chunk-6YE5BL3A.cjs +50 -0
- package/dist/chunk-7Z7TN5N3.js +318 -0
- package/dist/{chunk-TRLASNPQ.cjs → chunk-GXQYMPHE.cjs} +1 -1
- package/dist/{chunk-TBPR2QND.cjs → chunk-IUIRVKJI.cjs} +736 -399
- package/dist/chunk-TBUEXRFQ.cjs +318 -0
- package/dist/{chunk-FODE2W2H.js → chunk-XGP2MN5R.js} +688 -351
- package/dist/{chunk-6JOMESNT.js → chunk-XL4CISVQ.js} +1 -1
- package/dist/chunk-ZSKSXOCZ.js +139 -0
- package/dist/convex-command-subscription-Cabh9tND.d.ts +41 -0
- package/dist/convex-command-subscription-DUgpu75l.d.cts +41 -0
- package/dist/device-agent/index.cjs +973 -44
- package/dist/device-agent/index.d.cts +339 -3
- package/dist/device-agent/index.d.ts +339 -3
- package/dist/device-agent/index.js +940 -11
- package/dist/{engine-CCSSqPbZ.d.cts → engine-BSvSdCSE.d.cts} +227 -2
- package/dist/{engine-CCSSqPbZ.d.ts → engine-BSvSdCSE.d.ts} +227 -2
- package/dist/index.cjs +419 -937
- package/dist/index.d.cts +315 -32
- package/dist/index.d.ts +315 -32
- package/dist/index.js +423 -941
- package/dist/plugin.cjs +11 -13
- package/dist/plugin.d.cts +15 -1
- package/dist/plugin.d.ts +15 -1
- package/dist/plugin.js +7 -9
- package/dist/realtime/index.cjs +31 -0
- package/dist/realtime/index.d.cts +15 -0
- package/dist/realtime/index.d.ts +15 -0
- package/dist/realtime/index.js +31 -0
- package/dist/ui/index.cjs +1297 -0
- package/dist/ui/index.d.cts +493 -0
- package/dist/ui/index.d.ts +493 -0
- package/dist/ui/index.js +1297 -0
- package/dist/version.cjs +2 -2
- package/dist/version.js +1 -1
- package/package.json +31 -15
- package/src/advanced.ts +11 -9
- package/src/auto-resume.tsx +259 -0
- package/src/camera-controls.ts +99 -0
- package/src/camera-grant-provider.ts +392 -0
- package/src/camera-settings.ts +133 -0
- package/src/contracts.ts +73 -0
- package/src/device-agent/agent.ts +262 -9
- package/src/device-agent/beat-policy.ts +46 -0
- package/src/device-agent/component.tsx +11 -0
- package/src/device-agent/convex-beat-transport.ts +140 -0
- package/src/device-agent/convex-command-subscription.ts +101 -0
- package/src/device-agent/convex-control-channel.ts +7 -1
- package/src/device-agent/http-transport.ts +22 -1
- package/src/device-agent/index.ts +22 -0
- package/src/device-agent/mqtt-channel.ts +379 -0
- package/src/device-agent/mqtt-codec.ts +347 -0
- package/src/device-agent/tournament.ts +352 -0
- package/src/engine.ts +580 -15
- package/src/http-session-provider.ts +21 -189
- package/src/index.ts +84 -5
- package/src/local-video-quality.ts +43 -0
- package/src/native-runtime.ts +234 -78
- package/src/plugin.ts +19 -6
- package/src/provider.tsx +94 -18
- package/src/realtime/index.ts +56 -0
- package/src/resume-policy.ts +85 -0
- package/src/resume.ts +132 -0
- package/src/rtmp-room-adapter.ts +164 -12
- package/src/session-grant.ts +256 -0
- package/src/ui/camera-screen.tsx +484 -0
- package/src/ui/controls-sheet.tsx +445 -0
- package/src/ui/copy.ts +326 -0
- package/src/ui/helpers.ts +105 -0
- package/src/ui/hooks.ts +59 -0
- package/src/ui/index.ts +42 -0
- package/src/ui/preview-view.tsx +39 -0
- package/src/ui/primitives.tsx +304 -0
- package/src/uplink-check.ts +173 -0
- package/dist/advanced-BXDrDl1h.d.ts +0 -316
- package/dist/advanced-BdAa2Erv.d.cts +0 -316
- package/src/livekit-room-adapter.ts +0 -390
- package/src/livestream-screen.tsx +0 -1002
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExpoSdkConfigurationError,
|
|
3
|
+
ExpoSdkTimeoutError,
|
|
4
|
+
InvalidResponseError,
|
|
5
|
+
NetworkUnavailableError,
|
|
6
|
+
PickleballExpoError,
|
|
7
|
+
errorFromCode,
|
|
8
|
+
isSdkRemoteConfig
|
|
9
|
+
} from "./chunk-XGP2MN5R.js";
|
|
10
|
+
|
|
11
|
+
// src/session-grant.ts
|
|
12
|
+
function isRecord(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
function isFiniteNumber(value) {
|
|
16
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
17
|
+
}
|
|
18
|
+
function isBootstrap(value) {
|
|
19
|
+
return isRecord(value) && isSdkRemoteConfig(value.config) && isFiniteNumber(value.serverTime) && typeof value.rolloutEnabled === "boolean" && (value.message === void 0 || typeof value.message === "string");
|
|
20
|
+
}
|
|
21
|
+
function isTelemetryCredentials(value) {
|
|
22
|
+
return isRecord(value) && typeof value.endpoint === "string" && /^https:\/\//.test(value.endpoint) && typeof value.token === "string" && value.token.length > 0 && isFiniteNumber(value.expiresAt);
|
|
23
|
+
}
|
|
24
|
+
function isSessionGrant(value) {
|
|
25
|
+
return isRecord(value) && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.serverUrl === "string" && /^rtmps?:\/\//i.test(value.serverUrl) && typeof value.participantToken === "string" && value.participantToken.length > 0 && (value.playbackUrl === null || typeof value.playbackUrl === "string") && isFiniteNumber(value.tokenExpiresAt) && isTelemetryCredentials(value.telemetry) && isSdkRemoteConfig(value.config);
|
|
26
|
+
}
|
|
27
|
+
function optionalNullableString(value) {
|
|
28
|
+
return value === void 0 || value === null || typeof value === "string";
|
|
29
|
+
}
|
|
30
|
+
function isCameraGrant(value) {
|
|
31
|
+
return isSessionGrant(value) && /^rtmps?:\/\//i.test(value.serverUrl) && (value.status === "scheduled" || value.status === "live") && optionalNullableString(value.matchRef) && optionalNullableString(value.courtRef) && optionalNullableString(value.watchUrl) && optionalNullableString(value.convexUrl);
|
|
32
|
+
}
|
|
33
|
+
function isSessionRefresh(value) {
|
|
34
|
+
if (!isRecord(value) || !isSdkRemoteConfig(value.config)) return false;
|
|
35
|
+
if (value.participantToken !== void 0 && (typeof value.participantToken !== "string" || !value.participantToken)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (value.tokenExpiresAt !== void 0 && !isFiniteNumber(value.tokenExpiresAt)) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return value.telemetry === void 0 || isTelemetryCredentials(value.telemetry);
|
|
42
|
+
}
|
|
43
|
+
function isSessionStatus(value) {
|
|
44
|
+
return isRecord(value) && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.status === "string" && value.status.length > 0;
|
|
45
|
+
}
|
|
46
|
+
function sessionApiBaseFromTelemetryEndpoint(endpoint) {
|
|
47
|
+
if (!/^https:\/\//.test(endpoint) || !endpoint.endsWith("/telemetry")) {
|
|
48
|
+
throw new InvalidResponseError("The telemetry endpoint must be an HTTPS \u2026/telemetry URL");
|
|
49
|
+
}
|
|
50
|
+
return endpoint.slice(0, -"/telemetry".length);
|
|
51
|
+
}
|
|
52
|
+
var PRIVATE_LAN_HOST = /^(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})$/;
|
|
53
|
+
function normalizeBaseUrl(value) {
|
|
54
|
+
try {
|
|
55
|
+
const url = new URL(value);
|
|
56
|
+
const loopbackHosts = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
57
|
+
const secure = url.protocol === "https:";
|
|
58
|
+
const localDevelopment = url.protocol === "http:" && loopbackHosts.has(url.hostname);
|
|
59
|
+
const devPrivateLan = typeof __DEV__ !== "undefined" && __DEV__ === true && url.protocol === "http:" && PRIVATE_LAN_HOST.test(url.hostname);
|
|
60
|
+
if (!secure && !localDevelopment && !devPrivateLan || url.username || url.password) {
|
|
61
|
+
throw new Error();
|
|
62
|
+
}
|
|
63
|
+
return value.replace(/\/+$/, "");
|
|
64
|
+
} catch {
|
|
65
|
+
throw new ExpoSdkConfigurationError(
|
|
66
|
+
"baseUrl must use HTTPS (HTTP is allowed only for localhost loopback)"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function joinUrl(base, path) {
|
|
71
|
+
return `${base}/${path.replace(/^\/+/, "")}`;
|
|
72
|
+
}
|
|
73
|
+
function parseEnvelopeError(envelope, httpStatus) {
|
|
74
|
+
const body = isRecord(envelope) && isRecord(envelope.error) ? envelope.error : null;
|
|
75
|
+
const error = body && typeof body.code === "string" ? errorFromCode(body.code, typeof body.message === "string" ? body.message : void 0) : new InvalidResponseError();
|
|
76
|
+
return Object.assign(
|
|
77
|
+
error,
|
|
78
|
+
{ httpStatus },
|
|
79
|
+
body && typeof body.reason === "string" ? { reason: body.reason } : {},
|
|
80
|
+
body && typeof body.retryAfterMs === "number" ? { retryAfterMs: body.retryAfterMs } : {}
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function createJsonPoster(options = {}) {
|
|
84
|
+
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
85
|
+
if (typeof fetchImplementation !== "function") {
|
|
86
|
+
throw new ExpoSdkConfigurationError("A Fetch API implementation is required");
|
|
87
|
+
}
|
|
88
|
+
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
89
|
+
return async function post(url, body, headers = {}) {
|
|
90
|
+
const controller = new AbortController();
|
|
91
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
92
|
+
try {
|
|
93
|
+
const response = await fetchImplementation(url, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
96
|
+
body: JSON.stringify(body),
|
|
97
|
+
signal: controller.signal,
|
|
98
|
+
redirect: "error"
|
|
99
|
+
});
|
|
100
|
+
const envelope = await response.json().catch(() => {
|
|
101
|
+
throw new InvalidResponseError();
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) throw parseEnvelopeError(envelope, response.status);
|
|
104
|
+
if (!isRecord(envelope) || !("data" in envelope)) {
|
|
105
|
+
throw new InvalidResponseError();
|
|
106
|
+
}
|
|
107
|
+
return envelope.data;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (controller.signal.aborted) throw new ExpoSdkTimeoutError();
|
|
110
|
+
if (error instanceof PickleballExpoError) throw error;
|
|
111
|
+
if (error instanceof TypeError) {
|
|
112
|
+
throw new NetworkUnavailableError(void 0, { cause: error });
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
} finally {
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function httpStatusOf(error) {
|
|
121
|
+
const status = error?.httpStatus;
|
|
122
|
+
return typeof status === "number" ? status : void 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
isRecord,
|
|
127
|
+
isFiniteNumber,
|
|
128
|
+
isBootstrap,
|
|
129
|
+
isTelemetryCredentials,
|
|
130
|
+
isSessionGrant,
|
|
131
|
+
isCameraGrant,
|
|
132
|
+
isSessionRefresh,
|
|
133
|
+
isSessionStatus,
|
|
134
|
+
sessionApiBaseFromTelemetryEndpoint,
|
|
135
|
+
normalizeBaseUrl,
|
|
136
|
+
joinUrl,
|
|
137
|
+
createJsonPoster,
|
|
138
|
+
httpStatusOf
|
|
139
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { S as SessionCommandSubscription } from './engine-BSvSdCSE.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Kênh nhận lệnh device-rtmp qua WEBSOCKET (Convex subscription) thay poll HTTP
|
|
5
|
+
* 2 giây. Vì sao đổi: poll 2s là 2 function call mỗi 2 giây MỖI MÁY chạy suốt
|
|
6
|
+
* ngày đêm — ở 200 máy là ~518 triệu call/tháng, gấp 20 lần quota gói Pro.
|
|
7
|
+
* Subscription chỉ chạy lại (và tính tiền) KHI hàng lệnh của phiên đổi: lệnh về
|
|
8
|
+
* tức thì (<1s), còn lúc rảnh gần như 0.
|
|
9
|
+
*
|
|
10
|
+
* CHỈ dùng cho máy FIRST-PARTY nối thẳng Convex (có URL .convex.cloud). Máy đối
|
|
11
|
+
* tác đi qua proxy không có đường websocket trực tiếp → giữ nguyên poll HTTP.
|
|
12
|
+
*
|
|
13
|
+
* Auth: gửi telemetry token THÔ làm tham số query, backend hash server-side
|
|
14
|
+
* (sessionCommands.pendingForSession) — client không có crypto. Cùng lối với
|
|
15
|
+
* deviceControl.pendingCommands (cũng nhận token thô trong query).
|
|
16
|
+
*
|
|
17
|
+
* ConvexClient được dựng MỘT lần và tái dùng qua mọi phiên: engine chỉ
|
|
18
|
+
* subscribe/unsubscribe theo phiên, KHÔNG đóng client giữa chừng (đóng rồi mở
|
|
19
|
+
* lại là bắt tay websocket mới mỗi lần đổi độ phân giải/phiên).
|
|
20
|
+
*/
|
|
21
|
+
declare function createConvexCommandSubscription(convexUrl: string): SessionCommandSubscription;
|
|
22
|
+
/**
|
|
23
|
+
* Mọi kênh Convex realtime của máy first-party trên MỘT websocket duy nhất:
|
|
24
|
+
* subscription lệnh (đợt 2) + heartbeat 1-call (đợt 3). Convex client tự
|
|
25
|
+
* multiplex query/mutation trên cùng socket — dựng hai client là trả giá hai
|
|
26
|
+
* lần bắt tay + hai kết nối phải nuôi.
|
|
27
|
+
*/
|
|
28
|
+
interface ConvexDeviceRealtime {
|
|
29
|
+
commandSubscription: SessionCommandSubscription;
|
|
30
|
+
/**
|
|
31
|
+
* Heartbeat qua websocket = 1 function call (mutation `deviceApp.beat`),
|
|
32
|
+
* thay cho đường HTTP httpAction→runMutation = 2 call. Trả envelope `data`
|
|
33
|
+
* thô cùng hợp đồng với POST /devices/heartbeat. NÉM lỗi khi thất bại —
|
|
34
|
+
* caller (withConvexBeat) tự rơi về HTTP.
|
|
35
|
+
*/
|
|
36
|
+
beat(args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
37
|
+
dispose(): void;
|
|
38
|
+
}
|
|
39
|
+
declare function createConvexDeviceRealtime(convexUrl: string): ConvexDeviceRealtime;
|
|
40
|
+
|
|
41
|
+
export { type ConvexDeviceRealtime as C, createConvexDeviceRealtime as a, createConvexCommandSubscription as c };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { S as SessionCommandSubscription } from './engine-BSvSdCSE.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Kênh nhận lệnh device-rtmp qua WEBSOCKET (Convex subscription) thay poll HTTP
|
|
5
|
+
* 2 giây. Vì sao đổi: poll 2s là 2 function call mỗi 2 giây MỖI MÁY chạy suốt
|
|
6
|
+
* ngày đêm — ở 200 máy là ~518 triệu call/tháng, gấp 20 lần quota gói Pro.
|
|
7
|
+
* Subscription chỉ chạy lại (và tính tiền) KHI hàng lệnh của phiên đổi: lệnh về
|
|
8
|
+
* tức thì (<1s), còn lúc rảnh gần như 0.
|
|
9
|
+
*
|
|
10
|
+
* CHỈ dùng cho máy FIRST-PARTY nối thẳng Convex (có URL .convex.cloud). Máy đối
|
|
11
|
+
* tác đi qua proxy không có đường websocket trực tiếp → giữ nguyên poll HTTP.
|
|
12
|
+
*
|
|
13
|
+
* Auth: gửi telemetry token THÔ làm tham số query, backend hash server-side
|
|
14
|
+
* (sessionCommands.pendingForSession) — client không có crypto. Cùng lối với
|
|
15
|
+
* deviceControl.pendingCommands (cũng nhận token thô trong query).
|
|
16
|
+
*
|
|
17
|
+
* ConvexClient được dựng MỘT lần và tái dùng qua mọi phiên: engine chỉ
|
|
18
|
+
* subscribe/unsubscribe theo phiên, KHÔNG đóng client giữa chừng (đóng rồi mở
|
|
19
|
+
* lại là bắt tay websocket mới mỗi lần đổi độ phân giải/phiên).
|
|
20
|
+
*/
|
|
21
|
+
declare function createConvexCommandSubscription(convexUrl: string): SessionCommandSubscription;
|
|
22
|
+
/**
|
|
23
|
+
* Mọi kênh Convex realtime của máy first-party trên MỘT websocket duy nhất:
|
|
24
|
+
* subscription lệnh (đợt 2) + heartbeat 1-call (đợt 3). Convex client tự
|
|
25
|
+
* multiplex query/mutation trên cùng socket — dựng hai client là trả giá hai
|
|
26
|
+
* lần bắt tay + hai kết nối phải nuôi.
|
|
27
|
+
*/
|
|
28
|
+
interface ConvexDeviceRealtime {
|
|
29
|
+
commandSubscription: SessionCommandSubscription;
|
|
30
|
+
/**
|
|
31
|
+
* Heartbeat qua websocket = 1 function call (mutation `deviceApp.beat`),
|
|
32
|
+
* thay cho đường HTTP httpAction→runMutation = 2 call. Trả envelope `data`
|
|
33
|
+
* thô cùng hợp đồng với POST /devices/heartbeat. NÉM lỗi khi thất bại —
|
|
34
|
+
* caller (withConvexBeat) tự rơi về HTTP.
|
|
35
|
+
*/
|
|
36
|
+
beat(args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
37
|
+
dispose(): void;
|
|
38
|
+
}
|
|
39
|
+
declare function createConvexDeviceRealtime(convexUrl: string): ConvexDeviceRealtime;
|
|
40
|
+
|
|
41
|
+
export { type ConvexDeviceRealtime as C, createConvexDeviceRealtime as a, createConvexCommandSubscription as c };
|