@reactor-team/js-sdk 2.3.2 → 2.4.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/dist/index.d.mts +39 -8
- package/dist/index.d.ts +39 -8
- package/dist/index.js +131 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +137 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -31,7 +31,22 @@ interface ConnectOptions {
|
|
|
31
31
|
/** Maximum number of SDP polling attempts before giving up. Default: 6. */
|
|
32
32
|
maxAttempts?: number;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
interface ConnectionStats {
|
|
35
|
+
/** ICE candidate-pair round-trip time in milliseconds */
|
|
36
|
+
rtt?: number;
|
|
37
|
+
/** ICE candidate type: "host", "srflx", "prflx", or "relay" (TURN) */
|
|
38
|
+
candidateType?: string;
|
|
39
|
+
/** Estimated available outgoing bitrate in bits/second */
|
|
40
|
+
availableOutgoingBitrate?: number;
|
|
41
|
+
/** Received video frames per second */
|
|
42
|
+
framesPerSecond?: number;
|
|
43
|
+
/** Ratio of packets lost (0-1) */
|
|
44
|
+
packetLossRatio?: number;
|
|
45
|
+
/** Network jitter in seconds (from inbound-rtp) */
|
|
46
|
+
jitter?: number;
|
|
47
|
+
timestamp: number;
|
|
48
|
+
}
|
|
49
|
+
type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "streamChanged" | "error" | "sessionExpirationChanged" | "statsUpdate";
|
|
35
50
|
|
|
36
51
|
declare const PROD_COORDINATOR_URL = "https://api.reactor.inc";
|
|
37
52
|
declare const OptionsSchema: z.ZodObject<{
|
|
@@ -114,6 +129,7 @@ declare class Reactor {
|
|
|
114
129
|
* Get the last error that occurred
|
|
115
130
|
*/
|
|
116
131
|
getLastError(): ReactorError | undefined;
|
|
132
|
+
getStats(): ConnectionStats | undefined;
|
|
117
133
|
/**
|
|
118
134
|
* Create and store an error
|
|
119
135
|
*/
|
|
@@ -195,15 +211,30 @@ declare function WebcamStream({ className, style, videoConstraints, showWebcam,
|
|
|
195
211
|
*/
|
|
196
212
|
declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
197
213
|
/**
|
|
198
|
-
* Hook for
|
|
214
|
+
* Hook for receiving model application messages.
|
|
215
|
+
*
|
|
216
|
+
* Only fires for messages sent by the model via `get_ctx().send()`.
|
|
217
|
+
* Internal platform-level messages (e.g. capabilities) are NOT delivered here.
|
|
218
|
+
*
|
|
219
|
+
* @param handler - Callback invoked with each application message payload.
|
|
220
|
+
*/
|
|
221
|
+
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
222
|
+
/**
|
|
223
|
+
* Hook for receiving internal platform-level (runtime) messages.
|
|
199
224
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
225
|
+
* This is intended for advanced use cases that need access to the runtime
|
|
226
|
+
* control layer, such as capabilities negotiation. Model application messages
|
|
227
|
+
* sent via `get_ctx().send()` are NOT delivered through this hook — use
|
|
228
|
+
* {@link useReactorMessage} for those.
|
|
203
229
|
*
|
|
204
|
-
* @param handler -
|
|
230
|
+
* @param handler - Callback invoked with each runtime message payload.
|
|
231
|
+
*/
|
|
232
|
+
declare function useReactorInternalMessage(handler: (message: any) => void): void;
|
|
233
|
+
/**
|
|
234
|
+
* Hook that returns the current connection stats (RTT, etc.).
|
|
235
|
+
* Updates every ~2s while connected. Returns undefined when disconnected.
|
|
205
236
|
*/
|
|
206
|
-
declare function
|
|
237
|
+
declare function useStats(): ConnectionStats | undefined;
|
|
207
238
|
|
|
208
239
|
/**
|
|
209
240
|
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
@@ -218,4 +249,4 @@ declare function useReactorMessage(handler: (message: any, scope: MessageScope)
|
|
|
218
249
|
*/
|
|
219
250
|
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
220
251
|
|
|
221
|
-
export { ConflictError, type ConnectOptions, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
|
252
|
+
export { ConflictError, type ConnectOptions, type ConnectionStats, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats };
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,22 @@ interface ConnectOptions {
|
|
|
31
31
|
/** Maximum number of SDP polling attempts before giving up. Default: 6. */
|
|
32
32
|
maxAttempts?: number;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
interface ConnectionStats {
|
|
35
|
+
/** ICE candidate-pair round-trip time in milliseconds */
|
|
36
|
+
rtt?: number;
|
|
37
|
+
/** ICE candidate type: "host", "srflx", "prflx", or "relay" (TURN) */
|
|
38
|
+
candidateType?: string;
|
|
39
|
+
/** Estimated available outgoing bitrate in bits/second */
|
|
40
|
+
availableOutgoingBitrate?: number;
|
|
41
|
+
/** Received video frames per second */
|
|
42
|
+
framesPerSecond?: number;
|
|
43
|
+
/** Ratio of packets lost (0-1) */
|
|
44
|
+
packetLossRatio?: number;
|
|
45
|
+
/** Network jitter in seconds (from inbound-rtp) */
|
|
46
|
+
jitter?: number;
|
|
47
|
+
timestamp: number;
|
|
48
|
+
}
|
|
49
|
+
type ReactorEvent = "statusChanged" | "sessionIdChanged" | "message" | "runtimeMessage" | "streamChanged" | "error" | "sessionExpirationChanged" | "statsUpdate";
|
|
35
50
|
|
|
36
51
|
declare const PROD_COORDINATOR_URL = "https://api.reactor.inc";
|
|
37
52
|
declare const OptionsSchema: z.ZodObject<{
|
|
@@ -114,6 +129,7 @@ declare class Reactor {
|
|
|
114
129
|
* Get the last error that occurred
|
|
115
130
|
*/
|
|
116
131
|
getLastError(): ReactorError | undefined;
|
|
132
|
+
getStats(): ConnectionStats | undefined;
|
|
117
133
|
/**
|
|
118
134
|
* Create and store an error
|
|
119
135
|
*/
|
|
@@ -195,15 +211,30 @@ declare function WebcamStream({ className, style, videoConstraints, showWebcam,
|
|
|
195
211
|
*/
|
|
196
212
|
declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
197
213
|
/**
|
|
198
|
-
* Hook for
|
|
214
|
+
* Hook for receiving model application messages.
|
|
215
|
+
*
|
|
216
|
+
* Only fires for messages sent by the model via `get_ctx().send()`.
|
|
217
|
+
* Internal platform-level messages (e.g. capabilities) are NOT delivered here.
|
|
218
|
+
*
|
|
219
|
+
* @param handler - Callback invoked with each application message payload.
|
|
220
|
+
*/
|
|
221
|
+
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
222
|
+
/**
|
|
223
|
+
* Hook for receiving internal platform-level (runtime) messages.
|
|
199
224
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
225
|
+
* This is intended for advanced use cases that need access to the runtime
|
|
226
|
+
* control layer, such as capabilities negotiation. Model application messages
|
|
227
|
+
* sent via `get_ctx().send()` are NOT delivered through this hook — use
|
|
228
|
+
* {@link useReactorMessage} for those.
|
|
203
229
|
*
|
|
204
|
-
* @param handler -
|
|
230
|
+
* @param handler - Callback invoked with each runtime message payload.
|
|
231
|
+
*/
|
|
232
|
+
declare function useReactorInternalMessage(handler: (message: any) => void): void;
|
|
233
|
+
/**
|
|
234
|
+
* Hook that returns the current connection stats (RTT, etc.).
|
|
235
|
+
* Updates every ~2s while connected. Returns undefined when disconnected.
|
|
205
236
|
*/
|
|
206
|
-
declare function
|
|
237
|
+
declare function useStats(): ConnectionStats | undefined;
|
|
207
238
|
|
|
208
239
|
/**
|
|
209
240
|
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
@@ -218,4 +249,4 @@ declare function useReactorMessage(handler: (message: any, scope: MessageScope)
|
|
|
218
249
|
*/
|
|
219
250
|
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
220
251
|
|
|
221
|
-
export { ConflictError, type ConnectOptions, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
|
252
|
+
export { ConflictError, type ConnectOptions, type ConnectionStats, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, type ReactorConnectOptions, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorInternalMessage, useReactorMessage, useReactorStore, useStats };
|
package/dist/index.js
CHANGED
|
@@ -88,8 +88,10 @@ __export(index_exports, {
|
|
|
88
88
|
WebcamStream: () => WebcamStream,
|
|
89
89
|
fetchInsecureJwtToken: () => fetchInsecureJwtToken,
|
|
90
90
|
useReactor: () => useReactor,
|
|
91
|
+
useReactorInternalMessage: () => useReactorInternalMessage,
|
|
91
92
|
useReactorMessage: () => useReactorMessage,
|
|
92
|
-
useReactorStore: () => useReactorStore
|
|
93
|
+
useReactorStore: () => useReactorStore,
|
|
94
|
+
useStats: () => useStats
|
|
93
95
|
});
|
|
94
96
|
module.exports = __toCommonJS(index_exports);
|
|
95
97
|
|
|
@@ -249,6 +251,52 @@ function parseMessage(data) {
|
|
|
249
251
|
function closePeerConnection(pc) {
|
|
250
252
|
pc.close();
|
|
251
253
|
}
|
|
254
|
+
function extractConnectionStats(report) {
|
|
255
|
+
let rtt;
|
|
256
|
+
let availableOutgoingBitrate;
|
|
257
|
+
let localCandidateId;
|
|
258
|
+
let framesPerSecond;
|
|
259
|
+
let jitter;
|
|
260
|
+
let packetLossRatio;
|
|
261
|
+
report.forEach((stat) => {
|
|
262
|
+
if (stat.type === "candidate-pair" && stat.state === "succeeded") {
|
|
263
|
+
if (stat.currentRoundTripTime !== void 0) {
|
|
264
|
+
rtt = stat.currentRoundTripTime * 1e3;
|
|
265
|
+
}
|
|
266
|
+
if (stat.availableOutgoingBitrate !== void 0) {
|
|
267
|
+
availableOutgoingBitrate = stat.availableOutgoingBitrate;
|
|
268
|
+
}
|
|
269
|
+
localCandidateId = stat.localCandidateId;
|
|
270
|
+
}
|
|
271
|
+
if (stat.type === "inbound-rtp" && stat.kind === "video") {
|
|
272
|
+
if (stat.framesPerSecond !== void 0) {
|
|
273
|
+
framesPerSecond = stat.framesPerSecond;
|
|
274
|
+
}
|
|
275
|
+
if (stat.jitter !== void 0) {
|
|
276
|
+
jitter = stat.jitter;
|
|
277
|
+
}
|
|
278
|
+
if (stat.packetsReceived !== void 0 && stat.packetsLost !== void 0 && stat.packetsReceived + stat.packetsLost > 0) {
|
|
279
|
+
packetLossRatio = stat.packetsLost / (stat.packetsReceived + stat.packetsLost);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
let candidateType;
|
|
284
|
+
if (localCandidateId) {
|
|
285
|
+
const localCandidate = report.get(localCandidateId);
|
|
286
|
+
if (localCandidate == null ? void 0 : localCandidate.candidateType) {
|
|
287
|
+
candidateType = localCandidate.candidateType;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
rtt,
|
|
292
|
+
candidateType,
|
|
293
|
+
availableOutgoingBitrate,
|
|
294
|
+
framesPerSecond,
|
|
295
|
+
packetLossRatio,
|
|
296
|
+
jitter,
|
|
297
|
+
timestamp: Date.now()
|
|
298
|
+
};
|
|
299
|
+
}
|
|
252
300
|
|
|
253
301
|
// src/core/CoordinatorClient.ts
|
|
254
302
|
var INITIAL_BACKOFF_MS = 500;
|
|
@@ -624,6 +672,7 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
624
672
|
|
|
625
673
|
// src/core/GPUMachineClient.ts
|
|
626
674
|
var PING_INTERVAL_MS = 5e3;
|
|
675
|
+
var STATS_INTERVAL_MS = 2e3;
|
|
627
676
|
var GPUMachineClient = class {
|
|
628
677
|
constructor(config) {
|
|
629
678
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
@@ -707,6 +756,7 @@ var GPUMachineClient = class {
|
|
|
707
756
|
disconnect() {
|
|
708
757
|
return __async(this, null, function* () {
|
|
709
758
|
this.stopPing();
|
|
759
|
+
this.stopStatsPolling();
|
|
710
760
|
if (this.publishedTrack) {
|
|
711
761
|
yield this.unpublishTrack();
|
|
712
762
|
}
|
|
@@ -863,6 +913,31 @@ var GPUMachineClient = class {
|
|
|
863
913
|
}
|
|
864
914
|
}
|
|
865
915
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
916
|
+
// Stats Polling (RTT)
|
|
917
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
918
|
+
getStats() {
|
|
919
|
+
return this.stats;
|
|
920
|
+
}
|
|
921
|
+
startStatsPolling() {
|
|
922
|
+
this.stopStatsPolling();
|
|
923
|
+
this.statsInterval = setInterval(() => __async(this, null, function* () {
|
|
924
|
+
if (!this.peerConnection) return;
|
|
925
|
+
try {
|
|
926
|
+
const report = yield this.peerConnection.getStats();
|
|
927
|
+
this.stats = extractConnectionStats(report);
|
|
928
|
+
this.emit("statsUpdate", this.stats);
|
|
929
|
+
} catch (e) {
|
|
930
|
+
}
|
|
931
|
+
}), STATS_INTERVAL_MS);
|
|
932
|
+
}
|
|
933
|
+
stopStatsPolling() {
|
|
934
|
+
if (this.statsInterval !== void 0) {
|
|
935
|
+
clearInterval(this.statsInterval);
|
|
936
|
+
this.statsInterval = void 0;
|
|
937
|
+
}
|
|
938
|
+
this.stats = void 0;
|
|
939
|
+
}
|
|
940
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
866
941
|
// Private Helpers
|
|
867
942
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
868
943
|
setStatus(newStatus) {
|
|
@@ -881,6 +956,7 @@ var GPUMachineClient = class {
|
|
|
881
956
|
switch (state) {
|
|
882
957
|
case "connected":
|
|
883
958
|
this.setStatus("connected");
|
|
959
|
+
this.startStatsPolling();
|
|
884
960
|
break;
|
|
885
961
|
case "disconnected":
|
|
886
962
|
case "closed":
|
|
@@ -1170,7 +1246,11 @@ var Reactor = class {
|
|
|
1170
1246
|
setupMachineClientHandlers() {
|
|
1171
1247
|
if (!this.machineClient) return;
|
|
1172
1248
|
this.machineClient.on("message", (message, scope) => {
|
|
1173
|
-
|
|
1249
|
+
if (scope === "application") {
|
|
1250
|
+
this.emit("message", message);
|
|
1251
|
+
} else if (scope === "runtime") {
|
|
1252
|
+
this.emit("runtimeMessage", message);
|
|
1253
|
+
}
|
|
1174
1254
|
});
|
|
1175
1255
|
this.machineClient.on("statusChanged", (status) => {
|
|
1176
1256
|
switch (status) {
|
|
@@ -1197,6 +1277,9 @@ var Reactor = class {
|
|
|
1197
1277
|
this.emit("streamChanged", track, stream);
|
|
1198
1278
|
}
|
|
1199
1279
|
);
|
|
1280
|
+
this.machineClient.on("statsUpdate", (stats) => {
|
|
1281
|
+
this.emit("statsUpdate", stats);
|
|
1282
|
+
});
|
|
1200
1283
|
}
|
|
1201
1284
|
/**
|
|
1202
1285
|
* Disconnects from the coordinator and the gpu machine.
|
|
@@ -1283,6 +1366,10 @@ var Reactor = class {
|
|
|
1283
1366
|
getLastError() {
|
|
1284
1367
|
return this.lastError;
|
|
1285
1368
|
}
|
|
1369
|
+
getStats() {
|
|
1370
|
+
var _a;
|
|
1371
|
+
return (_a = this.machineClient) == null ? void 0 : _a.getStats();
|
|
1372
|
+
}
|
|
1286
1373
|
/**
|
|
1287
1374
|
* Create and store an error
|
|
1288
1375
|
*/
|
|
@@ -1371,10 +1458,10 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
|
|
|
1371
1458
|
// actions
|
|
1372
1459
|
onMessage: (handler) => {
|
|
1373
1460
|
console.debug("[ReactorStore] Registering message handler");
|
|
1374
|
-
get().internal.reactor.on("
|
|
1461
|
+
get().internal.reactor.on("message", handler);
|
|
1375
1462
|
return () => {
|
|
1376
1463
|
console.debug("[ReactorStore] Cleaning up message handler");
|
|
1377
|
-
get().internal.reactor.off("
|
|
1464
|
+
get().internal.reactor.off("message", handler);
|
|
1378
1465
|
};
|
|
1379
1466
|
},
|
|
1380
1467
|
sendCommand: (command, data, scope) => __async(null, null, function* () {
|
|
@@ -1588,21 +1675,45 @@ function useReactorMessage(handler) {
|
|
|
1588
1675
|
handlerRef.current = handler;
|
|
1589
1676
|
}, [handler]);
|
|
1590
1677
|
(0, import_react4.useEffect)(() => {
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1678
|
+
const stableHandler = (message) => {
|
|
1679
|
+
handlerRef.current(message);
|
|
1680
|
+
};
|
|
1681
|
+
reactor.on("message", stableHandler);
|
|
1682
|
+
return () => {
|
|
1683
|
+
reactor.off("message", stableHandler);
|
|
1684
|
+
};
|
|
1685
|
+
}, [reactor]);
|
|
1686
|
+
}
|
|
1687
|
+
function useReactorInternalMessage(handler) {
|
|
1688
|
+
const reactor = useReactor((state) => state.internal.reactor);
|
|
1689
|
+
const handlerRef = (0, import_react4.useRef)(handler);
|
|
1690
|
+
(0, import_react4.useEffect)(() => {
|
|
1691
|
+
handlerRef.current = handler;
|
|
1692
|
+
}, [handler]);
|
|
1693
|
+
(0, import_react4.useEffect)(() => {
|
|
1694
|
+
const stableHandler = (message) => {
|
|
1695
|
+
handlerRef.current(message);
|
|
1696
|
+
};
|
|
1697
|
+
reactor.on("runtimeMessage", stableHandler);
|
|
1698
|
+
return () => {
|
|
1699
|
+
reactor.off("runtimeMessage", stableHandler);
|
|
1700
|
+
};
|
|
1701
|
+
}, [reactor]);
|
|
1702
|
+
}
|
|
1703
|
+
function useStats() {
|
|
1704
|
+
const reactor = useReactor((state) => state.internal.reactor);
|
|
1705
|
+
const [stats, setStats] = (0, import_react4.useState)(void 0);
|
|
1706
|
+
(0, import_react4.useEffect)(() => {
|
|
1707
|
+
const handler = (newStats) => {
|
|
1708
|
+
setStats(newStats);
|
|
1598
1709
|
};
|
|
1599
|
-
reactor.on("
|
|
1600
|
-
console.debug("[useReactorMessage] Message handler registered");
|
|
1710
|
+
reactor.on("statsUpdate", handler);
|
|
1601
1711
|
return () => {
|
|
1602
|
-
|
|
1603
|
-
|
|
1712
|
+
reactor.off("statsUpdate", handler);
|
|
1713
|
+
setStats(void 0);
|
|
1604
1714
|
};
|
|
1605
1715
|
}, [reactor]);
|
|
1716
|
+
return stats;
|
|
1606
1717
|
}
|
|
1607
1718
|
|
|
1608
1719
|
// src/react/ReactorView.tsx
|
|
@@ -1740,8 +1851,8 @@ function ReactorController({
|
|
|
1740
1851
|
}, 5e3);
|
|
1741
1852
|
return () => clearInterval(interval);
|
|
1742
1853
|
}, [status, commands, requestCapabilities]);
|
|
1743
|
-
|
|
1744
|
-
if (
|
|
1854
|
+
useReactorInternalMessage((message) => {
|
|
1855
|
+
if (message && typeof message === "object" && message.type === "modelCapabilities" && message.data && "commands" in message.data) {
|
|
1745
1856
|
const commandsMessage = message.data;
|
|
1746
1857
|
setCommands(commandsMessage.commands);
|
|
1747
1858
|
const initialValues = {};
|
|
@@ -2374,7 +2485,9 @@ function fetchInsecureJwtToken(_0) {
|
|
|
2374
2485
|
WebcamStream,
|
|
2375
2486
|
fetchInsecureJwtToken,
|
|
2376
2487
|
useReactor,
|
|
2488
|
+
useReactorInternalMessage,
|
|
2377
2489
|
useReactorMessage,
|
|
2378
|
-
useReactorStore
|
|
2490
|
+
useReactorStore,
|
|
2491
|
+
useStats
|
|
2379
2492
|
});
|
|
2380
2493
|
//# sourceMappingURL=index.js.map
|