@pollen-robotics/reachy-mini-sdk 1.7.3-main.5cd69ad

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/LICENSE +201 -0
  3. package/README.md +129 -0
  4. package/host/APP_AUTHOR_GUIDE.md +646 -0
  5. package/host/README.md +155 -0
  6. package/host/SPEC.md +618 -0
  7. package/host/dist/ReachyHost.d.ts +39 -0
  8. package/host/dist/ReachyHost.d.ts.map +1 -0
  9. package/host/dist/assets/index.d.ts +16 -0
  10. package/host/dist/assets/index.d.ts.map +1 -0
  11. package/host/dist/chunks/index-CyLPysJS.js +401 -0
  12. package/host/dist/chunks/index-CyLPysJS.js.map +1 -0
  13. package/host/dist/chunks/mountHost-8f-laxwI.js +48280 -0
  14. package/host/dist/chunks/mountHost-8f-laxwI.js.map +1 -0
  15. package/host/dist/chunks/reachy-mini-sdk-eBYlC77N.js +1719 -0
  16. package/host/dist/chunks/reachy-mini-sdk-eBYlC77N.js.map +1 -0
  17. package/host/dist/components/ConnectingView.d.ts +13 -0
  18. package/host/dist/components/ConnectingView.d.ts.map +1 -0
  19. package/host/dist/components/EmbedFrame.d.ts +16 -0
  20. package/host/dist/components/EmbedFrame.d.ts.map +1 -0
  21. package/host/dist/components/ErrorView.d.ts +21 -0
  22. package/host/dist/components/ErrorView.d.ts.map +1 -0
  23. package/host/dist/components/LeavingView.d.ts +33 -0
  24. package/host/dist/components/LeavingView.d.ts.map +1 -0
  25. package/host/dist/components/PickerView.d.ts +51 -0
  26. package/host/dist/components/PickerView.d.ts.map +1 -0
  27. package/host/dist/components/ReachyHostShell.d.ts +21 -0
  28. package/host/dist/components/ReachyHostShell.d.ts.map +1 -0
  29. package/host/dist/components/SignInView.d.ts +32 -0
  30. package/host/dist/components/SignInView.d.ts.map +1 -0
  31. package/host/dist/components/StepsProgressIndicator.d.ts +41 -0
  32. package/host/dist/components/StepsProgressIndicator.d.ts.map +1 -0
  33. package/host/dist/components/TopBar.d.ts +52 -0
  34. package/host/dist/components/TopBar.d.ts.map +1 -0
  35. package/host/dist/components/WelcomeBackOverlay.d.ts +28 -0
  36. package/host/dist/components/WelcomeBackOverlay.d.ts.map +1 -0
  37. package/host/dist/embed/index.d.ts +151 -0
  38. package/host/dist/embed/index.d.ts.map +1 -0
  39. package/host/dist/entry/auto.d.ts +12 -0
  40. package/host/dist/entry/auto.d.ts.map +1 -0
  41. package/host/dist/entry/auto.js +7 -0
  42. package/host/dist/entry/auto.js.map +1 -0
  43. package/host/dist/entry/embed.d.ts +12 -0
  44. package/host/dist/entry/embed.d.ts.map +1 -0
  45. package/host/dist/entry/embed.js +7 -0
  46. package/host/dist/entry/embed.js.map +1 -0
  47. package/host/dist/hooks/useHfProfile.d.ts +7 -0
  48. package/host/dist/hooks/useHfProfile.d.ts.map +1 -0
  49. package/host/dist/hooks/useHostBridge.d.ts +37 -0
  50. package/host/dist/hooks/useHostBridge.d.ts.map +1 -0
  51. package/host/dist/hooks/useOAuth.d.ts +16 -0
  52. package/host/dist/hooks/useOAuth.d.ts.map +1 -0
  53. package/host/dist/hooks/useRobots.d.ts +17 -0
  54. package/host/dist/hooks/useRobots.d.ts.map +1 -0
  55. package/host/dist/hooks/useSdk.d.ts +16 -0
  56. package/host/dist/hooks/useSdk.d.ts.map +1 -0
  57. package/host/dist/index.d.ts +25 -0
  58. package/host/dist/index.d.ts.map +1 -0
  59. package/host/dist/index.js +15 -0
  60. package/host/dist/index.js.map +1 -0
  61. package/host/dist/lib/centralListener.d.ts +73 -0
  62. package/host/dist/lib/centralListener.d.ts.map +1 -0
  63. package/host/dist/lib/centralRest.d.ts +35 -0
  64. package/host/dist/lib/centralRest.d.ts.map +1 -0
  65. package/host/dist/lib/protocol.d.ts +230 -0
  66. package/host/dist/lib/protocol.d.ts.map +1 -0
  67. package/host/dist/lib/protocol.js +48 -0
  68. package/host/dist/lib/protocol.js.map +1 -0
  69. package/host/dist/lib/sdk-types.d.ts +46 -0
  70. package/host/dist/lib/sdk-types.d.ts.map +1 -0
  71. package/host/dist/lib/settings.d.ts +69 -0
  72. package/host/dist/lib/settings.d.ts.map +1 -0
  73. package/host/dist/lib/signalingUrl.d.ts +28 -0
  74. package/host/dist/lib/signalingUrl.d.ts.map +1 -0
  75. package/host/dist/lib/theme.d.ts +4 -0
  76. package/host/dist/lib/theme.d.ts.map +1 -0
  77. package/host/dist/lib/themeMode.d.ts +9 -0
  78. package/host/dist/lib/themeMode.d.ts.map +1 -0
  79. package/host/dist/lib/tokens.d.ts +64 -0
  80. package/host/dist/lib/tokens.d.ts.map +1 -0
  81. package/host/dist/mountHost.d.ts +36 -0
  82. package/host/dist/mountHost.d.ts.map +1 -0
  83. package/package.json +109 -0
  84. package/reachy-mini-sdk.d.ts +294 -0
  85. package/reachy-mini-sdk.js +2618 -0
@@ -0,0 +1,16 @@
1
+ import type { ReachyMiniInstance } from '../lib/sdk-types';
2
+ export interface OAuthState {
3
+ /** SDK reports an active auth (token + user name resolved). */
4
+ isAuthenticated: boolean;
5
+ /** HF account user name when known. */
6
+ userName: string | null;
7
+ /** Boot started from an OAuth redirect (i.e. `oauth-pending`
8
+ * flag was set). Reset once `isAuthenticated` flips true. */
9
+ isPostOauthReturn: boolean;
10
+ /** Async wrapper around `sdk.login()`. */
11
+ signIn(): Promise<void>;
12
+ /** Sync wrapper around `sdk.logout()` + mark signed-out. */
13
+ signOut(): void;
14
+ }
15
+ export declare function useOAuth(sdk: ReachyMiniInstance | null): OAuthState;
16
+ //# sourceMappingURL=useOAuth.d.ts.map
@@ -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-eBYlC77N.js";
2
+ import { R as s, m as a } from "./chunks/mountHost-8f-laxwI.js";
3
+ import { c as t } from "./chunks/index-CyLPysJS.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"}