@pollen-robotics/reachy-mini-sdk 1.7.3-main.7457b2b
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 +188 -0
- package/LICENSE +201 -0
- package/README.md +129 -0
- package/host/APP_AUTHOR_GUIDE.md +646 -0
- package/host/README.md +155 -0
- package/host/SPEC.md +618 -0
- package/host/dist/ReachyHost.d.ts +39 -0
- package/host/dist/ReachyHost.d.ts.map +1 -0
- package/host/dist/assets/index.d.ts +16 -0
- package/host/dist/assets/index.d.ts.map +1 -0
- package/host/dist/chunks/index-C3B3FuBC.js +402 -0
- package/host/dist/chunks/index-C3B3FuBC.js.map +1 -0
- package/host/dist/chunks/mountHost-8f-laxwI.js +48280 -0
- package/host/dist/chunks/mountHost-8f-laxwI.js.map +1 -0
- package/host/dist/chunks/reachy-mini-sdk-T3Zr7Hwc.js +1726 -0
- package/host/dist/chunks/reachy-mini-sdk-T3Zr7Hwc.js.map +1 -0
- package/host/dist/components/ConnectingView.d.ts +13 -0
- package/host/dist/components/ConnectingView.d.ts.map +1 -0
- package/host/dist/components/EmbedFrame.d.ts +16 -0
- package/host/dist/components/EmbedFrame.d.ts.map +1 -0
- package/host/dist/components/ErrorView.d.ts +21 -0
- package/host/dist/components/ErrorView.d.ts.map +1 -0
- package/host/dist/components/LeavingView.d.ts +33 -0
- package/host/dist/components/LeavingView.d.ts.map +1 -0
- package/host/dist/components/PickerView.d.ts +51 -0
- package/host/dist/components/PickerView.d.ts.map +1 -0
- package/host/dist/components/ReachyHostShell.d.ts +21 -0
- package/host/dist/components/ReachyHostShell.d.ts.map +1 -0
- package/host/dist/components/SignInView.d.ts +32 -0
- package/host/dist/components/SignInView.d.ts.map +1 -0
- package/host/dist/components/StepsProgressIndicator.d.ts +41 -0
- package/host/dist/components/StepsProgressIndicator.d.ts.map +1 -0
- package/host/dist/components/TopBar.d.ts +52 -0
- package/host/dist/components/TopBar.d.ts.map +1 -0
- package/host/dist/components/WelcomeBackOverlay.d.ts +28 -0
- package/host/dist/components/WelcomeBackOverlay.d.ts.map +1 -0
- package/host/dist/embed/index.d.ts +150 -0
- package/host/dist/embed/index.d.ts.map +1 -0
- package/host/dist/entry/auto.d.ts +12 -0
- package/host/dist/entry/auto.d.ts.map +1 -0
- package/host/dist/entry/auto.js +7 -0
- package/host/dist/entry/auto.js.map +1 -0
- package/host/dist/entry/embed.d.ts +12 -0
- package/host/dist/entry/embed.d.ts.map +1 -0
- package/host/dist/entry/embed.js +7 -0
- package/host/dist/entry/embed.js.map +1 -0
- package/host/dist/hooks/useHfProfile.d.ts +7 -0
- package/host/dist/hooks/useHfProfile.d.ts.map +1 -0
- package/host/dist/hooks/useHostBridge.d.ts +37 -0
- package/host/dist/hooks/useHostBridge.d.ts.map +1 -0
- package/host/dist/hooks/useOAuth.d.ts +16 -0
- package/host/dist/hooks/useOAuth.d.ts.map +1 -0
- package/host/dist/hooks/useRobots.d.ts +17 -0
- package/host/dist/hooks/useRobots.d.ts.map +1 -0
- package/host/dist/hooks/useSdk.d.ts +16 -0
- package/host/dist/hooks/useSdk.d.ts.map +1 -0
- package/host/dist/index.d.ts +25 -0
- package/host/dist/index.d.ts.map +1 -0
- package/host/dist/index.js +15 -0
- package/host/dist/index.js.map +1 -0
- package/host/dist/lib/centralListener.d.ts +73 -0
- package/host/dist/lib/centralListener.d.ts.map +1 -0
- package/host/dist/lib/centralRest.d.ts +35 -0
- package/host/dist/lib/centralRest.d.ts.map +1 -0
- package/host/dist/lib/protocol.d.ts +230 -0
- package/host/dist/lib/protocol.d.ts.map +1 -0
- package/host/dist/lib/protocol.js +48 -0
- package/host/dist/lib/protocol.js.map +1 -0
- package/host/dist/lib/sdk-types.d.ts +46 -0
- package/host/dist/lib/sdk-types.d.ts.map +1 -0
- package/host/dist/lib/settings.d.ts +69 -0
- package/host/dist/lib/settings.d.ts.map +1 -0
- package/host/dist/lib/signalingUrl.d.ts +28 -0
- package/host/dist/lib/signalingUrl.d.ts.map +1 -0
- package/host/dist/lib/theme.d.ts +4 -0
- package/host/dist/lib/theme.d.ts.map +1 -0
- package/host/dist/lib/themeMode.d.ts +9 -0
- package/host/dist/lib/themeMode.d.ts.map +1 -0
- package/host/dist/lib/tokens.d.ts +64 -0
- package/host/dist/lib/tokens.d.ts.map +1 -0
- package/host/dist/mountHost.d.ts +36 -0
- package/host/dist/mountHost.d.ts.map +1 -0
- package/package.json +109 -0
- package/reachy-mini-sdk.d.ts +285 -0
- package/reachy-mini-sdk.js +2625 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOAuth.d.ts","sourceRoot":"","sources":["../../src/hooks/useOAuth.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAW3D,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,eAAe,EAAE,OAAO,CAAC;IACzB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;kEAC8D;IAC9D,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0CAA0C;IAC1C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAAC;CACjB;AAsBD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,GAAG,UAAU,CAsInE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RobotInfo } from '../lib/sdk-types';
|
|
2
|
+
export interface RobotsState {
|
|
3
|
+
robots: RobotInfo[];
|
|
4
|
+
/** True on the very first fetch (no data yet). */
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
/** True while a refresh is in-flight (poll or manual). */
|
|
7
|
+
isRefreshing: boolean;
|
|
8
|
+
/** Last error message or null. */
|
|
9
|
+
error: string | null;
|
|
10
|
+
/** Trigger an immediate REST refresh. */
|
|
11
|
+
refresh(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function useRobots(opts: {
|
|
14
|
+
hfToken: string | null;
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
}): RobotsState;
|
|
17
|
+
//# sourceMappingURL=useRobots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRobots.d.ts","sourceRoot":"","sources":["../../src/hooks/useRobots.ts"],"names":[],"mappings":"AAiDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIlD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,OAAO,CAAC;IACnB,0DAA0D;IAC1D,YAAY,EAAE,OAAO,CAAC;IACtB,kCAAkC;IAClC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yCAAyC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,WAAW,CAqId"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReachyMiniInstance, ReachyMiniOptions } from '../lib/sdk-types';
|
|
2
|
+
/** Get (or lazily create) the singleton SDK instance. */
|
|
3
|
+
export declare function getOrCreateSdk(opts: ReachyMiniOptions): ReachyMiniInstance;
|
|
4
|
+
/** Fully drop the singleton (used on logout / hard reset). */
|
|
5
|
+
export declare function destroySdk(): void;
|
|
6
|
+
/**
|
|
7
|
+
* React hook returning the SDK instance + a "ready" boolean that
|
|
8
|
+
* flips to true once `window.ReachyMini` is defined. The hook
|
|
9
|
+
* does NOT call `connect()` / `authenticate()`; that's the
|
|
10
|
+
* responsibility of `useHostPhase`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useSdk(opts: ReachyMiniOptions): {
|
|
13
|
+
sdk: ReachyMiniInstance | null;
|
|
14
|
+
sdkReady: boolean;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=useSdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSdk.d.ts","sourceRoot":"","sources":["../../src/hooks/useSdk.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAgB1B,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAgB1E;AAED,8DAA8D;AAC9D,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,iBAAiB,GAAG;IAC/C,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;CACnB,CA8BA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* npm entry point for the `./host` subpath.
|
|
3
|
+
*
|
|
4
|
+
* import { mountHost, connectToHost } from '@pollen-robotics/reachy-mini-sdk/host';
|
|
5
|
+
*
|
|
6
|
+
* works for IDE autocomplete and for app authors who prefer the
|
|
7
|
+
* package directly over the CDN `host/auto` bundle.
|
|
8
|
+
*
|
|
9
|
+
* Importing this module also auto-installs the SDK constructor on
|
|
10
|
+
* `window.ReachyMini` (when unset) and dispatches the
|
|
11
|
+
* `reachymini:ready` event the host's wait loops listen for.
|
|
12
|
+
* Apps consuming the host via npm therefore no longer need a
|
|
13
|
+
* separate jsdelivr `<script type="module">` to expose the SDK
|
|
14
|
+
* on the global — installing this package is enough.
|
|
15
|
+
*/
|
|
16
|
+
export { ReachyHost } from './ReachyHost';
|
|
17
|
+
export type { ReachyHostProps } from './ReachyHost';
|
|
18
|
+
export { mountHost } from './mountHost';
|
|
19
|
+
export type { MountHostOptions, MountedHost } from './mountHost';
|
|
20
|
+
export { connectToHost } from './embed';
|
|
21
|
+
export type { ConnectedHandle, ConnectToHostOptions } from './embed';
|
|
22
|
+
export type { AppConnectingStep, AppPhase, ConfigPayload, CredsBundle, EmbedToHostMsg, HostToEmbedMsg, LeavingReason, ThemeMode, } from './lib/protocol';
|
|
23
|
+
export { PROTOCOL_VERSION, decodeCredsFromHash, encodeCredsToHash, isProtocolMessage, } from './lib/protocol';
|
|
24
|
+
export type { ReachyMiniInstance, ReachyMiniOptions, ReachyMiniConstructor, RobotInfo, } from './lib/sdk-types';
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAIrE,YAAY,EACV,iBAAiB,EACjB,QAAQ,EACR,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EACb,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAIxB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,SAAS,GACV,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { R as o } from "./chunks/reachy-mini-sdk-T3Zr7Hwc.js";
|
|
2
|
+
import { R as s, m as a } from "./chunks/mountHost-8f-laxwI.js";
|
|
3
|
+
import { c as t } from "./chunks/index-C3B3FuBC.js";
|
|
4
|
+
import { PROTOCOL_VERSION as c, decodeCredsFromHash as m, encodeCredsToHash as w, isProtocolMessage as h } from "./lib/protocol.js";
|
|
5
|
+
typeof window < "u" && !window.ReachyMini && (window.ReachyMini = o, window.dispatchEvent(new Event("reachymini:ready")));
|
|
6
|
+
export {
|
|
7
|
+
c as PROTOCOL_VERSION,
|
|
8
|
+
s as ReachyHost,
|
|
9
|
+
t as connectToHost,
|
|
10
|
+
m as decodeCredsFromHash,
|
|
11
|
+
w as encodeCredsToHash,
|
|
12
|
+
h as isProtocolMessage,
|
|
13
|
+
a as mountHost
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * npm entry point for the `./host` subpath.\n *\n * import { mountHost, connectToHost } from '@pollen-robotics/reachy-mini-sdk/host';\n *\n * works for IDE autocomplete and for app authors who prefer the\n * package directly over the CDN `host/auto` bundle.\n *\n * Importing this module also auto-installs the SDK constructor on\n * `window.ReachyMini` (when unset) and dispatches the\n * `reachymini:ready` event the host's wait loops listen for.\n * Apps consuming the host via npm therefore no longer need a\n * separate jsdelivr `<script type=\"module\">` to expose the SDK\n * on the global — installing this package is enough.\n */\n\nimport { ReachyMini } from '../../reachy-mini-sdk';\n\nif (typeof window !== 'undefined' && !window.ReachyMini) {\n window.ReachyMini = ReachyMini;\n window.dispatchEvent(new Event('reachymini:ready'));\n}\n\nexport { ReachyHost } from './ReachyHost';\nexport type { ReachyHostProps } from './ReachyHost';\n\nexport { mountHost } from './mountHost';\nexport type { MountHostOptions, MountedHost } from './mountHost';\n\nexport { connectToHost } from './embed';\nexport type { ConnectedHandle, ConnectToHostOptions } from './embed';\n\n// Protocol types (useful for app authors implementing custom\n// flows or unit-testing their dispatcher).\nexport type {\n AppConnectingStep,\n AppPhase,\n ConfigPayload,\n CredsBundle,\n EmbedToHostMsg,\n HostToEmbedMsg,\n LeavingReason,\n ThemeMode,\n} from './lib/protocol';\nexport {\n PROTOCOL_VERSION,\n decodeCredsFromHash,\n encodeCredsToHash,\n isProtocolMessage,\n} from './lib/protocol';\n\n// SDK types (re-export so app authors can write\n// `import type { ReachyMiniInstance } from '@pollen-robotics/reachy-mini-sdk/host'`.\nexport type {\n ReachyMiniInstance,\n ReachyMiniOptions,\n ReachyMiniConstructor,\n RobotInfo,\n} from './lib/sdk-types';\n"],"names":["ReachyMini"],"mappings":";;;;AAkBI,OAAO,SAAW,OAAe,CAAC,OAAO,eAC3C,OAAO,aAAaA,GACpB,OAAO,cAAc,IAAI,MAAM,kBAAkB,CAAC;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Long-lived SSE listener channel to Hugging Face central.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the Reachy Mini mobile app (`centralListenerStream.ts`).
|
|
5
|
+
* Why this exists and how it relates to the SDK is documented in
|
|
6
|
+
* the docstring of `useRobots.ts`; in short:
|
|
7
|
+
*
|
|
8
|
+
* - The host shell needs realtime updates of the user's robot
|
|
9
|
+
* fleet (online/offline, busy/free).
|
|
10
|
+
* - The ReachyMini SDK can do this, but only by also registering
|
|
11
|
+
* a peer slot at central, which then conflicts with the
|
|
12
|
+
* iframe's session WebRTC handshake.
|
|
13
|
+
* - Solution: open a *bare* SSE channel here, registered with
|
|
14
|
+
* `roles: ["listener"]` only. On `close()` (when the user
|
|
15
|
+
* selects a robot and we mount the iframe) central retires
|
|
16
|
+
* the listener slot via its `token → peer_id` 1:1 mapping, so
|
|
17
|
+
* the iframe's SDK opens a fresh slot without contention.
|
|
18
|
+
*
|
|
19
|
+
* Wire surface we listen for
|
|
20
|
+
* ──────────────────────────
|
|
21
|
+
* - `welcome` opening handshake, includes the assigned peerId
|
|
22
|
+
* - `list` initial robot snapshot
|
|
23
|
+
* - `peerStatusChanged` a robot came online / went offline
|
|
24
|
+
* - `sessionStateChanged` busy / free transition
|
|
25
|
+
*
|
|
26
|
+
* Reconnect policy
|
|
27
|
+
* ────────────────
|
|
28
|
+
* Network blips, HF Space cold-restarts, and proxy idle culls all
|
|
29
|
+
* surface as a stream EOF or fetch error. We retry with exponential
|
|
30
|
+
* backoff capped at `MAX_BACKOFF_MS`, jittered to avoid thundering
|
|
31
|
+
* herds on a central restart.
|
|
32
|
+
*/
|
|
33
|
+
export interface CentralStreamProducer {
|
|
34
|
+
id: string;
|
|
35
|
+
meta?: Record<string, unknown>;
|
|
36
|
+
busy?: boolean;
|
|
37
|
+
activeApp?: string | null;
|
|
38
|
+
}
|
|
39
|
+
export interface CentralListEvent {
|
|
40
|
+
producers: CentralStreamProducer[];
|
|
41
|
+
}
|
|
42
|
+
export interface CentralPeerStatusChangedEvent {
|
|
43
|
+
peerId: string;
|
|
44
|
+
roles: string[];
|
|
45
|
+
meta?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
export interface CentralSessionStateChangedEvent {
|
|
48
|
+
peerId: string;
|
|
49
|
+
busy: boolean;
|
|
50
|
+
activeApp: string | null;
|
|
51
|
+
meta?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
export interface OpenCentralListenerOpts {
|
|
54
|
+
token: string;
|
|
55
|
+
signalingUrl: string;
|
|
56
|
+
onList?: (event: CentralListEvent) => void;
|
|
57
|
+
onPeerStatusChanged?: (event: CentralPeerStatusChangedEvent) => void;
|
|
58
|
+
onSessionStateChanged?: (event: CentralSessionStateChangedEvent) => void;
|
|
59
|
+
/** SSE is open and `setPeerStatus(listener)` has been POSTed. */
|
|
60
|
+
onConnect?: () => void;
|
|
61
|
+
/** SSE dropped (network, central restart, scheduled reconnect). */
|
|
62
|
+
onDisconnect?: (reason: string) => void;
|
|
63
|
+
/** Non-fatal errors. Fatal auth errors end the stream and call
|
|
64
|
+
* onDisconnect with a meaningful reason instead. */
|
|
65
|
+
onError?: (err: Error) => void;
|
|
66
|
+
}
|
|
67
|
+
export interface CentralListenerHandle {
|
|
68
|
+
/** Tear the stream down. Idempotent. No further callbacks
|
|
69
|
+
* fire after this returns. */
|
|
70
|
+
close(): void;
|
|
71
|
+
}
|
|
72
|
+
export declare function openCentralListener(opts: OpenCentralListenerOpts): CentralListenerHandle;
|
|
73
|
+
//# sourceMappingURL=centralListener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"centralListener.d.ts","sourceRoot":"","sources":["../../src/lib/centralListener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAgDH,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3C,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,CAAC;IACrE,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,+BAA+B,KAAK,IAAI,CAAC;IACzE,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;yDACqD;IACrD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC;mCAC+B;IAC/B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,uBAAuB,GAC5B,qBAAqB,CAsOvB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct REST access to the HF central signaling server.
|
|
3
|
+
*
|
|
4
|
+
* The picker needs a list of robots, but opening an SSE
|
|
5
|
+
* connection from the host shell (via `sdk.connect()`) breaks
|
|
6
|
+
* the iframe's WebRTC handshake: central can't reliably route
|
|
7
|
+
* the daemon's SDP offer once two SSE streams have been
|
|
8
|
+
* registered for the same HF token, even after one disconnects.
|
|
9
|
+
*
|
|
10
|
+
* Central exposes a public `GET /api/robot-status` endpoint
|
|
11
|
+
* authenticated by Bearer token that returns the same producer
|
|
12
|
+
* list as `setPeerStatus → list`, without requiring an SSE
|
|
13
|
+
* registration. The mobile app uses this for "remote mode" and
|
|
14
|
+
* we reuse the exact same wire shape here.
|
|
15
|
+
*/
|
|
16
|
+
import type { RobotInfo } from './sdk-types';
|
|
17
|
+
export interface FetchRobotsResult {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
robots: RobotInfo[];
|
|
20
|
+
reason?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch the user's robot list directly from central.
|
|
24
|
+
*
|
|
25
|
+
* @param signalingUrl Base URL of the central server (e.g.
|
|
26
|
+
* `https://pollen-robotics-reachy-mini-central.hf.space`)
|
|
27
|
+
* @param hfToken Hugging Face user token
|
|
28
|
+
* @param signal Optional AbortSignal for cancellation
|
|
29
|
+
*/
|
|
30
|
+
export declare function fetchRobotsFromCentral(opts: {
|
|
31
|
+
signalingUrl: string;
|
|
32
|
+
hfToken: string;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}): Promise<FetchRobotsResult>;
|
|
35
|
+
//# sourceMappingURL=centralRest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"centralRest.d.ts","sourceRoot":"","sources":["../../src/lib/centralRest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmB7C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkCD;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmD7B"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* postMessage protocol v1 between the host shell (parent window,
|
|
3
|
+
* exposed via `@pollen-robotics/reachy-mini-sdk/host`) and an
|
|
4
|
+
* embedded Reachy Mini app (iframe).
|
|
5
|
+
*
|
|
6
|
+
* Canonical reference: SPEC.md §6.
|
|
7
|
+
*
|
|
8
|
+
* Contract identity
|
|
9
|
+
* ─────────────────
|
|
10
|
+
* - Every message carries `version: 1`. Bumping that integer is
|
|
11
|
+
* the ONLY way to introduce a breaking change to the wire
|
|
12
|
+
* protocol. Additive changes (new optional fields, new typed
|
|
13
|
+
* messages) ship without a version bump.
|
|
14
|
+
* - Every message carries `source: 'reachy-mini'`. Lets receivers
|
|
15
|
+
* distinguish our envelopes from unrelated `postMessage` traffic
|
|
16
|
+
* (DevTools, MUI portals, browser extensions, ...).
|
|
17
|
+
* - Both sides validate `event.origin` against the expected origin
|
|
18
|
+
* before trusting the payload. In our deployment (same-origin
|
|
19
|
+
* iframe within an HF Space) the expected origin is
|
|
20
|
+
* `event.origin === window.location.origin`.
|
|
21
|
+
*
|
|
22
|
+
* Message families
|
|
23
|
+
* ────────────────
|
|
24
|
+
* 1. Lifecycle: boot / ready / leaving. Drive the visible state
|
|
25
|
+
* of the host shell.
|
|
26
|
+
* 2. State: `embed:app-state` lets the host render accurate
|
|
27
|
+
* connection / wake-up overlays.
|
|
28
|
+
* 3. Config & theme: opaque `config` payload + theme push.
|
|
29
|
+
* 4. Error: `embed:error` for tear-down on app failure.
|
|
30
|
+
*
|
|
31
|
+
* Intentionally NOT in v1 (see SPEC §6 and §11):
|
|
32
|
+
* - No `host:custom` / `embed:custom` free-form channel.
|
|
33
|
+
* - No `embed:request-config-update` (apps don't push config).
|
|
34
|
+
* - No heartbeat / ping-pong (backlog).
|
|
35
|
+
*/
|
|
36
|
+
/** Protocol version. Bump on breaking changes. */
|
|
37
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
38
|
+
/** Source tag attached to every envelope. */
|
|
39
|
+
export declare const PROTOCOL_SOURCE: "reachy-mini";
|
|
40
|
+
/** Theme mode the host applies to the embedded app. */
|
|
41
|
+
export type ThemeMode = 'dark' | 'light';
|
|
42
|
+
/**
|
|
43
|
+
* Connection lifecycle, as observed by the embedded app. Drives
|
|
44
|
+
* the host's `ConnectingView` stepper and visibility of the
|
|
45
|
+
* iframe.
|
|
46
|
+
*
|
|
47
|
+
* boot : app loaded, no SDK action yet
|
|
48
|
+
* connecting : ReachyMini.connect() / startSession() in flight
|
|
49
|
+
* live : session up, motors awake, app interactive
|
|
50
|
+
* leaving : `host:leaving` received, app tearing down
|
|
51
|
+
* error : non-recoverable failure
|
|
52
|
+
*/
|
|
53
|
+
export type AppPhase = 'boot' | 'connecting' | 'live' | 'leaving' | 'error';
|
|
54
|
+
/**
|
|
55
|
+
* Fine-grained step inside `connecting`. Maps to the 3 dots in
|
|
56
|
+
* `StepsProgressIndicator`:
|
|
57
|
+
* - `link` : waiting for `host:init` / `connect()` in flight
|
|
58
|
+
* - `session` : `startSession()` in flight
|
|
59
|
+
* - `wake` : `ensureAwake()` in flight
|
|
60
|
+
*
|
|
61
|
+
* Apps that don't differentiate can omit this field; the host
|
|
62
|
+
* treats it as `link`.
|
|
63
|
+
*/
|
|
64
|
+
export type AppConnectingStep = 'link' | 'session' | 'wake';
|
|
65
|
+
/** Opaque app-specific payload routed through the host. */
|
|
66
|
+
export type ConfigPayload = unknown;
|
|
67
|
+
/** Reason supplied with `host:leaving` for logging. */
|
|
68
|
+
export type LeavingReason = 'user-action' | 'session-stopped' | 'error' | 'pagehide';
|
|
69
|
+
/**
|
|
70
|
+
* First message sent by the host once the iframe has shouted
|
|
71
|
+
* `embed:ready`. Carries the credentials + initial state the app
|
|
72
|
+
* needs to bring a session up.
|
|
73
|
+
*
|
|
74
|
+
* Same-origin iframe: the SDK CDN script is imported with a
|
|
75
|
+
* relative URL from `index.html`. We still pass `signalingUrl`
|
|
76
|
+
* here so the host can swap centrals (staging / self-hosted)
|
|
77
|
+
* without a rebuild of the app.
|
|
78
|
+
*/
|
|
79
|
+
export interface HostInitMsg {
|
|
80
|
+
source: typeof PROTOCOL_SOURCE;
|
|
81
|
+
type: 'host:init';
|
|
82
|
+
version: 1;
|
|
83
|
+
theme: ThemeMode;
|
|
84
|
+
signalingUrl: string;
|
|
85
|
+
/** HF OAuth bearer token. Optional for apps that don't need to
|
|
86
|
+
* authenticate (rare). */
|
|
87
|
+
hfToken?: string;
|
|
88
|
+
/** HF account user name, when known. */
|
|
89
|
+
userName?: string | null;
|
|
90
|
+
/** Robot ID selected by the host's picker. */
|
|
91
|
+
robotPeerId: string;
|
|
92
|
+
/** Optional opaque payload from `?config=<base64>` or from the
|
|
93
|
+
* mobile-app handoff. App is responsible for parsing /
|
|
94
|
+
* validating. */
|
|
95
|
+
config: ConfigPayload;
|
|
96
|
+
/** Host display name (e.g. "Reachy Mini") - useful for the
|
|
97
|
+
* embed if it wants to surface "Connected via …" copy. */
|
|
98
|
+
hostName: string;
|
|
99
|
+
/** Embedded app's display name (passed by the dispatcher). */
|
|
100
|
+
appName: string;
|
|
101
|
+
}
|
|
102
|
+
/** Theme changed live (user toggled OS palette, host UI switched). */
|
|
103
|
+
export interface HostThemeChangedMsg {
|
|
104
|
+
source: typeof PROTOCOL_SOURCE;
|
|
105
|
+
type: 'host:theme-changed';
|
|
106
|
+
version: 1;
|
|
107
|
+
theme: ThemeMode;
|
|
108
|
+
}
|
|
109
|
+
/** Config updated live without an iframe reload. */
|
|
110
|
+
export interface HostConfigChangedMsg {
|
|
111
|
+
source: typeof PROTOCOL_SOURCE;
|
|
112
|
+
type: 'host:config-changed';
|
|
113
|
+
version: 1;
|
|
114
|
+
config: ConfigPayload;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Host is asking the app to wind down cleanly. The app SHOULD:
|
|
118
|
+
* 1. Stop emitting motion commands.
|
|
119
|
+
* 2. Disconnect any non-SDK resources (timers, listeners).
|
|
120
|
+
* 3. Resolve every registered `onLeave` callback before the
|
|
121
|
+
* `timeoutMs` deadline; otherwise the host force-unmounts
|
|
122
|
+
* the iframe.
|
|
123
|
+
*
|
|
124
|
+
* The host does NOT expect an explicit `leave-ack`; resolving
|
|
125
|
+
* `onLeave` callbacks within the deadline is sufficient.
|
|
126
|
+
*/
|
|
127
|
+
export interface HostLeavingMsg {
|
|
128
|
+
source: typeof PROTOCOL_SOURCE;
|
|
129
|
+
type: 'host:leaving';
|
|
130
|
+
version: 1;
|
|
131
|
+
reason: LeavingReason;
|
|
132
|
+
/** Soft deadline in ms. After this the host unmounts the iframe
|
|
133
|
+
* regardless. */
|
|
134
|
+
timeoutMs: number;
|
|
135
|
+
}
|
|
136
|
+
export type HostToEmbedMsg = HostInitMsg | HostThemeChangedMsg | HostConfigChangedMsg | HostLeavingMsg;
|
|
137
|
+
/**
|
|
138
|
+
* Emitted by the app as early as possible (synchronous tick of
|
|
139
|
+
* the embed entry, before the SDK is touched). Tells the host
|
|
140
|
+
* the iframe is alive and ready to receive `host:init`. The host
|
|
141
|
+
* MUST NOT send `host:init` before seeing this.
|
|
142
|
+
*/
|
|
143
|
+
export interface EmbedReadyMsg {
|
|
144
|
+
source: typeof PROTOCOL_SOURCE;
|
|
145
|
+
type: 'embed:ready';
|
|
146
|
+
version: 1;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* App-level connection state. The host renders its
|
|
150
|
+
* `ConnectingView` overlay over the (still-mounted) iframe until
|
|
151
|
+
* it sees `phase === 'live'`. Apps SHOULD emit this on every
|
|
152
|
+
* transition; the host caches the last value and won't re-render
|
|
153
|
+
* unless something changes.
|
|
154
|
+
*/
|
|
155
|
+
export interface EmbedAppStateMsg {
|
|
156
|
+
source: typeof PROTOCOL_SOURCE;
|
|
157
|
+
type: 'embed:app-state';
|
|
158
|
+
version: 1;
|
|
159
|
+
phase: AppPhase;
|
|
160
|
+
/** Sub-step inside `connecting`. Ignored for other phases. */
|
|
161
|
+
connectingStep?: AppConnectingStep | null;
|
|
162
|
+
/** Optional human-readable hint shown in the overlay caption. */
|
|
163
|
+
message?: string | null;
|
|
164
|
+
}
|
|
165
|
+
/** App requests to leave (user clicked an in-app exit, error,
|
|
166
|
+
* ...). The host runs the same tear-down as a top-bar
|
|
167
|
+
* "End session". */
|
|
168
|
+
export interface EmbedRequestLeaveMsg {
|
|
169
|
+
source: typeof PROTOCOL_SOURCE;
|
|
170
|
+
type: 'embed:request-leave';
|
|
171
|
+
version: 1;
|
|
172
|
+
}
|
|
173
|
+
/** App-level error report. `fatal: true` switches the host to
|
|
174
|
+
* ErrorView; `fatal: false` is logged and may surface a toast. */
|
|
175
|
+
export interface EmbedErrorMsg {
|
|
176
|
+
source: typeof PROTOCOL_SOURCE;
|
|
177
|
+
type: 'embed:error';
|
|
178
|
+
version: 1;
|
|
179
|
+
message: string;
|
|
180
|
+
fatal: boolean;
|
|
181
|
+
detail?: unknown;
|
|
182
|
+
}
|
|
183
|
+
export type EmbedToHostMsg = EmbedReadyMsg | EmbedAppStateMsg | EmbedRequestLeaveMsg | EmbedErrorMsg;
|
|
184
|
+
/**
|
|
185
|
+
* Serialised credentials passed from the host (Mode A) or the
|
|
186
|
+
* mobile app (Mode B) to the embed via the URL hash fragment.
|
|
187
|
+
*
|
|
188
|
+
* Hash-only (never URL search): browsers don't send the hash to
|
|
189
|
+
* any server, so the HF token never appears in access logs,
|
|
190
|
+
* referer headers, or HF Spaces frontend logs.
|
|
191
|
+
*
|
|
192
|
+
* The embed wipes the hash with `history.replaceState` on its
|
|
193
|
+
* first synchronous tick, before any `await`, then proceeds with
|
|
194
|
+
* the rest of the boot using the in-memory bundle.
|
|
195
|
+
*/
|
|
196
|
+
export interface CredsBundle {
|
|
197
|
+
hfToken?: string | null;
|
|
198
|
+
userName?: string | null;
|
|
199
|
+
robotPeerId: string;
|
|
200
|
+
signalingUrl: string;
|
|
201
|
+
theme: ThemeMode;
|
|
202
|
+
config: ConfigPayload;
|
|
203
|
+
hostName: string;
|
|
204
|
+
appName: string;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Cheap discriminator: does this `unknown` look like a v1
|
|
208
|
+
* envelope from our protocol? Receivers call this before
|
|
209
|
+
* narrowing on `type`. Conservative on the version: an unknown
|
|
210
|
+
* version is treated as "not our protocol" so the receiver
|
|
211
|
+
* silently ignores it (forward-compat for a future v2 peer).
|
|
212
|
+
*/
|
|
213
|
+
export declare function isProtocolMessage(value: unknown): value is {
|
|
214
|
+
source: typeof PROTOCOL_SOURCE;
|
|
215
|
+
type: string;
|
|
216
|
+
version: number;
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Encode a creds bundle to the URL hash fragment.
|
|
220
|
+
* URL-safe base64 wrapper around JSON to avoid percent-encoding
|
|
221
|
+
* noise.
|
|
222
|
+
*/
|
|
223
|
+
export declare function encodeCredsToHash(bundle: CredsBundle): string;
|
|
224
|
+
/**
|
|
225
|
+
* Decode the creds bundle from a URL hash fragment. Returns
|
|
226
|
+
* `null` if no `creds=` segment is present or if the payload is
|
|
227
|
+
* malformed (caller handles the error by rendering ErrorView).
|
|
228
|
+
*/
|
|
229
|
+
export declare function decodeCredsFromHash(hash: string | null): CredsBundle | null;
|
|
230
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/lib/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const f = 1, c = "reachy-mini";
|
|
2
|
+
function d(e) {
|
|
3
|
+
if (!e || typeof e != "object") return !1;
|
|
4
|
+
const n = e;
|
|
5
|
+
return n.source === c && typeof n.type == "string" && n.version === 1;
|
|
6
|
+
}
|
|
7
|
+
function u(e) {
|
|
8
|
+
const n = JSON.stringify(e), o = s(n);
|
|
9
|
+
return `creds=${encodeURIComponent(o)}`;
|
|
10
|
+
}
|
|
11
|
+
function a(e) {
|
|
12
|
+
if (!e) return null;
|
|
13
|
+
const n = e.startsWith("#") ? e.slice(1) : e;
|
|
14
|
+
for (const o of n.split("&"))
|
|
15
|
+
if (o.startsWith("creds="))
|
|
16
|
+
try {
|
|
17
|
+
const t = decodeURIComponent(o.slice(6)), r = i(t);
|
|
18
|
+
return JSON.parse(r);
|
|
19
|
+
} catch (t) {
|
|
20
|
+
return console.warn("[reachy-mini-sdk/host] failed to decode creds hash", t), null;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function s(e) {
|
|
25
|
+
if (typeof window < "u" && typeof window.btoa == "function") {
|
|
26
|
+
const n = new TextEncoder().encode(e);
|
|
27
|
+
let o = "";
|
|
28
|
+
for (const t of n) o += String.fromCharCode(t);
|
|
29
|
+
return window.btoa(o);
|
|
30
|
+
}
|
|
31
|
+
return Buffer.from(e, "utf8").toString("base64");
|
|
32
|
+
}
|
|
33
|
+
function i(e) {
|
|
34
|
+
if (typeof window < "u" && typeof window.atob == "function") {
|
|
35
|
+
const n = window.atob(e), o = new Uint8Array(n.length);
|
|
36
|
+
for (let t = 0; t < n.length; t++) o[t] = n.charCodeAt(t);
|
|
37
|
+
return new TextDecoder().decode(o);
|
|
38
|
+
}
|
|
39
|
+
return Buffer.from(e, "base64").toString("utf8");
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
c as PROTOCOL_SOURCE,
|
|
43
|
+
f as PROTOCOL_VERSION,
|
|
44
|
+
a as decodeCredsFromHash,
|
|
45
|
+
u as encodeCredsToHash,
|
|
46
|
+
d as isProtocolMessage
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sources":["../../src/lib/protocol.ts"],"sourcesContent":["/**\n * postMessage protocol v1 between the host shell (parent window,\n * exposed via `@pollen-robotics/reachy-mini-sdk/host`) and an\n * embedded Reachy Mini app (iframe).\n *\n * Canonical reference: SPEC.md §6.\n *\n * Contract identity\n * ─────────────────\n * - Every message carries `version: 1`. Bumping that integer is\n * the ONLY way to introduce a breaking change to the wire\n * protocol. Additive changes (new optional fields, new typed\n * messages) ship without a version bump.\n * - Every message carries `source: 'reachy-mini'`. Lets receivers\n * distinguish our envelopes from unrelated `postMessage` traffic\n * (DevTools, MUI portals, browser extensions, ...).\n * - Both sides validate `event.origin` against the expected origin\n * before trusting the payload. In our deployment (same-origin\n * iframe within an HF Space) the expected origin is\n * `event.origin === window.location.origin`.\n *\n * Message families\n * ────────────────\n * 1. Lifecycle: boot / ready / leaving. Drive the visible state\n * of the host shell.\n * 2. State: `embed:app-state` lets the host render accurate\n * connection / wake-up overlays.\n * 3. Config & theme: opaque `config` payload + theme push.\n * 4. Error: `embed:error` for tear-down on app failure.\n *\n * Intentionally NOT in v1 (see SPEC §6 and §11):\n * - No `host:custom` / `embed:custom` free-form channel.\n * - No `embed:request-config-update` (apps don't push config).\n * - No heartbeat / ping-pong (backlog).\n */\n\n/** Protocol version. Bump on breaking changes. */\nexport const PROTOCOL_VERSION = 1;\n\n/** Source tag attached to every envelope. */\nexport const PROTOCOL_SOURCE = 'reachy-mini' as const;\n\n/** Theme mode the host applies to the embedded app. */\nexport type ThemeMode = 'dark' | 'light';\n\n/**\n * Connection lifecycle, as observed by the embedded app. Drives\n * the host's `ConnectingView` stepper and visibility of the\n * iframe.\n *\n * boot : app loaded, no SDK action yet\n * connecting : ReachyMini.connect() / startSession() in flight\n * live : session up, motors awake, app interactive\n * leaving : `host:leaving` received, app tearing down\n * error : non-recoverable failure\n */\nexport type AppPhase = 'boot' | 'connecting' | 'live' | 'leaving' | 'error';\n\n/**\n * Fine-grained step inside `connecting`. Maps to the 3 dots in\n * `StepsProgressIndicator`:\n * - `link` : waiting for `host:init` / `connect()` in flight\n * - `session` : `startSession()` in flight\n * - `wake` : `ensureAwake()` in flight\n *\n * Apps that don't differentiate can omit this field; the host\n * treats it as `link`.\n */\nexport type AppConnectingStep = 'link' | 'session' | 'wake';\n\n/** Opaque app-specific payload routed through the host. */\nexport type ConfigPayload = unknown;\n\n/** Reason supplied with `host:leaving` for logging. */\nexport type LeavingReason =\n | 'user-action'\n | 'session-stopped'\n | 'error'\n | 'pagehide';\n\n/* ─────────────────── HOST → EMBED ─────────────────── */\n\n/**\n * First message sent by the host once the iframe has shouted\n * `embed:ready`. Carries the credentials + initial state the app\n * needs to bring a session up.\n *\n * Same-origin iframe: the SDK CDN script is imported with a\n * relative URL from `index.html`. We still pass `signalingUrl`\n * here so the host can swap centrals (staging / self-hosted)\n * without a rebuild of the app.\n */\nexport interface HostInitMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'host:init';\n version: 1;\n theme: ThemeMode;\n signalingUrl: string;\n /** HF OAuth bearer token. Optional for apps that don't need to\n * authenticate (rare). */\n hfToken?: string;\n /** HF account user name, when known. */\n userName?: string | null;\n /** Robot ID selected by the host's picker. */\n robotPeerId: string;\n /** Optional opaque payload from `?config=<base64>` or from the\n * mobile-app handoff. App is responsible for parsing /\n * validating. */\n config: ConfigPayload;\n /** Host display name (e.g. \"Reachy Mini\") - useful for the\n * embed if it wants to surface \"Connected via …\" copy. */\n hostName: string;\n /** Embedded app's display name (passed by the dispatcher). */\n appName: string;\n}\n\n/** Theme changed live (user toggled OS palette, host UI switched). */\nexport interface HostThemeChangedMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'host:theme-changed';\n version: 1;\n theme: ThemeMode;\n}\n\n/** Config updated live without an iframe reload. */\nexport interface HostConfigChangedMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'host:config-changed';\n version: 1;\n config: ConfigPayload;\n}\n\n/**\n * Host is asking the app to wind down cleanly. The app SHOULD:\n * 1. Stop emitting motion commands.\n * 2. Disconnect any non-SDK resources (timers, listeners).\n * 3. Resolve every registered `onLeave` callback before the\n * `timeoutMs` deadline; otherwise the host force-unmounts\n * the iframe.\n *\n * The host does NOT expect an explicit `leave-ack`; resolving\n * `onLeave` callbacks within the deadline is sufficient.\n */\nexport interface HostLeavingMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'host:leaving';\n version: 1;\n reason: LeavingReason;\n /** Soft deadline in ms. After this the host unmounts the iframe\n * regardless. */\n timeoutMs: number;\n}\n\nexport type HostToEmbedMsg =\n | HostInitMsg\n | HostThemeChangedMsg\n | HostConfigChangedMsg\n | HostLeavingMsg;\n\n/* ─────────────────── EMBED → HOST ─────────────────── */\n\n/**\n * Emitted by the app as early as possible (synchronous tick of\n * the embed entry, before the SDK is touched). Tells the host\n * the iframe is alive and ready to receive `host:init`. The host\n * MUST NOT send `host:init` before seeing this.\n */\nexport interface EmbedReadyMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'embed:ready';\n version: 1;\n}\n\n/**\n * App-level connection state. The host renders its\n * `ConnectingView` overlay over the (still-mounted) iframe until\n * it sees `phase === 'live'`. Apps SHOULD emit this on every\n * transition; the host caches the last value and won't re-render\n * unless something changes.\n */\nexport interface EmbedAppStateMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'embed:app-state';\n version: 1;\n phase: AppPhase;\n /** Sub-step inside `connecting`. Ignored for other phases. */\n connectingStep?: AppConnectingStep | null;\n /** Optional human-readable hint shown in the overlay caption. */\n message?: string | null;\n}\n\n/** App requests to leave (user clicked an in-app exit, error,\n * ...). The host runs the same tear-down as a top-bar\n * \"End session\". */\nexport interface EmbedRequestLeaveMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'embed:request-leave';\n version: 1;\n}\n\n/** App-level error report. `fatal: true` switches the host to\n * ErrorView; `fatal: false` is logged and may surface a toast. */\nexport interface EmbedErrorMsg {\n source: typeof PROTOCOL_SOURCE;\n type: 'embed:error';\n version: 1;\n message: string;\n fatal: boolean;\n detail?: unknown;\n}\n\nexport type EmbedToHostMsg =\n | EmbedReadyMsg\n | EmbedAppStateMsg\n | EmbedRequestLeaveMsg\n | EmbedErrorMsg;\n\n/* ─────────────────── CREDS BUNDLE ─────────────────── */\n\n/**\n * Serialised credentials passed from the host (Mode A) or the\n * mobile app (Mode B) to the embed via the URL hash fragment.\n *\n * Hash-only (never URL search): browsers don't send the hash to\n * any server, so the HF token never appears in access logs,\n * referer headers, or HF Spaces frontend logs.\n *\n * The embed wipes the hash with `history.replaceState` on its\n * first synchronous tick, before any `await`, then proceeds with\n * the rest of the boot using the in-memory bundle.\n */\nexport interface CredsBundle {\n hfToken?: string | null;\n userName?: string | null;\n robotPeerId: string;\n signalingUrl: string;\n theme: ThemeMode;\n config: ConfigPayload;\n hostName: string;\n appName: string;\n}\n\n/* ─────────────────── HELPERS ─────────────────── */\n\n/**\n * Cheap discriminator: does this `unknown` look like a v1\n * envelope from our protocol? Receivers call this before\n * narrowing on `type`. Conservative on the version: an unknown\n * version is treated as \"not our protocol\" so the receiver\n * silently ignores it (forward-compat for a future v2 peer).\n */\nexport function isProtocolMessage(\n value: unknown,\n): value is { source: typeof PROTOCOL_SOURCE; type: string; version: number } {\n if (!value || typeof value !== 'object') return false;\n const record = value as Record<string, unknown>;\n return (\n record.source === PROTOCOL_SOURCE &&\n typeof record.type === 'string' &&\n record.version === PROTOCOL_VERSION\n );\n}\n\n/**\n * Encode a creds bundle to the URL hash fragment.\n * URL-safe base64 wrapper around JSON to avoid percent-encoding\n * noise.\n */\nexport function encodeCredsToHash(bundle: CredsBundle): string {\n const json = JSON.stringify(bundle);\n const b64 = encodeBase64Utf8(json);\n return `creds=${encodeURIComponent(b64)}`;\n}\n\n/**\n * Decode the creds bundle from a URL hash fragment. Returns\n * `null` if no `creds=` segment is present or if the payload is\n * malformed (caller handles the error by rendering ErrorView).\n */\nexport function decodeCredsFromHash(hash: string | null): CredsBundle | null {\n if (!hash) return null;\n const raw = hash.startsWith('#') ? hash.slice(1) : hash;\n for (const segment of raw.split('&')) {\n if (!segment.startsWith('creds=')) continue;\n try {\n const b64 = decodeURIComponent(segment.slice('creds='.length));\n const json = decodeBase64Utf8(b64);\n return JSON.parse(json) as CredsBundle;\n } catch (err) {\n console.warn('[reachy-mini-sdk/host] failed to decode creds hash', err);\n return null;\n }\n }\n return null;\n}\n\n/* UTF-8 safe base64 helpers (btoa / atob choke on non-Latin\n * characters in `config` payloads). Works in browsers and Node\n * (for unit tests). */\n\nfunction encodeBase64Utf8(input: string): string {\n if (typeof window !== 'undefined' && typeof window.btoa === 'function') {\n const bytes = new TextEncoder().encode(input);\n let bin = '';\n for (const b of bytes) bin += String.fromCharCode(b);\n return window.btoa(bin);\n }\n // Node fallback (tests / SSR).\n return Buffer.from(input, 'utf8').toString('base64');\n}\n\nfunction decodeBase64Utf8(input: string): string {\n if (typeof window !== 'undefined' && typeof window.atob === 'function') {\n const bin = window.atob(input);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n return Buffer.from(input, 'base64').toString('utf8');\n}\n"],"names":["PROTOCOL_VERSION","PROTOCOL_SOURCE","isProtocolMessage","value","record","encodeCredsToHash","bundle","json","b64","encodeBase64Utf8","decodeCredsFromHash","hash","raw","segment","decodeBase64Utf8","err","input","bytes","bin","b","i"],"mappings":"AAqCO,MAAMA,IAAmB,GAGnBC,IAAkB;AAmNxB,SAASC,EACdC,GAC4E;AAC5E,MAAI,CAACA,KAAS,OAAOA,KAAU,SAAU,QAAO;AAChD,QAAMC,IAASD;AACf,SACEC,EAAO,WAAWH,KAClB,OAAOG,EAAO,QAAS,YACvBA,EAAO,YAAY;AAEvB;AAOO,SAASC,EAAkBC,GAA6B;AAC7D,QAAMC,IAAO,KAAK,UAAUD,CAAM,GAC5BE,IAAMC,EAAiBF,CAAI;AACjC,SAAO,SAAS,mBAAmBC,CAAG,CAAC;AACzC;AAOO,SAASE,EAAoBC,GAAyC;AAC3E,MAAI,CAACA,EAAM,QAAO;AAClB,QAAMC,IAAMD,EAAK,WAAW,GAAG,IAAIA,EAAK,MAAM,CAAC,IAAIA;AACnD,aAAWE,KAAWD,EAAI,MAAM,GAAG;AACjC,QAAKC,EAAQ,WAAW,QAAQ;AAChC,UAAI;AACF,cAAML,IAAM,mBAAmBK,EAAQ,MAAM,CAAe,CAAC,GACvDN,IAAOO,EAAiBN,CAAG;AACjC,eAAO,KAAK,MAAMD,CAAI;AAAA,MACxB,SAASQ,GAAK;AACZ,uBAAQ,KAAK,sDAAsDA,CAAG,GAC/D;AAAA,MACT;AAEF,SAAO;AACT;AAMA,SAASN,EAAiBO,GAAuB;AAC/C,MAAI,OAAO,SAAW,OAAe,OAAO,OAAO,QAAS,YAAY;AACtE,UAAMC,IAAQ,IAAI,cAAc,OAAOD,CAAK;AAC5C,QAAIE,IAAM;AACV,eAAWC,KAAKF,EAAO,CAAAC,KAAO,OAAO,aAAaC,CAAC;AACnD,WAAO,OAAO,KAAKD,CAAG;AAAA,EACxB;AAEA,SAAO,OAAO,KAAKF,GAAO,MAAM,EAAE,SAAS,QAAQ;AACrD;AAEA,SAASF,EAAiBE,GAAuB;AAC/C,MAAI,OAAO,SAAW,OAAe,OAAO,OAAO,QAAS,YAAY;AACtE,UAAME,IAAM,OAAO,KAAKF,CAAK,GACvBC,IAAQ,IAAI,WAAWC,EAAI,MAAM;AACvC,aAASE,IAAI,GAAGA,IAAIF,EAAI,QAAQE,IAAK,CAAAH,EAAMG,CAAC,IAAIF,EAAI,WAAWE,CAAC;AAChE,WAAO,IAAI,YAAA,EAAc,OAAOH,CAAK;AAAA,EACvC;AACA,SAAO,OAAO,KAAKD,GAAO,QAAQ,EAAE,SAAS,MAAM;AACrD;"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export of the SDK type surface, sourced from the canonical
|
|
3
|
+
* declarations next to the SDK runtime
|
|
4
|
+
* (`../../../reachy-mini-sdk.d.ts`). Kept as a thin barrel so existing
|
|
5
|
+
* `import type ... from '../lib/sdk-types'` call sites in the host
|
|
6
|
+
* code (`useSdk`, `useRobots`, `embed/index`, picker view, etc.)
|
|
7
|
+
* don't need to reach across the package layout themselves.
|
|
8
|
+
*
|
|
9
|
+
* If you're touching the type surface, edit the canonical file at
|
|
10
|
+
* `js/reachy-mini-sdk.d.ts` — it ships in the npm tarball as
|
|
11
|
+
* the companion `.d.ts` next to `reachy-mini-sdk.js`.
|
|
12
|
+
*/
|
|
13
|
+
export type { RobotInfo, RobotState, ReachyMiniOptions, ReachyMiniInstance, ReachyMiniConstructor, AutoConnectOptions, AutoConnectRobotChoice, AutoConnectResult, MotionAwaitOptions, SubscribeLogsOptions, } from '../../../reachy-mini-sdk';
|
|
14
|
+
import type { ReachyMiniConstructor } from '../../../reachy-mini-sdk';
|
|
15
|
+
/**
|
|
16
|
+
* Host-internal global augmentation: the host shell instantiates
|
|
17
|
+
* `new window.ReachyMini(opts)` (see `useSdk`, `embed/index.ts`)
|
|
18
|
+
* after either the npm entry points or the CDN bundles have
|
|
19
|
+
* auto-assigned the constructor at module-load time. We declare
|
|
20
|
+
* the global as non-optional here so those use sites stay
|
|
21
|
+
* non-null-asserted on the type level; the runtime guarantee is
|
|
22
|
+
* upheld by the side-effect imports in `entry/auto.ts`,
|
|
23
|
+
* `entry/embed.ts` and `index.ts`.
|
|
24
|
+
*
|
|
25
|
+
* The SDK package's companion `reachy-mini-sdk.d.ts` deliberately
|
|
26
|
+
* does NOT augment `Window.ReachyMini` so external consumers who
|
|
27
|
+
* import only the SDK don't have a phantom non-optional global
|
|
28
|
+
* appear in their type-checker.
|
|
29
|
+
*/
|
|
30
|
+
declare global {
|
|
31
|
+
interface Window {
|
|
32
|
+
ReachyMini: ReachyMiniConstructor;
|
|
33
|
+
/** Injected by HF Spaces at container start when
|
|
34
|
+
* `hf_oauth: true` is set in the Space frontmatter. */
|
|
35
|
+
huggingface?: {
|
|
36
|
+
variables?: {
|
|
37
|
+
OAUTH_CLIENT_ID?: string;
|
|
38
|
+
OAUTH_SCOPES?: string;
|
|
39
|
+
SPACE_HOST?: string;
|
|
40
|
+
SPACE_ID?: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=sdk-types.d.ts.map
|
|
@@ -0,0 +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,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEtE;;;;;;;;;;;;;;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"}
|