@xorgate/react-native 0.1.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 ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ First release: live telemetry and live video on React Native, over
6
+ `@xorgate/react` 0.2.0's platform slot.
7
+
8
+ - `nativePlatform()` — three of `@xorgate/react`'s four platform slots: a
9
+ `WebRtcPlatform` whose peer connection is `react-native-webrtc`'s
10
+ (`iceTransportPolicy: "all"`, because a viewer on a carrier NAT often has no
11
+ path but the TURN relay), the `AppState` foreground edge as the wake source,
12
+ and id entropy from `expo-crypto`. `mqttConnect` is deliberately left unset:
13
+ mqtt.js 5 runs on React Native's global WebSocket unmodified. The three AWS
14
+ bodies — signaling endpoints, ICE servers, the lazy signaling facade — are
15
+ `@xorgate/react`'s own.
16
+ - `XorgateNativeProvider` — `XorgateProvider` with that platform already in it,
17
+ plus `randomId` / `wake` / `mqttConnect` props and a `platform` escape hatch.
18
+ - `useLiveVideo(channel)` / `<LiveVideo channel …/>` over `RTCView`. The
19
+ component holds the outgoing picture across a reconnect until the incoming
20
+ stream reports its first frame, so a blip does not flash black the way a new
21
+ `streamURL` on a bare `RTCView` would; it gives the hold up after 3 s rather
22
+ than pin a stale frame.
23
+ - `appStateWake` / `composeWake` — the foreground edge, and a way to add "the
24
+ network came back" without this package depending on a network library.
25
+ - `@xorgate/react-native/polyfills` — `getRandomValues` and `randomUUID` from
26
+ `expo-crypto` onto `globalThis.crypto`. **Required for live video**, though
27
+ not by this package: `nativePlatform()` covers the SDK's own entropy and
28
+ telemetry needs no polyfill, but `@smithy/core`'s React Native serde bundle
29
+ dereferences a BARE `crypto` in the very fallback it takes when `crypto` is
30
+ undefined, so the first KVS call throws `Property 'crypto' doesn't exist` on
31
+ Hermes (smithy-typescript#2276). A separate entry point so the polyfill is a deliberate line in the
32
+ consumer's entry file rather than an import side effect — and the WebRTC
33
+ platform checks for the global at its first AWS call and says so by name,
34
+ because the raw symptom is a `ReferenceError` the session retries forever.
35
+ - Live telemetry, the data hooks, the live-block policy, the replay timeline,
36
+ lanes, clock and telemetry math are re-exported unchanged from
37
+ `@xorgate/react`; its browser-only hooks deliberately are not.
38
+ - `@xorgate/react-native/webcrypto` — the WebCrypto subset the KVS signaling
39
+ client's SigV4 signer needs (`digest`, `importKey`, `sign`, all SHA-256),
40
+ for Metro to alias `isomorphic-webcrypto` at; that package's own React
41
+ Native build evaluates to `undefined` on Hermes.
42
+
43
+ Metro needs four resolver rules for the AWS / KVS tree; they are in the README
44
+ and nothing else (`buffer`, `process`, `events`, `url`, stream or URL
45
+ polyfills) was necessary on Expo SDK 57 / Hermes.
46
+
47
+ Replay over `expo-video` is 0.2.0.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Epye Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@xorgate/react-native` — the React Native half of `@xorgate/react`.
3
+ *
4
+ * Everything that is pure or platform-neutral lives in `@xorgate/react` and is
5
+ * re-exported here, so an app imports from ONE package: the data hooks, live
6
+ * telemetry, the live-block policy, the replay timeline and clock, the
7
+ * telemetry math, the types. What this package adds is the runtime underneath
8
+ * them (`nativePlatform`, `XorgateNativeProvider`) and the two pieces that
9
+ * cannot be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
+ * react-native-webrtc's `RTCView`.
11
+ *
12
+ * The browser-only exports of `@xorgate/react` — its `useLiveVideo`,
13
+ * `LiveVideo`, `useReplayPlayer`, `ReplayVideo` and the `browser*` platform
14
+ * helpers — are deliberately NOT re-exported: they need `HTMLVideoElement`,
15
+ * `window` or Media Source Extensions, none of which exist here. Importing
16
+ * `@xorgate/react` directly still works and is how you reach them on web.
17
+ */
18
+ export { nativePlatform, type NativePlatformOptions } from "./platform.js";
19
+ export { createNativeWebRtcPlatform } from "./webrtc-platform.js";
20
+ export { appStateWake, composeWake, type WakeSource } from "./wake.js";
21
+ export { XorgateNativeProvider, type XorgateNativeProviderProps, } from "./provider.js";
22
+ export { useLiveVideo, type UseLiveVideo, type UseLiveVideoOptions, } from "./use-live-video.js";
23
+ export { LiveVideo, type LiveVideoProps } from "./live-video.js";
24
+ export { XorgateProvider, useXorgate, useXorgateTenancy, DEFAULT_BASE_URL, type XorgateProviderProps, type XorgateConfig, type XorgateAuth, type FirstPartyAuth, type SessionTokenAuth, type ApiKeyAuth, type LiveCredentialsAuth, type LiveCredentials, type LiveUnavailableReason, type Awaitable, type XorgatePlatform, XorgateError, isXorgateError, type Device, type DeviceModel, type LatestByMetric, type LatestReading, type MediaSession, type Me, type MetricName, type Organization, type PageMeta, type RecordingRun, type ReplayGap, type ReplayManifest, type ReplaySegment, type ReplaySession, type StreamKey, type TelemetryHistory, type TelemetryReading, type VideoChannel, type Workspace, type XorgateClient, useMe, useOrganizations, useWorkspaces, useDevices, useDevice, useDeviceModel, useTelemetryLatest, useTelemetryHistory, useVideoChannels, useRecordingRuns, useSessions, type QueryResult, type QueryOptions, type UseDevicesParams, type UseDevicesResult, type UseTelemetryHistoryParams, type UseSessionsParams, type UseRunsResult, type UseSessionsResult, useLiveTelemetry, useLivePlane, useLiveCredentials, parseTelemetryPayload, presignIotWssUrl, type UseLiveTelemetry, type UseLiveTelemetryOptions, type LiveStatus, type TelemetryPoint, type TelemetrySnapshot, type TelemetryFeedDeps, type MqttLikeClient, type MqttConnectionSpec, type ResolvedLiveCredentials, type ParsedTelemetryPayload, type TelemetryRecordingStatus, type TelemetryMediaStatus, type TelemetryStreamStatus, type LiveBlockPayload, useLiveBlock, resolveLiveBlock, liveBlockElapsedMs, LIVE_BLOCK_STALE_MS, type LiveBlockReason, type LiveBlockOpenReason, type LiveBlockState, type ResolveLiveBlockInput, useLiveVideoSession, type UseLiveVideoSession, type UseLiveVideoSessionOptions, type LiveVideoStatus, type LiveVideoStats, type WebRtcPlatform, type PeerConnectionLike, type SignalingLike, type TimerHost, useReplayManifest, useReplayPlayerCore, useReplayTelemetry, buildTimeline, segmentEnd, segmentAt, hasCoverageAt, gapAt, nextSegmentAfter, prevBoundary, nextBoundary, clampTs, buildLanes, buildClockTimeline, segmentUrlKey, ReplayClock, REPLAY_RATES, parseSegmentMediaInfo, seriesFromReadings, floorIndex, latestWithin, metricGroup, stalenessMs, overviewStalenessMs, chooseIntervalSeconds, windowBoundsFor, windowNeedsRefetch, buildTrace, traceLines, traveledLines, positionAt, GROUP_STALENESS_MS, DEFAULT_STALENESS_MS, WINDOW_SPAN_MS, WINDOW_MIN_SPAN_MS, type UseReplayManifestParams, type UseReplayManifestResult, type UseReplayPlayerCore, type UseReplayTelemetry, type UseReplayTelemetryOptions, type ReplayEngine, type ReplayEngineOptions, type ReplayEngineFactory, type ReplayTimeline, type ReplayLane, type LaneSegment, type ReplayClockState, type ReplayRate, type PacerCandidate, type GapSkipEvent, type SegmentMediaInfo, type MetricSeries, type GpsTrace, type WindowBounds, type PositionResolution, } from "@xorgate/react";
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `@xorgate/react-native` — the React Native half of `@xorgate/react`.
3
+ *
4
+ * Everything that is pure or platform-neutral lives in `@xorgate/react` and is
5
+ * re-exported here, so an app imports from ONE package: the data hooks, live
6
+ * telemetry, the live-block policy, the replay timeline and clock, the
7
+ * telemetry math, the types. What this package adds is the runtime underneath
8
+ * them (`nativePlatform`, `XorgateNativeProvider`) and the two pieces that
9
+ * cannot be neutral because they are pixels: `useLiveVideo` / `LiveVideo` over
10
+ * react-native-webrtc's `RTCView`.
11
+ *
12
+ * The browser-only exports of `@xorgate/react` — its `useLiveVideo`,
13
+ * `LiveVideo`, `useReplayPlayer`, `ReplayVideo` and the `browser*` platform
14
+ * helpers — are deliberately NOT re-exported: they need `HTMLVideoElement`,
15
+ * `window` or Media Source Extensions, none of which exist here. Importing
16
+ * `@xorgate/react` directly still works and is how you reach them on web.
17
+ */
18
+ // ---------------------------------------------------------------------------
19
+ // The React Native runtime
20
+ // ---------------------------------------------------------------------------
21
+ export { nativePlatform } from "./platform.js";
22
+ export { createNativeWebRtcPlatform } from "./webrtc-platform.js";
23
+ export { appStateWake, composeWake } from "./wake.js";
24
+ export { XorgateNativeProvider, } from "./provider.js";
25
+ // ---------------------------------------------------------------------------
26
+ // Live video (RTCView)
27
+ // ---------------------------------------------------------------------------
28
+ export { useLiveVideo, } from "./use-live-video.js";
29
+ export { LiveVideo } from "./live-video.js";
30
+ // ---------------------------------------------------------------------------
31
+ // Re-exported unchanged from `@xorgate/react`
32
+ // ---------------------------------------------------------------------------
33
+ export {
34
+ // Provider and tenancy
35
+ XorgateProvider, useXorgate, useXorgateTenancy, DEFAULT_BASE_URL,
36
+ // Errors and the backend vocabulary
37
+ XorgateError, isXorgateError,
38
+ // Data hooks
39
+ useMe, useOrganizations, useWorkspaces, useDevices, useDevice, useDeviceModel, useTelemetryLatest, useTelemetryHistory, useVideoChannels, useRecordingRuns, useSessions,
40
+ // Live telemetry and the live plane
41
+ useLiveTelemetry, useLivePlane, useLiveCredentials, parseTelemetryPayload, presignIotWssUrl,
42
+ // Live-block policy
43
+ useLiveBlock, resolveLiveBlock, liveBlockElapsedMs, LIVE_BLOCK_STALE_MS,
44
+ // The video session core and its platform boundary
45
+ useLiveVideoSession,
46
+ // Replay: pure timeline, lanes, clock and telemetry math (the engine is N3)
47
+ useReplayManifest, useReplayPlayerCore, useReplayTelemetry, buildTimeline, segmentEnd, segmentAt, hasCoverageAt, gapAt, nextSegmentAfter, prevBoundary, nextBoundary, clampTs, buildLanes, buildClockTimeline, segmentUrlKey, ReplayClock, REPLAY_RATES, parseSegmentMediaInfo, seriesFromReadings, floorIndex, latestWithin, metricGroup, stalenessMs, overviewStalenessMs, chooseIntervalSeconds, windowBoundsFor, windowNeedsRefetch, buildTrace, traceLines, traveledLines, positionAt, GROUP_STALENESS_MS, DEFAULT_STALENESS_MS, WINDOW_SPAN_MS, WINDOW_MIN_SPAN_MS, } from "@xorgate/react";
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,OAAO,EAAE,cAAc,EAA8B,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,OAAO,EACL,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAEjE,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,OAAO;AACL,uBAAuB;AACvB,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,gBAAgB;AAahB,oCAAoC;AACpC,YAAY,EACZ,cAAc;AAsBd,aAAa;AACb,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,SAAS,EACT,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,WAAW;AAUX,oCAAoC;AACpC,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB;AAgBhB,oBAAoB;AACpB,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB;AAMnB,mDAAmD;AACnD,mBAAmB;AAUnB,4EAA4E;AAC5E,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,KAAK,EACL,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,GAqBnB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ViewProps } from "react-native";
3
+ import type { RTCVideoViewProps } from "react-native-webrtc";
4
+ import type { VideoChannel, XorgateError } from "@xorgate/react";
5
+ import type { LiveVideoStats, LiveVideoStatus, UseLiveVideoOptions } from "./use-live-video.js";
6
+ export interface LiveVideoProps extends Omit<ViewProps, "children"> {
7
+ channel: VideoChannel | null;
8
+ options?: UseLiveVideoOptions;
9
+ /** Defaults to "cover", matching the web component's object-fit. */
10
+ objectFit?: RTCVideoViewProps["objectFit"];
11
+ zOrder?: RTCVideoViewProps["zOrder"];
12
+ mirror?: RTCVideoViewProps["mirror"];
13
+ /** Called on every transition. The component renders no status chrome of its own. */
14
+ onStatusChange?: (status: LiveVideoStatus, error: XorgateError | null) => void;
15
+ /** Each inbound-rtp sample, for a stats row. Null between sessions. */
16
+ onStats?: (stats: LiveVideoStats | null) => void;
17
+ /** The encoded size of the picture on screen, as the renderer reports it. */
18
+ onVideoDimensions?: (dimensions: {
19
+ width: number;
20
+ height: number;
21
+ }) => void;
22
+ /**
23
+ * The stream actually ON SCREEN, which during a reconnect lags the session's
24
+ * by the length of the hold below. Null while nothing is displayed.
25
+ */
26
+ onDisplayedStreamChange?: (streamURL: string | null) => void;
27
+ }
28
+ /**
29
+ * `useLiveVideo` plus the native video view, and nothing else: no card, no
30
+ * spinner, no status text, no aspect ratio. It exists so the 90% case is one
31
+ * line, not so it can be your player — the web `LiveVideo` makes the same
32
+ * promise.
33
+ *
34
+ * What it does add over a bare `RTCView` is the reconnect hold. Every
35
+ * reconnect produces a new `MediaStream` with a new `streamURL`, and an
36
+ * `RTCView` pointed at a stream that has not decoded a frame yet is black —
37
+ * so a 2 s blip on a phone would blank the picture, where the browser's
38
+ * `<video>` simply keeps its last frame. Here the new stream is mounted
39
+ * underneath at zero opacity and only promoted once the renderer reports its
40
+ * dimensions, which is the first-frame signal; until then the outgoing view
41
+ * stays on screen. If the new stream never produces a frame the swap happens
42
+ * anyway after {@link HOLD_TIMEOUT_MS}, so a dead stream cannot pin a stale
43
+ * frame forever.
44
+ */
45
+ export declare function LiveVideo(props: LiveVideoProps): ReactNode;
46
+ //# sourceMappingURL=live-video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-video.d.ts","sourceRoot":"","sources":["../src/live-video.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IACjE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,oEAAoE;IACpE,SAAS,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACrC,qFAAqF;IACrF,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IAC/E,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5E;;;OAGG;IACH,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CA+F1D"}
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { StyleSheet, View } from "react-native";
4
+ import { RTCView } from "react-native-webrtc";
5
+ import { useLiveVideo } from "./use-live-video.js";
6
+ /** How long to keep the outgoing picture if the incoming stream never reports a frame. */
7
+ const HOLD_TIMEOUT_MS = 3000;
8
+ /**
9
+ * `useLiveVideo` plus the native video view, and nothing else: no card, no
10
+ * spinner, no status text, no aspect ratio. It exists so the 90% case is one
11
+ * line, not so it can be your player — the web `LiveVideo` makes the same
12
+ * promise.
13
+ *
14
+ * What it does add over a bare `RTCView` is the reconnect hold. Every
15
+ * reconnect produces a new `MediaStream` with a new `streamURL`, and an
16
+ * `RTCView` pointed at a stream that has not decoded a frame yet is black —
17
+ * so a 2 s blip on a phone would blank the picture, where the browser's
18
+ * `<video>` simply keeps its last frame. Here the new stream is mounted
19
+ * underneath at zero opacity and only promoted once the renderer reports its
20
+ * dimensions, which is the first-frame signal; until then the outgoing view
21
+ * stays on screen. If the new stream never produces a frame the swap happens
22
+ * anyway after {@link HOLD_TIMEOUT_MS}, so a dead stream cannot pin a stale
23
+ * frame forever.
24
+ */
25
+ export function LiveVideo(props) {
26
+ const { channel, options, objectFit = "cover", zOrder, mirror, onStatusChange, onStats, onVideoDimensions, onDisplayedStreamChange, style, ...viewProps } = props;
27
+ const { streamURL, status, error, stats } = useLiveVideo(channel, options);
28
+ const onStatusChangeRef = useRef(onStatusChange);
29
+ onStatusChangeRef.current = onStatusChange;
30
+ useEffect(() => {
31
+ onStatusChangeRef.current?.(status, error);
32
+ }, [status, error]);
33
+ const onStatsRef = useRef(onStats);
34
+ onStatsRef.current = onStats;
35
+ useEffect(() => {
36
+ onStatsRef.current?.(stats);
37
+ }, [stats]);
38
+ const onVideoDimensionsRef = useRef(onVideoDimensions);
39
+ onVideoDimensionsRef.current = onVideoDimensions;
40
+ // `shown` is the picture on screen; `incoming` is a newer stream warming up
41
+ // behind it. A first stream goes straight to `shown` — there is nothing to
42
+ // hold on to and no reason to make the viewer wait.
43
+ const [shown, setShown] = useState(null);
44
+ const [incoming, setIncoming] = useState(null);
45
+ useEffect(() => {
46
+ if (streamURL === null) {
47
+ setShown(null);
48
+ setIncoming(null);
49
+ return;
50
+ }
51
+ setShown((current) => {
52
+ if (current === null)
53
+ return streamURL;
54
+ if (current !== streamURL)
55
+ setIncoming(streamURL);
56
+ return current;
57
+ });
58
+ }, [streamURL]);
59
+ useEffect(() => {
60
+ if (incoming === null)
61
+ return;
62
+ const timer = setTimeout(() => {
63
+ setShown(incoming);
64
+ setIncoming(null);
65
+ }, HOLD_TIMEOUT_MS);
66
+ return () => clearTimeout(timer);
67
+ }, [incoming]);
68
+ const promote = (url) => {
69
+ setShown(url);
70
+ setIncoming((current) => (current === url ? null : current));
71
+ };
72
+ const onDisplayedStreamChangeRef = useRef(onDisplayedStreamChange);
73
+ onDisplayedStreamChangeRef.current = onDisplayedStreamChange;
74
+ useEffect(() => {
75
+ onDisplayedStreamChangeRef.current?.(shown);
76
+ }, [shown]);
77
+ return (_jsxs(View, { style: style, ...viewProps, children: [shown !== null && (_jsx(RTCView, { streamURL: shown, objectFit: objectFit, ...(zOrder !== undefined ? { zOrder } : {}), ...(mirror !== undefined ? { mirror } : {}), style: StyleSheet.absoluteFill, onDimensionsChange: (event) => onVideoDimensionsRef.current?.(event.nativeEvent) })), incoming !== null && (_jsx(RTCView, { streamURL: incoming, objectFit: objectFit, ...(zOrder !== undefined ? { zOrder } : {}), ...(mirror !== undefined ? { mirror } : {}), style: [StyleSheet.absoluteFill, styles.warming], onDimensionsChange: () => promote(incoming) }))] }));
78
+ }
79
+ const styles = StyleSheet.create({
80
+ // Mounted so the renderer decodes, invisible so the outgoing frame stands.
81
+ warming: { opacity: 0 },
82
+ });
83
+ //# sourceMappingURL=live-video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-video.js","sourceRoot":"","sources":["../src/live-video.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOnD,0FAA0F;AAC1F,MAAM,eAAe,GAAG,IAAI,CAAC;AAsB7B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,EACJ,OAAO,EACP,OAAO,EACP,SAAS,GAAG,OAAO,EACnB,MAAM,EACN,MAAM,EACN,cAAc,EACd,OAAO,EACP,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,EACL,GAAG,SAAS,EACb,GAAG,KAAK,CAAC;IAEV,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE3E,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACjD,iBAAiB,CAAC,OAAO,GAAG,cAAc,CAAC;IAC3C,SAAS,CAAC,GAAG,EAAE;QACb,iBAAiB,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAEpB,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAC7B,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,MAAM,oBAAoB,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACvD,oBAAoB,CAAC,OAAO,GAAG,iBAAiB,CAAC;IAEjD,4EAA4E;IAC5E,2EAA2E;IAC3E,oDAAoD;IACpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAE9D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE;YACnB,IAAI,OAAO,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YACvC,IAAI,OAAO,KAAK,SAAS;gBAAE,WAAW,CAAC,SAAS,CAAC,CAAC;YAClD,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO;QAC9B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnB,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,EAAE,eAAe,CAAC,CAAC;QACpB,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE;QAC9B,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,WAAW,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC;IAEF,MAAM,0BAA0B,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;IACnE,0BAA0B,CAAC,OAAO,GAAG,uBAAuB,CAAC;IAC7D,SAAS,CAAC,GAAG,EAAE;QACb,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,KAAM,SAAS,aAC9B,KAAK,KAAK,IAAI,IAAI,CACjB,KAAC,OAAO,IACN,SAAS,EAAE,KAAK,EAChB,SAAS,EAAE,SAAS,KAChB,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACxC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5C,KAAK,EAAE,UAAU,CAAC,YAAY,EAC9B,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAChF,CACH,EACA,QAAQ,KAAK,IAAI,IAAI,CACpB,KAAC,OAAO,IACN,SAAS,EAAE,QAAQ,EACnB,SAAS,EAAE,SAAS,KAChB,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KACxC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5C,KAAK,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,EAChD,kBAAkB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAC3C,CACH,IACI,CACR,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,2EAA2E;IAC3E,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;CACxB,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { XorgatePlatform } from "@xorgate/react";
2
+ import { type WakeSource } from "./wake.js";
3
+ export interface NativePlatformOptions {
4
+ /**
5
+ * Client-id entropy for MQTT and KVS signaling. Default: `expo-crypto`'s
6
+ * `randomUUID()`. Hermes has no `crypto` global, so there is nothing else
7
+ * to default to; pass your own only to use a different source.
8
+ */
9
+ randomId?: () => string;
10
+ /**
11
+ * Extra wake sources, merged with the foreground edge. "The network came
12
+ * back" belongs here; the README has the expo-network and NetInfo recipes.
13
+ */
14
+ wake?: WakeSource[];
15
+ /**
16
+ * Replace the MQTT transport. Leave unset: mqtt.js 5 runs unmodified on
17
+ * React Native's global WebSocket (its `react-native` export condition
18
+ * resolves to a self-contained ESM build), which is what the telemetry
19
+ * plane was measured on.
20
+ */
21
+ mqttConnect?: XorgatePlatform["mqttConnect"];
22
+ }
23
+ /**
24
+ * The React Native half of `@xorgate/react`: pass it to the provider once and
25
+ * every neutral hook in that package — telemetry, live video, the data hooks'
26
+ * refetch-on-focus — runs on this runtime instead of a browser's.
27
+ *
28
+ * `XorgateNativeProvider` calls this for you; call it yourself only when you
29
+ * are composing the platform with slots of your own.
30
+ */
31
+ export declare function nativePlatform(options?: NativePlatformOptions): XorgatePlatform;
32
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvE,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,eAAe,CAUnF"}
@@ -0,0 +1,23 @@
1
+ import { randomUUID } from "expo-crypto";
2
+ import { createNativeWebRtcPlatform } from "./webrtc-platform.js";
3
+ import { appStateWake, composeWake } from "./wake.js";
4
+ /**
5
+ * The React Native half of `@xorgate/react`: pass it to the provider once and
6
+ * every neutral hook in that package — telemetry, live video, the data hooks'
7
+ * refetch-on-focus — runs on this runtime instead of a browser's.
8
+ *
9
+ * `XorgateNativeProvider` calls this for you; call it yourself only when you
10
+ * are composing the platform with slots of your own.
11
+ */
12
+ export function nativePlatform(options = {}) {
13
+ const randomId = options.randomId ?? randomUUID;
14
+ return {
15
+ createWebRtcPlatform: () => createNativeWebRtcPlatform(randomId),
16
+ subscribeWake: options.wake?.length
17
+ ? composeWake(appStateWake, ...options.wake)
18
+ : appStateWake,
19
+ randomId,
20
+ ...(options.mqttConnect ? { mqttConnect: options.mqttConnect } : {}),
21
+ };
22
+ }
23
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,WAAW,CAAC;AAuBvE;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,UAAiC,EAAE;IAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC;IAChD,OAAO;QACL,oBAAoB,EAAE,GAAG,EAAE,CAAC,0BAA0B,CAAC,QAAQ,CAAC;QAChE,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM;YACjC,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAC5C,CAAC,CAAC,YAAY;QAChB,QAAQ;QACR,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** What this module installed, for diagnostics screens. Empty = nothing was missing. */
2
+ export declare const INSTALLED_POLYFILLS: string[];
3
+ //# sourceMappingURL=polyfills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polyfills.d.ts","sourceRoot":"","sources":["../src/polyfills.ts"],"names":[],"mappings":"AAyCA,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAAO,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `@xorgate/react-native/polyfills` — the one runtime shim React Native needs
3
+ * for the live plane. Import it for its side effect, once, at the very top of
4
+ * your entry file, before anything that reaches the SDK:
5
+ *
6
+ * ```ts
7
+ * import "@xorgate/react-native/polyfills"
8
+ * ```
9
+ *
10
+ * Hermes on Expo SDK 57 has NO `crypto` global — measured, not assumed: not
11
+ * `randomUUID`, not `getRandomValues`, not `subtle`.
12
+ *
13
+ * **Live video does not work without this import**, though not because of
14
+ * this package: `nativePlatform()` covers the SDK's own client ids through
15
+ * the `randomId` slot, and live telemetry runs with no polyfill at all. It is
16
+ * the AWS SDK underneath the KVS viewer. `@smithy/core`'s React Native serde
17
+ * bundle ends its UUID v4 path in `(array) => crypto.getRandomValues(array)`
18
+ * with a BARE `crypto`, and that is the fallback `bindV4` selects precisely
19
+ * when `typeof crypto === "undefined"` — so the guard hands control to the
20
+ * one line that cannot survive the case it guards for (the same bug was fixed
21
+ * for the Node build in smithy-typescript#2022; the native build was not —
22
+ * smithy-typescript#2276). `createNativeWebRtcPlatform` checks for the global
23
+ * at its first AWS call so the message names this import rather than leaving
24
+ * a `ReferenceError` to be retried forever.
25
+ *
26
+ * It is additive — an existing `crypto` keeps every function it already has —
27
+ * and it is a separate entry point so the polyfill is a deliberate line in
28
+ * your entry file rather than a side effect of importing the package.
29
+ *
30
+ * NOTE this is entropy and UUIDs only. `crypto.subtle` is NOT installed: the
31
+ * one place the SDK needs WebCrypto is SigV4 signing inside the KVS signaling
32
+ * client, and that is a Metro resolver rule (`isomorphic-webcrypto`), not a
33
+ * global. See README "Metro setup".
34
+ */
35
+ import * as Crypto from "expo-crypto";
36
+ /** What this module installed, for diagnostics screens. Empty = nothing was missing. */
37
+ export const INSTALLED_POLYFILLS = [];
38
+ const g = globalThis;
39
+ if (!g.crypto) {
40
+ g.crypto = {
41
+ getRandomValues: Crypto.getRandomValues,
42
+ randomUUID: Crypto.randomUUID,
43
+ };
44
+ INSTALLED_POLYFILLS.push("crypto.getRandomValues", "crypto.randomUUID");
45
+ }
46
+ else {
47
+ if (typeof g.crypto.getRandomValues !== "function") {
48
+ g.crypto.getRandomValues = Crypto.getRandomValues;
49
+ INSTALLED_POLYFILLS.push("crypto.getRandomValues");
50
+ }
51
+ if (typeof g.crypto.randomUUID !== "function") {
52
+ g.crypto.randomUUID = Crypto.randomUUID;
53
+ INSTALLED_POLYFILLS.push("crypto.randomUUID");
54
+ }
55
+ }
56
+ //# sourceMappingURL=polyfills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polyfills.js","sourceRoot":"","sources":["../src/polyfills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAOtC,wFAAwF;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAa,EAAE,CAAC;AAEhD,MAAM,CAAC,GAAG,UAAuC,CAAC;AAElD,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACd,CAAC,CAAC,MAAM,GAAG;QACT,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;IACF,mBAAmB,CAAC,IAAI,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC;AAC1E,CAAC;KAAM,CAAC;IACN,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QACnD,CAAC,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;QAClD,mBAAmB,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC9C,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACxC,mBAAmB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChD,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ import type { XorgatePlatform, XorgateProviderProps } from "@xorgate/react";
3
+ import { type NativePlatformOptions } from "./platform.js";
4
+ export interface XorgateNativeProviderProps extends Omit<XorgateProviderProps, "platform">, NativePlatformOptions {
5
+ /**
6
+ * Slots merged OVER the native defaults, for the rare case where one of
7
+ * them is wrong for your app. Everything you leave out stays native.
8
+ */
9
+ platform?: XorgatePlatform;
10
+ }
11
+ /**
12
+ * `XorgateProvider` with the React Native platform already in it. Use it
13
+ * exactly where a web app uses `XorgateProvider` — same `auth`,
14
+ * `organizationId`, `workspaceId`, `config` and `onError` props, same rule
15
+ * that remounting on the organization (`key={orgId}`) is how you switch
16
+ * tenants.
17
+ */
18
+ export declare function XorgateNativeProvider(props: XorgateNativeProviderProps): ReactNode;
19
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,WAAW,0BACf,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,EAC5C,qBAAqB;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,SAAS,CAuBlF"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { XorgateProvider } from "@xorgate/react";
4
+ import { nativePlatform } from "./platform.js";
5
+ /**
6
+ * `XorgateProvider` with the React Native platform already in it. Use it
7
+ * exactly where a web app uses `XorgateProvider` — same `auth`,
8
+ * `organizationId`, `workspaceId`, `config` and `onError` props, same rule
9
+ * that remounting on the organization (`key={orgId}`) is how you switch
10
+ * tenants.
11
+ */
12
+ export function XorgateNativeProvider(props) {
13
+ const { randomId, wake, mqttConnect, platform, children, ...providerProps } = props;
14
+ const merged = useMemo(() => ({
15
+ ...nativePlatform({
16
+ ...(randomId ? { randomId } : {}),
17
+ ...(wake ? { wake } : {}),
18
+ ...(mqttConnect ? { mqttConnect } : {}),
19
+ }),
20
+ ...platform,
21
+ }),
22
+ // The wake array is read once per subscription; an inline literal must not
23
+ // rebuild the platform on every render.
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
25
+ [randomId, mqttConnect, platform]);
26
+ return (_jsx(XorgateProvider, { ...providerProps, platform: merged, children: children }));
27
+ }
28
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAA8B,MAAM,eAAe,CAAC;AAY3E;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAiC;IACrE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,GAAG,KAAK,CAAC;IAEpF,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,CAAC;QACL,GAAG,cAAc,CAAC;YAChB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC,CAAC;QACF,GAAG,QAAQ;KACZ,CAAC;IACF,2EAA2E;IAC3E,wCAAwC;IACxC,uDAAuD;IACvD,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAClC,CAAC;IAEF,OAAO,CACL,KAAC,eAAe,OAAK,aAAa,EAAE,QAAQ,EAAE,MAAM,YACjD,QAAQ,GACO,CACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { LiveUnavailableReason, LiveVideoStats, LiveVideoStatus, UseLiveVideoSessionOptions, VideoChannel, XorgateError } from "@xorgate/react";
2
+ import type { MediaStream } from "react-native-webrtc";
3
+ export type { LiveVideoStatus, LiveVideoStats } from "@xorgate/react";
4
+ export interface UseLiveVideo {
5
+ /**
6
+ * The received remote stream, or null while idle. A reconnect delivers a
7
+ * NEW stream object: the previous one is dead, not resumable.
8
+ */
9
+ stream: MediaStream | null;
10
+ /** `stream.toURL()`, the only thing `RTCView` takes. Null while idle. */
11
+ streamURL: string | null;
12
+ status: LiveVideoStatus;
13
+ unavailableReason: LiveUnavailableReason | null;
14
+ error: XorgateError | null;
15
+ /** Null until the first sample lands. Reset to null on every reconnect. */
16
+ stats: LiveVideoStats | null;
17
+ }
18
+ export type UseLiveVideoOptions = Omit<UseLiveVideoSessionOptions, "onStream">;
19
+ /**
20
+ * Run a KVS WebRTC VIEWER for one signaling channel and hand back the
21
+ * received stream for an `RTCView`. Pass `null` to stay idle.
22
+ *
23
+ * This is the React Native wrapper over `@xorgate/react`'s
24
+ * `useLiveVideoSession`: the session itself — generation counter, per-step and
25
+ * whole-attempt deadlines, the disconnect grace, backoff, the ~50 minute
26
+ * credential cycle, the wake nudge — is the same code the web app runs, and it
27
+ * was earned against real LTE devices. What differs on a phone is the
28
+ * platform underneath it (`nativePlatform()`) and the fact that the picture
29
+ * goes to a native view instead of an element.
30
+ *
31
+ * Unlike the browser, where a reconnect leaves the last frame in the `<video>`
32
+ * element, `streamURL` changes on every reconnect and an `RTCView` handed a
33
+ * new URL has nothing to show until the first frame decodes. `LiveVideo`
34
+ * holds the outgoing picture across that swap; if you render `RTCView`
35
+ * yourself and care, do the same.
36
+ */
37
+ export declare function useLiveVideo(channel: VideoChannel | null, options?: UseLiveVideoOptions): UseLiveVideo;
38
+ //# sourceMappingURL=use-live-video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-live-video.d.ts","sourceRoot":"","sources":["../src/use-live-video.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,0BAA0B,EAC1B,YAAY,EACZ,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,yEAAyE;IACzE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;IACxB,iBAAiB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAChD,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,0BAA0B,EAAE,UAAU,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,OAAO,GAAE,mBAAwB,GAChC,YAAY,CA8Bd"}
@@ -0,0 +1,49 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useLiveVideoSession } from "@xorgate/react";
3
+ /**
4
+ * Run a KVS WebRTC VIEWER for one signaling channel and hand back the
5
+ * received stream for an `RTCView`. Pass `null` to stay idle.
6
+ *
7
+ * This is the React Native wrapper over `@xorgate/react`'s
8
+ * `useLiveVideoSession`: the session itself — generation counter, per-step and
9
+ * whole-attempt deadlines, the disconnect grace, backoff, the ~50 minute
10
+ * credential cycle, the wake nudge — is the same code the web app runs, and it
11
+ * was earned against real LTE devices. What differs on a phone is the
12
+ * platform underneath it (`nativePlatform()`) and the fact that the picture
13
+ * goes to a native view instead of an element.
14
+ *
15
+ * Unlike the browser, where a reconnect leaves the last frame in the `<video>`
16
+ * element, `streamURL` changes on every reconnect and an `RTCView` handed a
17
+ * new URL has nothing to show until the first frame decodes. `LiveVideo`
18
+ * holds the outgoing picture across that swap; if you render `RTCView`
19
+ * yourself and care, do the same.
20
+ */
21
+ export function useLiveVideo(channel, options = {}) {
22
+ const [stream, setStream] = useState(null);
23
+ const [streamURL, setStreamURL] = useState(null);
24
+ const onStream = useCallback((next) => {
25
+ const ms = next;
26
+ setStream(ms);
27
+ setStreamURL(ms.toURL());
28
+ }, []);
29
+ const session = useLiveVideoSession(channel, {
30
+ onStream,
31
+ ...(options.enabled !== undefined ? { enabled: options.enabled } : {}),
32
+ ...(options.statsIntervalMs !== undefined
33
+ ? { statsIntervalMs: options.statsIntervalMs }
34
+ : {}),
35
+ });
36
+ // Drop the stream when the session goes away (channel change, disable,
37
+ // unmount) — never on a reconnect, which replaces it through `onStream`.
38
+ const active = channel !== null && options.enabled !== false;
39
+ useEffect(() => {
40
+ if (!active)
41
+ return;
42
+ return () => {
43
+ setStream(null);
44
+ setStreamURL(null);
45
+ };
46
+ }, [active, channel?.channelRef, channel?.region]);
47
+ return { stream, streamURL, ...session };
48
+ }
49
+ //# sourceMappingURL=use-live-video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-live-video.js","sourceRoot":"","sources":["../src/use-live-video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AA8BrD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA4B,EAC5B,UAA+B,EAAE;IAEjC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAC/D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAEhE,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,IAAa,EAAE,EAAE;QAC7C,MAAM,EAAE,GAAG,IAAmB,CAAC;QAC/B,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAC3B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,EAAE;QAC3C,QAAQ;QACR,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,GAAG,CAAC,OAAO,CAAC,eAAe,KAAK,SAAS;YACvC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE;YAC9C,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;IAEH,uEAAuE;IACvE,yEAAyE;IACzE,MAAM,MAAM,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,CAAC;IAC7D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,YAAY,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC;AAC3C,CAAC"}
package/dist/wake.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /** `XorgatePlatform["subscribeWake"]`: call `onWake`, get an unsubscribe back. */
2
+ export type WakeSource = (onWake: () => void) => () => void;
3
+ /**
4
+ * The foreground edge. This is the wake source a phone actually needs: iOS
5
+ * suspends the app's sockets within seconds of it leaving the screen, so both
6
+ * the MQTT connection and the peer connection are usually dead by the time the
7
+ * user comes back — and the live plane would otherwise sit out a backoff of up
8
+ * to 30 s in front of them. A browser tab has the same problem in miniature;
9
+ * `visibilitychange` is the web's version of this listener.
10
+ *
11
+ * Only the `active` edge counts. "inactive" is the app switcher or a system
12
+ * sheet over the app, where nothing has been torn down yet.
13
+ */
14
+ export declare function appStateWake(onWake: () => void): () => void;
15
+ /**
16
+ * Fan one `onWake` out over several sources. Used to add "the network came
17
+ * back" to the foreground edge; see the README for the expo-network and
18
+ * NetInfo recipes, which are four lines each and stay in the consumer so this
19
+ * package needs neither as a dependency.
20
+ *
21
+ * A wake is a hint, never a command: the feeds and the video session ignore
22
+ * one while they are connected or mid-connect, so firing twice costs nothing.
23
+ */
24
+ export declare function composeWake(...sources: WakeSource[]): WakeSource;
25
+ //# sourceMappingURL=wake.d.ts.map