@mentra/miniapp 0.3.0-dev.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.
- package/README.md +259 -0
- package/dist/background/index.d.ts +59 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +25 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/register.d.ts +38 -0
- package/dist/background/register.d.ts.map +1 -0
- package/dist/background/register.js +75 -0
- package/dist/background/register.js.map +1 -0
- package/dist/dev-reload.d.ts +21 -0
- package/dist/dev-reload.d.ts.map +1 -0
- package/dist/dev-reload.js +62 -0
- package/dist/dev-reload.js.map +1 -0
- package/dist/envelope.d.ts +23 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +47 -0
- package/dist/envelope.js.map +1 -0
- package/dist/globals.d.ts +54 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +12 -0
- package/dist/globals.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/actions.d.ts +54 -0
- package/dist/modules/actions.d.ts.map +1 -0
- package/dist/modules/actions.js +122 -0
- package/dist/modules/actions.js.map +1 -0
- package/dist/modules/auth.d.ts +25 -0
- package/dist/modules/auth.d.ts.map +1 -0
- package/dist/modules/auth.js +52 -0
- package/dist/modules/auth.js.map +1 -0
- package/dist/modules/base64.d.ts +16 -0
- package/dist/modules/base64.d.ts.map +1 -0
- package/dist/modules/base64.js +92 -0
- package/dist/modules/base64.js.map +1 -0
- package/dist/modules/blob.d.ts +161 -0
- package/dist/modules/blob.d.ts.map +1 -0
- package/dist/modules/blob.js +277 -0
- package/dist/modules/blob.js.map +1 -0
- package/dist/modules/camera.d.ts +137 -0
- package/dist/modules/camera.d.ts.map +1 -0
- package/dist/modules/camera.js +104 -0
- package/dist/modules/camera.js.map +1 -0
- package/dist/modules/cloud.d.ts +34 -0
- package/dist/modules/cloud.d.ts.map +1 -0
- package/dist/modules/cloud.js +70 -0
- package/dist/modules/cloud.js.map +1 -0
- package/dist/modules/dashboard.d.ts +16 -0
- package/dist/modules/dashboard.d.ts.map +1 -0
- package/dist/modules/dashboard.js +27 -0
- package/dist/modules/dashboard.js.map +1 -0
- package/dist/modules/display.d.ts +106 -0
- package/dist/modules/display.d.ts.map +1 -0
- package/dist/modules/display.js +57 -0
- package/dist/modules/display.js.map +1 -0
- package/dist/modules/events.d.ts +167 -0
- package/dist/modules/events.d.ts.map +1 -0
- package/dist/modules/events.js +123 -0
- package/dist/modules/events.js.map +1 -0
- package/dist/modules/glasses.d.ts +28 -0
- package/dist/modules/glasses.d.ts.map +1 -0
- package/dist/modules/glasses.js +39 -0
- package/dist/modules/glasses.js.map +1 -0
- package/dist/modules/heading.d.ts +16 -0
- package/dist/modules/heading.d.ts.map +1 -0
- package/dist/modules/heading.js +20 -0
- package/dist/modules/heading.js.map +1 -0
- package/dist/modules/imu.d.ts +31 -0
- package/dist/modules/imu.d.ts.map +1 -0
- package/dist/modules/imu.js +40 -0
- package/dist/modules/imu.js.map +1 -0
- package/dist/modules/input.d.ts +34 -0
- package/dist/modules/input.d.ts.map +1 -0
- package/dist/modules/input.js +50 -0
- package/dist/modules/input.js.map +1 -0
- package/dist/modules/led.d.ts +35 -0
- package/dist/modules/led.d.ts.map +1 -0
- package/dist/modules/led.js +39 -0
- package/dist/modules/led.js.map +1 -0
- package/dist/modules/location.d.ts +27 -0
- package/dist/modules/location.d.ts.map +1 -0
- package/dist/modules/location.js +35 -0
- package/dist/modules/location.js.map +1 -0
- package/dist/modules/mic.d.ts +44 -0
- package/dist/modules/mic.d.ts.map +1 -0
- package/dist/modules/mic.js +67 -0
- package/dist/modules/mic.js.map +1 -0
- package/dist/modules/miniapps.d.ts +72 -0
- package/dist/modules/miniapps.d.ts.map +1 -0
- package/dist/modules/miniapps.js +48 -0
- package/dist/modules/miniapps.js.map +1 -0
- package/dist/modules/navigation.d.ts +326 -0
- package/dist/modules/navigation.d.ts.map +1 -0
- package/dist/modules/navigation.js +386 -0
- package/dist/modules/navigation.js.map +1 -0
- package/dist/modules/permissions.d.ts +58 -0
- package/dist/modules/permissions.d.ts.map +1 -0
- package/dist/modules/permissions.js +66 -0
- package/dist/modules/permissions.js.map +1 -0
- package/dist/modules/phone.d.ts +61 -0
- package/dist/modules/phone.d.ts.map +1 -0
- package/dist/modules/phone.js +94 -0
- package/dist/modules/phone.js.map +1 -0
- package/dist/modules/pivots/engine.d.ts +169 -0
- package/dist/modules/pivots/engine.d.ts.map +1 -0
- package/dist/modules/pivots/engine.js +779 -0
- package/dist/modules/pivots/engine.js.map +1 -0
- package/dist/modules/pivots/geometry.d.ts +84 -0
- package/dist/modules/pivots/geometry.d.ts.map +1 -0
- package/dist/modules/pivots/geometry.js +371 -0
- package/dist/modules/pivots/geometry.js.map +1 -0
- package/dist/modules/pivots/instructions.d.ts +139 -0
- package/dist/modules/pivots/instructions.d.ts.map +1 -0
- package/dist/modules/pivots/instructions.js +280 -0
- package/dist/modules/pivots/instructions.js.map +1 -0
- package/dist/modules/speaker.d.ts +163 -0
- package/dist/modules/speaker.d.ts.map +1 -0
- package/dist/modules/speaker.js +250 -0
- package/dist/modules/speaker.js.map +1 -0
- package/dist/modules/storage.d.ts +50 -0
- package/dist/modules/storage.d.ts.map +1 -0
- package/dist/modules/storage.js +99 -0
- package/dist/modules/storage.js.map +1 -0
- package/dist/modules/stream.d.ts +129 -0
- package/dist/modules/stream.d.ts.map +1 -0
- package/dist/modules/stream.js +52 -0
- package/dist/modules/stream.js.map +1 -0
- package/dist/modules/system.d.ts +45 -0
- package/dist/modules/system.d.ts.map +1 -0
- package/dist/modules/system.js +42 -0
- package/dist/modules/system.js.map +1 -0
- package/dist/modules/transcription.d.ts +67 -0
- package/dist/modules/transcription.d.ts.map +1 -0
- package/dist/modules/transcription.js +106 -0
- package/dist/modules/transcription.js.map +1 -0
- package/dist/modules/translation.d.ts +59 -0
- package/dist/modules/translation.d.ts.map +1 -0
- package/dist/modules/translation.js +119 -0
- package/dist/modules/translation.js.map +1 -0
- package/dist/modules/ui.d.ts +186 -0
- package/dist/modules/ui.d.ts.map +1 -0
- package/dist/modules/ui.js +293 -0
- package/dist/modules/ui.js.map +1 -0
- package/dist/protocol.d.ts +294 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +320 -0
- package/dist/protocol.js.map +1 -0
- package/dist/react/MentraProvider.d.ts +33 -0
- package/dist/react/MentraProvider.d.ts.map +1 -0
- package/dist/react/MentraProvider.js +15 -0
- package/dist/react/MentraProvider.js.map +1 -0
- package/dist/react/MiniappHeader.d.ts +44 -0
- package/dist/react/MiniappHeader.d.ts.map +1 -0
- package/dist/react/MiniappHeader.js +32 -0
- package/dist/react/MiniappHeader.js.map +1 -0
- package/dist/react/index.d.ts +13 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +9 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useCapabilities.d.ts +26 -0
- package/dist/react/useCapabilities.d.ts.map +1 -0
- package/dist/react/useCapabilities.js +27 -0
- package/dist/react/useCapabilities.js.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts +27 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.js +36 -0
- package/dist/react/useCapsuleHeaderStyle.js.map +1 -0
- package/dist/react/useColorScheme.d.ts +18 -0
- package/dist/react/useColorScheme.d.ts.map +1 -0
- package/dist/react/useColorScheme.js +24 -0
- package/dist/react/useColorScheme.js.map +1 -0
- package/dist/react/useConnected.d.ts +17 -0
- package/dist/react/useConnected.d.ts.map +1 -0
- package/dist/react/useConnected.js +39 -0
- package/dist/react/useConnected.js.map +1 -0
- package/dist/react/useRpc.d.ts +29 -0
- package/dist/react/useRpc.d.ts.map +1 -0
- package/dist/react/useRpc.js +82 -0
- package/dist/react/useRpc.js.map +1 -0
- package/dist/react/useSafeArea.d.ts +21 -0
- package/dist/react/useSafeArea.d.ts.map +1 -0
- package/dist/react/useSafeArea.js +22 -0
- package/dist/react/useSafeArea.js.map +1 -0
- package/dist/session.d.ts +310 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +653 -0
- package/dist/session.js.map +1 -0
- package/dist/sub-path-types.test-d.d.ts +28 -0
- package/dist/sub-path-types.test-d.d.ts.map +1 -0
- package/dist/sub-path-types.test-d.js +37 -0
- package/dist/sub-path-types.test-d.js.map +1 -0
- package/dist/transport/auto.d.ts +35 -0
- package/dist/transport/auto.d.ts.map +1 -0
- package/dist/transport/auto.js +125 -0
- package/dist/transport/auto.js.map +1 -0
- package/dist/transport/dispatch.d.ts +43 -0
- package/dist/transport/dispatch.d.ts.map +1 -0
- package/dist/transport/dispatch.js +91 -0
- package/dist/transport/dispatch.js.map +1 -0
- package/dist/transport/local-socket.d.ts +28 -0
- package/dist/transport/local-socket.d.ts.map +1 -0
- package/dist/transport/local-socket.js +80 -0
- package/dist/transport/local-socket.js.map +1 -0
- package/dist/transport/mock.d.ts +54 -0
- package/dist/transport/mock.d.ts.map +1 -0
- package/dist/transport/mock.js +205 -0
- package/dist/transport/mock.js.map +1 -0
- package/dist/transport/postmessage.d.ts +36 -0
- package/dist/transport/postmessage.d.ts.map +1 -0
- package/dist/transport/postmessage.js +78 -0
- package/dist/transport/postmessage.js.map +1 -0
- package/dist/transport/types.d.ts +25 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +11 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/ui/index.d.ts +98 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +32 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +75 -0
- package/src/background/index.ts +152 -0
- package/src/background/register.ts +85 -0
- package/src/dev-reload.ts +60 -0
- package/src/envelope.ts +54 -0
- package/src/globals.ts +62 -0
- package/src/index.ts +171 -0
- package/src/modules/actions.ts +156 -0
- package/src/modules/auth.ts +68 -0
- package/src/modules/base64.ts +87 -0
- package/src/modules/blob.ts +341 -0
- package/src/modules/camera.ts +196 -0
- package/src/modules/cloud.ts +94 -0
- package/src/modules/dashboard.ts +31 -0
- package/src/modules/display.ts +122 -0
- package/src/modules/events.ts +264 -0
- package/src/modules/glasses.ts +44 -0
- package/src/modules/heading.ts +23 -0
- package/src/modules/imu.ts +44 -0
- package/src/modules/input.ts +71 -0
- package/src/modules/led.ts +61 -0
- package/src/modules/location.ts +39 -0
- package/src/modules/mic.ts +74 -0
- package/src/modules/miniapps.ts +90 -0
- package/src/modules/navigation.ts +670 -0
- package/src/modules/permissions.ts +84 -0
- package/src/modules/phone.ts +120 -0
- package/src/modules/pivots/engine.ts +863 -0
- package/src/modules/pivots/geometry.ts +409 -0
- package/src/modules/pivots/instructions.ts +343 -0
- package/src/modules/speaker.ts +328 -0
- package/src/modules/storage.ts +109 -0
- package/src/modules/stream.ts +163 -0
- package/src/modules/system.ts +76 -0
- package/src/modules/transcription.ts +128 -0
- package/src/modules/translation.ts +149 -0
- package/src/modules/ui.ts +498 -0
- package/src/protocol.ts +371 -0
- package/src/react/MentraProvider.tsx +50 -0
- package/src/react/MiniappHeader.tsx +122 -0
- package/src/react/index.ts +12 -0
- package/src/react/useCapabilities.ts +29 -0
- package/src/react/useCapsuleHeaderStyle.ts +54 -0
- package/src/react/useColorScheme.ts +26 -0
- package/src/react/useConnected.ts +47 -0
- package/src/react/useRpc.ts +106 -0
- package/src/react/useSafeArea.ts +40 -0
- package/src/session.ts +878 -0
- package/src/sub-path-types.test-d.ts +49 -0
- package/src/transport/auto.ts +143 -0
- package/src/transport/dispatch.ts +106 -0
- package/src/transport/local-socket.ts +93 -0
- package/src/transport/mock.ts +248 -0
- package/src/transport/postmessage.ts +95 -0
- package/src/transport/types.ts +26 -0
- package/src/ui/index.ts +122 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview SimpleStorage — phone-local key-value store scoped to
|
|
3
|
+
* (userId, packageName). Mirrors cloud SDK v3's StorageManager surface.
|
|
4
|
+
*
|
|
5
|
+
* All operations round-trip to LocalMiniappRuntime, which reads/writes
|
|
6
|
+
* the phone's storage with a namespaced key format:
|
|
7
|
+
* mentraos_localstorage_{userId}_{packageName}_{key}
|
|
8
|
+
*
|
|
9
|
+
* Values are plain strings. Callers serialize structured data with
|
|
10
|
+
* JSON.stringify themselves (matching cloud's SimpleStorage shape).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {MiniappRequestType} from "../protocol"
|
|
14
|
+
import {MiniappSession} from "../session"
|
|
15
|
+
|
|
16
|
+
export class SimpleStorage {
|
|
17
|
+
constructor(private readonly session: MiniappSession) {}
|
|
18
|
+
|
|
19
|
+
/** Get a value by key. Resolves to null when the key is unset. */
|
|
20
|
+
async get(key: string): Promise<string | null> {
|
|
21
|
+
const result = await this.session.sendRequest<{value: string | null}>({
|
|
22
|
+
type: MiniappRequestType.STORAGE_GET,
|
|
23
|
+
key,
|
|
24
|
+
})
|
|
25
|
+
return result?.value ?? null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Set a single key/value pair. Overwrites silently. */
|
|
29
|
+
async set(key: string, value: string): Promise<void> {
|
|
30
|
+
await this.session.sendRequest<void>({
|
|
31
|
+
type: MiniappRequestType.STORAGE_SET,
|
|
32
|
+
key,
|
|
33
|
+
value,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Delete one key. No-op if the key is unset. */
|
|
38
|
+
async delete(key: string): Promise<void> {
|
|
39
|
+
await this.session.sendRequest<void>({
|
|
40
|
+
type: MiniappRequestType.STORAGE_DELETE,
|
|
41
|
+
key,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** List every key in this miniapp's namespace. */
|
|
46
|
+
async keys(): Promise<string[]> {
|
|
47
|
+
const result = await this.session.sendRequest<{keys: string[]}>({
|
|
48
|
+
type: MiniappRequestType.STORAGE_LIST,
|
|
49
|
+
})
|
|
50
|
+
return result?.keys ?? []
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @deprecated Renamed to `keys()` for cloud SDK parity. This alias will be
|
|
55
|
+
* removed in a future release.
|
|
56
|
+
*/
|
|
57
|
+
async list(): Promise<string[]> {
|
|
58
|
+
return this.keys()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Drop every key in this miniapp's namespace. */
|
|
62
|
+
async clear(): Promise<void> {
|
|
63
|
+
await this.session.sendRequest<void>({
|
|
64
|
+
type: MiniappRequestType.STORAGE_CLEAR,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** True iff `key` is set in this miniapp's namespace. */
|
|
69
|
+
async has(key: string): Promise<boolean> {
|
|
70
|
+
const result = await this.session.sendRequest<{has: boolean}>({
|
|
71
|
+
type: MiniappRequestType.STORAGE_HAS,
|
|
72
|
+
key,
|
|
73
|
+
})
|
|
74
|
+
return !!result?.has
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read every key/value pair in this miniapp's namespace. Useful for
|
|
79
|
+
* hydrating state on bootstrap. Bounded by the underlying namespace
|
|
80
|
+
* size — keep total stored payload small (typical < 1 MB) to avoid
|
|
81
|
+
* stalling the JSContext when this resolves.
|
|
82
|
+
*/
|
|
83
|
+
async getAll(): Promise<Record<string, string>> {
|
|
84
|
+
const result = await this.session.sendRequest<{values: Record<string, string>}>({
|
|
85
|
+
type: MiniappRequestType.STORAGE_GET_ALL,
|
|
86
|
+
})
|
|
87
|
+
return result?.values ?? {}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Write many key/value pairs in one round-trip. */
|
|
91
|
+
async setMultiple(values: Record<string, string>): Promise<void> {
|
|
92
|
+
await this.session.sendRequest<void>({
|
|
93
|
+
type: MiniappRequestType.STORAGE_SET_MULTIPLE,
|
|
94
|
+
values,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Force any pending in-flight writes to disk. No-op today because the
|
|
100
|
+
* host writes through immediately, but reserved so a future debounced
|
|
101
|
+
* backend can honor "flush before I quit" calls without breaking the
|
|
102
|
+
* API.
|
|
103
|
+
*/
|
|
104
|
+
async flush(): Promise<void> {
|
|
105
|
+
await this.session.sendRequest<void>({
|
|
106
|
+
type: MiniappRequestType.STORAGE_FLUSH,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview StreamModule -- video streaming from glasses.
|
|
3
|
+
*
|
|
4
|
+
* Wires to cloud streaming extensions via the __phone__ subscriber path.
|
|
5
|
+
*
|
|
6
|
+
* One entry point: `startStream`. By default it provisions a Mentra-hosted
|
|
7
|
+
* stream and returns playback URLs (managed). Pass `direct` to publish straight
|
|
8
|
+
* to your own ingest URL with no relay.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {MiniappRequestType} from "../protocol"
|
|
12
|
+
import {MiniappSession} from "../session"
|
|
13
|
+
|
|
14
|
+
export interface StreamVideoConfig {
|
|
15
|
+
width?: number
|
|
16
|
+
height?: number
|
|
17
|
+
bitrate?: number
|
|
18
|
+
fps?: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface StreamAudioConfig {
|
|
22
|
+
bitrate?: number
|
|
23
|
+
sampleRate?: number
|
|
24
|
+
echoCancellation?: boolean
|
|
25
|
+
noiseSuppression?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StreamResolvedConfig {
|
|
29
|
+
transport?: "rtmp" | "srt" | "whip"
|
|
30
|
+
video?: {
|
|
31
|
+
width: number
|
|
32
|
+
height: number
|
|
33
|
+
captureWidth?: number
|
|
34
|
+
captureHeight?: number
|
|
35
|
+
bitrate: number
|
|
36
|
+
fps: number
|
|
37
|
+
}
|
|
38
|
+
audio?: {
|
|
39
|
+
bitrate?: number
|
|
40
|
+
sampleRate?: number
|
|
41
|
+
echoCancellation?: boolean
|
|
42
|
+
noiseSuppression?: boolean
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Restream destination. The full stream key is part of the URL (e.g.
|
|
48
|
+
* `rtmp://yt.com/live/STREAM-KEY`). `name` is a human label that surfaces
|
|
49
|
+
* in dashboards but doesn't affect routing.
|
|
50
|
+
*/
|
|
51
|
+
export interface RestreamDestination {
|
|
52
|
+
url: string
|
|
53
|
+
name?: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface StartStreamOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Publish straight to your own ingest URL (rtmp/rtmps/srt/whip). The glasses
|
|
59
|
+
* connect to it directly with no Mentra relay, so no playback URLs come back.
|
|
60
|
+
* Omit this to use the managed relay (the default, best for most apps).
|
|
61
|
+
*/
|
|
62
|
+
direct?: string
|
|
63
|
+
/**
|
|
64
|
+
* Restream destinations the managed relay fans out to (YouTube, Twitch, …).
|
|
65
|
+
* Bare URL strings or `{url, name?}` objects; mix freely. Managed streams
|
|
66
|
+
* only — ignored when `direct` is set.
|
|
67
|
+
*/
|
|
68
|
+
destinations?: Array<string | RestreamDestination>
|
|
69
|
+
video?: StreamVideoConfig
|
|
70
|
+
audio?: StreamAudioConfig
|
|
71
|
+
/** Play glasses-side stream start/stop sounds. Defaults to true. */
|
|
72
|
+
sound?: boolean
|
|
73
|
+
/**
|
|
74
|
+
* Managed ingest protocol, a latency/durability trade. Ignored when `direct`
|
|
75
|
+
* is set.
|
|
76
|
+
* - "srt" (default): ~10-20s latency via LL-HLS, shareable HLS/DASH URLs,
|
|
77
|
+
* and automatic recording.
|
|
78
|
+
* - "whip": sub-second WebRTC playback (use `webrtcUrl`/WHEP), but no
|
|
79
|
+
* HLS/DASH and no recording.
|
|
80
|
+
*/
|
|
81
|
+
ingest?: "srt" | "whip"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface StreamResult {
|
|
85
|
+
streamId: string
|
|
86
|
+
status: string
|
|
87
|
+
resolvedConfig?: StreamResolvedConfig
|
|
88
|
+
/** Managed streams only: the live-input UID for building hosted-player URLs. */
|
|
89
|
+
liveInputId?: string
|
|
90
|
+
/** Managed streams only: which playback this stream serves. In "webrtc" mode
|
|
91
|
+
* `hlsUrl` never serves content. */
|
|
92
|
+
mode?: "hls" | "webrtc"
|
|
93
|
+
/** Managed streams only: HLS playback URL. */
|
|
94
|
+
hlsUrl?: string
|
|
95
|
+
/** Managed streams only: DASH playback URL. */
|
|
96
|
+
dashUrl?: string
|
|
97
|
+
/** Managed streams only: WHEP playback URL (present in "webrtc" mode). */
|
|
98
|
+
webrtcUrl?: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Live encoder telemetry, when the glasses emit it (no firmware does yet). */
|
|
102
|
+
export interface StreamLiveStats {
|
|
103
|
+
/** Current encoded video bitrate in bits per second. */
|
|
104
|
+
bitrate?: number
|
|
105
|
+
/** Current encode frame rate. */
|
|
106
|
+
fps?: number
|
|
107
|
+
droppedFrames?: number
|
|
108
|
+
/** Seconds since the stream started. */
|
|
109
|
+
duration?: number
|
|
110
|
+
/** Device temperature in °C, if the hardware reports it. */
|
|
111
|
+
temperatureC?: number
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface StreamStatus {
|
|
115
|
+
streamId: string
|
|
116
|
+
status: string
|
|
117
|
+
errorDetails?: string
|
|
118
|
+
/** Negotiated encode config — forwarded once, on the first status ack. */
|
|
119
|
+
resolvedConfig?: StreamResolvedConfig
|
|
120
|
+
stats?: StreamLiveStats
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class StreamModule {
|
|
124
|
+
constructor(private readonly session: MiniappSession) {}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Start a live video stream from the glasses camera.
|
|
128
|
+
*
|
|
129
|
+
* Managed (default) -- Mentra hosts the stream and the result carries
|
|
130
|
+
* `hlsUrl`/`dashUrl`/`webrtcUrl` for playback. Optionally fan out to your own
|
|
131
|
+
* `destinations`.
|
|
132
|
+
*
|
|
133
|
+
* Direct -- pass `direct` with your own ingest URL; the glasses publish to it
|
|
134
|
+
* and no playback URLs are returned.
|
|
135
|
+
*/
|
|
136
|
+
async startStream(options: StartStreamOptions = {}): Promise<StreamResult> {
|
|
137
|
+
if (options.direct !== undefined) {
|
|
138
|
+
return this.session.sendRequest<StreamResult>({
|
|
139
|
+
type: MiniappRequestType.STREAM_START,
|
|
140
|
+
streamUrl: options.direct,
|
|
141
|
+
video: options.video,
|
|
142
|
+
audio: options.audio,
|
|
143
|
+
sound: options.sound ?? true,
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
return this.session.sendRequest<StreamResult>({
|
|
147
|
+
type: MiniappRequestType.MANAGED_STREAM_START,
|
|
148
|
+
restreamDestinations: options.destinations,
|
|
149
|
+
video: options.video,
|
|
150
|
+
audio: options.audio,
|
|
151
|
+
sound: options.sound ?? true,
|
|
152
|
+
ingest: options.ingest,
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Stop the active stream, or a specific one by `streamId`. */
|
|
157
|
+
async stop(streamId?: string): Promise<void> {
|
|
158
|
+
await this.session.sendRequest<void>({
|
|
159
|
+
type: MiniappRequestType.STREAM_STOP,
|
|
160
|
+
streamId,
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview SystemModule — OS-level utilities (share, open URL, clipboard, download).
|
|
3
|
+
*
|
|
4
|
+
* These bridge to native phone capabilities via LocalMiniappRuntime.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { MiniappRequestType } from "../protocol"
|
|
8
|
+
import { MiniappSession } from "../session"
|
|
9
|
+
|
|
10
|
+
export interface ShareOptions {
|
|
11
|
+
text?: string
|
|
12
|
+
url?: string
|
|
13
|
+
title?: string
|
|
14
|
+
/** Base64-encoded file data for file sharing. */
|
|
15
|
+
base64?: string
|
|
16
|
+
/** MIME type when sharing base64 data. */
|
|
17
|
+
mimeType?: string
|
|
18
|
+
/** Filename when sharing base64 data. */
|
|
19
|
+
filename?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ShareResult {
|
|
23
|
+
success: boolean
|
|
24
|
+
cancelled?: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DownloadOptions {
|
|
28
|
+
/** URL to download from, OR base64 data. */
|
|
29
|
+
url?: string
|
|
30
|
+
base64?: string
|
|
31
|
+
filename?: string
|
|
32
|
+
mimeType?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DownloadResult {
|
|
36
|
+
success: boolean
|
|
37
|
+
cancelled?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class SystemModule {
|
|
41
|
+
constructor(private readonly session: MiniappSession) {}
|
|
42
|
+
|
|
43
|
+
/** Open the OS share sheet with the given content. */
|
|
44
|
+
async share(options: ShareOptions): Promise<ShareResult> {
|
|
45
|
+
const result = await this.session.sendRequest<ShareResult>({
|
|
46
|
+
type: MiniappRequestType.SHARE,
|
|
47
|
+
...options,
|
|
48
|
+
})
|
|
49
|
+
return result ?? { success: false }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Open a URL in the system browser. Blocks dangerous schemes (javascript:, file:). */
|
|
53
|
+
openUrl(url: string): void {
|
|
54
|
+
this.session.sendOneShot({
|
|
55
|
+
type: MiniappRequestType.OPEN_URL,
|
|
56
|
+
url,
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Copy text to the system clipboard. */
|
|
61
|
+
async copyToClipboard(text: string): Promise<void> {
|
|
62
|
+
await this.session.sendRequest<void>({
|
|
63
|
+
type: MiniappRequestType.COPY_CLIPBOARD,
|
|
64
|
+
text,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Download a file. Opens the OS share sheet so user can choose save location. */
|
|
69
|
+
async download(options: DownloadOptions): Promise<DownloadResult> {
|
|
70
|
+
const result = await this.session.sendRequest<DownloadResult>({
|
|
71
|
+
type: MiniappRequestType.DOWNLOAD,
|
|
72
|
+
...options,
|
|
73
|
+
})
|
|
74
|
+
return result ?? { success: false }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TranscriptionModule — top-level transcription API.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors cloud SDK v3's TranscriptionManager:
|
|
5
|
+
*
|
|
6
|
+
* session.transcription.on(handler) // auto-detect
|
|
7
|
+
* session.transcription.forLanguage("en-US", handler) // single language
|
|
8
|
+
* session.transcription.forLanguage(["en-US", "es-ES"], handler) // multi-language
|
|
9
|
+
* session.transcription.configure({languageHints, vocabulary, diarization})
|
|
10
|
+
* session.transcription.stop() // tear down all
|
|
11
|
+
*
|
|
12
|
+
* Hoisted to top-level (vs. nested under `session.mic`) because transcription
|
|
13
|
+
* is a domain in its own right, not a microphone-input event. The `mic`
|
|
14
|
+
* module still exposes lower-level audio chunks + VAD; this module is for
|
|
15
|
+
* "give me text from speech."
|
|
16
|
+
*
|
|
17
|
+
* MICROPHONE permission must be declared in miniapp.json. The phone runtime
|
|
18
|
+
* rejects with PERMISSION_NOT_DECLARED otherwise.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {MiniappRequestType, MiniappStreamType} from "../protocol"
|
|
22
|
+
import {MiniappSession} from "../session"
|
|
23
|
+
import type {TranscriptionData, UnsubscribeFn} from "./events"
|
|
24
|
+
|
|
25
|
+
/** Configuration for cloud-side transcription behavior. */
|
|
26
|
+
export interface TranscriptionConfig {
|
|
27
|
+
/** ISO 639-1 language hints to improve detection accuracy (e.g. ["en", "ja"]). */
|
|
28
|
+
languageHints?: string[]
|
|
29
|
+
/** Custom vocabulary / boosted terms (e.g. ["MentraOS", "HIPAA"]). */
|
|
30
|
+
vocabulary?: string[]
|
|
31
|
+
/** Enable speaker diarisation. Defaults vary by provider. */
|
|
32
|
+
diarization?: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class TranscriptionModule {
|
|
36
|
+
private readonly unsubs = new Set<UnsubscribeFn>()
|
|
37
|
+
private currentConfig: TranscriptionConfig | null = null
|
|
38
|
+
|
|
39
|
+
constructor(private readonly session: MiniappSession) {}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to all transcription events (auto-detect language). The
|
|
43
|
+
* detected language is in `data.language`.
|
|
44
|
+
*
|
|
45
|
+
* Wire-level: subscribes to `transcription:auto`. Today's wildcard fan-out
|
|
46
|
+
* (handlers on `transcription:auto` receive any `transcription:<lang>`
|
|
47
|
+
* event) preserves existing semantics.
|
|
48
|
+
*/
|
|
49
|
+
on(handler: (data: TranscriptionData) => void): UnsubscribeFn {
|
|
50
|
+
return this.track(
|
|
51
|
+
this.session._subscribe(`${MiniappStreamType.TRANSCRIPTION}:auto`, handler as (data: unknown) => void),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Subscribe to transcription for one or more specific languages. Each call
|
|
57
|
+
* is independent; multiple can be active simultaneously.
|
|
58
|
+
*
|
|
59
|
+
* @param language - BCP-47 tag(s), e.g. `"en-US"` or `["en-US", "es-ES"]`.
|
|
60
|
+
* @param handler - Called for every event in any of the listed languages.
|
|
61
|
+
*/
|
|
62
|
+
forLanguage(language: string | string[], handler: (data: TranscriptionData) => void): UnsubscribeFn {
|
|
63
|
+
const langs = Array.isArray(language) ? language : [language]
|
|
64
|
+
if (langs.length === 0) return () => {}
|
|
65
|
+
|
|
66
|
+
const unsubs: UnsubscribeFn[] = []
|
|
67
|
+
for (const lang of langs) {
|
|
68
|
+
unsubs.push(
|
|
69
|
+
this.session._subscribe(`${MiniappStreamType.TRANSCRIPTION}:${lang}`, handler as (data: unknown) => void),
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
const combined: UnsubscribeFn = () => {
|
|
73
|
+
for (const u of unsubs) {
|
|
74
|
+
try {
|
|
75
|
+
u()
|
|
76
|
+
} catch {
|
|
77
|
+
/* ignore */
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return this.track(combined)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Apply transcription configuration (language hints, custom vocabulary,
|
|
86
|
+
* diarisation toggle). Sent to the cloud immediately. Cached locally so we
|
|
87
|
+
* could re-send on reconnect (future).
|
|
88
|
+
*/
|
|
89
|
+
configure(config: TranscriptionConfig): void {
|
|
90
|
+
this.currentConfig = {...config}
|
|
91
|
+
this.session.sendOneShot({
|
|
92
|
+
type: MiniappRequestType.TRANSCRIPTION_CONFIG,
|
|
93
|
+
config: {...config},
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Tear down every transcription subscription this module owns. */
|
|
98
|
+
stop(): void {
|
|
99
|
+
for (const u of this.unsubs) {
|
|
100
|
+
try {
|
|
101
|
+
u()
|
|
102
|
+
} catch {
|
|
103
|
+
/* ignore */
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.unsubs.clear()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** True iff `MICROPHONE` is declared in the miniapp's manifest. */
|
|
110
|
+
get hasPermission(): boolean {
|
|
111
|
+
return this.session._hasManifestPermission("MICROPHONE")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** @internal — current config, read by tests / future reconnect logic. */
|
|
115
|
+
_getConfig(): TranscriptionConfig | null {
|
|
116
|
+
return this.currentConfig ? {...this.currentConfig} : null
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
private track(unsub: UnsubscribeFn): UnsubscribeFn {
|
|
122
|
+
this.unsubs.add(unsub)
|
|
123
|
+
return () => {
|
|
124
|
+
this.unsubs.delete(unsub)
|
|
125
|
+
unsub()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TranslationModule — top-level translation API.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors cloud SDK v3's TranslationManager surface:
|
|
5
|
+
*
|
|
6
|
+
* session.translation.on(handler) // any pair
|
|
7
|
+
* session.translation.to(target, handler) // any-source → target
|
|
8
|
+
* session.translation.to([targets], handler) // any-source → many
|
|
9
|
+
* session.translation.fromTo(source, target, handler) // specific pair
|
|
10
|
+
* session.translation.fromTo(source, [targets], handler) // source → many
|
|
11
|
+
* session.translation.stop() // tear down all
|
|
12
|
+
*
|
|
13
|
+
* Internally each subscribe registers against a `translation:<source>:<target>`
|
|
14
|
+
* stream pattern; LocalMiniappRuntime's wildcard matcher routes incoming
|
|
15
|
+
* `translation:<src>:<dst>` events to any matching `*` patterns.
|
|
16
|
+
*
|
|
17
|
+
* MICROPHONE permission required.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import {MiniappStreamType} from "../protocol"
|
|
21
|
+
import {MiniappSession} from "../session"
|
|
22
|
+
import type {TranslationData, UnsubscribeFn} from "./events"
|
|
23
|
+
|
|
24
|
+
export type TranslationHandler = (data: TranslationData) => void
|
|
25
|
+
|
|
26
|
+
export class TranslationModule {
|
|
27
|
+
private readonly unsubs = new Set<UnsubscribeFn>()
|
|
28
|
+
|
|
29
|
+
constructor(private readonly session: MiniappSession) {}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Subscribe to every translation event from the cloud, regardless of
|
|
33
|
+
* source or target language.
|
|
34
|
+
*
|
|
35
|
+
* Uses the wildcard stream `translation:*:*` — cheap to register on the
|
|
36
|
+
* client, expensive on the cloud side (cloud fans every active pair out
|
|
37
|
+
* to this subscriber). Prefer `to` or `fromTo` when you know the
|
|
38
|
+
* language(s) you care about.
|
|
39
|
+
*/
|
|
40
|
+
on(handler: TranslationHandler): UnsubscribeFn {
|
|
41
|
+
return this.track(
|
|
42
|
+
this.session._subscribe(
|
|
43
|
+
`${MiniappStreamType.TRANSLATION}:*:*`,
|
|
44
|
+
handler as (data: unknown) => void,
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Subscribe to any translation that lands at the given target language(s),
|
|
51
|
+
* regardless of source. Useful for "I'm a Spanish speaker, translate
|
|
52
|
+
* whatever I hear to Spanish."
|
|
53
|
+
*/
|
|
54
|
+
to(target: string | string[], handler: TranslationHandler): UnsubscribeFn {
|
|
55
|
+
const targets = Array.isArray(target) ? target : [target]
|
|
56
|
+
if (targets.length === 0) return () => {}
|
|
57
|
+
const unsubs: UnsubscribeFn[] = []
|
|
58
|
+
for (const t of targets) {
|
|
59
|
+
unsubs.push(
|
|
60
|
+
this.session._subscribe(
|
|
61
|
+
`${MiniappStreamType.TRANSLATION}:*:${t}`,
|
|
62
|
+
handler as (data: unknown) => void,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
const composite = () => {
|
|
67
|
+
for (const u of unsubs) {
|
|
68
|
+
try {
|
|
69
|
+
u()
|
|
70
|
+
} catch {
|
|
71
|
+
/* ignore */
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return this.track(composite)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Subscribe to a specific source → target translation pair. Pass an
|
|
80
|
+
* array for `target` to fan a single handler across multiple targets
|
|
81
|
+
* from the same source.
|
|
82
|
+
*/
|
|
83
|
+
fromTo(
|
|
84
|
+
source: string,
|
|
85
|
+
target: string | string[],
|
|
86
|
+
handler: TranslationHandler,
|
|
87
|
+
): UnsubscribeFn {
|
|
88
|
+
const targets = Array.isArray(target) ? target : [target]
|
|
89
|
+
if (targets.length === 0) return () => {}
|
|
90
|
+
const unsubs: UnsubscribeFn[] = []
|
|
91
|
+
for (const t of targets) {
|
|
92
|
+
unsubs.push(
|
|
93
|
+
this.session._subscribe(
|
|
94
|
+
`${MiniappStreamType.TRANSLATION}:${source}:${t}`,
|
|
95
|
+
handler as (data: unknown) => void,
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
const composite = () => {
|
|
100
|
+
for (const u of unsubs) {
|
|
101
|
+
try {
|
|
102
|
+
u()
|
|
103
|
+
} catch {
|
|
104
|
+
/* ignore */
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return this.track(composite)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated Renamed to `fromTo(source, target, handler)` for cloud
|
|
113
|
+
* SDK v3 parity. This alias will be removed in a future release.
|
|
114
|
+
*/
|
|
115
|
+
forLanguagePair(
|
|
116
|
+
fromLang: string,
|
|
117
|
+
toLang: string,
|
|
118
|
+
handler: TranslationHandler,
|
|
119
|
+
): UnsubscribeFn {
|
|
120
|
+
return this.fromTo(fromLang, toLang, handler)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Tear down every translation subscription this module owns. */
|
|
124
|
+
stop(): void {
|
|
125
|
+
for (const u of this.unsubs) {
|
|
126
|
+
try {
|
|
127
|
+
u()
|
|
128
|
+
} catch {
|
|
129
|
+
/* ignore */
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.unsubs.clear()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** True iff `MICROPHONE` is declared in the miniapp's manifest. */
|
|
136
|
+
get hasPermission(): boolean {
|
|
137
|
+
return this.session._hasManifestPermission("MICROPHONE")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
private track(unsub: UnsubscribeFn): UnsubscribeFn {
|
|
143
|
+
this.unsubs.add(unsub)
|
|
144
|
+
return () => {
|
|
145
|
+
this.unsubs.delete(unsub)
|
|
146
|
+
unsub()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|