@pollen-robotics/reachy-mini-sdk 1.10.0-dev.0.main.b50d97e → 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 +202 -88
- package/dist/lib/reachy-mini.d.ts.map +1 -1
- package/dist/lib/reachy-mini.js +651 -566
- 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 +280 -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-DjE5zE9R.js → mountHost-BTTF4Uu9.js} +24933 -27488
- package/host/dist/components/ConnectingView.d.ts.map +1 -1
- 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/LeavingView.d.ts.map +1 -1
- 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/components/WelcomeBackOverlay.d.ts.map +1 -1
- package/host/dist/embed/index.d.ts +68 -5
- package/host/dist/embed/index.d.ts.map +1 -1
- package/host/dist/entry/auto.js +2 -2
- package/host/dist/entry/embed.d.ts +5 -4
- package/host/dist/entry/embed.d.ts.map +1 -1
- package/host/dist/entry/embed.js +5 -4
- 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.d.ts +2 -2
- package/host/dist/index.d.ts.map +1 -1
- package/host/dist/index.js +11 -10
- 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 +11 -4
- package/host/dist/chunks/index-lMs2sCXG.js +0 -439
- package/host/dist/chunks/reachy-mini-CdsdQLIU.js +0 -1523
- package/host/dist/lib/centralListener.d.ts +0 -73
- package/host/dist/lib/centralListener.d.ts.map +0 -1
package/host/dist/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { R as o } from "./chunks/
|
|
2
|
-
import { R as
|
|
3
|
-
import { c as
|
|
4
|
-
import { PROTOCOL_VERSION as
|
|
1
|
+
import { R as o } from "./chunks/centralRest-uXNMidlL.js";
|
|
2
|
+
import { R as i, m as a } from "./chunks/mountHost-BTTF4Uu9.js";
|
|
3
|
+
import { c as r, a as c } from "./chunks/index-Beu4GNzi.js";
|
|
4
|
+
import { PROTOCOL_VERSION as m, decodeCredsFromHash as w, encodeCredsToHash as h, isProtocolMessage as y } from "./lib/protocol.js";
|
|
5
5
|
typeof window < "u" && !window.ReachyMini && (window.ReachyMini = o, window.dispatchEvent(new Event("reachymini:ready")));
|
|
6
6
|
export {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
w as
|
|
12
|
-
h as
|
|
7
|
+
m as PROTOCOL_VERSION,
|
|
8
|
+
i as ReachyHost,
|
|
9
|
+
r as connectToHost,
|
|
10
|
+
c as connectToHostCredsOnly,
|
|
11
|
+
w as decodeCredsFromHash,
|
|
12
|
+
h as encodeCredsToHash,
|
|
13
|
+
y as isProtocolMessage,
|
|
13
14
|
a as mountHost
|
|
14
15
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon version policy for the standalone web shell.
|
|
3
|
+
*
|
|
4
|
+
* Why the shell cares
|
|
5
|
+
* ───────────────────
|
|
6
|
+
* A Space runs against whatever daemon the user's robot happens to have.
|
|
7
|
+
* Neither central nor the host holds a data channel, so the only version
|
|
8
|
+
* signal is the one the embed forwards on `embed:app-state` once its
|
|
9
|
+
* session is up (`daemonVersion`).
|
|
10
|
+
*
|
|
11
|
+
* Why this is softer than the mobile app
|
|
12
|
+
* ──────────────────────────────────────
|
|
13
|
+
* The mobile app blocks the moment the daemon is behind the latest
|
|
14
|
+
* GitHub release. That is defensible for a controlled first-party
|
|
15
|
+
* funnel; it is not for the web, where every published Space would turn
|
|
16
|
+
* a daemon release into a global kill switch for robots that were
|
|
17
|
+
* working fine a minute earlier. So the web policy has two tiers:
|
|
18
|
+
*
|
|
19
|
+
* block - the daemon is below `MIN_SUPPORTED_DAEMON_VERSION`, i.e.
|
|
20
|
+
* too old for the app contract to hold. Blocking is the only
|
|
21
|
+
* honest answer.
|
|
22
|
+
* notice - the daemon merely trails the latest release. Dismissable
|
|
23
|
+
* banner, the app stays usable.
|
|
24
|
+
*
|
|
25
|
+
* Fail-open discipline
|
|
26
|
+
* ────────────────────
|
|
27
|
+
* Every unknown resolves to "no action". An unparseable version, a
|
|
28
|
+
* daemon too old to answer `get_version`, an offline or rate-limited
|
|
29
|
+
* GitHub: none of these may ever cost the user their app. We only act
|
|
30
|
+
* on versions we positively understand.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Floor below which the shell refuses to run an app.
|
|
34
|
+
*
|
|
35
|
+
* Set to the first release that understands the WebRTC `start_update`
|
|
36
|
+
* command (reachy_mini#1208, v1.8.2), which makes it the lowest version
|
|
37
|
+
* we can still repair from here: under it, the gate's own "Update now"
|
|
38
|
+
* button would do nothing and the user has to go through the desktop
|
|
39
|
+
* app anyway.
|
|
40
|
+
*/
|
|
41
|
+
export declare const MIN_SUPPORTED_DAEMON_VERSION = "1.8.2";
|
|
42
|
+
export interface SemVer {
|
|
43
|
+
major: number;
|
|
44
|
+
minor: number;
|
|
45
|
+
patch: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse a `MAJOR.MINOR.PATCH` string into a `SemVer`. Tolerates a
|
|
49
|
+
* leading `v` (GitHub tags) and trailing pre-release / build metadata
|
|
50
|
+
* (`1.8.2-rc1` → `1.8.2`). Returns `null` when the first three numeric
|
|
51
|
+
* components can't be read, so callers can fail-open.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseSemver(value: string | null | undefined): SemVer | null;
|
|
54
|
+
/** Negative if `a < b`, positive if `a > b`, 0 if equal. */
|
|
55
|
+
export declare function compareSemver(a: SemVer, b: SemVer): number;
|
|
56
|
+
/**
|
|
57
|
+
* True only when BOTH versions parse AND `current` is strictly behind
|
|
58
|
+
* `latest`. Any unparseable input returns `false` (fail-open).
|
|
59
|
+
*/
|
|
60
|
+
export declare function isDaemonOutdated(current: string | null | undefined, latest: string | null | undefined): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* What the shell should do about this daemon.
|
|
63
|
+
*
|
|
64
|
+
* `'block'` - below the supported floor: hard gate.
|
|
65
|
+
* `'notice'` - behind the latest release: dismissable banner.
|
|
66
|
+
* `null` - up to date, or not enough information to judge.
|
|
67
|
+
*/
|
|
68
|
+
export type DaemonUpdateSeverity = 'block' | 'notice';
|
|
69
|
+
export declare function daemonUpdateSeverity(current: string | null | undefined, latest: string | null | undefined): DaemonUpdateSeverity | null;
|
|
70
|
+
/**
|
|
71
|
+
* True when the daemon is new enough to install its own update over the
|
|
72
|
+
* data channel. Unknown / unparseable → false, so the caller points the
|
|
73
|
+
* user at the desktop app rather than offering a dead button.
|
|
74
|
+
*/
|
|
75
|
+
export declare function supportsSelfUpdate(current: string | null | undefined): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Resolve the latest published daemon version (e.g. `"1.8.2"`), or
|
|
78
|
+
* `null` when it can't be determined. Cached in localStorage for
|
|
79
|
+
* `TTL_MS`: the unauthenticated GitHub API allows 60 requests per
|
|
80
|
+
* hour per IP, and a Space reloads far more often than daemons ship.
|
|
81
|
+
* Never throws.
|
|
82
|
+
*/
|
|
83
|
+
export declare function fetchLatestDaemonVersion(): Promise<string | null>;
|
|
84
|
+
//# sourceMappingURL=daemonRelease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemonRelease.d.ts","sourceRoot":"","sources":["../../src/lib/daemonRelease.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAWH;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,UAAU,CAAC;AAEpD,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAS3E;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,OAAO,CAKT;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,oBAAoB,GAAG,IAAI,CAW7B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAI9E;AAsBD;;;;;;GAMG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBvE"}
|
|
@@ -14,10 +14,12 @@
|
|
|
14
14
|
* - Every message carries `source: 'reachy-mini'`. Lets receivers
|
|
15
15
|
* distinguish our envelopes from unrelated `postMessage` traffic
|
|
16
16
|
* (DevTools, MUI portals, browser extensions, ...).
|
|
17
|
-
* - Both sides validate `event.origin`
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* - Both sides validate `event.origin` before trusting the payload,
|
|
18
|
+
* but against different references: the web shell requires strict
|
|
19
|
+
* same-origin (`window.location.origin` - Mode A, the Space embeds
|
|
20
|
+
* itself), while the embed accepts its PARENT's origin resolved via
|
|
21
|
+
* `document.referrer` (Mode B, the mobile shell at e.g.
|
|
22
|
+
* `tauri.localhost` is a different origin by construction).
|
|
21
23
|
*
|
|
22
24
|
* Message families
|
|
23
25
|
* ────────────────
|
|
@@ -87,8 +89,19 @@ export interface HostInitMsg {
|
|
|
87
89
|
hfToken?: string;
|
|
88
90
|
/** HF account user name, when known. */
|
|
89
91
|
userName?: string | null;
|
|
90
|
-
/** Robot ID selected by the host's picker.
|
|
92
|
+
/** Robot ID selected by the host's picker. Unstable: the central
|
|
93
|
+
* peer id rotates on every relay reconnect, so the embed treats
|
|
94
|
+
* this as a starting point and re-resolves the live id from
|
|
95
|
+
* `robotHardwareId` right before `startSession()`. */
|
|
91
96
|
robotPeerId: string;
|
|
97
|
+
/** Stable hardware id of the selected robot (central
|
|
98
|
+
* `meta.hardware_id`), when the daemon exposes one. Lets the embed
|
|
99
|
+
* re-resolve the CURRENT `robotPeerId` from central just before
|
|
100
|
+
* dialing, so a rotated peer id (long iframe cold-start, relay
|
|
101
|
+
* reconnect) doesn't strand the app on a dead producer. Omitted for
|
|
102
|
+
* daemons too old to advertise it - the embed then uses
|
|
103
|
+
* `robotPeerId` as-is. */
|
|
104
|
+
robotHardwareId?: string | null;
|
|
92
105
|
/** Optional opaque payload from `?config=<base64>` or from the
|
|
93
106
|
* mobile-app handoff. App is responsible for parsing /
|
|
94
107
|
* validating. */
|
|
@@ -133,7 +146,45 @@ export interface HostLeavingMsg {
|
|
|
133
146
|
* regardless. */
|
|
134
147
|
timeoutMs: number;
|
|
135
148
|
}
|
|
136
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Ask the embed to trigger the daemon's PyPI self-update.
|
|
151
|
+
*
|
|
152
|
+
* Only the embed holds a data channel, so the host cannot send
|
|
153
|
+
* `start_update` itself - it delegates here and watches the
|
|
154
|
+
* `embed:update-progress` replies. A successful update ends with a
|
|
155
|
+
* `systemctl restart` on the robot, which kills the session: the embed
|
|
156
|
+
* will go silent and the host is expected to remount the iframe once
|
|
157
|
+
* the robot is back on central.
|
|
158
|
+
*
|
|
159
|
+
* Additive message (no version bump): an embed too old to know this
|
|
160
|
+
* type ignores it, so the host must not block on a reply.
|
|
161
|
+
*/
|
|
162
|
+
export interface HostStartUpdateMsg {
|
|
163
|
+
source: typeof PROTOCOL_SOURCE;
|
|
164
|
+
type: 'host:start-update';
|
|
165
|
+
version: 1;
|
|
166
|
+
/** Install the latest pre-release instead of the latest stable. */
|
|
167
|
+
preRelease?: boolean;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The host gave up on the update it started (its own stall timer
|
|
171
|
+
* fired while the session was still alive). This does NOT abort the
|
|
172
|
+
* daemon-side job - nothing can, the install owns the robot - it
|
|
173
|
+
* disarms the embed's update-mode plumbing: the sessionStopped →
|
|
174
|
+
* `rebooting` translator and the auto-reconnect stand-down. Without
|
|
175
|
+
* it, the user's next NORMAL end-session would replay a stale
|
|
176
|
+
* `rebooting` frame into a host that already declared the update
|
|
177
|
+
* failed.
|
|
178
|
+
*
|
|
179
|
+
* Additive message (no version bump): an embed too old to know this
|
|
180
|
+
* type ignores it, and its own translator dies with the iframe.
|
|
181
|
+
*/
|
|
182
|
+
export interface HostCancelUpdateMsg {
|
|
183
|
+
source: typeof PROTOCOL_SOURCE;
|
|
184
|
+
type: 'host:cancel-update';
|
|
185
|
+
version: 1;
|
|
186
|
+
}
|
|
187
|
+
export type HostToEmbedMsg = HostInitMsg | HostThemeChangedMsg | HostConfigChangedMsg | HostLeavingMsg | HostStartUpdateMsg | HostCancelUpdateMsg;
|
|
137
188
|
/**
|
|
138
189
|
* Emitted by the app as early as possible (synchronous tick of
|
|
139
190
|
* the embed entry, before the SDK is touched). Tells the host
|
|
@@ -175,6 +226,65 @@ export interface EmbedAppStateMsg {
|
|
|
175
226
|
* ignore it.
|
|
176
227
|
*/
|
|
177
228
|
rttMs?: number | null;
|
|
229
|
+
/**
|
|
230
|
+
* Daemon version reported by the robot (`get_version` over the data
|
|
231
|
+
* channel), resolved once the session is up. Additive field (no
|
|
232
|
+
* version bump).
|
|
233
|
+
*
|
|
234
|
+
* The host has no data channel of its own and central exposes no
|
|
235
|
+
* version, so this is the ONLY way a shell can tell whether the robot
|
|
236
|
+
* it just handed the app to is running current software. The web
|
|
237
|
+
* shell uses it to gate on a minimum supported version; hosts that
|
|
238
|
+
* don't care ignore it.
|
|
239
|
+
*
|
|
240
|
+
* `null` (or omitted) until resolved, or when the daemon predates
|
|
241
|
+
* `get_version`. Receivers MUST treat "unknown" as "fine" - never
|
|
242
|
+
* block a robot just because it stayed silent.
|
|
243
|
+
*/
|
|
244
|
+
daemonVersion?: string | null;
|
|
245
|
+
/**
|
|
246
|
+
* Build version of the SDK bundle the app loaded
|
|
247
|
+
* (`ReachyMini.version`, generated at publish time). Additive field
|
|
248
|
+
* (no version bump).
|
|
249
|
+
*
|
|
250
|
+
* The embed rides whatever `window.ReachyMini` the app shipped, so
|
|
251
|
+
* this tells the shell how stale the app's robot stack is - e.g. to
|
|
252
|
+
* warn that behaviour may be off against a newer daemon. `null` (or
|
|
253
|
+
* omitted) when the SDK predates the field - which, unlike
|
|
254
|
+
* `daemonVersion`, is a meaningful signal: every SDK from the release
|
|
255
|
+
* that introduced this field reports it, so silence through a live
|
|
256
|
+
* session means "built before that". Receivers may surface a notice
|
|
257
|
+
* on it, but MUST never block on it.
|
|
258
|
+
*/
|
|
259
|
+
sdkVersion?: string | null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Progress of a `host:start-update` job, relayed from the SDK's
|
|
263
|
+
* `update_progress` stream one message per log line.
|
|
264
|
+
*
|
|
265
|
+
* in_progress : a log line of the install.
|
|
266
|
+
* rebooting : the WebRTC session died while the update was in
|
|
267
|
+
* flight. Synthesised by the embed, NOT by the daemon -
|
|
268
|
+
* a successful install restarts the daemon before it
|
|
269
|
+
* can report anything, so the transport dropping is the
|
|
270
|
+
* success signal. Nothing more will arrive on this
|
|
271
|
+
* channel: the host should tear the iframe down and
|
|
272
|
+
* wait for the robot to reappear on central.
|
|
273
|
+
* done : the daemon explicitly reported completion. Rare (see
|
|
274
|
+
* above), but forwarded when it happens.
|
|
275
|
+
* failed : the daemon declined the job (not wireless, no update
|
|
276
|
+
* available, one already running) or the install raised
|
|
277
|
+
* before the restart.
|
|
278
|
+
*/
|
|
279
|
+
export interface EmbedUpdateProgressMsg {
|
|
280
|
+
source: typeof PROTOCOL_SOURCE;
|
|
281
|
+
type: 'embed:update-progress';
|
|
282
|
+
version: 1;
|
|
283
|
+
status: 'in_progress' | 'rebooting' | 'done' | 'failed';
|
|
284
|
+
/** Log line for `in_progress`. */
|
|
285
|
+
line?: string | null;
|
|
286
|
+
/** Reason for `failed`. */
|
|
287
|
+
error?: string | null;
|
|
178
288
|
}
|
|
179
289
|
/** App requests to leave (user clicked an in-app exit, error,
|
|
180
290
|
* ...). The host runs the same tear-down as a top-bar
|
|
@@ -184,6 +294,22 @@ export interface EmbedRequestLeaveMsg {
|
|
|
184
294
|
type: 'embed:request-leave';
|
|
185
295
|
version: 1;
|
|
186
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* The embed finished its `host:leaving` tear-down: app `onLeave`
|
|
299
|
+
* callbacks ran AND the SDK's host-owned sleep sequence completed
|
|
300
|
+
* (goto_sleep trajectory + motors disabled). Lets the host unmount as
|
|
301
|
+
* soon as the robot is actually asleep instead of after a fixed
|
|
302
|
+
* worst-case timeout - and, because the WebRTC session is still up when
|
|
303
|
+
* this fires, the motors are already `Disabled` before the app-slot lock
|
|
304
|
+
* frees, so the daemon's idle-reset sees "already asleep" and does NOT
|
|
305
|
+
* replay a second goto_sleep (no double trajectory / go_sleep sound).
|
|
306
|
+
* The host still force-unmounts after its own cap if this never arrives.
|
|
307
|
+
*/
|
|
308
|
+
export interface EmbedLeftMsg {
|
|
309
|
+
source: typeof PROTOCOL_SOURCE;
|
|
310
|
+
type: 'embed:left';
|
|
311
|
+
version: 1;
|
|
312
|
+
}
|
|
187
313
|
/** App-level error report. `fatal: true` switches the host to
|
|
188
314
|
* ErrorView; `fatal: false` is logged and may surface a toast. */
|
|
189
315
|
export interface EmbedErrorMsg {
|
|
@@ -194,7 +320,7 @@ export interface EmbedErrorMsg {
|
|
|
194
320
|
fatal: boolean;
|
|
195
321
|
detail?: unknown;
|
|
196
322
|
}
|
|
197
|
-
export type EmbedToHostMsg = EmbedReadyMsg | EmbedAppStateMsg | EmbedRequestLeaveMsg | EmbedErrorMsg;
|
|
323
|
+
export type EmbedToHostMsg = EmbedReadyMsg | EmbedAppStateMsg | EmbedRequestLeaveMsg | EmbedLeftMsg | EmbedErrorMsg | EmbedUpdateProgressMsg;
|
|
198
324
|
/**
|
|
199
325
|
* Serialised credentials passed from the host (Mode A) or the
|
|
200
326
|
* mobile app (Mode B) to the embed via the URL hash fragment.
|
|
@@ -211,6 +337,14 @@ export interface CredsBundle {
|
|
|
211
337
|
hfToken?: string | null;
|
|
212
338
|
userName?: string | null;
|
|
213
339
|
robotPeerId: string;
|
|
340
|
+
/** Stable hardware id of the selected robot (central
|
|
341
|
+
* `meta.hardware_id`), when the daemon exposes one. Lets the embed
|
|
342
|
+
* re-resolve the CURRENT `robotPeerId` from central just before
|
|
343
|
+
* dialing, so a rotated peer id (long iframe cold-start, relay
|
|
344
|
+
* reconnect) doesn't strand the app on a dead producer. Omitted for
|
|
345
|
+
* daemons too old to advertise it - the embed then uses
|
|
346
|
+
* `robotPeerId` as-is. */
|
|
347
|
+
robotHardwareId?: string | null;
|
|
214
348
|
signalingUrl: string;
|
|
215
349
|
theme: ThemeMode;
|
|
216
350
|
config: ConfigPayload;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/lib/protocol.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/lib/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline-first latch for the daemon-update reboot watch.
|
|
3
|
+
*
|
|
4
|
+
* Problem: when the daemon restarts mid-update, the shell tears the
|
|
5
|
+
* iframe down and waits for the robot to reappear on central before
|
|
6
|
+
* telling `DaemonUpdateGate` the update is done. But central can keep
|
|
7
|
+
* the robot's PRE-reboot registration listed for a while (the SSE
|
|
8
|
+
* offline event or the listing TTL hasn't fired yet), so "the robot is
|
|
9
|
+
* listed" alone reads the STALE entry as "back online" seconds after
|
|
10
|
+
* the reboot started - the gate then declares success while the robot
|
|
11
|
+
* is still down, and the user re-picks a dead robot.
|
|
12
|
+
*
|
|
13
|
+
* Peer-id exclusion doesn't fix this: the embed re-resolves the live
|
|
14
|
+
* peer id right before dialing, so the shell doesn't reliably know
|
|
15
|
+
* which id the stale listing carries. What IS reliable is the order of
|
|
16
|
+
* observations: the dying relay connection makes central drop the old
|
|
17
|
+
* registration (realtime SSE `roles: []` event), and only then does the
|
|
18
|
+
* rebooted daemon re-register under a fresh id. So the watch requires
|
|
19
|
+
* seeing the robot ABSENT from the list at least once (the sticky
|
|
20
|
+
* `sawTargetOffline` boolean) before accepting its presence as "back
|
|
21
|
+
* online". Callers must skip observations while the list is still in
|
|
22
|
+
* its initial-loading window, where an empty array means "no data yet".
|
|
23
|
+
*
|
|
24
|
+
* If central never drops the stale entry (not observed in practice -
|
|
25
|
+
* the relay socket dies with the daemon), the watch never completes and
|
|
26
|
+
* the gate's reboot timeout produces an honest "check your robot"
|
|
27
|
+
* message instead of a false success.
|
|
28
|
+
*/
|
|
29
|
+
import type { RobotInfo } from './sdk-types';
|
|
30
|
+
/** What the shell remembers about the robot it dropped mid-update. */
|
|
31
|
+
export interface RebootTarget {
|
|
32
|
+
/** Stable hardware id (serial), the strongest match. */
|
|
33
|
+
hardwareId: string | null;
|
|
34
|
+
/** Advertised name, fallback for daemons without a hardware id. */
|
|
35
|
+
name: string | null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Is the rebooting robot present in the central listing? Matched on
|
|
39
|
+
* hardware id first (survives the peer-id rotation), then name. With
|
|
40
|
+
* neither identity (older daemon), fall back to "any robot listed":
|
|
41
|
+
* combined with the offline-first latch this means "the list emptied,
|
|
42
|
+
* then repopulated", which is correct for single-robot accounts and
|
|
43
|
+
* degrades to the gate's reboot timeout on multi-robot ones.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isTargetListed(robots: readonly RobotInfo[], target: RebootTarget): boolean;
|
|
46
|
+
/** Sticky offline latch, advanced on every settled observation: once
|
|
47
|
+
* the target has been seen absent, it stays seen. The watch completes
|
|
48
|
+
* when `sawTargetOffline(...) && isTargetListed(...)` - never on a run
|
|
49
|
+
* of presence-only observations (the stale-listing regression). */
|
|
50
|
+
export declare function sawTargetOffline(prev: boolean, targetListed: boolean): boolean;
|
|
51
|
+
//# sourceMappingURL=rebootWatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rebootWatch.d.ts","sourceRoot":"","sources":["../../src/lib/rebootWatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mEAAmE;IACnE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,MAAM,EAAE,YAAY,GACnB,OAAO,CAMT;AAED;;;oEAGoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAE9E"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* `ts/lib/types.ts` (re-exported from `ts/reachy-mini-sdk.ts`) — the
|
|
11
11
|
* shipped `.d.ts` is auto-generated by `tsc` from that source.
|
|
12
12
|
*/
|
|
13
|
-
export type { RobotInfo, RobotState, ReachyMiniOptions, ReachyMiniInstance, ReachyMiniConstructor, AutoConnectOptions, AutoConnectRobotChoice, AutoConnectResult, MotionAwaitOptions, SubscribeLogsOptions, } from '@pollen-robotics/reachy-mini-sdk';
|
|
13
|
+
export type { RobotInfo, RobotState, ReachyMiniOptions, ReachyMiniInstance, ReachyMiniConstructor, AutoConnectOptions, AutoConnectRobotChoice, AutoConnectResult, MotionAwaitOptions, SubscribeLogsOptions, StartDaemonUpdateOptions, UpdateProgressEvent, } from '@pollen-robotics/reachy-mini-sdk';
|
|
14
14
|
import type { ReachyMiniConstructor } from '@pollen-robotics/reachy-mini-sdk';
|
|
15
15
|
/**
|
|
16
16
|
* Host-internal global augmentation: the host shell instantiates
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-types.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,YAAY,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"sdk-types.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,YAAY,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAE9E;;;;;;;;;;;;;;GAcG;AACH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,EAAE,qBAAqB,CAAC;QAClC;gEACwD;QACxD,WAAW,CAAC,EAAE;YACZ,SAAS,CAAC,EAAE;gBACV,eAAe,CAAC,EAAE,MAAM,CAAC;gBACzB,YAAY,CAAC,EAAE,MAAM,CAAC;gBACtB,UAAU,CAAC,EAAE,MAAM,CAAC;gBACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;aACnB,CAAC;SACH,CAAC;KACH;CACF;AAED,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK staleness self-check for the embed runtime.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists
|
|
5
|
+
* ───────────────
|
|
6
|
+
* A published Space bundles its SDK at build time and is never
|
|
7
|
+
* rebuilt: if a bundled SDK generation ever becomes incompatible with
|
|
8
|
+
* the deployed daemons, there is NO channel to tell the users of those
|
|
9
|
+
* frozen apps - except code that ships inside the app itself. This
|
|
10
|
+
* module is that channel. It runs inside the iframe, so every host
|
|
11
|
+
* (web shell, mobile WebView, anything future) is covered with zero
|
|
12
|
+
* parent integration. The one case it structurally cannot cover is a
|
|
13
|
+
* bundle that predates this very check; an independently-updated
|
|
14
|
+
* parent catches that instead (the mobile app, via the absence of
|
|
15
|
+
* `sdkVersion` on app-state).
|
|
16
|
+
*
|
|
17
|
+
* Why it is this conservative (learned in #1316 review)
|
|
18
|
+
* ─────────────────────────────────────────────────────
|
|
19
|
+
* The first cut of this feature was the "global kill switch" the
|
|
20
|
+
* daemon update policy explicitly argues against: it warned on ANY
|
|
21
|
+
* version gap, full-screen, on every reload, comparing the npm bundle
|
|
22
|
+
* version against the DAEMON's GitHub release tag - two version lines
|
|
23
|
+
* that only agree while they happen to be tagged together. This
|
|
24
|
+
* version inverts every one of those choices:
|
|
25
|
+
*
|
|
26
|
+
* - source of truth: the npm registry entry of the package itself.
|
|
27
|
+
* The registry is what apps actually install from, so it cannot
|
|
28
|
+
* drift from the bundle's own version line.
|
|
29
|
+
* - trigger: MAJOR gap only. A major bump is the only signal that
|
|
30
|
+
* the app/robot contract may genuinely no longer hold; minor and
|
|
31
|
+
* patch releases must never nag a working app.
|
|
32
|
+
* - dismissal: persisted (localStorage). One "I understand" covers
|
|
33
|
+
* everything up to the dismissed major; the overlay returns only
|
|
34
|
+
* when a NEWER major ships.
|
|
35
|
+
* - theming: follows `prefers-color-scheme` instead of hardcoding a
|
|
36
|
+
* light card into apps that may be dark.
|
|
37
|
+
*
|
|
38
|
+
* Fail-open discipline: unparseable versions, dev placeholders
|
|
39
|
+
* (`0.x`), an unreachable registry - all resolve to "stay silent".
|
|
40
|
+
* Advisory code must never cost the user their app.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the latest published SDK version from the npm registry's
|
|
44
|
+
* `latest` dist-tag (a ~200-byte JSON, CORS-enabled), or `null` when
|
|
45
|
+
* it can't be determined. Cached in localStorage for `TTL_MS`; a
|
|
46
|
+
* failed refresh serves the stale value rather than flapping to null.
|
|
47
|
+
* Never throws.
|
|
48
|
+
*/
|
|
49
|
+
export declare function fetchLatestSdkVersion(): Promise<string | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Should the overlay show for this current/latest pair? True only
|
|
52
|
+
* when BOTH versions parse, the current one is a real release (not a
|
|
53
|
+
* `0.x` dev placeholder), and the latest is a strictly NEWER MAJOR.
|
|
54
|
+
* Anything unknown resolves to false.
|
|
55
|
+
*/
|
|
56
|
+
export declare function isSdkMajorBehind(current: string | null | undefined, latest: string | null | undefined): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* A dismissal covers every release up to the dismissed latest's
|
|
59
|
+
* major: the overlay returns only when a newer major ships than the
|
|
60
|
+
* one the user already acknowledged.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isSdkWarningDismissed(latest: string | null | undefined): boolean;
|
|
63
|
+
export declare function dismissSdkWarning(latest: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Fire-and-forget entry point for the embed: check, and show the
|
|
66
|
+
* overlay when (and only when) the bundled SDK is a full major behind
|
|
67
|
+
* the npm registry and the user hasn't already acknowledged that
|
|
68
|
+
* major. Never throws, never blocks the session.
|
|
69
|
+
*/
|
|
70
|
+
export declare function maybeWarnSdkStale(currentVersion: string | null): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Plain-DOM overlay (the embed is framework-agnostic). Colors follow
|
|
73
|
+
* `prefers-color-scheme` - an advisory card must not hardcode a light
|
|
74
|
+
* theme into an app that may be dark. Exported for tests; production
|
|
75
|
+
* code goes through `maybeWarnSdkStale`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function showSdkStalenessOverlay(current: string, latest: string): void;
|
|
78
|
+
//# sourceMappingURL=sdkStaleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdkStaleness.d.ts","sourceRoot":"","sources":["../../src/lib/sdkStaleness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AA6CH;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBpE;AAID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,OAAO,CAMT;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAChC,OAAO,CAUT;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMtD;AAID;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,OAAO,CAAC,IAAI,CAAC,CASf;AAWD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,IAAI,CA2DN"}
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Storage rules (APP_CREATION_GUIDE §13.5.2 hash-only creds):
|
|
14
14
|
* - HF token + user name live in `sessionStorage` (tab-scoped,
|
|
15
|
-
*
|
|
16
|
-
* `hf_token` / `hf_username` / `hf_token_expires
|
|
15
|
+
* dies with the tab). The Reachy Mini SDK owns those keys via its
|
|
16
|
+
* token-store (`hf_token` / `hf_username` / `hf_token_expires` /
|
|
17
|
+
* `hf_token_last_seen`), which bounds their lifetime with the OAuth
|
|
18
|
+
* expiry plus a sliding idle window.
|
|
17
19
|
* - Persistent flags (`hf_oauth_client_id`, `oauth-pending`,
|
|
18
|
-
* `signed-out`) live in `localStorage
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* `signed-out`) live in `localStorage`; the one-shot silent-auth
|
|
21
|
+
* attempt flag lives in `sessionStorage` (must survive the OAuth
|
|
22
|
+
* redirect round trip but reset with a fresh tab).
|
|
21
23
|
*/
|
|
22
24
|
export type ClientIdSource = 'none' | 'caller' | 'space' | 'localStorage';
|
|
23
25
|
export interface DevTokenConfig {
|
|
@@ -59,6 +61,15 @@ export declare function markUserSignedOut(): void;
|
|
|
59
61
|
export declare function clearSignedOutFlag(): void;
|
|
60
62
|
/** Returns `true` if the user explicitly signed out earlier. */
|
|
61
63
|
export declare function isUserSignedOut(): boolean;
|
|
64
|
+
/** Mark that this tab already attempted a silent sign-in
|
|
65
|
+
* (`login({ prompt: 'none' })`), successful or not. Read before
|
|
66
|
+
* auto-redirecting so a declined silent auth can never loop. */
|
|
67
|
+
export declare function markSilentAuthAttempted(): void;
|
|
68
|
+
/** `true` if this tab already attempted a silent sign-in. */
|
|
69
|
+
export declare function hasSilentAuthAttempted(): boolean;
|
|
70
|
+
/** Re-arm the silent attempt (explicit "Sign in" click), so a future
|
|
71
|
+
* boot in this tab may try silently again. */
|
|
72
|
+
export declare function clearSilentAuthAttempted(): void;
|
|
62
73
|
/** Wipe HF token keys from sessionStorage. Called by the embed
|
|
63
74
|
* on `host:leaving` before the iframe unmounts
|
|
64
75
|
* (APP_CREATION_GUIDE §13.5.2). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/lib/settings.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/lib/settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAgBH,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,0DAA0D;AAC1D,wBAAgB,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW3E;AAED;wDACwD;AACxD,wBAAgB,qBAAqB,CACnC,cAAc,CAAC,EAAE,MAAM,GACtB;IAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAW1D;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMpD;AAWD;8CAC8C;AAC9C,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAYzD;AAED;;2BAE2B;AAC3B,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;iCAEiC;AACjC,wBAAgB,iBAAiB,IAAI,OAAO,CAI3C;AAID;mEACmE;AACnE,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC;AAED;+DAC+D;AAC/D,wBAAgB,mBAAmB,IAAI,OAAO,CAQ7C;AAID;+DAC+D;AAC/D,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC;AAED;iCACiC;AACjC,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED,gEAAgE;AAChE,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAID;;iEAEiE;AACjE,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,IAAI,OAAO,CAMhD;AAED;+CAC+C;AAC/C,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAID;;oCAEoC;AACpC,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C;AAID;;sDAEsD;AACtD,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,CAUrD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pollen-robotics/reachy-mini-sdk",
|
|
3
|
-
"version": "1.10.0-dev.0.main.
|
|
3
|
+
"version": "1.10.0-dev.0.main.c8367cd",
|
|
4
4
|
"description": "Browser SDK for controlling a Reachy Mini robot over WebRTC, plus an optional Hugging Face Spaces host shell (OAuth + robot picker + iframe bridge) exposed via the ./host subpath.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/reachy-mini-sdk.js",
|
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
],
|
|
46
46
|
"sideEffects": false,
|
|
47
47
|
"scripts": {
|
|
48
|
+
"gen:version": "node scripts/gen-version.mjs",
|
|
49
|
+
"prebuild:sdk": "node scripts/gen-version.mjs",
|
|
48
50
|
"build:sdk": "tsc -p tsconfig.json",
|
|
49
51
|
"build:host": "cd host && vite build && tsc -p tsconfig.build.json",
|
|
50
52
|
"build": "npm run build:sdk && npm run build:host",
|
|
@@ -53,14 +55,16 @@
|
|
|
53
55
|
"typecheck:host": "cd host && tsc --noEmit",
|
|
54
56
|
"typecheck": "npm run typecheck:sdk && npm run typecheck:host",
|
|
55
57
|
"dev": "cd host && vite",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:watch": "vitest",
|
|
56
60
|
"clean": "rm -rf dist host/dist"
|
|
57
61
|
},
|
|
58
62
|
"dependencies": {
|
|
59
63
|
"@emotion/react": "^11.14.0",
|
|
60
64
|
"@emotion/styled": "^11.14.1",
|
|
61
65
|
"@huggingface/hub": "^0.15.2",
|
|
62
|
-
"@mui/icons-material": "^
|
|
63
|
-
"@mui/material": "^
|
|
66
|
+
"@mui/icons-material": "^9.0.0",
|
|
67
|
+
"@mui/material": "^9.0.0"
|
|
64
68
|
},
|
|
65
69
|
"peerDependencies": {
|
|
66
70
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -75,14 +79,17 @@
|
|
|
75
79
|
}
|
|
76
80
|
},
|
|
77
81
|
"devDependencies": {
|
|
82
|
+
"@testing-library/react": "^16.3.2",
|
|
78
83
|
"@types/node": "^25.7.0",
|
|
79
84
|
"@types/react": "^19.2.14",
|
|
80
85
|
"@types/react-dom": "^19.2.3",
|
|
81
86
|
"@vitejs/plugin-react-swc": "^4.0.0",
|
|
87
|
+
"jsdom": "^29.1.1",
|
|
82
88
|
"react": "^19.2.5",
|
|
83
89
|
"react-dom": "^19.2.5",
|
|
84
90
|
"typescript": "^5.7.3",
|
|
85
|
-
"vite": "^7.2.1"
|
|
91
|
+
"vite": "^7.2.1",
|
|
92
|
+
"vitest": "^4.1.10"
|
|
86
93
|
},
|
|
87
94
|
"keywords": [
|
|
88
95
|
"reachy",
|