@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,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,139 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+ var _chunkIUIRVKJIcjs = require('./chunk-IUIRVKJI.cjs');
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) && _chunkIUIRVKJIcjs.isSdkRemoteConfig.call(void 0, 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) && _chunkIUIRVKJIcjs.isSdkRemoteConfig.call(void 0, 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) || !_chunkIUIRVKJIcjs.isSdkRemoteConfig.call(void 0, 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 (0, _chunkIUIRVKJIcjs.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 (e) {
65
+ throw new (0, _chunkIUIRVKJIcjs.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" ? _chunkIUIRVKJIcjs.errorFromCode.call(void 0, body.code, typeof body.message === "string" ? body.message : void 0) : new (0, _chunkIUIRVKJIcjs.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 = _nullishCoalesce(options.fetch, () => ( globalThis.fetch));
85
+ if (typeof fetchImplementation !== "function") {
86
+ throw new (0, _chunkIUIRVKJIcjs.ExpoSdkConfigurationError)("A Fetch API implementation is required");
87
+ }
88
+ const timeoutMs = _nullishCoalesce(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 (0, _chunkIUIRVKJIcjs.InvalidResponseError)();
102
+ });
103
+ if (!response.ok) throw parseEnvelopeError(envelope, response.status);
104
+ if (!isRecord(envelope) || !("data" in envelope)) {
105
+ throw new (0, _chunkIUIRVKJIcjs.InvalidResponseError)();
106
+ }
107
+ return envelope.data;
108
+ } catch (error) {
109
+ if (controller.signal.aborted) throw new (0, _chunkIUIRVKJIcjs.ExpoSdkTimeoutError)();
110
+ if (error instanceof _chunkIUIRVKJIcjs.PickleballExpoError) throw error;
111
+ if (error instanceof TypeError) {
112
+ throw new (0, _chunkIUIRVKJIcjs.NetworkUnavailableError)(void 0, { cause: error });
113
+ }
114
+ throw error;
115
+ } finally {
116
+ clearTimeout(timeout);
117
+ }
118
+ };
119
+ }
120
+ function httpStatusOf(error) {
121
+ const status = _optionalChain([error, 'optionalAccess', _ => _.httpStatus]);
122
+ return typeof status === "number" ? status : void 0;
123
+ }
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+ exports.isRecord = isRecord; exports.isFiniteNumber = isFiniteNumber; exports.isBootstrap = isBootstrap; exports.isTelemetryCredentials = isTelemetryCredentials; exports.isSessionGrant = isSessionGrant; exports.isCameraGrant = isCameraGrant; exports.isSessionRefresh = isSessionRefresh; exports.isSessionStatus = isSessionStatus; exports.sessionApiBaseFromTelemetryEndpoint = sessionApiBaseFromTelemetryEndpoint; exports.normalizeBaseUrl = normalizeBaseUrl; exports.joinUrl = joinUrl; exports.createJsonPoster = createJsonPoster; exports.httpStatusOf = httpStatusOf;
@@ -0,0 +1,50 @@
1
+ // src/device-agent/convex-command-subscription.ts
2
+ import { ConvexClient } from "convex/browser";
3
+ import { anyApi } from "convex/server";
4
+ function createConvexCommandSubscription(convexUrl) {
5
+ return createConvexDeviceRealtime(convexUrl).commandSubscription;
6
+ }
7
+ function createConvexDeviceRealtime(convexUrl) {
8
+ const client = new ConvexClient(convexUrl);
9
+ return {
10
+ commandSubscription: {
11
+ subscribe(credentials, sessionId, onCommands, onError) {
12
+ return client.onUpdate(
13
+ anyApi.sessionCommands.pendingForSession,
14
+ { sessionId, token: credentials.token, after: 0 },
15
+ (value) => onCommands(toCommands(value)),
16
+ (error) => onError?.(error)
17
+ );
18
+ },
19
+ // Client dùng chung với beat — đóng ở dispose() của cả cụm, không ở đây.
20
+ dispose() {
21
+ }
22
+ },
23
+ async beat(args) {
24
+ const result = await client.mutation(anyApi.deviceApp.beat, args);
25
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? result : {};
26
+ },
27
+ dispose() {
28
+ void client.close();
29
+ }
30
+ };
31
+ }
32
+ function toCommands(value) {
33
+ if (value === null || typeof value !== "object") return [];
34
+ const commands = value.commands;
35
+ if (!Array.isArray(commands)) return [];
36
+ const out = [];
37
+ for (const item of commands) {
38
+ if (item === null || typeof item !== "object") continue;
39
+ const record = item;
40
+ if (typeof record.id === "string" && (record.action === "start" || record.action === "stop" || record.action === "end") && typeof record.issuedAt === "number" && Number.isFinite(record.issuedAt)) {
41
+ out.push({ id: record.id, action: record.action, issuedAt: record.issuedAt });
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+
47
+ export {
48
+ createConvexCommandSubscription,
49
+ createConvexDeviceRealtime
50
+ };
@@ -0,0 +1,50 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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; }// src/device-agent/convex-command-subscription.ts
2
+ var _browser = require('convex/browser');
3
+ var _server = require('convex/server');
4
+ function createConvexCommandSubscription(convexUrl) {
5
+ return createConvexDeviceRealtime(convexUrl).commandSubscription;
6
+ }
7
+ function createConvexDeviceRealtime(convexUrl) {
8
+ const client = new (0, _browser.ConvexClient)(convexUrl);
9
+ return {
10
+ commandSubscription: {
11
+ subscribe(credentials, sessionId, onCommands, onError) {
12
+ return client.onUpdate(
13
+ _server.anyApi.sessionCommands.pendingForSession,
14
+ { sessionId, token: credentials.token, after: 0 },
15
+ (value) => onCommands(toCommands(value)),
16
+ (error) => _optionalChain([onError, 'optionalCall', _ => _(error)])
17
+ );
18
+ },
19
+ // Client dùng chung với beat — đóng ở dispose() của cả cụm, không ở đây.
20
+ dispose() {
21
+ }
22
+ },
23
+ async beat(args) {
24
+ const result = await client.mutation(_server.anyApi.deviceApp.beat, args);
25
+ return result !== null && typeof result === "object" && !Array.isArray(result) ? result : {};
26
+ },
27
+ dispose() {
28
+ void client.close();
29
+ }
30
+ };
31
+ }
32
+ function toCommands(value) {
33
+ if (value === null || typeof value !== "object") return [];
34
+ const commands = value.commands;
35
+ if (!Array.isArray(commands)) return [];
36
+ const out = [];
37
+ for (const item of commands) {
38
+ if (item === null || typeof item !== "object") continue;
39
+ const record = item;
40
+ if (typeof record.id === "string" && (record.action === "start" || record.action === "stop" || record.action === "end") && typeof record.issuedAt === "number" && Number.isFinite(record.issuedAt)) {
41
+ out.push({ id: record.id, action: record.action, issuedAt: record.issuedAt });
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+
47
+
48
+
49
+
50
+ exports.createConvexCommandSubscription = createConvexCommandSubscription; exports.createConvexDeviceRealtime = createConvexDeviceRealtime;
@@ -0,0 +1,33 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+
28
+
29
+
30
+
31
+
32
+
33
+ exports.__require = __require; exports.__esm = __esm; exports.__export = __export; exports.__toCommonJS = __toCommonJS;