@pollen-robotics/reachy-mini-sdk 1.10.0-dev.0.main.9f78da7 → 1.10.0-dev.0.main.c8367cd
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/APP_CREATION_GUIDE.md +98 -0
- package/dist/lib/central-listener.d.ts +71 -0
- package/dist/lib/central-listener.d.ts.map +1 -0
- package/dist/lib/central-listener.js +277 -0
- package/dist/lib/central-listener.js.map +1 -0
- package/dist/lib/central-listener.test.d.ts +2 -0
- package/dist/lib/central-listener.test.d.ts.map +1 -0
- package/dist/lib/central-listener.test.js +378 -0
- package/dist/lib/central-listener.test.js.map +1 -0
- package/dist/lib/dc-watchdog.test.d.ts +2 -0
- package/dist/lib/dc-watchdog.test.d.ts.map +1 -0
- package/dist/lib/dc-watchdog.test.js +154 -0
- package/dist/lib/dc-watchdog.test.js.map +1 -0
- package/dist/lib/ensure-awake.test.d.ts +2 -0
- package/dist/lib/ensure-awake.test.d.ts.map +1 -0
- package/dist/lib/ensure-awake.test.js +117 -0
- package/dist/lib/ensure-awake.test.js.map +1 -0
- package/dist/lib/ice-grace.test.d.ts +2 -0
- package/dist/lib/ice-grace.test.d.ts.map +1 -0
- package/dist/lib/ice-grace.test.js +211 -0
- package/dist/lib/ice-grace.test.js.map +1 -0
- package/dist/lib/imu.test.d.ts +2 -0
- package/dist/lib/imu.test.d.ts.map +1 -0
- package/dist/lib/imu.test.js +78 -0
- package/dist/lib/imu.test.js.map +1 -0
- package/dist/lib/logger.d.ts +38 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +81 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/pending-replies.d.ts +127 -0
- package/dist/lib/pending-replies.d.ts.map +1 -0
- package/dist/lib/pending-replies.js +255 -0
- package/dist/lib/pending-replies.js.map +1 -0
- package/dist/lib/pending-replies.test.d.ts +2 -0
- package/dist/lib/pending-replies.test.d.ts.map +1 -0
- package/dist/lib/pending-replies.test.js +217 -0
- package/dist/lib/pending-replies.test.js.map +1 -0
- package/dist/lib/reachy-mini.d.ts +118 -94
- package/dist/lib/reachy-mini.d.ts.map +1 -1
- package/dist/lib/reachy-mini.js +427 -690
- package/dist/lib/reachy-mini.js.map +1 -1
- package/dist/lib/redial.test.d.ts +2 -0
- package/dist/lib/redial.test.d.ts.map +1 -0
- package/dist/lib/redial.test.js +206 -0
- package/dist/lib/redial.test.js.map +1 -0
- package/dist/lib/request.test.d.ts +2 -0
- package/dist/lib/request.test.d.ts.map +1 -0
- package/dist/lib/request.test.js +90 -0
- package/dist/lib/request.test.js.map +1 -0
- package/dist/lib/session-supervisor.d.ts +201 -0
- package/dist/lib/session-supervisor.d.ts.map +1 -0
- package/dist/lib/session-supervisor.js +520 -0
- package/dist/lib/session-supervisor.js.map +1 -0
- package/dist/lib/token-store.d.ts +50 -0
- package/dist/lib/token-store.d.ts.map +1 -0
- package/dist/lib/token-store.js +120 -0
- package/dist/lib/token-store.js.map +1 -0
- package/dist/lib/token-store.test.d.ts +2 -0
- package/dist/lib/token-store.test.d.ts.map +1 -0
- package/dist/lib/token-store.test.js +82 -0
- package/dist/lib/token-store.test.js.map +1 -0
- package/dist/lib/types.d.ts +261 -6
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/url-helpers.d.ts.map +1 -1
- package/dist/lib/url-helpers.js +3 -1
- package/dist/lib/url-helpers.js.map +1 -1
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +5 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/reachy-mini-sdk.d.ts +15 -1
- package/dist/reachy-mini-sdk.d.ts.map +1 -1
- package/dist/reachy-mini-sdk.js +12 -0
- package/dist/reachy-mini-sdk.js.map +1 -1
- package/host/dist/ReachyHost.d.ts.map +1 -1
- package/host/dist/chunks/centralRest-uXNMidlL.js +2315 -0
- package/host/dist/chunks/index-Beu4GNzi.js +821 -0
- package/host/dist/chunks/{mountHost-DztGlWwu.js → mountHost-BTTF4Uu9.js} +26739 -29305
- package/host/dist/components/DaemonUpdateGate.d.ts +65 -0
- package/host/dist/components/DaemonUpdateGate.d.ts.map +1 -0
- package/host/dist/components/ErrorView.d.ts.map +1 -1
- package/host/dist/components/HostErrorBoundary.d.ts +30 -0
- package/host/dist/components/HostErrorBoundary.d.ts.map +1 -0
- package/host/dist/components/PickerView.d.ts +16 -14
- package/host/dist/components/PickerView.d.ts.map +1 -1
- package/host/dist/components/PostOAuthSplash.d.ts +14 -9
- package/host/dist/components/PostOAuthSplash.d.ts.map +1 -1
- package/host/dist/components/ReachyHostShell.d.ts.map +1 -1
- package/host/dist/components/SignInView.d.ts.map +1 -1
- package/host/dist/components/TopBar.d.ts +5 -6
- package/host/dist/components/TopBar.d.ts.map +1 -1
- package/host/dist/embed/index.d.ts +8 -5
- package/host/dist/embed/index.d.ts.map +1 -1
- package/host/dist/entry/auto.js +2 -2
- package/host/dist/entry/embed.js +2 -2
- package/host/dist/hooks/useHostBridge.d.ts +35 -1
- package/host/dist/hooks/useHostBridge.d.ts.map +1 -1
- package/host/dist/hooks/useLatestDaemonVersion.d.ts +7 -0
- package/host/dist/hooks/useLatestDaemonVersion.d.ts.map +1 -0
- package/host/dist/hooks/useOAuth.d.ts +18 -0
- package/host/dist/hooks/useOAuth.d.ts.map +1 -1
- package/host/dist/hooks/useRobots.d.ts +0 -2
- package/host/dist/hooks/useRobots.d.ts.map +1 -1
- package/host/dist/index.js +3 -3
- package/host/dist/lib/daemonRelease.d.ts +84 -0
- package/host/dist/lib/daemonRelease.d.ts.map +1 -0
- package/host/dist/lib/protocol.d.ts +141 -7
- package/host/dist/lib/protocol.d.ts.map +1 -1
- package/host/dist/lib/rebootWatch.d.ts +51 -0
- package/host/dist/lib/rebootWatch.d.ts.map +1 -0
- package/host/dist/lib/sdk-types.d.ts +1 -1
- package/host/dist/lib/sdk-types.d.ts.map +1 -1
- package/host/dist/lib/sdkStaleness.d.ts +78 -0
- package/host/dist/lib/sdkStaleness.d.ts.map +1 -0
- package/host/dist/lib/settings.d.ts +16 -5
- package/host/dist/lib/settings.d.ts.map +1 -1
- package/package.json +9 -2
- package/host/dist/chunks/index-rW7LY0k3.js +0 -530
- package/host/dist/chunks/reachy-mini-DblK_lhG.js +0 -1749
- package/host/dist/lib/centralListener.d.ts +0 -73
- package/host/dist/lib/centralListener.d.ts.map +0 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* request() - the generic command round-trip escape hatch.
|
|
3
|
+
*
|
|
4
|
+
* The properties that must hold:
|
|
5
|
+
* - `request({type})` sends the command as-is and resolves with the
|
|
6
|
+
* first robot message whose `command` field echoes that type (the
|
|
7
|
+
* daemon's reply convention), so a new daemon command is usable
|
|
8
|
+
* without an SDK release;
|
|
9
|
+
* - unrelated replies don't settle the call, and a custom `match`
|
|
10
|
+
* predicate overrides the default echo matcher;
|
|
11
|
+
* - a daemon that never answers (predates the command) fail-opens to
|
|
12
|
+
* `null` on the shared round-trip timeout instead of hanging;
|
|
13
|
+
* - replies the SDK consumes internally (e.g. `get_imu`) are swallowed
|
|
14
|
+
* by their own handlers and never leak into a `request()` waiter;
|
|
15
|
+
* - a closed data channel rejects immediately.
|
|
16
|
+
*
|
|
17
|
+
* Same approach as the other SDK suites: private surface + a fake data
|
|
18
|
+
* channel, fake timers for the fail-open path.
|
|
19
|
+
*/
|
|
20
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
21
|
+
import { ReachyMini } from './reachy-mini.js';
|
|
22
|
+
function makeInstance() {
|
|
23
|
+
const r = new ReachyMini();
|
|
24
|
+
const internals = r;
|
|
25
|
+
const sent = [];
|
|
26
|
+
internals._dc = {
|
|
27
|
+
readyState: 'open',
|
|
28
|
+
send: (msg) => { sent.push(JSON.parse(msg)); },
|
|
29
|
+
};
|
|
30
|
+
return { r, internals, sent };
|
|
31
|
+
}
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
vi.useFakeTimers();
|
|
34
|
+
});
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
vi.useRealTimers();
|
|
37
|
+
});
|
|
38
|
+
describe('request - wire contract', () => {
|
|
39
|
+
it('sends the command and resolves the echoed reply untouched', async () => {
|
|
40
|
+
const { r, internals, sent } = makeInstance();
|
|
41
|
+
const promise = r.request({ type: 'get_battery', detail: true });
|
|
42
|
+
expect(sent).toEqual([{ type: 'get_battery', detail: true }]);
|
|
43
|
+
internals._handleRobotMessage({ command: 'get_battery', level: 0.87 });
|
|
44
|
+
await expect(promise).resolves.toEqual({ command: 'get_battery', level: 0.87 });
|
|
45
|
+
});
|
|
46
|
+
it('ignores unrelated replies while waiting', async () => {
|
|
47
|
+
const { r, internals } = makeInstance();
|
|
48
|
+
const settled = vi.fn();
|
|
49
|
+
void r.request({ type: 'get_battery' }).then(settled);
|
|
50
|
+
internals._handleRobotMessage({ command: 'get_something_else', value: 1 });
|
|
51
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
52
|
+
expect(settled).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
it('honors a custom match predicate for non-echo replies', async () => {
|
|
55
|
+
const { r, internals } = makeInstance();
|
|
56
|
+
const promise = r.request({ type: 'get_battery' }, { match: (m) => 'battery_level' in m });
|
|
57
|
+
internals._handleRobotMessage({ battery_level: 0.42 });
|
|
58
|
+
await expect(promise).resolves.toEqual({ battery_level: 0.42 });
|
|
59
|
+
});
|
|
60
|
+
it('does not steal replies owned by the SDK\'s typed handlers', async () => {
|
|
61
|
+
const { r, internals } = makeInstance();
|
|
62
|
+
const settled = vi.fn();
|
|
63
|
+
// get_imu replies are consumed by the imu reply slot before the
|
|
64
|
+
// broadcast matcher runs, even with no getImu() call pending.
|
|
65
|
+
void r.request({ type: 'get_imu' }).then(settled);
|
|
66
|
+
internals._handleRobotMessage({ command: 'get_imu', imu: null });
|
|
67
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
68
|
+
expect(settled).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('request - degraded paths', () => {
|
|
72
|
+
it('fail-opens to null when the daemon never answers (old daemon)', async () => {
|
|
73
|
+
const { r } = makeInstance();
|
|
74
|
+
const promise = r.request({ type: 'get_battery' });
|
|
75
|
+
await vi.advanceTimersByTimeAsync(4000);
|
|
76
|
+
await expect(promise).resolves.toBeNull();
|
|
77
|
+
});
|
|
78
|
+
it('respects a caller-provided timeout', async () => {
|
|
79
|
+
const { r } = makeInstance();
|
|
80
|
+
const promise = r.request({ type: 'get_battery' }, { timeoutMs: 500 });
|
|
81
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
82
|
+
await expect(promise).resolves.toBeNull();
|
|
83
|
+
});
|
|
84
|
+
it('rejects immediately when the data channel is not open', async () => {
|
|
85
|
+
const { r, internals } = makeInstance();
|
|
86
|
+
internals._dc = null;
|
|
87
|
+
await expect(r.request({ type: 'get_battery' })).rejects.toThrow(/Data channel not open/);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=request.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.test.js","sourceRoot":"","sources":["../../lib/request.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session resilience supervisor for the ReachyMini SDK.
|
|
3
|
+
*
|
|
4
|
+
* Owns the three transport-resilience mechanisms so the main class only
|
|
5
|
+
* has to forward browser/pc events and expose narrow accessors:
|
|
6
|
+
*
|
|
7
|
+
* 1. ICE-blip debounce + network awareness — grace windows around
|
|
8
|
+
* `iceConnectionState` transitions (visibility-deferred while the
|
|
9
|
+
* tab is hidden) and `online`/`offline`/`connection.change`
|
|
10
|
+
* forwarding as public events.
|
|
11
|
+
* 2. Automatic session re-dial — the daemon's `webrtcbin` cannot do a
|
|
12
|
+
* standards ICE restart (missing upstream support), so the recovery
|
|
13
|
+
* unit is the whole SESSION: tear down the dead RTCPeerConnection
|
|
14
|
+
* and dial the same robot again through central. Runs inside the
|
|
15
|
+
* SDK so every consumer (host embed, mobile app, third-party apps)
|
|
16
|
+
* inherits it.
|
|
17
|
+
* 3. Data-channel silence watchdog — application-level heartbeat
|
|
18
|
+
* without any daemon change: a streaming session already receives
|
|
19
|
+
* constant inbound traffic (get_state poll replies and/or pushed
|
|
20
|
+
* pose frames), so prolonged TOTAL silence is a dead transport that
|
|
21
|
+
* ICE hasn't noticed yet.
|
|
22
|
+
*
|
|
23
|
+
* The supervisor never touches the RTCPeerConnection, data channel or
|
|
24
|
+
* pending promises directly: every side effect goes through
|
|
25
|
+
* `SessionSupervisorDeps`, implemented by `ReachyMini` as closures over
|
|
26
|
+
* its own private state. That keeps the ownership boundary honest — the
|
|
27
|
+
* class owns the transport, the supervisor owns the RECOVERY POLICY.
|
|
28
|
+
*/
|
|
29
|
+
import type { ReachyMiniEventMap } from './types.js';
|
|
30
|
+
/**
|
|
31
|
+
* Everything the supervisor needs from `ReachyMini`, as read accessors
|
|
32
|
+
* and side-effect callbacks. Implemented with arrow closures so every
|
|
33
|
+
* call reads the CURRENT class state (tests stub instance methods and
|
|
34
|
+
* the closures pick the stubs up transparently).
|
|
35
|
+
*/
|
|
36
|
+
export interface SessionSupervisorDeps {
|
|
37
|
+
/** Live ICE state, or `null` when no RTCPeerConnection exists. */
|
|
38
|
+
iceState(): RTCIceConnectionState | null;
|
|
39
|
+
/** True while a live RTCPeerConnection exists. */
|
|
40
|
+
hasPc(): boolean;
|
|
41
|
+
/** True once the session reached `streaming`. */
|
|
42
|
+
isStreaming(): boolean;
|
|
43
|
+
/** True while startSession() is mid-handshake (resolvers armed). */
|
|
44
|
+
isMidSetup(): boolean;
|
|
45
|
+
/** True when the signaling SSE feed is down (`state === 'disconnected'`). */
|
|
46
|
+
isSignalingDown(): boolean;
|
|
47
|
+
/** Robot id of the current / last dialed session. */
|
|
48
|
+
selectedRobotId(): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Reject the pending startSession() promise, if armed, and clear the
|
|
51
|
+
* resolvers. Returns `true` when one was actually pending — the
|
|
52
|
+
* supervisor then leaves the retry decision to the original caller.
|
|
53
|
+
*/
|
|
54
|
+
rejectPendingSession(err: Error): boolean;
|
|
55
|
+
/** Re-establish the signaling feed (the SSE died with the network). */
|
|
56
|
+
reconnectSignaling(): Promise<void>;
|
|
57
|
+
/** One dial attempt: the class's full startSession() flow. */
|
|
58
|
+
dial(robotId: string): Promise<void>;
|
|
59
|
+
/** Transport-only teardown between attempts (owned by the class). */
|
|
60
|
+
teardownForRedial(): void;
|
|
61
|
+
/** Send one `get_state` probe over the data channel. */
|
|
62
|
+
nudgeState(): void;
|
|
63
|
+
/** Emit one public event on the instance. */
|
|
64
|
+
emit<K extends keyof ReachyMiniEventMap>(name: K, detail: ReachyMiniEventMap[K]['detail']): void;
|
|
65
|
+
}
|
|
66
|
+
export declare class SessionSupervisor {
|
|
67
|
+
private readonly _deps;
|
|
68
|
+
private _iceGraceTimer;
|
|
69
|
+
private _iceGraceReason;
|
|
70
|
+
private _pendingVisibilityHandler;
|
|
71
|
+
private _onlineHandler;
|
|
72
|
+
private _offlineHandler;
|
|
73
|
+
private _connectionChangeHandler;
|
|
74
|
+
private _autoReconnect;
|
|
75
|
+
private _redialing;
|
|
76
|
+
private _redialWake;
|
|
77
|
+
private _dcWatchdogId;
|
|
78
|
+
private _lastDcInboundAt;
|
|
79
|
+
private _dcWatchdogLastTickAt;
|
|
80
|
+
private _dcSilenceNudged;
|
|
81
|
+
constructor(deps: SessionSupervisorDeps, options: {
|
|
82
|
+
autoReconnect: boolean;
|
|
83
|
+
});
|
|
84
|
+
/** True while the re-dial loop is running. */
|
|
85
|
+
get redialing(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Enable/disable the automatic session re-dial at runtime.
|
|
88
|
+
* Disabling also aborts any re-dial already in flight.
|
|
89
|
+
*/
|
|
90
|
+
setAutoReconnect(enabled: boolean): void;
|
|
91
|
+
/** Fatal errors carry the classic webrtc `error` payload shape. */
|
|
92
|
+
private _emitError;
|
|
93
|
+
/** ICE healed back to `connected`/`completed`. */
|
|
94
|
+
onIceHealed(): void;
|
|
95
|
+
/**
|
|
96
|
+
* ICE hit `disconnected` — TRANSIENT per spec, debounce before
|
|
97
|
+
* escalating. If the tab is hidden, JS timers are throttled and
|
|
98
|
+
* would fire unpredictably late, so defer the grace window to the
|
|
99
|
+
* next foreground frame.
|
|
100
|
+
*/
|
|
101
|
+
onIceDisconnected(): void;
|
|
102
|
+
/**
|
|
103
|
+
* ICE hit `failed` — terminal per spec, but in practice we've seen
|
|
104
|
+
* `failed → connected` on rapid AP roams / BT route changes on iOS.
|
|
105
|
+
* Give the ICE agent a short window to surprise us before rejecting
|
|
106
|
+
* the session.
|
|
107
|
+
*/
|
|
108
|
+
onIceFailed(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Cancel any pending ICE grace timer and visibility handler. Called
|
|
111
|
+
* on a healed `connected`/`completed` transition AND from the
|
|
112
|
+
* lifecycle teardown paths so a callback can't fire after the pc
|
|
113
|
+
* is closed.
|
|
114
|
+
*/
|
|
115
|
+
clearIceGrace(): void;
|
|
116
|
+
/**
|
|
117
|
+
* Start a grace window. After `ms`, re-check the live ICE state:
|
|
118
|
+
* - If we healed back to `connected`/`completed`, the timer was
|
|
119
|
+
* already cancelled in the pc's state handler, so we never get
|
|
120
|
+
* here.
|
|
121
|
+
* - If we're still in the originally-observed bad state (or
|
|
122
|
+
* worse), surface the error and reject any pending session
|
|
123
|
+
* promise. The original code path is preserved verbatim so
|
|
124
|
+
* downstream consumers see the same `error` payload shape.
|
|
125
|
+
*/
|
|
126
|
+
private _scheduleIceGrace;
|
|
127
|
+
/**
|
|
128
|
+
* `disconnected` while the tab is hidden. JS timers are throttled
|
|
129
|
+
* in background tabs (Chrome clamps to ~1 Hz, Safari can pause
|
|
130
|
+
* altogether), so a foreground grace timer would either miss the
|
|
131
|
+
* window or fire long after the connection healed. Wait for the
|
|
132
|
+
* tab to come back, then re-evaluate.
|
|
133
|
+
*/
|
|
134
|
+
private _armIceGraceOnVisibility;
|
|
135
|
+
/**
|
|
136
|
+
* Install browser-level network listeners and forward them as
|
|
137
|
+
* public `networkOnline` / `networkOffline` / `networkChange`
|
|
138
|
+
* events on the instance. Idempotent: called from `startSession()`,
|
|
139
|
+
* removed by `uninstallNetworkListeners` on teardown. Reachable
|
|
140
|
+
* only when there's a live `window` (defensive guard for SSR /
|
|
141
|
+
* test environments).
|
|
142
|
+
*
|
|
143
|
+
* `online` / `offline` are semantically about CONNECTIVITY:
|
|
144
|
+
* "does the OS think we can reach the internet". They flip
|
|
145
|
+
* symmetrically.
|
|
146
|
+
*
|
|
147
|
+
* `connection.change` (NetworkInformation API, Chrome / Android
|
|
148
|
+
* WebView only) is semantically about the TRANSPORT: it fires
|
|
149
|
+
* on Wi-Fi → 4G swaps, AP roams, etc. without necessarily going
|
|
150
|
+
* through `offline`. We forward it as its own `networkChange`
|
|
151
|
+
* event rather than aliasing it onto `networkOnline`, so
|
|
152
|
+
* consumers don't have to guess whether they're seeing a real
|
|
153
|
+
* connectivity recovery or a silent transport swap.
|
|
154
|
+
*/
|
|
155
|
+
installNetworkListeners(): void;
|
|
156
|
+
/** Counterpart to `installNetworkListeners`. */
|
|
157
|
+
uninstallNetworkListeners(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Escalation funnel for dead-transport signals. Returns `true` when
|
|
160
|
+
* the failure is being handled by a re-dial (callers should then skip
|
|
161
|
+
* their fatal `error` emit). Only fires for an ESTABLISHED session:
|
|
162
|
+
* mid-setup failures keep rejecting the startSession() promise so the
|
|
163
|
+
* original caller stays in charge of retries.
|
|
164
|
+
*/
|
|
165
|
+
maybeBeginRedial(cause: string): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* The re-dial loop. One teardown, then up to REDIAL_BACKOFF_MS.length
|
|
168
|
+
* attempts, each preceded by its backoff slot. Every attempt re-runs
|
|
169
|
+
* the normal startSession() flow (and connect() first if the SSE feed
|
|
170
|
+
* died with the network), so a success is indistinguishable from a
|
|
171
|
+
* fresh session: `streaming` re-fires, videoTrack re-attaches, the
|
|
172
|
+
* pose subscription is re-asserted by the session-ready path.
|
|
173
|
+
*
|
|
174
|
+
* Exits early — without emitting anything further — when the user
|
|
175
|
+
* calls stopSession()/disconnect() or dials another robot, all of
|
|
176
|
+
* which flip `_redialing` off via `cancelRedial`.
|
|
177
|
+
*/
|
|
178
|
+
private _runRedialLoop;
|
|
179
|
+
/**
|
|
180
|
+
* Cancellable backoff sleep — `cancelRedial` wakes it immediately.
|
|
181
|
+
* A timer firing after a cancel is harmless: the loop re-checks
|
|
182
|
+
* `_redialing` right after every sleep.
|
|
183
|
+
*/
|
|
184
|
+
private _redialSleep;
|
|
185
|
+
/**
|
|
186
|
+
* Abort a pending re-dial. Called from stopSession(), disconnect()
|
|
187
|
+
* and an external startSession() — every path where the user (or the
|
|
188
|
+
* consumer app) takes over the session lifecycle.
|
|
189
|
+
*/
|
|
190
|
+
cancelRedial(): void;
|
|
191
|
+
/** (Re)start the watchdog. Called when a session reaches ready. */
|
|
192
|
+
startDcWatchdog(): void;
|
|
193
|
+
stopDcWatchdog(): void;
|
|
194
|
+
/**
|
|
195
|
+
* Liveness stamp: every inbound data-channel message — control
|
|
196
|
+
* replies, broadcasts, pose frames — proves the transport is alive.
|
|
197
|
+
*/
|
|
198
|
+
stampDcInbound(): void;
|
|
199
|
+
private _dcWatchdogTick;
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=session-supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-supervisor.d.ts","sourceRoot":"","sources":["../../lib/session-supervisor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgDrD;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IAClC,kEAAkE;IAClE,QAAQ,IAAI,qBAAqB,GAAG,IAAI,CAAC;IACzC,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC;IACjB,iDAAiD;IACjD,WAAW,IAAI,OAAO,CAAC;IACvB,oEAAoE;IACpE,UAAU,IAAI,OAAO,CAAC;IACtB,6EAA6E;IAC7E,eAAe,IAAI,OAAO,CAAC;IAC3B,qDAAqD;IACrD,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,oBAAoB,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC;IAC1C,uEAAuE;IACvE,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,8DAA8D;IAC9D,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,qEAAqE;IACrE,iBAAiB,IAAI,IAAI,CAAC;IAC1B,wDAAwD;IACxD,UAAU,IAAI,IAAI,CAAC;IACnB,6CAA6C;IAC7C,IAAI,CAAC,CAAC,SAAS,MAAM,kBAAkB,EACnC,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GACxC,IAAI,CAAC;CACX;AAID,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAK9C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,yBAAyB,CAA6B;IAG9D,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,wBAAwB,CAA6B;IAK7D,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA6B;IAGhD,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,gBAAgB,CAAS;gBAErB,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE;IAK5E,8CAA8C;IAC9C,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKxC,mEAAmE;IACnE,OAAO,CAAC,UAAU;IAYlB,kDAAkD;IAClD,WAAW,IAAI,IAAI;IAInB;;;;;OAKG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;;;;OAKG;IACH,WAAW,IAAI,IAAI;IAInB;;;;;OAKG;IACH,aAAa,IAAI,IAAI;IAYrB;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAwCzB;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IA6ChC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,uBAAuB,IAAI,IAAI;IA+B/B,gDAAgD;IAChD,yBAAyB,IAAI,IAAI;IAwBjC;;;;;;OAMG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAYxC;;;;;;;;;;;OAWG;YACW,cAAc;IA6C5B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAWpB;;;;OAIG;IACH,YAAY,IAAI,IAAI;IAYpB,mEAAmE;IACnE,eAAe,IAAI,IAAI;IASvB,cAAc,IAAI,IAAI;IAOtB;;;OAGG;IACH,cAAc,IAAI,IAAI;IAKtB,OAAO,CAAC,eAAe;CA+C1B"}
|