@mentra/miniapp 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +259 -0
  2. package/dist/background/index.d.ts +60 -0
  3. package/dist/background/index.d.ts.map +1 -0
  4. package/dist/background/index.js +25 -0
  5. package/dist/background/index.js.map +1 -0
  6. package/dist/background/register.d.ts +38 -0
  7. package/dist/background/register.d.ts.map +1 -0
  8. package/dist/background/register.js +75 -0
  9. package/dist/background/register.js.map +1 -0
  10. package/dist/dev-reload.d.ts +21 -0
  11. package/dist/dev-reload.d.ts.map +1 -0
  12. package/dist/dev-reload.js +62 -0
  13. package/dist/dev-reload.js.map +1 -0
  14. package/dist/envelope.d.ts +23 -0
  15. package/dist/envelope.d.ts.map +1 -0
  16. package/dist/envelope.js +47 -0
  17. package/dist/envelope.js.map +1 -0
  18. package/dist/globals.d.ts +54 -0
  19. package/dist/globals.d.ts.map +1 -0
  20. package/dist/globals.js +12 -0
  21. package/dist/globals.js.map +1 -0
  22. package/dist/index.d.ts +59 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +31 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/modules/actions.d.ts +54 -0
  27. package/dist/modules/actions.d.ts.map +1 -0
  28. package/dist/modules/actions.js +122 -0
  29. package/dist/modules/actions.js.map +1 -0
  30. package/dist/modules/auth.d.ts +25 -0
  31. package/dist/modules/auth.d.ts.map +1 -0
  32. package/dist/modules/auth.js +52 -0
  33. package/dist/modules/auth.js.map +1 -0
  34. package/dist/modules/base64.d.ts +16 -0
  35. package/dist/modules/base64.d.ts.map +1 -0
  36. package/dist/modules/base64.js +92 -0
  37. package/dist/modules/base64.js.map +1 -0
  38. package/dist/modules/blob.d.ts +161 -0
  39. package/dist/modules/blob.d.ts.map +1 -0
  40. package/dist/modules/blob.js +277 -0
  41. package/dist/modules/blob.js.map +1 -0
  42. package/dist/modules/camera.d.ts +170 -0
  43. package/dist/modules/camera.d.ts.map +1 -0
  44. package/dist/modules/camera.js +116 -0
  45. package/dist/modules/camera.js.map +1 -0
  46. package/dist/modules/cloud.d.ts +34 -0
  47. package/dist/modules/cloud.d.ts.map +1 -0
  48. package/dist/modules/cloud.js +70 -0
  49. package/dist/modules/cloud.js.map +1 -0
  50. package/dist/modules/dashboard.d.ts +16 -0
  51. package/dist/modules/dashboard.d.ts.map +1 -0
  52. package/dist/modules/dashboard.js +27 -0
  53. package/dist/modules/dashboard.js.map +1 -0
  54. package/dist/modules/display.d.ts +106 -0
  55. package/dist/modules/display.d.ts.map +1 -0
  56. package/dist/modules/display.js +57 -0
  57. package/dist/modules/display.js.map +1 -0
  58. package/dist/modules/events.d.ts +160 -0
  59. package/dist/modules/events.d.ts.map +1 -0
  60. package/dist/modules/events.js +168 -0
  61. package/dist/modules/events.js.map +1 -0
  62. package/dist/modules/glasses.d.ts +28 -0
  63. package/dist/modules/glasses.d.ts.map +1 -0
  64. package/dist/modules/glasses.js +39 -0
  65. package/dist/modules/glasses.js.map +1 -0
  66. package/dist/modules/heading.d.ts +16 -0
  67. package/dist/modules/heading.d.ts.map +1 -0
  68. package/dist/modules/heading.js +20 -0
  69. package/dist/modules/heading.js.map +1 -0
  70. package/dist/modules/imu.d.ts +31 -0
  71. package/dist/modules/imu.d.ts.map +1 -0
  72. package/dist/modules/imu.js +40 -0
  73. package/dist/modules/imu.js.map +1 -0
  74. package/dist/modules/input.d.ts +34 -0
  75. package/dist/modules/input.d.ts.map +1 -0
  76. package/dist/modules/input.js +50 -0
  77. package/dist/modules/input.js.map +1 -0
  78. package/dist/modules/led.d.ts +35 -0
  79. package/dist/modules/led.d.ts.map +1 -0
  80. package/dist/modules/led.js +39 -0
  81. package/dist/modules/led.js.map +1 -0
  82. package/dist/modules/location.d.ts +27 -0
  83. package/dist/modules/location.d.ts.map +1 -0
  84. package/dist/modules/location.js +35 -0
  85. package/dist/modules/location.js.map +1 -0
  86. package/dist/modules/mic.d.ts +44 -0
  87. package/dist/modules/mic.d.ts.map +1 -0
  88. package/dist/modules/mic.js +67 -0
  89. package/dist/modules/mic.js.map +1 -0
  90. package/dist/modules/miniapps.d.ts +72 -0
  91. package/dist/modules/miniapps.d.ts.map +1 -0
  92. package/dist/modules/miniapps.js +48 -0
  93. package/dist/modules/miniapps.js.map +1 -0
  94. package/dist/modules/navigation.d.ts +326 -0
  95. package/dist/modules/navigation.d.ts.map +1 -0
  96. package/dist/modules/navigation.js +386 -0
  97. package/dist/modules/navigation.js.map +1 -0
  98. package/dist/modules/permissions.d.ts +58 -0
  99. package/dist/modules/permissions.d.ts.map +1 -0
  100. package/dist/modules/permissions.js +66 -0
  101. package/dist/modules/permissions.js.map +1 -0
  102. package/dist/modules/phone.d.ts +95 -0
  103. package/dist/modules/phone.d.ts.map +1 -0
  104. package/dist/modules/phone.js +110 -0
  105. package/dist/modules/phone.js.map +1 -0
  106. package/dist/modules/pivots/engine.d.ts +169 -0
  107. package/dist/modules/pivots/engine.d.ts.map +1 -0
  108. package/dist/modules/pivots/engine.js +779 -0
  109. package/dist/modules/pivots/engine.js.map +1 -0
  110. package/dist/modules/pivots/geometry.d.ts +84 -0
  111. package/dist/modules/pivots/geometry.d.ts.map +1 -0
  112. package/dist/modules/pivots/geometry.js +371 -0
  113. package/dist/modules/pivots/geometry.js.map +1 -0
  114. package/dist/modules/pivots/instructions.d.ts +139 -0
  115. package/dist/modules/pivots/instructions.d.ts.map +1 -0
  116. package/dist/modules/pivots/instructions.js +280 -0
  117. package/dist/modules/pivots/instructions.js.map +1 -0
  118. package/dist/modules/speaker.d.ts +169 -0
  119. package/dist/modules/speaker.d.ts.map +1 -0
  120. package/dist/modules/speaker.js +251 -0
  121. package/dist/modules/speaker.js.map +1 -0
  122. package/dist/modules/storage.d.ts +50 -0
  123. package/dist/modules/storage.d.ts.map +1 -0
  124. package/dist/modules/storage.js +99 -0
  125. package/dist/modules/storage.js.map +1 -0
  126. package/dist/modules/stream.d.ts +129 -0
  127. package/dist/modules/stream.d.ts.map +1 -0
  128. package/dist/modules/stream.js +52 -0
  129. package/dist/modules/stream.js.map +1 -0
  130. package/dist/modules/system.d.ts +45 -0
  131. package/dist/modules/system.d.ts.map +1 -0
  132. package/dist/modules/system.js +42 -0
  133. package/dist/modules/system.js.map +1 -0
  134. package/dist/modules/transcription.d.ts +75 -0
  135. package/dist/modules/transcription.d.ts.map +1 -0
  136. package/dist/modules/transcription.js +106 -0
  137. package/dist/modules/transcription.js.map +1 -0
  138. package/dist/modules/translation.d.ts +59 -0
  139. package/dist/modules/translation.d.ts.map +1 -0
  140. package/dist/modules/translation.js +119 -0
  141. package/dist/modules/translation.js.map +1 -0
  142. package/dist/modules/ui.d.ts +186 -0
  143. package/dist/modules/ui.d.ts.map +1 -0
  144. package/dist/modules/ui.js +293 -0
  145. package/dist/modules/ui.js.map +1 -0
  146. package/dist/protocol.d.ts +299 -0
  147. package/dist/protocol.d.ts.map +1 -0
  148. package/dist/protocol.js +325 -0
  149. package/dist/protocol.js.map +1 -0
  150. package/dist/react/MentraProvider.d.ts +33 -0
  151. package/dist/react/MentraProvider.d.ts.map +1 -0
  152. package/dist/react/MentraProvider.js +15 -0
  153. package/dist/react/MentraProvider.js.map +1 -0
  154. package/dist/react/MiniappHeader.d.ts +44 -0
  155. package/dist/react/MiniappHeader.d.ts.map +1 -0
  156. package/dist/react/MiniappHeader.js +32 -0
  157. package/dist/react/MiniappHeader.js.map +1 -0
  158. package/dist/react/index.d.ts +13 -0
  159. package/dist/react/index.d.ts.map +1 -0
  160. package/dist/react/index.js +9 -0
  161. package/dist/react/index.js.map +1 -0
  162. package/dist/react/useCapabilities.d.ts +26 -0
  163. package/dist/react/useCapabilities.d.ts.map +1 -0
  164. package/dist/react/useCapabilities.js +27 -0
  165. package/dist/react/useCapabilities.js.map +1 -0
  166. package/dist/react/useCapsuleHeaderStyle.d.ts +27 -0
  167. package/dist/react/useCapsuleHeaderStyle.d.ts.map +1 -0
  168. package/dist/react/useCapsuleHeaderStyle.js +36 -0
  169. package/dist/react/useCapsuleHeaderStyle.js.map +1 -0
  170. package/dist/react/useColorScheme.d.ts +18 -0
  171. package/dist/react/useColorScheme.d.ts.map +1 -0
  172. package/dist/react/useColorScheme.js +24 -0
  173. package/dist/react/useColorScheme.js.map +1 -0
  174. package/dist/react/useConnected.d.ts +17 -0
  175. package/dist/react/useConnected.d.ts.map +1 -0
  176. package/dist/react/useConnected.js +39 -0
  177. package/dist/react/useConnected.js.map +1 -0
  178. package/dist/react/useRpc.d.ts +29 -0
  179. package/dist/react/useRpc.d.ts.map +1 -0
  180. package/dist/react/useRpc.js +82 -0
  181. package/dist/react/useRpc.js.map +1 -0
  182. package/dist/react/useSafeArea.d.ts +21 -0
  183. package/dist/react/useSafeArea.d.ts.map +1 -0
  184. package/dist/react/useSafeArea.js +22 -0
  185. package/dist/react/useSafeArea.js.map +1 -0
  186. package/dist/session.d.ts +312 -0
  187. package/dist/session.d.ts.map +1 -0
  188. package/dist/session.js +653 -0
  189. package/dist/session.js.map +1 -0
  190. package/dist/sub-path-types.test-d.d.ts +28 -0
  191. package/dist/sub-path-types.test-d.d.ts.map +1 -0
  192. package/dist/sub-path-types.test-d.js +37 -0
  193. package/dist/sub-path-types.test-d.js.map +1 -0
  194. package/dist/transport/auto.d.ts +35 -0
  195. package/dist/transport/auto.d.ts.map +1 -0
  196. package/dist/transport/auto.js +125 -0
  197. package/dist/transport/auto.js.map +1 -0
  198. package/dist/transport/dispatch.d.ts +43 -0
  199. package/dist/transport/dispatch.d.ts.map +1 -0
  200. package/dist/transport/dispatch.js +91 -0
  201. package/dist/transport/dispatch.js.map +1 -0
  202. package/dist/transport/local-socket.d.ts +28 -0
  203. package/dist/transport/local-socket.d.ts.map +1 -0
  204. package/dist/transport/local-socket.js +80 -0
  205. package/dist/transport/local-socket.js.map +1 -0
  206. package/dist/transport/mock.d.ts +54 -0
  207. package/dist/transport/mock.d.ts.map +1 -0
  208. package/dist/transport/mock.js +207 -0
  209. package/dist/transport/mock.js.map +1 -0
  210. package/dist/transport/postmessage.d.ts +36 -0
  211. package/dist/transport/postmessage.d.ts.map +1 -0
  212. package/dist/transport/postmessage.js +78 -0
  213. package/dist/transport/postmessage.js.map +1 -0
  214. package/dist/transport/types.d.ts +25 -0
  215. package/dist/transport/types.d.ts.map +1 -0
  216. package/dist/transport/types.js +11 -0
  217. package/dist/transport/types.js.map +1 -0
  218. package/dist/ui/index.d.ts +98 -0
  219. package/dist/ui/index.d.ts.map +1 -0
  220. package/dist/ui/index.js +32 -0
  221. package/dist/ui/index.js.map +1 -0
  222. package/package.json +84 -0
  223. package/src/background/index.ts +152 -0
  224. package/src/background/register.ts +85 -0
  225. package/src/dev-reload.ts +60 -0
  226. package/src/envelope.ts +54 -0
  227. package/src/globals.ts +62 -0
  228. package/src/index.ts +171 -0
  229. package/src/modules/actions.ts +156 -0
  230. package/src/modules/auth.ts +68 -0
  231. package/src/modules/base64.ts +87 -0
  232. package/src/modules/blob.ts +341 -0
  233. package/src/modules/camera.ts +242 -0
  234. package/src/modules/cloud.ts +94 -0
  235. package/src/modules/dashboard.ts +31 -0
  236. package/src/modules/display.ts +122 -0
  237. package/src/modules/events.ts +291 -0
  238. package/src/modules/glasses.ts +44 -0
  239. package/src/modules/heading.ts +23 -0
  240. package/src/modules/imu.ts +44 -0
  241. package/src/modules/input.ts +71 -0
  242. package/src/modules/led.ts +61 -0
  243. package/src/modules/location.ts +39 -0
  244. package/src/modules/mic.ts +74 -0
  245. package/src/modules/miniapps.ts +90 -0
  246. package/src/modules/navigation.ts +670 -0
  247. package/src/modules/permissions.ts +84 -0
  248. package/src/modules/phone.ts +155 -0
  249. package/src/modules/pivots/engine.ts +863 -0
  250. package/src/modules/pivots/geometry.ts +409 -0
  251. package/src/modules/pivots/instructions.ts +343 -0
  252. package/src/modules/speaker.ts +335 -0
  253. package/src/modules/storage.ts +109 -0
  254. package/src/modules/stream.ts +163 -0
  255. package/src/modules/system.ts +76 -0
  256. package/src/modules/transcription.ts +145 -0
  257. package/src/modules/translation.ts +149 -0
  258. package/src/modules/ui.ts +498 -0
  259. package/src/protocol.ts +378 -0
  260. package/src/react/MentraProvider.tsx +50 -0
  261. package/src/react/MiniappHeader.tsx +122 -0
  262. package/src/react/index.ts +12 -0
  263. package/src/react/useCapabilities.ts +29 -0
  264. package/src/react/useCapsuleHeaderStyle.ts +54 -0
  265. package/src/react/useColorScheme.ts +26 -0
  266. package/src/react/useConnected.ts +47 -0
  267. package/src/react/useRpc.ts +106 -0
  268. package/src/react/useSafeArea.ts +40 -0
  269. package/src/session.ts +886 -0
  270. package/src/sub-path-types.test-d.ts +49 -0
  271. package/src/transport/auto.ts +143 -0
  272. package/src/transport/dispatch.ts +106 -0
  273. package/src/transport/local-socket.ts +93 -0
  274. package/src/transport/mock.ts +251 -0
  275. package/src/transport/postmessage.ts +95 -0
  276. package/src/transport/types.ts +26 -0
  277. package/src/ui/index.ts +122 -0
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ # @mentra/miniapp
2
+
3
+ SDK for building MentraOS local miniapps — static web apps that run inside the MentraOS phone app's WebView and talk to smart glasses via a typed session API.
4
+
5
+ > Developing this SDK or running the in-repo example from a fresh clone? Start at the **[SDK developer guide](../../../sdk/README.md)** (setup, build loop, doc map).
6
+ > Per-module deep dives (return shapes, events, error codes): **[`sdk/docs/`](../../../sdk/docs/README.md)**.
7
+ > Companion package: **[`@mentra/miniapp-cli`](../../../sdk/miniapp-cli/README.md)** — `mentra-miniapp` CLI (`dev`, `release`, `pack`, `manifest`, `permission`, `hardware`, `schema`). Per-command docs live there.
8
+ > Scaffolder: `bunx create-mentra-miniapp my-app`.
9
+ > Reference miniapp: [`sdk/example-miniapp/`](../../../sdk/example-miniapp).
10
+ > High-level walkthrough: [`agents/miniapp-sdk-overview.md`](../../../agents/miniapp-sdk-overview.md).
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ bun add @mentra/miniapp
16
+ # or
17
+ npm install @mentra/miniapp
18
+ ```
19
+
20
+ `react` is an optional peer dependency — only required if you use `@mentra/miniapp/react`.
21
+
22
+ ## Entry points
23
+
24
+ | Specifier | Contents |
25
+ | -------------------------- | ------------------------------------------------------------------------------------------------- |
26
+ | `@mentra/miniapp` | `MiniappSession`, `NotConnectedError`, transports, manifest-types re-exports, module type exports |
27
+ | `@mentra/miniapp/react` | React hooks + `<MentraProvider>` + `<MiniappHeader>` |
28
+ | `@mentra/miniapp/protocol` | `MiniappRequestType`, `MiniappResponseType`, `MiniappStreamType`, `MiniappErrorCode` |
29
+
30
+ ## Quick start
31
+
32
+ ```ts
33
+ import {MiniappSession} from "@mentra/miniapp"
34
+
35
+ const session = new MiniappSession()
36
+ await session.connect() // sends CONNECT, resolves on CONNECT_ACK
37
+
38
+ // render() replaces the whole frame; stable ids update in place, render([]) clears.
39
+ const box = {x: 0, y: 0, w: 576, h: 288} // raw device px — see session.capabilities.display
40
+ session.display.render([{type: "text", id: "hello", box, text: "hello"}])
41
+ const unsub = session.transcription.on((d) => session.display.render([{type: "text", id: "hello", box, text: d.text}]))
42
+ // later: unsub()
43
+ ```
44
+
45
+ React:
46
+
47
+ ```tsx
48
+ import {MentraProvider, useSession, useConnected} from "@mentra/miniapp/react"
49
+
50
+ function App() {
51
+ const session = useSession() // shared session, auto-connects
52
+ const ready = useConnected()
53
+ // ...
54
+ }
55
+
56
+ // root:
57
+ ;<MentraProvider>
58
+ <App />
59
+ </MentraProvider>
60
+ ```
61
+
62
+ ## Session
63
+
64
+ `MiniappSession` is the only object you construct. It owns the transport, the request/response correlation map, the pre-ready outbound queue, the keepalive PONG, and the cached visibility / capabilities / color-scheme / permissions state.
65
+
66
+ ### Lifecycle
67
+
68
+ ```ts
69
+ const session = new MiniappSession(options?)
70
+ await session.connect() // idempotent; same Promise on repeat calls
71
+ session.isConnected()
72
+ session.disconnect()
73
+ ```
74
+
75
+ `MiniappSessionOptions`:
76
+
77
+ - `packageName?: string` — overrides auto-detection from `window.MentraOS`
78
+ - `connectTimeoutMs?: number` — defaults to 10s
79
+ - transport-selection options from `createTransport` (`mode`, `transport`, `localSocket`)
80
+
81
+ ### Lifecycle events
82
+
83
+ ```ts
84
+ const off = session.on("ready", () => {})
85
+ session.off("ready", handler)
86
+ ```
87
+
88
+ | Event | Signature |
89
+ | -------------- | --------------------------------------------- |
90
+ | `ready` | `() => void` — fires after CONNECT_ACK |
91
+ | `disconnect` | `(reason: string) => void` |
92
+ | `error` | `(err: Error) => void` |
93
+ | `visibility` | `("foreground" \| "background") => void` |
94
+ | `capabilities` | `(caps: GlassesCapabilities \| null) => void` |
95
+ | `colorScheme` | `("light" \| "dark") => void` |
96
+ | `permissions` | `(perms: PermissionRecord) => void` |
97
+ | `speakerState` | `(event: SpeakerStateEvent) => void` |
98
+
99
+ Convenience wrappers: `onVisibilityChange`, `onCapabilitiesChange`, `onColorSchemeChange`. Each `on(...)` call also returns an unsubscribe function.
100
+
101
+ ### Cached state
102
+
103
+ `session.userId`, `session.packageName`, `session.capabilities`, `session.visibility`, `session.colorScheme`, `session.ready` — populated from `CONNECT_ACK` and kept in sync via the lifecycle events above.
104
+
105
+ ## Modules
106
+
107
+ All event subscribers return an `UnsubscribeFn`. Subscriptions are ref-counted: the SDK sends `SUBSCRIBE` when a stream's active state or routing metadata changes.
108
+
109
+ | Module | Methods |
110
+ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
111
+ | `session.display` | `render(elements, opts?)` — scene API: diffed frames, stable-id in-place updates, `render([])` clears |
112
+ | `session.speaker` | `play({audioUrl})`, `speak(text, options?)`, `createStream({sampleRate?, volume?})` for bounded 16-bit PCM output, `stop()`, `onStateChange(handler)` |
113
+ | `session.mic` | `onAudioChunk(handler)`, `onVoiceActivity(handler)`, `stop()`, `hasPermission` |
114
+ | `session.transcription` | `on(handler, {forceLocal?})`, `forLanguage(lang \| [langs], handler, {forceLocal?})`, `configure({languageHints, vocabulary, diarization})`, `stop()`, `hasPermission` |
115
+ | `session.translation` | `forLanguagePair(from, to, handler)`, `stop()`, `hasPermission` |
116
+ | `session.input` | `onButtonPress(handler)`, `onTouch(handler \| gesture, handler \| gestures, handler)` |
117
+ | `session.location` | `onUpdate(handler)`, `hasPermission` |
118
+ | `session.imu` | `onHeadPosition(handler)` |
119
+ | `session.glasses` | `onBattery(handler)`, `onConnection(handler)` |
120
+ | `session.phone.notifications` | `on(handler)`, `onDismissed(handler)`, `stop()`, `hasPermission` |
121
+ | `session.phone.calendar` | `listEvents({startsAt, endsAt, limit?})`, `hasPermission` |
122
+ | `session.phone` | `onBattery(handler)` |
123
+ | `session.system` | `share(opts)`, `openUrl(url)`, `copyToClipboard(text)`, `download(opts)` |
124
+ | `session.camera` | `takePhoto({size?, mode?, compress?, sound?, saveToGallery?})`, `setFov({fov, roiPosition?} \| {preset})`, `hasPermission` |
125
+ | `session.led` | `turnOn({color?, ontime?, offtime?, count?})`, `turnOff()`, `blink(color, ontime, offtime, count)`, `solid(color, duration)` — resolve after the glasses acknowledge the RGB command |
126
+ | `session.permissions` | `has(type)`, `getAll()`, `onUpdate(handler)`, `onPermissionError(handler)` |
127
+ | `session.storage` | `get(key)`, `set(key, value)`, `delete(key)`, `list()` — strings only, scoped to `(userId, packageName)` |
128
+ | `session.stream` | `startUnmanaged({streamUrl, video?, audio?, sound?})`, `startManaged({restreamDestinations?, video?, audio?, sound?, ingest?})`, `stop(streamId?)` — stream video input fields are `width`, `height`, `bitrate`, and `fps`; resolved status reports effective frame rate as `resolvedConfig.video.fps`. Start resolves with `{streamId, status, resolvedConfig?}` after glasses report the publisher is streaming; managed starts also return playback URLs; `ingest` selects `"srt"` for HLS/recording or `"whip"` for low-latency WebRTC; stop is idempotent for an already-stopped stream |
129
+ | `session.dashboard` | `setContent(mode, content)` — **noop in v1**, prints a one-time `console.warn`. Cloud DashboardManager owns rendering. |
130
+
131
+ `session.events` is **internal**. It exposes `subscribe(rawStreamType, handler)` only as a forward-compat escape hatch for new event types not yet wrapped on a domain module — prefer the typed module surface.
132
+
133
+ ### Camera FOV
134
+
135
+ `await session.camera.setFov({fov, roiPosition})` applies a temporary, miniapp-owned FOV/ROI override and resolves with `CameraFovResult` after the ASG client reports the setting was applied following the camera restart cooldown. The host restores the previous live miniapp override—or the persistent 102-degree centered base—when this miniapp closes. `roiPosition` accepts `"center"`, `"bottom"`, or `"top"` and defaults to `"center"`. You can also call `setFov({preset: "narrow" | "standard" | "wide"})`; presets map to 82, 102, and 118 degrees with center ROI. The call requires `CAMERA` in `miniapp.json` and rejects with `MiniappRequestError` if the host or glasses cannot apply it.
136
+
137
+ ### Camera Photos
138
+
139
+ `await session.camera.takePhoto(...)` resolves only after the photo is delivered through the phone/cloud upload path. The result includes `{requestId, photoUrl, mimeType, size}`. Glasses-side or phone-relay failures such as `CAMERA_BUSY`, `BATTERY_LOW`, storage errors, or fallback upload failures reject before upload polling completes; intermediate `photo_status` progress and request acceptance alone do not resolve the miniapp photo promise.
140
+
141
+ ### Transcription language convention
142
+
143
+ Transcription/translation streams use a colon-suffixed wire format: `transcription:en-US`, `translation:en-US:fr-FR`. `session.transcription.on(handler)` subscribes to `transcription:auto` (cloud auto-detects). The detected language is in the payload. A handler on `transcription:auto` receives any `transcription:<lang>` event — wildcard fan-out — so "give me transcripts in whatever language" works without manual wiring. Use `session.transcription.forLanguage(lang | [langs], handler)` to pin specific languages. Pass `{forceLocal: true}` as the final argument to either method to require on-device transcription and suppress cloud results for that subscription. Routing is per listener, so a default listener on the same stream can continue receiving cloud transcription.
144
+
145
+ ### Permissions semantics
146
+
147
+ `session.permissions.has("microphone")` returns whether the manifest declared the permission. Same semantics as cloud SDK v3. **It does NOT report OS-level grant state** — even when `has(...)` returns `true` the user can have denied the OS prompt and your subscriptions will silently receive no events. OS-grant tracking and `request(...)` are deferred and will land additively on the same module.
148
+
149
+ `PermissionType` is the lowercase canonical union: `"location" | "microphone" | "camera" | "notifications" | "calendar"`. Manifest UPPER_CASE names map onto these (`BACKGROUND_LOCATION` → `location`; `READ_NOTIFICATIONS`, `POST_NOTIFICATIONS` → `notifications`).
150
+
151
+ ## React bindings — `@mentra/miniapp/react`
152
+
153
+ All hooks share a single session per app, created on first `useSession()` call.
154
+
155
+ | Hook | Returns |
156
+ | ------------------------- | ------------------------------------------------------------------------------------------ |
157
+ | `useSession()` | Shared `MiniappSession`. Auto-calls `connect()` once. |
158
+ | `useConnected()` | `boolean` — flips on `ready` / `disconnect` |
159
+ | `useCapabilities()` | The current glasses capability profile, or `null` |
160
+ | `useVisibility()` | `"foreground" \| "background"` |
161
+ | `useColorScheme()` | `"light" \| "dark"` (host theme) |
162
+ | `useSafeArea()` | `{insets, capsuleMenu}` — pixel insets + bounding rect of the host's floating capsule menu |
163
+ | `useCapsuleHeaderStyle()` | Pre-computed CSS for a header row that aligns with the capsule menu |
164
+
165
+ Components:
166
+
167
+ - `<MentraProvider>` — root provider. Keeps `<html class="dark">` in sync with the host color scheme during render (no FOUC).
168
+ - `<MiniappHeader title="…" left={…} right={…} onBack={…} />` — drop-in header that respects the safe area and leaves room for the capsule menu.
169
+
170
+ ## Manifest — `miniapp.json`
171
+
172
+ ```json
173
+ {
174
+ "packageName": "com.mentra.example",
175
+ "version": "1.0.0",
176
+ "name": "Live Captions",
177
+ "description": "…",
178
+ "icon": "icon.png",
179
+ "permissions": [{"type": "MICROPHONE", "description": "…"}],
180
+ "hardwareRequirements": [
181
+ {"type": "DISPLAY", "level": "REQUIRED"},
182
+ {"type": "MICROPHONE", "level": "REQUIRED"}
183
+ ]
184
+ }
185
+ ```
186
+
187
+ - `permissions[].type` ∈ `MICROPHONE | CAMERA | CALENDAR | LOCATION | BACKGROUND_LOCATION | READ_NOTIFICATIONS | POST_NOTIFICATIONS`
188
+ - `hardwareRequirements[].type` ∈ `CAMERA | DISPLAY | MICROPHONE | SPEAKER | IMU | BUTTON | LIGHT | WIFI`, `level` ∈ `REQUIRED | OPTIONAL`
189
+
190
+ The CLI validates the manifest on every `dev`, `release`, and `pack`. Run `mentra-miniapp schema print` for the canonical JSON Schema.
191
+
192
+ ## CLI
193
+
194
+ The author-facing CLI lives in a sibling package: **[`@mentra/miniapp-cli`](../../../sdk/miniapp-cli/README.md)** (binary: `mentra-miniapp`). Full per-command docs there. Quick map:
195
+
196
+ | Command | Purpose |
197
+ | -------------------------------------------------------------- | ------------------------------------------------------------ |
198
+ | `mentra-miniapp dev` | Hot-reload dev server + QR sideload onto a phone over LAN |
199
+ | `mentra-miniapp release` | Build, pack, and serve a QR to install on a phone |
200
+ | `mentra-miniapp pack` | Validate manifest and zip `dist/` into `<pkg>-<version>.zip` |
201
+ | `mentra-miniapp manifest` | Interactive top-level wizard for `miniapp.json` |
202
+ | `mentra-miniapp permission list \| add \| remove [TYPE]` | Object-verb manifest edits for permissions |
203
+ | `mentra-miniapp hardware list \| add \| remove [TYPE] [LEVEL]` | Object-verb manifest edits for hardware requirements |
204
+ | `mentra-miniapp schema print` | Print the canonical `miniapp.json` JSON Schema |
205
+
206
+ See [the CLI README](../../../sdk/miniapp-cli/README.md) for flags, semantics, and the `miniapp://` URL schemes the QR codes encode.
207
+
208
+ ## Host-injected globals — `window.MentraOS`
209
+
210
+ The MentraOS app injects this before content loads. Authors generally use the React hooks instead, but the raw shape is:
211
+
212
+ ```ts
213
+ {
214
+ packageName, platform, capabilities,
215
+ miniappLocal, miniappDeveloperMode,
216
+ safeAreaInsets: {top, bottom, left, right},
217
+ capsuleMenu: {top, right, bottom, left, width, height},
218
+ colorScheme: "light" | "dark"
219
+ }
220
+ ```
221
+
222
+ Use `getMentraOSGlobals()` (exported from the package) to read it with the right TypeScript types.
223
+
224
+ ## Transports
225
+
226
+ Auto-selected by `createTransport(options)`:
227
+
228
+ - **`PostMessageTransport`** — used inside the MentraOS WebView. `window.ReactNativeWebView.postMessage` outbound, `window` `message` listener inbound.
229
+ - **`LocalSocketTransport`** — fallback for laptop browsers. Default endpoint `ws://127.0.0.1:8765`. The in-laptop-browser dev story is currently broken; see the overview doc for status.
230
+
231
+ Both are exported for advanced uses (forced transport, tests). `MockTransport` is also exported for unit tests.
232
+
233
+ ## Wire protocol
234
+
235
+ Every message is a `{payload, requestId?}` envelope, JSON over the chosen transport. `requestId` correlates request ↔ response for methods that return a value. Constants live in `@mentra/miniapp/protocol`:
236
+
237
+ - `MiniappRequestType` — `CONNECT`, `SUBSCRIBE`, etc.
238
+ - `MiniappResponseType` — `CONNECT_ACK`, `EVENT`, `REQUEST_RESULT`, `PERMISSIONS_UPDATE`, …
239
+ - `MiniappStreamType` — typed names for stream identifiers
240
+ - `MiniappErrorCode` — `NOT_CONNECTED`, `PERMISSION_NOT_DECLARED`, …
241
+
242
+ Full enum listings in [`src/protocol.ts`](./src/protocol.ts).
243
+
244
+ ## Controller pattern (recommended)
245
+
246
+ Smart-glasses miniapps are **always-on services**. The webview is a UI on top of a continuously-running session. If you tie subscriptions to React component lifecycle, closing or navigating away from a page also stops the glasses behavior — wrong shape for glasses.
247
+
248
+ **Rule:** user-facing glasses logic lives in a session-scoped controller, instantiated once at module init. React pages read controller-driven state via a store (Zustand recommended) and call imperative methods on the controller for user-triggered actions. They do **not** subscribe to `session.*` directly.
249
+
250
+ See [`sdk/example-miniapp/src/controller/GlassesController.ts`](../../../sdk/example-miniapp/src/background/controllers/GlassesController.ts) for a worked reference.
251
+
252
+ **Tester pages exception:** `pages/tester/*` are diagnostic surfaces — by design they inline-subscribe to `session.*` and tear down on unmount. This is the only place where that pattern is acceptable.
253
+
254
+ ## File map
255
+
256
+ - Runtime: [`src/{session,protocol,envelope,globals}.ts`](./src/), [`src/modules/`](./src/modules/), [`src/transport/`](./src/transport/), [`src/react/`](./src/react/)
257
+ - CLI: [`../miniapp-cli/src/`](../../../sdk/miniapp-cli/src/)
258
+ - Scaffolder: [`../create-mentra-miniapp/`](../../../sdk/create-mentra-miniapp/)
259
+ - Reference miniapp: [`../example-miniapp/`](../../../sdk/example-miniapp/)
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @mentra/miniapp/background — background-side SDK entry point.
3
+ *
4
+ * Imported from a miniapp's `src/background/index.ts` to access the
5
+ * per-miniapp `MiniappSession` and its typed `session.*` module
6
+ * wrappers. This is the **always-running JSContext side** of a two-layer
7
+ * miniapp.
8
+ *
9
+ * What's NOT in this entry point:
10
+ * - `mentra` WebView global (UI-only — import from `@mentra/miniapp/ui`).
11
+ * - `MentraProvider` / React hooks (UI-only).
12
+ * - Any DOM-bound API. The JSContext has no DOM.
13
+ *
14
+ * Importing the wrong sub-path is caught at compile time by the
15
+ * separate type-roots on each `exports` entry.
16
+ */
17
+ export { MiniappSession, type MiniappSessionOptions } from "../session";
18
+ export { registerMiniapp, type MiniappInitHandler } from "./register";
19
+ export type { TranscriptionData, TranslationData, ButtonPressData, AudioChunkData, VadData, BatteryData, ConnectionData, WifiData, HeadPositionData, AccelData, LocationData, PhoneNotificationData, NotificationDismissedData, HeadingData, TouchData, UnsubscribeFn, } from "../modules/events";
20
+ export type { CalendarEvent, CalendarListOptions, CalendarListResult } from "../modules/phone";
21
+ export { MiniappRequestType, MiniappResponseType, MiniappStreamType, MiniappErrorCode } from "../protocol";
22
+ export type { ActionContext, ActionHandler, InvokeOptions } from "../modules/actions";
23
+ export type { DisplayManager } from "../modules/display";
24
+ export type { CameraFovPreset, CameraFovRequest, CameraFovResult, CameraModule, CameraRoiPosition, SetCameraFovOptions, } from "../modules/camera";
25
+ export type { CloudClientAudioTransport, CloudClientConnectionStatus, CloudClientStatus, CloudModule, } from "../modules/cloud";
26
+ export type { DashboardAPI } from "../modules/dashboard";
27
+ export type { GlassesModule } from "../modules/glasses";
28
+ export type { HeadingModule } from "../modules/heading";
29
+ export type { ImuModule } from "../modules/imu";
30
+ export type { InputModule } from "../modules/input";
31
+ export type { LedModule } from "../modules/led";
32
+ export type { LocationModule } from "../modules/location";
33
+ export type { MicModule } from "../modules/mic";
34
+ export type { NavigationModule } from "../modules/navigation";
35
+ export type { PermissionsModule } from "../modules/permissions";
36
+ export type { PhoneModule } from "../modules/phone";
37
+ export type { SimpleStorage } from "../modules/storage";
38
+ export { BlobModule, BlobWriter, BlobReader, BLOB_WRITE_CHUNK_BYTES, BLOB_READ_ALL_MAX_BYTES } from "../modules/blob";
39
+ export type { BlobMeta, BlobSetOptions, BlobSetFromUrlOptions, BlobImportOptions } from "../modules/blob";
40
+ export { bytesToBase64, base64ToBytes } from "../modules/base64";
41
+ export type { SpeakerModule } from "../modules/speaker";
42
+ export type { StreamModule } from "../modules/stream";
43
+ export type { SystemModule } from "../modules/system";
44
+ export type { TranscriptionModule } from "../modules/transcription";
45
+ export type { TranslationModule } from "../modules/translation";
46
+ export type { UIModule, UIChannelHandler, UIUnsubscribe } from "../modules/ui";
47
+ export type { Rpc, IsRpc, RpcReq, RpcRes, RpcRequestOptions, RpcHandlerContext } from "../modules/ui";
48
+ export { MentraRpcError, MentraRpcTimeoutError } from "../modules/ui";
49
+ export type { LedColor, LedControlOptions } from "../modules/led";
50
+ export type { ViewType, DisplayBreakMode, RenderBox, RenderElement, RenderOptions, RenderRectStyle, RenderResult, RenderTextStyle, } from "../modules/display";
51
+ export type { DashboardMode } from "../modules/dashboard";
52
+ export type { PlayAudioOptions, SpeakOptions, SpeakResult, SpeakerState, SpeakerStateEvent } from "../modules/speaker";
53
+ export type { ShareOptions, ShareResult, DownloadOptions, DownloadResult } from "../modules/system";
54
+ export type { TranscriptionConfig, TranscriptionOptions } from "../modules/transcription";
55
+ export type { PermissionErrorEvent } from "../modules/permissions";
56
+ export type { AuthUpdatePayload, MiniappVisibility, PermissionType, PermissionRecord, GlassesCapabilities, ConnectAckPayload, MiniappAuthState, MiniappRequestError, } from "../session";
57
+ export type { AuthFetchOptions, AuthModule } from "../modules/auth";
58
+ export type { MiniappColorScheme } from "../globals";
59
+ export type { LatLng, TravelMode, ManeuverKind, RouteAvoidances, NavManeuver, NavOffRoute, NavRerouting, NavArrived, NavError, NavUpdate, NavRoute, PivotOptions, Pivot, PivotEvent, NavStep, NavigationDev, StartNavigationOptions, NavState, NavPermissionResult, ComputeRouteOptions, ComputedRouteStep, ComputedRoute, ComputeRouteResult, } from "../modules/navigation";
60
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @mentra/miniapp/background — background-side SDK entry point.
3
+ *
4
+ * Imported from a miniapp's `src/background/index.ts` to access the
5
+ * per-miniapp `MiniappSession` and its typed `session.*` module
6
+ * wrappers. This is the **always-running JSContext side** of a two-layer
7
+ * miniapp.
8
+ *
9
+ * What's NOT in this entry point:
10
+ * - `mentra` WebView global (UI-only — import from `@mentra/miniapp/ui`).
11
+ * - `MentraProvider` / React hooks (UI-only).
12
+ * - Any DOM-bound API. The JSContext has no DOM.
13
+ *
14
+ * Importing the wrong sub-path is caught at compile time by the
15
+ * separate type-roots on each `exports` entry.
16
+ */
17
+ export { MiniappSession } from "../session";
18
+ export { registerMiniapp } from "./register";
19
+ // Public envelope + protocol types so authors can write strongly-typed
20
+ // glue when they need to fall back to session.sendOneShot / sendRequest.
21
+ export { MiniappRequestType, MiniappResponseType, MiniappStreamType, MiniappErrorCode } from "../protocol";
22
+ export { BlobModule, BlobWriter, BlobReader, BLOB_WRITE_CHUNK_BYTES, BLOB_READ_ALL_MAX_BYTES } from "../modules/blob";
23
+ export { bytesToBase64, base64ToBytes } from "../modules/base64";
24
+ export { MentraRpcError, MentraRpcTimeoutError } from "../modules/ui";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/background/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,cAAc,EAA6B,MAAM,YAAY,CAAA;AACrE,OAAO,EAAC,eAAe,EAA0B,MAAM,YAAY,CAAA;AAwBnE,uEAAuE;AACvE,yEAAyE;AACzE,OAAO,EAAC,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,gBAAgB,EAAC,MAAM,aAAa,CAAA;AAoCxG,OAAO,EAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,uBAAuB,EAAC,MAAM,iBAAiB,CAAA;AAEnH,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,mBAAmB,CAAA;AAQ9D,OAAO,EAAC,cAAc,EAAE,qBAAqB,EAAC,MAAM,eAAe,CAAA"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * registerMiniapp — entry hook for the background JSContext.
3
+ *
4
+ * The MentraJS host loads the polyfill (which installs __dispatch /
5
+ * __deliver / timers / fetch / etc.), then evaluates the miniapp's
6
+ * background bundle. After both scripts have evaluated successfully,
7
+ * the host delivers a single `{kind: "init", sessionId}` envelope.
8
+ * The polyfill turns that into a call to `__mentraInitCallback(sessionId)`.
9
+ *
10
+ * This module wires that callback to:
11
+ * 1. Construct a `MiniappSession` (DispatchTransport picks itself
12
+ * automatically because `__dispatch` is on globalThis).
13
+ * 2. Call the user-supplied handler synchronously so subscriptions
14
+ * are registered before any host events fan out.
15
+ * 3. Call `session.connect()` so the host receives CONNECT and the
16
+ * first CONNECT_ACK populates `userId`, `capabilities`, etc.
17
+ *
18
+ * The handler runs once per spawn. If the host kills + respawns the
19
+ * JSContext (crash recovery, dev reload), the polyfill + bundle are
20
+ * re-evaluated and the handler fires again with a fresh session.
21
+ */
22
+ import { MiniappSession, type MiniappSessionOptions } from "../session";
23
+ export type MiniappInitHandler = (session: MiniappSession) => void | Promise<void>;
24
+ /**
25
+ * Register the miniapp's startup handler. Call once at the top level of
26
+ * `src/background/index.ts`. Top-level side effects are fine, but the
27
+ * vast majority of setup should live inside the handler so it can run
28
+ * with a connected session.
29
+ *
30
+ * @example
31
+ * registerMiniapp((session) => {
32
+ * session.transcription.on((tx) => {
33
+ * session.display.render([{type: "text", id: "tx", box, text: tx.text}])
34
+ * })
35
+ * })
36
+ */
37
+ export declare function registerMiniapp(handler: MiniappInitHandler, options?: MiniappSessionOptions): void;
38
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/background/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAC,cAAc,EAAE,KAAK,qBAAqB,EAAC,MAAM,YAAY,CAAA;AAErE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAYlF;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,GAAE,qBAA0B,GAAG,IAAI,CAmCtG"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * registerMiniapp — entry hook for the background JSContext.
3
+ *
4
+ * The MentraJS host loads the polyfill (which installs __dispatch /
5
+ * __deliver / timers / fetch / etc.), then evaluates the miniapp's
6
+ * background bundle. After both scripts have evaluated successfully,
7
+ * the host delivers a single `{kind: "init", sessionId}` envelope.
8
+ * The polyfill turns that into a call to `__mentraInitCallback(sessionId)`.
9
+ *
10
+ * This module wires that callback to:
11
+ * 1. Construct a `MiniappSession` (DispatchTransport picks itself
12
+ * automatically because `__dispatch` is on globalThis).
13
+ * 2. Call the user-supplied handler synchronously so subscriptions
14
+ * are registered before any host events fan out.
15
+ * 3. Call `session.connect()` so the host receives CONNECT and the
16
+ * first CONNECT_ACK populates `userId`, `capabilities`, etc.
17
+ *
18
+ * The handler runs once per spawn. If the host kills + respawns the
19
+ * JSContext (crash recovery, dev reload), the polyfill + bundle are
20
+ * re-evaluated and the handler fires again with a fresh session.
21
+ */
22
+ import { MiniappSession } from "../session";
23
+ /**
24
+ * Register the miniapp's startup handler. Call once at the top level of
25
+ * `src/background/index.ts`. Top-level side effects are fine, but the
26
+ * vast majority of setup should live inside the handler so it can run
27
+ * with a connected session.
28
+ *
29
+ * @example
30
+ * registerMiniapp((session) => {
31
+ * session.transcription.on((tx) => {
32
+ * session.display.render([{type: "text", id: "tx", box, text: tx.text}])
33
+ * })
34
+ * })
35
+ */
36
+ export function registerMiniapp(handler, options = {}) {
37
+ const g = globalThis;
38
+ g.__mentraInitCallback = (_sessionId) => {
39
+ const session = new MiniappSession(options);
40
+ // Fire the user handler first so any session.* subscriptions get
41
+ // registered before the CONNECT_ACK fan-out lands.
42
+ try {
43
+ const result = handler(session);
44
+ if (result && typeof result.then === "function") {
45
+ ;
46
+ result.catch((err) => {
47
+ // eslint-disable-next-line no-console
48
+ console.error("[mentra-miniapp] registerMiniapp handler rejected:", err);
49
+ });
50
+ }
51
+ }
52
+ catch (err) {
53
+ // eslint-disable-next-line no-console
54
+ console.error("[mentra-miniapp] registerMiniapp handler threw:", err);
55
+ }
56
+ session.connect().catch((err) => {
57
+ // eslint-disable-next-line no-console
58
+ console.error("[mentra-miniapp] session.connect() rejected:", err);
59
+ // Surface to the host's crash controller as a structured uncaught
60
+ // error so the existing backoff + crashloop machinery handles it.
61
+ // Repeated connect failures eventually flip the miniapp to
62
+ // CRASHLOOP_DISABLED, which the host turns into a user-facing
63
+ // alert + automatic incident report.
64
+ try {
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ const stack = err instanceof Error && err.stack ? err.stack : "";
67
+ g.__hostError?.(JSON.stringify({ message: `session.connect() failed: ${message}`, stack }));
68
+ }
69
+ catch {
70
+ /* host bridge missing in tests — ignore */
71
+ }
72
+ });
73
+ };
74
+ }
75
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/background/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAC,cAAc,EAA6B,MAAM,YAAY,CAAA;AAcrE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,OAA2B,EAAE,UAAiC,EAAE;IAC9F,MAAM,CAAC,GAAG,UAAoC,CAAA;IAC9C,CAAC,CAAC,oBAAoB,GAAG,CAAC,UAAkB,EAAE,EAAE;QAC9C,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,iEAAiE;QACjE,mDAAmD;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;YAC/B,IAAI,MAAM,IAAI,OAAQ,MAAwB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACnE,CAAC;gBAAC,MAAwB,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;oBAChD,sCAAsC;oBACtC,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,CAAC,CAAA;gBAC1E,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,GAAG,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACvC,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,GAAG,CAAC,CAAA;YAClE,kEAAkE;YAClE,kEAAkE;YAClE,2DAA2D;YAC3D,8DAA8D;YAC9D,qCAAqC;YACrC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBAChE,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;gBAChE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,OAAO,EAAE,6BAA6B,OAAO,EAAE,EAAE,KAAK,EAAC,CAAC,CAAC,CAAA;YAC3F,CAAC;YAAC,MAAM,CAAC;gBACP,2CAA2C;YAC7C,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview SDK-side dev-reload listener — auto-installed when the host
3
+ * indicates we're running in a dev miniapp.
4
+ *
5
+ * Companion to the phone-side console-tap shim (which is injected by the
6
+ * MentraOS app, not by the SDK). The SDK installs this listener on import so
7
+ * authors get live reload without any opt-in code.
8
+ *
9
+ * Mechanism:
10
+ * - Phone-side `DevServerBridge` receives `{type: "reload"}` from the dev
11
+ * server's WebSocket.
12
+ * - Phone-side `MiniappHost` then injects a `MessageEvent` into the WebView
13
+ * with payload `{type: "miniapp_dev_reload"}`.
14
+ * - This listener catches that MessageEvent and calls `location.reload()`.
15
+ *
16
+ * Gated on `window.MentraOS.miniappDeveloperMode === true` so production
17
+ * miniapps never set up the listener. In production WebViews the host won't
18
+ * inject the message anyway, but belt-and-suspenders.
19
+ */
20
+ export declare function installDevReloadListenerIfDevMode(): void;
21
+ //# sourceMappingURL=dev-reload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-reload.d.ts","sourceRoot":"","sources":["../src/dev-reload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,wBAAgB,iCAAiC,IAAI,IAAI,CAqCxD"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview SDK-side dev-reload listener — auto-installed when the host
3
+ * indicates we're running in a dev miniapp.
4
+ *
5
+ * Companion to the phone-side console-tap shim (which is injected by the
6
+ * MentraOS app, not by the SDK). The SDK installs this listener on import so
7
+ * authors get live reload without any opt-in code.
8
+ *
9
+ * Mechanism:
10
+ * - Phone-side `DevServerBridge` receives `{type: "reload"}` from the dev
11
+ * server's WebSocket.
12
+ * - Phone-side `MiniappHost` then injects a `MessageEvent` into the WebView
13
+ * with payload `{type: "miniapp_dev_reload"}`.
14
+ * - This listener catches that MessageEvent and calls `location.reload()`.
15
+ *
16
+ * Gated on `window.MentraOS.miniappDeveloperMode === true` so production
17
+ * miniapps never set up the listener. In production WebViews the host won't
18
+ * inject the message anyway, but belt-and-suspenders.
19
+ */
20
+ const RELOAD_MESSAGE_TYPE = "miniapp_dev_reload";
21
+ export function installDevReloadListenerIfDevMode() {
22
+ if (typeof window === "undefined")
23
+ return;
24
+ const mentra = window.MentraOS;
25
+ if (!mentra?.miniappDeveloperMode)
26
+ return;
27
+ // Avoid double-install if the SDK is hot-reloaded mid-session.
28
+ const flagKey = "__mentraDevReloadInstalled";
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ if (window[flagKey])
31
+ return;
32
+ window[flagKey] = true;
33
+ const handler = (ev) => {
34
+ const data = typeof ev.data === "string" ? ev.data : null;
35
+ if (!data)
36
+ return;
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(data);
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ const env = parsed;
45
+ const type = env?.payload?.type;
46
+ if (type !== RELOAD_MESSAGE_TYPE)
47
+ return;
48
+ // eslint-disable-next-line no-console
49
+ console.log("[mentra-miniapp] dev reload signal received — reloading");
50
+ try {
51
+ location.reload();
52
+ }
53
+ catch {
54
+ // Some embedded contexts forbid reload; ignore.
55
+ }
56
+ };
57
+ window.addEventListener("message", handler);
58
+ if (typeof document !== "undefined") {
59
+ document.addEventListener("message", handler);
60
+ }
61
+ }
62
+ //# sourceMappingURL=dev-reload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-reload.js","sourceRoot":"","sources":["../src/dev-reload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,mBAAmB,GAAG,oBAAoB,CAAA;AAEhD,MAAM,UAAU,iCAAiC;IAC/C,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAM;IACzC,MAAM,MAAM,GAAI,MAAwD,CAAC,QAAQ,CAAA;IACjF,IAAI,CAAC,MAAM,EAAE,oBAAoB;QAAE,OAAM;IAEzC,+DAA+D;IAC/D,MAAM,OAAO,GAAG,4BAA4B,CAAA;IAC5C,8DAA8D;IAC9D,IAAK,MAAc,CAAC,OAAO,CAAC;QAAE,OAE7B;IAAC,MAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IAEhC,MAAM,OAAO,GAAG,CAAC,EAAgB,EAAQ,EAAE;QACzC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QACzD,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,MAAe,CAAA;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,MAAM,GAAG,GAAG,MAAqC,CAAA;QACjD,MAAM,IAAI,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,CAAA;QAC/B,IAAI,IAAI,KAAK,mBAAmB;YAAE,OAAM;QACxC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAA;QACtE,IAAI,CAAC;YACH,QAAQ,CAAC,MAAM,EAAE,CAAA;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC,CAAA;IAED,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC3C,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAmC,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Bridge envelope format.
3
+ *
4
+ * Every message between @mentra/miniapp and LocalMiniappRuntime is wrapped in
5
+ * this envelope for request/response correlation.
6
+ *
7
+ * { payload: {...}, requestId?: string }
8
+ */
9
+ export interface MiniappEnvelope<P = unknown> {
10
+ payload: P;
11
+ /** Correlates request/response pairs. Set by the sender when it wants a reply. */
12
+ requestId?: string;
13
+ }
14
+ /** Serialize an envelope for postMessage / WebSocket transport. */
15
+ export declare function serializeEnvelope(envelope: MiniappEnvelope): string;
16
+ /**
17
+ * Parse a serialized envelope. Returns null for any malformed input — never throws.
18
+ * Transports should pass raw strings in and silently drop nulls.
19
+ */
20
+ export declare function parseEnvelope(raw: unknown): MiniappEnvelope | null;
21
+ /** Generate a short random requestId. Browser-native (crypto.randomUUID). */
22
+ export declare function makeRequestId(): string;
23
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,OAAO,EAAE,CAAC,CAAA;IACV,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAoBlE;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,IAAI,MAAM,CAMtC"}