@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.
Files changed (89) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +155 -101
  3. package/dist/advanced-DcbHBCGb.d.ts +300 -0
  4. package/dist/advanced-DeQwg7MK.d.cts +300 -0
  5. package/dist/advanced.cjs +14 -2
  6. package/dist/advanced.d.cts +2 -2
  7. package/dist/advanced.d.ts +2 -2
  8. package/dist/advanced.js +17 -5
  9. package/dist/camera-controls-By8tHigY.d.cts +97 -0
  10. package/dist/camera-controls-rCBUGGPC.d.ts +97 -0
  11. package/dist/chunk-62YV3PCD.cjs +139 -0
  12. package/dist/chunk-6F3HN6US.js +50 -0
  13. package/dist/chunk-6YE5BL3A.cjs +50 -0
  14. package/dist/chunk-7Z7TN5N3.js +318 -0
  15. package/dist/{chunk-TRLASNPQ.cjs → chunk-GXQYMPHE.cjs} +1 -1
  16. package/dist/{chunk-TBPR2QND.cjs → chunk-IUIRVKJI.cjs} +736 -399
  17. package/dist/chunk-TBUEXRFQ.cjs +318 -0
  18. package/dist/{chunk-FODE2W2H.js → chunk-XGP2MN5R.js} +688 -351
  19. package/dist/{chunk-6JOMESNT.js → chunk-XL4CISVQ.js} +1 -1
  20. package/dist/chunk-ZSKSXOCZ.js +139 -0
  21. package/dist/convex-command-subscription-Cabh9tND.d.ts +41 -0
  22. package/dist/convex-command-subscription-DUgpu75l.d.cts +41 -0
  23. package/dist/device-agent/index.cjs +973 -44
  24. package/dist/device-agent/index.d.cts +339 -3
  25. package/dist/device-agent/index.d.ts +339 -3
  26. package/dist/device-agent/index.js +940 -11
  27. package/dist/{engine-CCSSqPbZ.d.cts → engine-BSvSdCSE.d.cts} +227 -2
  28. package/dist/{engine-CCSSqPbZ.d.ts → engine-BSvSdCSE.d.ts} +227 -2
  29. package/dist/index.cjs +419 -937
  30. package/dist/index.d.cts +315 -32
  31. package/dist/index.d.ts +315 -32
  32. package/dist/index.js +423 -941
  33. package/dist/plugin.cjs +11 -13
  34. package/dist/plugin.d.cts +15 -1
  35. package/dist/plugin.d.ts +15 -1
  36. package/dist/plugin.js +7 -9
  37. package/dist/realtime/index.cjs +31 -0
  38. package/dist/realtime/index.d.cts +15 -0
  39. package/dist/realtime/index.d.ts +15 -0
  40. package/dist/realtime/index.js +31 -0
  41. package/dist/ui/index.cjs +1297 -0
  42. package/dist/ui/index.d.cts +493 -0
  43. package/dist/ui/index.d.ts +493 -0
  44. package/dist/ui/index.js +1297 -0
  45. package/dist/version.cjs +2 -2
  46. package/dist/version.js +1 -1
  47. package/package.json +31 -15
  48. package/src/advanced.ts +11 -9
  49. package/src/auto-resume.tsx +259 -0
  50. package/src/camera-controls.ts +99 -0
  51. package/src/camera-grant-provider.ts +392 -0
  52. package/src/camera-settings.ts +133 -0
  53. package/src/contracts.ts +73 -0
  54. package/src/device-agent/agent.ts +262 -9
  55. package/src/device-agent/beat-policy.ts +46 -0
  56. package/src/device-agent/component.tsx +11 -0
  57. package/src/device-agent/convex-beat-transport.ts +140 -0
  58. package/src/device-agent/convex-command-subscription.ts +101 -0
  59. package/src/device-agent/convex-control-channel.ts +7 -1
  60. package/src/device-agent/http-transport.ts +22 -1
  61. package/src/device-agent/index.ts +22 -0
  62. package/src/device-agent/mqtt-channel.ts +379 -0
  63. package/src/device-agent/mqtt-codec.ts +347 -0
  64. package/src/device-agent/tournament.ts +352 -0
  65. package/src/engine.ts +580 -15
  66. package/src/http-session-provider.ts +21 -189
  67. package/src/index.ts +84 -5
  68. package/src/local-video-quality.ts +43 -0
  69. package/src/native-runtime.ts +234 -78
  70. package/src/plugin.ts +19 -6
  71. package/src/provider.tsx +94 -18
  72. package/src/realtime/index.ts +56 -0
  73. package/src/resume-policy.ts +85 -0
  74. package/src/resume.ts +132 -0
  75. package/src/rtmp-room-adapter.ts +164 -12
  76. package/src/session-grant.ts +256 -0
  77. package/src/ui/camera-screen.tsx +484 -0
  78. package/src/ui/controls-sheet.tsx +445 -0
  79. package/src/ui/copy.ts +326 -0
  80. package/src/ui/helpers.ts +105 -0
  81. package/src/ui/hooks.ts +59 -0
  82. package/src/ui/index.ts +42 -0
  83. package/src/ui/preview-view.tsx +39 -0
  84. package/src/ui/primitives.tsx +304 -0
  85. package/src/uplink-check.ts +173 -0
  86. package/dist/advanced-BXDrDl1h.d.ts +0 -316
  87. package/dist/advanced-BdAa2Erv.d.cts +0 -316
  88. package/src/livekit-room-adapter.ts +0 -390
  89. package/src/livestream-screen.tsx +0 -1002
package/dist/plugin.cjs CHANGED
@@ -1,7 +1,4 @@
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
- var _chunkTRLASNPQcjs = require('./chunk-TRLASNPQ.cjs');
4
- require('./chunk-7OX2DSKI.cjs');
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');
5
2
 
6
3
  // src/plugin.ts
7
4
 
@@ -10,13 +7,16 @@ require('./chunk-7OX2DSKI.cjs');
10
7
 
11
8
 
12
9
 
13
-
14
10
  var _configplugins = require('expo/config-plugins');
15
11
  var _promises = require('fs/promises');
16
12
  var _path = require('path');
13
+ var PLUGIN_SCHEMA_VERSION = "1";
17
14
  var CORE_ANDROID_PERMISSIONS = [
18
15
  "android.permission.ACCESS_NETWORK_STATE",
19
16
  "android.permission.CAMERA",
17
+ "android.permission.FOREGROUND_SERVICE",
18
+ "android.permission.FOREGROUND_SERVICE_CAMERA",
19
+ "android.permission.FOREGROUND_SERVICE_MICROPHONE",
20
20
  "android.permission.INTERNET",
21
21
  "android.permission.MODIFY_AUDIO_SETTINGS",
22
22
  "android.permission.RECORD_AUDIO",
@@ -65,9 +65,6 @@ var withPickleballLive = (config, props = {}) => {
65
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
66
  const remoteEnabled = _optionalChain([props, 'optionalAccess', _4 => _4.modules, 'optionalAccess', _5 => _5.remote]) !== false;
67
67
  const androidPermissions = remoteEnabled ? [...CORE_ANDROID_PERMISSIONS, ...REMOTE_ANDROID_PERMISSIONS] : [...CORE_ANDROID_PERMISSIONS];
68
- config = _configplugins.withPlugins.call(void 0, config, [
69
- ["@livekit/react-native-expo-plugin", _optionalChain([props, 'optionalAccess', _6 => _6.liveKit])]
70
- ]);
71
68
  config.ios = { ...config.ios, bitcode: false };
72
69
  config = _configplugins.withInfoPlist.call(void 0, config, (mod) => {
73
70
  mod.modResults.NSCameraUsageDescription = cameraPermission;
@@ -91,7 +88,7 @@ var withPickleballLive = (config, props = {}) => {
91
88
  };
92
89
  const byName = /* @__PURE__ */ new Map();
93
90
  for (const entry of existing) {
94
- const name = _optionalChain([entry, 'access', _7 => _7.$, 'optionalAccess', _8 => _8["android:name"]]);
91
+ const name = _optionalChain([entry, 'access', _6 => _6.$, 'optionalAccess', _7 => _7["android:name"]]);
95
92
  if (name && !byName.has(name)) byName.set(name, entry);
96
93
  }
97
94
  for (const permission of androidPermissions) {
@@ -105,14 +102,14 @@ var withPickleballLive = (config, props = {}) => {
105
102
  const requiredNames = new Set(androidPermissions);
106
103
  manifest["uses-permission"] = [
107
104
  ...existing.filter((entry) => {
108
- const name = _optionalChain([entry, 'access', _9 => _9.$, 'optionalAccess', _10 => _10["android:name"]]);
105
+ const name = _optionalChain([entry, 'access', _8 => _8.$, 'optionalAccess', _9 => _9["android:name"]]);
109
106
  return !name || !requiredNames.has(name);
110
107
  }),
111
108
  ...androidPermissions.map((name) => byName.get(name))
112
109
  ];
113
110
  return mod;
114
111
  });
115
- if (remoteEnabled && _optionalChain([props, 'optionalAccess', _11 => _11.consumeHidVolumeKeys]) !== false) {
112
+ if (remoteEnabled && _optionalChain([props, 'optionalAccess', _10 => _10.consumeHidVolumeKeys]) !== false) {
116
113
  config = _configplugins.withDangerousMod.call(void 0, config, ["android", async (mod) => {
117
114
  const root = _path.join.call(void 0, mod.modRequest.platformProjectRoot, "app", "src", "main", "java");
118
115
  const path = await findMainActivity(root);
@@ -128,9 +125,10 @@ var withPickleballLive = (config, props = {}) => {
128
125
  var plugin_default = _configplugins.createRunOncePlugin.call(void 0,
129
126
  withPickleballLive,
130
127
  "@pickleball/expo-sdk",
131
- _chunkTRLASNPQcjs.PICKLEBALL_EXPO_SDK_VERSION
128
+ PLUGIN_SCHEMA_VERSION
132
129
  );
133
130
 
134
131
 
135
132
 
136
- exports.default = plugin_default; exports.injectHidVolumeMainActivity = injectHidVolumeMainActivity;
133
+
134
+ exports.PLUGIN_SCHEMA_VERSION = PLUGIN_SCHEMA_VERSION; exports.default = plugin_default; exports.injectHidVolumeMainActivity = injectHidVolumeMainActivity;
package/dist/plugin.d.cts CHANGED
@@ -1,5 +1,13 @@
1
1
  import { ConfigPlugin } from 'expo/config-plugins';
2
2
 
3
+ /**
4
+ * Version của SCHEMA plugin — tách khỏi version package có chủ ý. Giá trị này
5
+ * được inline vào dist/plugin.cjs, mà @expo/fingerprint băm file đó làm
6
+ * runtimeVersion của app fleet: gắn theo version package là MỖI lần bump SDK
7
+ * (kể cả patch JS-only) đổi fingerprint và toàn bộ máy ngoài sân mất OTA. Chỉ
8
+ * nâng khi plugin đổi hành vi native (permission, mod).
9
+ */
10
+ declare const PLUGIN_SCHEMA_VERSION = "1";
3
11
  interface PickleballLivePluginProps {
4
12
  cameraPermission?: string;
5
13
  microphonePermission?: string;
@@ -13,11 +21,17 @@ interface PickleballLivePluginProps {
13
21
  * - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
14
22
  * nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
15
23
  * expo.autolinking.exclude trong package.json của app (xem README).
24
+ * - livekit: KHÔNG còn tác dụng từ 1.0 (SDK RTMP-only, không compose plugin
25
+ * LiveKit nữa). Vẫn nhận để app.config cũ của fleet không phải sửa — sửa
26
+ * là đổi fingerprint OTA.
16
27
  */
17
28
  modules?: {
18
29
  remote?: boolean;
19
30
  voice?: boolean;
31
+ /** @deprecated bị bỏ qua từ 1.0 */
32
+ livekit?: boolean;
20
33
  };
34
+ /** @deprecated bị bỏ qua từ 1.0 (SDK không còn LiveKit). */
21
35
  liveKit?: {
22
36
  android?: {
23
37
  audioType?: string;
@@ -31,4 +45,4 @@ interface PickleballLivePluginProps {
31
45
  declare function injectHidVolumeMainActivity(source: string): string;
32
46
  declare const _default: ConfigPlugin<PickleballLivePluginProps | undefined>;
33
47
 
34
- export { type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
48
+ export { PLUGIN_SCHEMA_VERSION, type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
package/dist/plugin.d.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import { ConfigPlugin } from 'expo/config-plugins';
2
2
 
3
+ /**
4
+ * Version của SCHEMA plugin — tách khỏi version package có chủ ý. Giá trị này
5
+ * được inline vào dist/plugin.cjs, mà @expo/fingerprint băm file đó làm
6
+ * runtimeVersion của app fleet: gắn theo version package là MỖI lần bump SDK
7
+ * (kể cả patch JS-only) đổi fingerprint và toàn bộ máy ngoài sân mất OTA. Chỉ
8
+ * nâng khi plugin đổi hành vi native (permission, mod).
9
+ */
10
+ declare const PLUGIN_SCHEMA_VERSION = "1";
3
11
  interface PickleballLivePluginProps {
4
12
  cameraPermission?: string;
5
13
  microphonePermission?: string;
@@ -13,11 +21,17 @@ interface PickleballLivePluginProps {
13
21
  * - voice: false → hiện chưa gate gì trong plugin (mic thuộc livestream);
14
22
  * nhận trước để tương thích về sau. Muốn loại hẳn native khỏi binary, thêm
15
23
  * expo.autolinking.exclude trong package.json của app (xem README).
24
+ * - livekit: KHÔNG còn tác dụng từ 1.0 (SDK RTMP-only, không compose plugin
25
+ * LiveKit nữa). Vẫn nhận để app.config cũ của fleet không phải sửa — sửa
26
+ * là đổi fingerprint OTA.
16
27
  */
17
28
  modules?: {
18
29
  remote?: boolean;
19
30
  voice?: boolean;
31
+ /** @deprecated bị bỏ qua từ 1.0 */
32
+ livekit?: boolean;
20
33
  };
34
+ /** @deprecated bị bỏ qua từ 1.0 (SDK không còn LiveKit). */
21
35
  liveKit?: {
22
36
  android?: {
23
37
  audioType?: string;
@@ -31,4 +45,4 @@ interface PickleballLivePluginProps {
31
45
  declare function injectHidVolumeMainActivity(source: string): string;
32
46
  declare const _default: ConfigPlugin<PickleballLivePluginProps | undefined>;
33
47
 
34
- export { type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
48
+ export { PLUGIN_SCHEMA_VERSION, type PickleballLivePluginProps, _default as default, injectHidVolumeMainActivity };
package/dist/plugin.js CHANGED
@@ -1,6 +1,3 @@
1
- import {
2
- PICKLEBALL_EXPO_SDK_VERSION
3
- } from "./chunk-6JOMESNT.js";
4
1
  import "./chunk-KFQGP6VL.js";
5
2
 
6
3
  // src/plugin.ts
@@ -9,14 +6,17 @@ import {
9
6
  createRunOncePlugin,
10
7
  withAndroidManifest,
11
8
  withDangerousMod,
12
- withInfoPlist,
13
- withPlugins
9
+ withInfoPlist
14
10
  } from "expo/config-plugins";
15
11
  import { readdir, readFile, writeFile } from "fs/promises";
16
12
  import { join } from "path";
13
+ var PLUGIN_SCHEMA_VERSION = "1";
17
14
  var CORE_ANDROID_PERMISSIONS = [
18
15
  "android.permission.ACCESS_NETWORK_STATE",
19
16
  "android.permission.CAMERA",
17
+ "android.permission.FOREGROUND_SERVICE",
18
+ "android.permission.FOREGROUND_SERVICE_CAMERA",
19
+ "android.permission.FOREGROUND_SERVICE_MICROPHONE",
20
20
  "android.permission.INTERNET",
21
21
  "android.permission.MODIFY_AUDIO_SETTINGS",
22
22
  "android.permission.RECORD_AUDIO",
@@ -65,9 +65,6 @@ var withPickleballLive = (config, props = {}) => {
65
65
  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.";
66
66
  const remoteEnabled = props?.modules?.remote !== false;
67
67
  const androidPermissions = remoteEnabled ? [...CORE_ANDROID_PERMISSIONS, ...REMOTE_ANDROID_PERMISSIONS] : [...CORE_ANDROID_PERMISSIONS];
68
- config = withPlugins(config, [
69
- ["@livekit/react-native-expo-plugin", props?.liveKit]
70
- ]);
71
68
  config.ios = { ...config.ios, bitcode: false };
72
69
  config = withInfoPlist(config, (mod) => {
73
70
  mod.modResults.NSCameraUsageDescription = cameraPermission;
@@ -128,9 +125,10 @@ var withPickleballLive = (config, props = {}) => {
128
125
  var plugin_default = createRunOncePlugin(
129
126
  withPickleballLive,
130
127
  "@pickleball/expo-sdk",
131
- PICKLEBALL_EXPO_SDK_VERSION
128
+ PLUGIN_SCHEMA_VERSION
132
129
  );
133
130
  export {
131
+ PLUGIN_SCHEMA_VERSION,
134
132
  plugin_default as default,
135
133
  injectHidVolumeMainActivity
136
134
  };
@@ -0,0 +1,31 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+ var _chunk6YE5BL3Acjs = require('../chunk-6YE5BL3A.cjs');
5
+ require('../chunk-7OX2DSKI.cjs');
6
+
7
+ // src/realtime/index.ts
8
+ function createGrantCommandSubscription(getConvexUrl) {
9
+ const clients = /* @__PURE__ */ new Map();
10
+ return {
11
+ subscribe(credentials, sessionId, onCommands, onError) {
12
+ const url = getConvexUrl();
13
+ if (!url) return () => void 0;
14
+ let realtime = clients.get(url);
15
+ if (!realtime) {
16
+ realtime = _chunk6YE5BL3Acjs.createConvexDeviceRealtime.call(void 0, url);
17
+ clients.set(url, realtime);
18
+ }
19
+ return realtime.commandSubscription.subscribe(credentials, sessionId, onCommands, onError);
20
+ },
21
+ dispose() {
22
+ for (const realtime of clients.values()) realtime.dispose();
23
+ clients.clear();
24
+ }
25
+ };
26
+ }
27
+
28
+
29
+
30
+
31
+ exports.createConvexCommandSubscription = _chunk6YE5BL3Acjs.createConvexCommandSubscription; exports.createConvexDeviceRealtime = _chunk6YE5BL3Acjs.createConvexDeviceRealtime; exports.createGrantCommandSubscription = createGrantCommandSubscription;
@@ -0,0 +1,15 @@
1
+ export { C as ConvexDeviceRealtime, c as createConvexCommandSubscription, a as createConvexDeviceRealtime } from '../convex-command-subscription-DUgpu75l.cjs';
2
+ import { S as SessionCommandSubscription } from '../engine-BSvSdCSE.cjs';
3
+
4
+ /**
5
+ * Subscription cho app dùng camera grant: URL Convex nằm TRONG grant
6
+ * (`grant.convexUrl`) nên chỉ biết sau khi start — đọc URL lúc engine subscribe
7
+ * (ngay sau khi vào phiên), dựng MỘT client mỗi origin và tái dùng qua các
8
+ * phiên. Không có URL (deployment không lộ origin chuẩn) → không subscribe,
9
+ * engine giữ poll HTTP như cũ.
10
+ *
11
+ * Dùng với createCameraGrantProvider: `() => provider.getActiveGrant()?.convexUrl`.
12
+ */
13
+ declare function createGrantCommandSubscription(getConvexUrl: () => string | null | undefined): SessionCommandSubscription;
14
+
15
+ export { createGrantCommandSubscription };
@@ -0,0 +1,15 @@
1
+ export { C as ConvexDeviceRealtime, c as createConvexCommandSubscription, a as createConvexDeviceRealtime } from '../convex-command-subscription-Cabh9tND.js';
2
+ import { S as SessionCommandSubscription } from '../engine-BSvSdCSE.js';
3
+
4
+ /**
5
+ * Subscription cho app dùng camera grant: URL Convex nằm TRONG grant
6
+ * (`grant.convexUrl`) nên chỉ biết sau khi start — đọc URL lúc engine subscribe
7
+ * (ngay sau khi vào phiên), dựng MỘT client mỗi origin và tái dùng qua các
8
+ * phiên. Không có URL (deployment không lộ origin chuẩn) → không subscribe,
9
+ * engine giữ poll HTTP như cũ.
10
+ *
11
+ * Dùng với createCameraGrantProvider: `() => provider.getActiveGrant()?.convexUrl`.
12
+ */
13
+ declare function createGrantCommandSubscription(getConvexUrl: () => string | null | undefined): SessionCommandSubscription;
14
+
15
+ export { createGrantCommandSubscription };
@@ -0,0 +1,31 @@
1
+ import {
2
+ createConvexCommandSubscription,
3
+ createConvexDeviceRealtime
4
+ } from "../chunk-6F3HN6US.js";
5
+ import "../chunk-KFQGP6VL.js";
6
+
7
+ // src/realtime/index.ts
8
+ function createGrantCommandSubscription(getConvexUrl) {
9
+ const clients = /* @__PURE__ */ new Map();
10
+ return {
11
+ subscribe(credentials, sessionId, onCommands, onError) {
12
+ const url = getConvexUrl();
13
+ if (!url) return () => void 0;
14
+ let realtime = clients.get(url);
15
+ if (!realtime) {
16
+ realtime = createConvexDeviceRealtime(url);
17
+ clients.set(url, realtime);
18
+ }
19
+ return realtime.commandSubscription.subscribe(credentials, sessionId, onCommands, onError);
20
+ },
21
+ dispose() {
22
+ for (const realtime of clients.values()) realtime.dispose();
23
+ clients.clear();
24
+ }
25
+ };
26
+ }
27
+ export {
28
+ createConvexCommandSubscription,
29
+ createConvexDeviceRealtime,
30
+ createGrantCommandSubscription
31
+ };