@glassly/miniapp 0.1.0-dev.98 → 0.2.8-dev.444
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 +218 -73
- package/dist/background/index.d.ts +14 -8
- package/dist/background/index.d.ts.map +1 -1
- package/dist/background/index.js +4 -0
- package/dist/background/index.js.map +1 -1
- package/dist/background/register.d.ts +1 -1
- package/dist/background/register.js +1 -1
- package/dist/display/index.d.ts +23 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +17 -0
- package/dist/display/index.js.map +1 -0
- package/dist/display/measurer/TextMeasurer.d.ts +160 -0
- package/dist/display/measurer/TextMeasurer.d.ts.map +1 -0
- package/dist/display/measurer/TextMeasurer.js +272 -0
- package/dist/display/measurer/TextMeasurer.js.map +1 -0
- package/dist/display/measurer/index.d.ts +10 -0
- package/dist/display/measurer/index.d.ts.map +1 -0
- package/dist/display/measurer/index.js +11 -0
- package/dist/display/measurer/index.js.map +1 -0
- package/dist/display/measurer/script-detection.d.ts +53 -0
- package/dist/display/measurer/script-detection.d.ts.map +1 -0
- package/dist/display/measurer/script-detection.js +184 -0
- package/dist/display/measurer/script-detection.js.map +1 -0
- package/dist/display/pixelArt.d.ts +22 -0
- package/dist/display/pixelArt.d.ts.map +1 -0
- package/dist/display/pixelArt.js +126 -0
- package/dist/display/pixelArt.js.map +1 -0
- package/dist/display/profiles/g1.d.ts +33 -0
- package/dist/display/profiles/g1.d.ts.map +1 -0
- package/dist/display/profiles/g1.js +214 -0
- package/dist/display/profiles/g1.js.map +1 -0
- package/dist/display/profiles/g2.d.ts +13 -0
- package/dist/display/profiles/g2.d.ts.map +1 -0
- package/dist/display/profiles/g2.js +34 -0
- package/dist/display/profiles/g2.js.map +1 -0
- package/dist/display/profiles/index.d.ts +12 -0
- package/dist/display/profiles/index.d.ts.map +1 -0
- package/dist/display/profiles/index.js +15 -0
- package/dist/display/profiles/index.js.map +1 -0
- package/dist/display/profiles/nex.d.ts +10 -0
- package/dist/display/profiles/nex.d.ts.map +1 -0
- package/dist/display/profiles/nex.js +150 -0
- package/dist/display/profiles/nex.js.map +1 -0
- package/dist/display/profiles/types.d.ts +103 -0
- package/dist/display/profiles/types.d.ts.map +1 -0
- package/dist/display/profiles/types.js +2 -0
- package/dist/display/profiles/types.js.map +1 -0
- package/dist/display/profiles/z100.d.ts +33 -0
- package/dist/display/profiles/z100.d.ts.map +1 -0
- package/dist/display/profiles/z100.js +182 -0
- package/dist/display/profiles/z100.js.map +1 -0
- package/dist/display/scene/types.d.ts +292 -0
- package/dist/display/scene/types.d.ts.map +1 -0
- package/dist/display/scene/types.js +0 -0
- package/dist/display/scene/types.js.map +1 -0
- package/dist/display/wrapper/TextWrapper.d.ts +102 -0
- package/dist/display/wrapper/TextWrapper.d.ts.map +1 -0
- package/dist/display/wrapper/TextWrapper.js +469 -0
- package/dist/display/wrapper/TextWrapper.js.map +1 -0
- package/dist/display/wrapper/index.d.ts +12 -0
- package/dist/display/wrapper/index.d.ts.map +1 -0
- package/dist/display/wrapper/index.js +12 -0
- package/dist/display/wrapper/index.js.map +1 -0
- package/dist/display/wrapper/types.d.ts +75 -0
- package/dist/display/wrapper/types.d.ts.map +1 -0
- package/dist/display/wrapper/types.js +11 -0
- package/dist/display/wrapper/types.js.map +1 -0
- package/dist/globals.d.ts +5 -5
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +1 -1
- package/dist/globals.js.map +1 -1
- package/dist/index.d.ts +16 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/knownApps.d.ts +26 -0
- package/dist/knownApps.d.ts.map +1 -0
- package/dist/knownApps.js +140 -0
- package/dist/knownApps.js.map +1 -0
- package/dist/mirror/canvas.d.ts +22 -0
- package/dist/mirror/canvas.d.ts.map +1 -0
- package/dist/mirror/canvas.js +311 -0
- package/dist/mirror/canvas.js.map +1 -0
- package/dist/mirror/geometry.d.ts +69 -0
- package/dist/mirror/geometry.d.ts.map +1 -0
- package/dist/mirror/geometry.js +75 -0
- package/dist/mirror/geometry.js.map +1 -0
- package/dist/mirror/index.d.ts +3 -0
- package/dist/mirror/index.d.ts.map +1 -0
- package/dist/mirror/index.js +2 -0
- package/dist/mirror/index.js.map +1 -0
- package/dist/mirror/types.d.ts +40 -0
- package/dist/mirror/types.d.ts.map +1 -0
- package/dist/mirror/types.js +2 -0
- package/dist/mirror/types.js.map +1 -0
- package/dist/modules/auth.d.ts +1 -1
- package/dist/modules/auth.d.ts.map +1 -1
- package/dist/modules/auth.js +2 -2
- package/dist/modules/auth.js.map +1 -1
- package/dist/modules/compass.d.ts +47 -0
- package/dist/modules/compass.d.ts.map +1 -0
- package/dist/modules/compass.js +39 -0
- package/dist/modules/compass.js.map +1 -0
- package/dist/modules/display.d.ts +189 -12
- package/dist/modules/display.d.ts.map +1 -1
- package/dist/modules/display.js +40 -3
- package/dist/modules/display.js.map +1 -1
- package/dist/modules/events.d.ts +30 -2
- package/dist/modules/events.d.ts.map +1 -1
- package/dist/modules/events.js.map +1 -1
- package/dist/modules/input.d.ts +34 -11
- package/dist/modules/input.d.ts.map +1 -1
- package/dist/modules/input.js +35 -11
- package/dist/modules/input.js.map +1 -1
- package/dist/modules/latest-render-scheduler.d.ts +19 -0
- package/dist/modules/latest-render-scheduler.d.ts.map +1 -0
- package/dist/modules/latest-render-scheduler.js +54 -0
- package/dist/modules/latest-render-scheduler.js.map +1 -0
- package/dist/modules/lightSensor.d.ts +44 -0
- package/dist/modules/lightSensor.d.ts.map +1 -0
- package/dist/modules/lightSensor.js +33 -0
- package/dist/modules/lightSensor.js.map +1 -0
- package/dist/modules/mic.d.ts +3 -2
- package/dist/modules/mic.d.ts.map +1 -1
- package/dist/modules/mic.js +3 -2
- package/dist/modules/mic.js.map +1 -1
- package/dist/modules/miniapps.d.ts +2 -0
- package/dist/modules/miniapps.d.ts.map +1 -1
- package/dist/modules/miniapps.js.map +1 -1
- package/dist/modules/mirror.d.ts +16 -0
- package/dist/modules/mirror.d.ts.map +1 -0
- package/dist/modules/mirror.js +40 -0
- package/dist/modules/mirror.js.map +1 -0
- package/dist/modules/mono-text-rows.d.ts +20 -0
- package/dist/modules/mono-text-rows.d.ts.map +1 -0
- package/dist/modules/mono-text-rows.js +26 -0
- package/dist/modules/mono-text-rows.js.map +1 -0
- package/dist/modules/navigation.d.ts.map +1 -1
- package/dist/modules/navigation.js +21 -14
- package/dist/modules/navigation.js.map +1 -1
- package/dist/modules/phone.d.ts +26 -1
- package/dist/modules/phone.d.ts.map +1 -1
- package/dist/modules/phone.js +28 -0
- package/dist/modules/phone.js.map +1 -1
- package/dist/modules/settings.d.ts +45 -0
- package/dist/modules/settings.d.ts.map +1 -0
- package/dist/modules/settings.js +54 -0
- package/dist/modules/settings.js.map +1 -0
- package/dist/modules/system.d.ts +21 -0
- package/dist/modules/system.d.ts.map +1 -1
- package/dist/modules/system.js +12 -0
- package/dist/modules/system.js.map +1 -1
- package/dist/modules/transcription.d.ts +3 -2
- package/dist/modules/transcription.d.ts.map +1 -1
- package/dist/modules/transcription.js +3 -2
- package/dist/modules/transcription.js.map +1 -1
- package/dist/protocol.d.ts +59 -5
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +60 -5
- package/dist/protocol.js.map +1 -1
- package/dist/react/MirrorCanvas.d.ts +10 -0
- package/dist/react/MirrorCanvas.d.ts.map +1 -0
- package/dist/react/MirrorCanvas.js +23 -0
- package/dist/react/MirrorCanvas.js.map +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/useColorScheme.d.ts +2 -3
- package/dist/react/useColorScheme.d.ts.map +1 -1
- package/dist/react/useColorScheme.js +15 -8
- package/dist/react/useColorScheme.js.map +1 -1
- package/dist/react/useRpc.js +2 -2
- package/dist/react/useRpc.js.map +1 -1
- package/dist/react/useSafeArea.d.ts.map +1 -1
- package/dist/react/useSafeArea.js +2 -2
- package/dist/react/useSafeArea.js.map +1 -1
- package/dist/session.d.ts +50 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +35 -6
- package/dist/session.js.map +1 -1
- package/dist/transport/auto.d.ts +2 -2
- package/dist/transport/auto.js +2 -2
- package/dist/transport/dispatch.d.ts +1 -1
- package/dist/transport/dispatch.js +1 -1
- package/dist/transport/mock.d.ts +4 -4
- package/dist/transport/mock.d.ts.map +1 -1
- package/dist/transport/mock.js +31 -7
- package/dist/transport/mock.js.map +1 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +15 -3
- package/src/background/index.ts +26 -4
- package/src/background/register.ts +1 -1
- package/src/display/index.ts +83 -0
- package/src/display/measurer/TextMeasurer.ts +346 -0
- package/src/display/measurer/index.ts +21 -0
- package/src/display/measurer/script-detection.ts +218 -0
- package/src/display/pixelArt.ts +141 -0
- package/src/display/profiles/g1.ts +237 -0
- package/src/display/profiles/g2.ts +39 -0
- package/src/display/profiles/index.ts +28 -0
- package/src/display/profiles/nex.ts +166 -0
- package/src/display/profiles/types.ts +132 -0
- package/src/display/profiles/z100.ts +198 -0
- package/src/display/scene/types.ts +335 -0
- package/src/display/wrapper/TextWrapper.ts +546 -0
- package/src/display/wrapper/index.ts +15 -0
- package/src/display/wrapper/types.ts +102 -0
- package/src/globals.ts +5 -5
- package/src/index.ts +34 -6
- package/src/knownApps.ts +170 -0
- package/src/mirror/canvas.ts +322 -0
- package/src/mirror/geometry.ts +128 -0
- package/src/mirror/index.ts +2 -0
- package/src/mirror/types.ts +38 -0
- package/src/modules/auth.ts +2 -2
- package/src/modules/compass.ts +69 -0
- package/src/modules/display.ts +219 -16
- package/src/modules/events.ts +27 -1
- package/src/modules/input.ts +44 -12
- package/src/modules/latest-render-scheduler.ts +55 -0
- package/src/modules/lightSensor.ts +61 -0
- package/src/modules/mic.ts +3 -2
- package/src/modules/miniapps.ts +2 -0
- package/src/modules/mirror.ts +42 -0
- package/src/modules/mono-text-rows.ts +30 -0
- package/src/modules/navigation.ts +20 -14
- package/src/modules/phone.ts +40 -1
- package/src/modules/settings.ts +64 -0
- package/src/modules/system.ts +30 -1
- package/src/modules/transcription.ts +3 -2
- package/src/protocol.ts +65 -5
- package/src/react/MirrorCanvas.tsx +35 -0
- package/src/react/index.ts +3 -0
- package/src/react/useColorScheme.ts +17 -8
- package/src/react/useRpc.ts +2 -2
- package/src/react/useSafeArea.ts +2 -2
- package/src/session.ts +78 -8
- package/src/transport/auto.ts +2 -2
- package/src/transport/dispatch.ts +1 -1
- package/src/transport/mock.ts +42 -11
- package/src/ui/index.ts +3 -0
- package/dist/modules/heading.d.ts +0 -16
- package/dist/modules/heading.d.ts.map +0 -1
- package/dist/modules/heading.js +0 -20
- package/dist/modules/heading.js.map +0 -1
- package/src/modules/heading.ts +0 -23
package/src/protocol.ts
CHANGED
|
@@ -25,9 +25,9 @@ export enum MiniappRequestType {
|
|
|
25
25
|
SUBSCRIBE = "miniapp_subscribe",
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Declare the touch gestures this miniapp is handling itself
|
|
29
|
-
* the host's default
|
|
30
|
-
*
|
|
28
|
+
* Declare the touch gestures this miniapp is handling itself. The most
|
|
29
|
+
* recent claimer of a gesture gets it alone and the host's default for it
|
|
30
|
+
* is skipped; releasing hands it back to the previous claimer.
|
|
31
31
|
*/
|
|
32
32
|
CLAIM_GESTURES = "miniapp_claim_gestures",
|
|
33
33
|
|
|
@@ -41,6 +41,17 @@ export enum MiniappRequestType {
|
|
|
41
41
|
/** Render a whole scene of positioned elements (replace-the-frame). */
|
|
42
42
|
RENDER = "miniapp_render",
|
|
43
43
|
|
|
44
|
+
/** Read the globally visible intended glasses canvas. DISPLAY_MIRROR permission. */
|
|
45
|
+
MIRROR_GET = "miniapp_mirror_get",
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Ask the host for a display view (display.showView). "main" is every
|
|
49
|
+
* app's; "dashboard" is the overlay slot above the main content, granted
|
|
50
|
+
* only to the running miniapp whose manifest type is "system_dashboard"
|
|
51
|
+
* while the glasses can show it.
|
|
52
|
+
*/
|
|
53
|
+
SHOW_VIEW = "miniapp_show_view",
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Feed the device's firmware-rendered navigation UI (capability
|
|
46
57
|
* `hasNativeNavigation`): structured turn-by-turn card fields and
|
|
@@ -77,6 +88,21 @@ export enum MiniappRequestType {
|
|
|
77
88
|
/** Read a bounded snapshot of phone calendar events. */
|
|
78
89
|
CALENDAR_LIST_EVENTS = "miniapp_calendar_list_events",
|
|
79
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Apps that post phone notifications, for a notification filter UI.
|
|
93
|
+
* SYSTEM-only. Android: installed apps with icons; iOS: the seeded
|
|
94
|
+
* catalog plus apps the glasses reported.
|
|
95
|
+
*/
|
|
96
|
+
NOTIFICATION_APPS_LIST = "miniapp_notification_apps_list",
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The engine's settings store behind an allowlist (session.settings).
|
|
100
|
+
* SYSTEM-only. GET takes optional `keys` and answers `{values}`; SET
|
|
101
|
+
* takes `key` and `value` and writes through the store.
|
|
102
|
+
*/
|
|
103
|
+
SETTINGS_GET = "miniapp_settings_get",
|
|
104
|
+
SETTINGS_SET = "miniapp_settings_set",
|
|
105
|
+
|
|
80
106
|
/** Start a turn-by-turn navigation trip. Android only. */
|
|
81
107
|
NAVIGATION_START = "miniapp_navigation_start",
|
|
82
108
|
/** Stop the active navigation trip (if any). */
|
|
@@ -182,6 +208,7 @@ export enum MiniappRequestType {
|
|
|
182
208
|
* for callers who want to control the sensor directly. G2 only today.
|
|
183
209
|
*/
|
|
184
210
|
IMU_SET_ENABLED = "miniapp_imu_set_enabled",
|
|
211
|
+
GLASSES_SENSOR_CONTROL = "miniapp_glasses_sensor_control",
|
|
185
212
|
|
|
186
213
|
/** Explicitly enable/disable glasses-side VAD (GX8002). Mirrors the app's mic settings toggle. */
|
|
187
214
|
MIC_SET_VAD_ENABLED = "miniapp_mic_set_vad_enabled",
|
|
@@ -199,6 +226,7 @@ export enum MiniappRequestType {
|
|
|
199
226
|
/** Open a URL in the system browser. */
|
|
200
227
|
OPEN_URL = "miniapp_open_url",
|
|
201
228
|
/** Copy text to the system clipboard. */
|
|
229
|
+
DISPLAY_DIAGNOSTICS = "miniapp_display_diagnostics",
|
|
202
230
|
COPY_CLIPBOARD = "miniapp_copy_clipboard",
|
|
203
231
|
/** Download a file (triggers OS share sheet for save location). */
|
|
204
232
|
DOWNLOAD = "miniapp_download",
|
|
@@ -302,6 +330,9 @@ export enum MiniappResponseType {
|
|
|
302
330
|
/** Push: glasses capabilities changed. */
|
|
303
331
|
CAPABILITIES_UPDATE = "miniapp_capabilities_update",
|
|
304
332
|
|
|
333
|
+
/** Push: host user preferences (units, clock format) changed. */
|
|
334
|
+
PREFERENCES_UPDATE = "miniapp_preferences_update",
|
|
335
|
+
|
|
305
336
|
/** Push: miniapp's foreground/background state changed. */
|
|
306
337
|
VISIBILITY_CHANGE = "miniapp_visibility_change",
|
|
307
338
|
|
|
@@ -359,7 +390,25 @@ export enum MiniappStreamType {
|
|
|
359
390
|
// Hardware / input events
|
|
360
391
|
BUTTON_PRESS = "button_press",
|
|
361
392
|
TOUCH_EVENT = "touch_event",
|
|
393
|
+
/**
|
|
394
|
+
* Physical keyboard paired to the glasses (input.onKey): DOM-style
|
|
395
|
+
* `{phase, key, code, modifiers, text?, repeat, timestamp}`. G2 Glassly CFW
|
|
396
|
+
* revision 39+ only; broadcast to every subscriber like button_press.
|
|
397
|
+
*/
|
|
398
|
+
KEYBOARD_EVENT = "keyboard_event",
|
|
362
399
|
HEAD_POSITION = "head_position",
|
|
400
|
+
/**
|
|
401
|
+
* The dashboard view's state (display.onViewChange): `{kind: "change",
|
|
402
|
+
* view, reason}` when the host grants or takes the overlay slot.
|
|
403
|
+
*/
|
|
404
|
+
DISPLAY_VIEW = "display_view",
|
|
405
|
+
/** Initial mirror snapshot and subsequent visible display changes. */
|
|
406
|
+
MIRROR_UPDATE = "mirror_update",
|
|
407
|
+
/**
|
|
408
|
+
* A gesture claim changed hands (input.onClaimChange): `{gesture, held}`,
|
|
409
|
+
* sent to the app that gained or lost the gesture.
|
|
410
|
+
*/
|
|
411
|
+
GESTURE_CLAIM = "gesture_claim",
|
|
363
412
|
/**
|
|
364
413
|
* Raw accelerometer reading from the glasses IMU — `{x, y, z}` in g, plus a
|
|
365
414
|
* timestamp. G2 only today. A richer combined IMU stream (accel + gyro +
|
|
@@ -382,19 +431,30 @@ export enum MiniappStreamType {
|
|
|
382
431
|
|
|
383
432
|
// Phone sensors
|
|
384
433
|
LOCATION_UPDATE = "location_update",
|
|
385
|
-
/**
|
|
434
|
+
/** Phone compass heading in degrees (0=N, 90=E). */
|
|
386
435
|
HEADING_UPDATE = "heading_update",
|
|
436
|
+
// Glasses sensors
|
|
437
|
+
LIGHT_SENSOR = "light_sensor",
|
|
438
|
+
/** Glasses compass heading; auto-starts on custom firmware, nav mode only on stock. */
|
|
439
|
+
GLASSES_COMPASS = "glasses_compass",
|
|
440
|
+
COMPASS_CALIBRATION = "compass_calibration",
|
|
387
441
|
/** Turn-by-turn navigation event (maneuver / rerouting / arrived / error). */
|
|
388
442
|
NAVIGATION_UPDATE = "navigation_update",
|
|
389
443
|
/** Active navigation route polyline — full path, fired once per route build. */
|
|
390
444
|
NAVIGATION_ROUTE = "navigation_route",
|
|
391
445
|
PHONE_NOTIFICATION = "phone_notification",
|
|
446
|
+
/**
|
|
447
|
+
* An allowlisted engine setting changed (session.settings.onChange), as
|
|
448
|
+
* `{key, value}`. SYSTEM-only; every key's current value is replayed on
|
|
449
|
+
* subscribe.
|
|
450
|
+
*/
|
|
451
|
+
SETTINGS_CHANGED = "settings_changed",
|
|
392
452
|
/**
|
|
393
453
|
* A previously-posted notification was dismissed by the user.
|
|
394
454
|
*
|
|
395
455
|
* Android-only today. iOS does not expose dismiss callbacks to apps
|
|
396
456
|
* (Apple privacy restriction); subscribing on iOS succeeds but no events
|
|
397
|
-
* fire. See agents/miniapp-speaker-state-and-notif-dismissed-plan.md.
|
|
457
|
+
* fire. See notes/archive/agents/miniapp-speaker-state-and-notif-dismissed-plan.md.
|
|
398
458
|
*/
|
|
399
459
|
PHONE_NOTIFICATION_DISMISSED = "phone_notification_dismissed",
|
|
400
460
|
// Photos, streaming
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {useEffect, useRef, type CSSProperties} from "react"
|
|
2
|
+
import {MirrorCanvasRenderer} from "../mirror/canvas"
|
|
3
|
+
import type {MirrorSnapshot} from "../mirror/types"
|
|
4
|
+
|
|
5
|
+
export interface MirrorCanvasProps {
|
|
6
|
+
frame: MirrorSnapshot | null
|
|
7
|
+
className?: string
|
|
8
|
+
style?: CSSProperties
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Browser preview of intended glasses output; pass snapshots over a UI channel. */
|
|
12
|
+
export function MirrorCanvas({frame, className, style}: MirrorCanvasProps) {
|
|
13
|
+
const canvas = useRef<HTMLCanvasElement>(null)
|
|
14
|
+
const renderer = useRef<MirrorCanvasRenderer | null>(null)
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!canvas.current) return
|
|
17
|
+
renderer.current = new MirrorCanvasRenderer(canvas.current)
|
|
18
|
+
return () => {
|
|
19
|
+
renderer.current?.dispose()
|
|
20
|
+
renderer.current = null
|
|
21
|
+
}
|
|
22
|
+
}, [])
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (frame) renderer.current?.update(frame)
|
|
25
|
+
}, [frame])
|
|
26
|
+
return (
|
|
27
|
+
<canvas
|
|
28
|
+
ref={canvas}
|
|
29
|
+
className={className}
|
|
30
|
+
role="img"
|
|
31
|
+
aria-label="Glasses display mirror"
|
|
32
|
+
style={{display: "block", width: "100%", height: "auto", ...style}}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
package/src/react/index.ts
CHANGED
|
@@ -10,3 +10,6 @@ export type {MiniappHeaderProps} from "./MiniappHeader"
|
|
|
10
10
|
export {MiniappProvider} from "./MiniappProvider"
|
|
11
11
|
export type {MiniappProviderProps} from "./MiniappProvider"
|
|
12
12
|
export {useRpc, type RpcCallable} from "./useRpc"
|
|
13
|
+
|
|
14
|
+
export {MirrorCanvas, type MirrorCanvasProps} from "./MirrorCanvas"
|
|
15
|
+
export type {MirrorSnapshot, MirrorContent, MirrorElement} from "../mirror/types"
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* color scheme.
|
|
4
4
|
*
|
|
5
5
|
* WebView-side hook: reads `window.Glassly.colorScheme`, injected by the host
|
|
6
|
-
* before the miniapp's content loads
|
|
7
|
-
*
|
|
8
|
-
* flipping the phone's theme forces a reload.
|
|
6
|
+
* before the miniapp's content loads, and follows the host's
|
|
7
|
+
* `glassly:color-scheme-change` events while the WebView remains mounted.
|
|
9
8
|
*
|
|
10
9
|
* IMPORTANT: this hook must NOT construct a `MiniappSession`. `MiniappSession`
|
|
11
10
|
* is the *background* (JSContext) API; inside a UI WebView its transport falls
|
|
@@ -14,13 +13,23 @@
|
|
|
14
13
|
* read host-injected globals instead (see `useSafeArea`).
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
|
-
import {useState} from "react"
|
|
16
|
+
import {useEffect, useState} from "react"
|
|
18
17
|
|
|
19
|
-
import {
|
|
18
|
+
import {getHostGlobals, type MiniappColorScheme} from "../globals"
|
|
19
|
+
|
|
20
|
+
const readScheme = (): MiniappColorScheme => (getHostGlobals().colorScheme === "dark" ? "dark" : "light")
|
|
20
21
|
|
|
21
22
|
export function useColorScheme(): MiniappColorScheme {
|
|
22
|
-
const [scheme] = useState<MiniappColorScheme>(
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const [scheme, setScheme] = useState<MiniappColorScheme>(readScheme)
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (typeof window === "undefined") return
|
|
27
|
+
const update = () => setScheme(readScheme())
|
|
28
|
+
window.addEventListener("glassly:color-scheme-change", update)
|
|
29
|
+
// Catch an update delivered between the initial render and subscription.
|
|
30
|
+
update()
|
|
31
|
+
return () => window.removeEventListener("glassly:color-scheme-change", update)
|
|
32
|
+
}, [])
|
|
33
|
+
|
|
25
34
|
return scheme
|
|
26
35
|
}
|
package/src/react/useRpc.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type {RpcReq, RpcRes, RpcRequestOptions} from "../modules/ui"
|
|
|
19
19
|
type RequestFn = (channel: string, payload: unknown, options?: RpcRequestOptions) => Promise<unknown>
|
|
20
20
|
|
|
21
21
|
/** Walk to the global `glassly.request` (typed). */
|
|
22
|
-
function
|
|
22
|
+
function getHostRequest(): RequestFn {
|
|
23
23
|
const m = (globalThis as unknown as {glassly?: {request?: RequestFn}}).glassly
|
|
24
24
|
if (!m || typeof m.request !== "function") {
|
|
25
25
|
throw new Error(
|
|
@@ -89,7 +89,7 @@ export function useRpc<TChannels extends object, C extends keyof TChannels & str
|
|
|
89
89
|
const signals: AbortSignal[] = [ctrl.signal, mountRef.current!.signal]
|
|
90
90
|
if (options?.signal) signals.push(options.signal)
|
|
91
91
|
const signal = mergeSignals(signals)
|
|
92
|
-
return
|
|
92
|
+
return getHostRequest()(channel, payload, {signal, timeout: options?.timeout}) as Promise<RpcRes<TChannels[C]>>
|
|
93
93
|
},
|
|
94
94
|
[channel],
|
|
95
95
|
) as RpcCallable<TChannels, C>
|
package/src/react/useSafeArea.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import {useState} from "react"
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {getHostGlobals, type MiniappCapsuleMenuRect, type MiniappSafeAreaInsets} from "../globals"
|
|
13
13
|
|
|
14
14
|
const EMPTY_INSETS: MiniappSafeAreaInsets = {top: 0, bottom: 0, left: 0, right: 0}
|
|
15
15
|
|
|
@@ -26,7 +26,7 @@ export interface UseSafeAreaResult {
|
|
|
26
26
|
|
|
27
27
|
export function useSafeArea(): UseSafeAreaResult {
|
|
28
28
|
const [result] = useState<UseSafeAreaResult>(() => {
|
|
29
|
-
const globals =
|
|
29
|
+
const globals = getHostGlobals()
|
|
30
30
|
return {
|
|
31
31
|
insets: globals.safeAreaInsets ?? EMPTY_INSETS,
|
|
32
32
|
capsuleMenu: globals.capsuleMenu ?? null,
|
package/src/session.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import {EventEmitter} from "eventemitter3"
|
|
16
16
|
|
|
17
17
|
import {makeRequestId, MiniappEnvelope, parseEnvelope, serializeEnvelope} from "./envelope"
|
|
18
|
-
import {
|
|
18
|
+
import {getHostGlobals, MiniappColorScheme} from "./globals"
|
|
19
19
|
import {MiniappErrorCode, MiniappRequestType, MiniappResponseType} from "./protocol"
|
|
20
20
|
import {createTransport, CreateTransportOptions} from "./transport/auto"
|
|
21
21
|
import {Transport} from "./transport/types"
|
|
@@ -26,15 +26,17 @@ import {DashboardAPI} from "./modules/dashboard"
|
|
|
26
26
|
import {DisplayManager} from "./modules/display"
|
|
27
27
|
import {EventManager, type TranscriptionEventRoute, type UnsubscribeFn} from "./modules/events"
|
|
28
28
|
import {GlassesModule} from "./modules/glasses"
|
|
29
|
-
import {HeadingModule} from "./modules/heading"
|
|
30
29
|
import {AiModule} from "./modules/ai"
|
|
31
30
|
import {ImuModule} from "./modules/imu"
|
|
31
|
+
import {CompassModule} from "./modules/compass"
|
|
32
|
+
import {LightSensorModule} from "./modules/lightSensor"
|
|
32
33
|
import {InputModule} from "./modules/input"
|
|
33
34
|
import {KeysModule} from "./modules/keys"
|
|
34
35
|
import {LedModule} from "./modules/led"
|
|
35
36
|
import {LocationModule} from "./modules/location"
|
|
36
37
|
import {MemoryModule} from "./modules/memory"
|
|
37
38
|
import {SpeakersModule} from "./modules/speakers"
|
|
39
|
+
import {MirrorModule} from "./modules/mirror"
|
|
38
40
|
import {MicModule} from "./modules/mic"
|
|
39
41
|
import {NavigationModule} from "./modules/navigation"
|
|
40
42
|
import {PermissionsModule} from "./modules/permissions"
|
|
@@ -42,6 +44,7 @@ import {PhoneModule} from "./modules/phone"
|
|
|
42
44
|
import {TranscriptionModule} from "./modules/transcription"
|
|
43
45
|
import {TranslationModule} from "./modules/translation"
|
|
44
46
|
import {UIModuleImpl, type UIModule} from "./modules/ui"
|
|
47
|
+
import {SettingsModule} from "./modules/settings"
|
|
45
48
|
import {SimpleStorage} from "./modules/storage"
|
|
46
49
|
import {SpeakerModule} from "./modules/speaker"
|
|
47
50
|
import {StreamModule} from "./modules/stream"
|
|
@@ -70,9 +73,23 @@ export interface DisplayCapabilities {
|
|
|
70
73
|
maxImageElements?: number
|
|
71
74
|
/** Per-image dimension cap (box-level), when the device has one. */
|
|
72
75
|
maxImagePx?: {width: number; height: number}
|
|
76
|
+
/** Shape element types the device draws ("rect", "circle", "line", …). */
|
|
73
77
|
shapes?: string[]
|
|
78
|
+
/** True ⇒ element `transition`s animate on the device. */
|
|
79
|
+
animation?: boolean
|
|
80
|
+
/** Geometric and SVG rotations, including duration-based transitions. */
|
|
81
|
+
rotation?: boolean
|
|
82
|
+
/** Per-element stereo `depth` (a lens disparity) is honored; otherwise elements draw flat. */
|
|
83
|
+
depth?: boolean
|
|
74
84
|
intensityLevels?: number
|
|
85
|
+
|
|
75
86
|
partialUpdate?: boolean
|
|
87
|
+
/**
|
|
88
|
+
* The views this app may draw right now. "main" always; "dashboard" only
|
|
89
|
+
* for the running app whose manifest type is "system_dashboard", while the
|
|
90
|
+
* connected glasses can show the overlay slot (see display.showView).
|
|
91
|
+
*/
|
|
92
|
+
views?: Array<"main" | "dashboard">
|
|
76
93
|
/** Legacy capability fields (resolution, isColor, maxTextLines, …) ride along. */
|
|
77
94
|
[key: string]: unknown
|
|
78
95
|
}
|
|
@@ -87,6 +104,8 @@ export interface GlassesCapabilities {
|
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
export type MiniappVisibility = "foreground" | "background"
|
|
107
|
+
/** Where the user started this session from: the phone app or the glasses menu. */
|
|
108
|
+
export type MiniappLaunchSource = "phone" | "glasses"
|
|
90
109
|
|
|
91
110
|
export interface MiniappSessionOptions extends CreateTransportOptions {
|
|
92
111
|
/** Override auto-detected packageName. Normally provided via window.Glassly. */
|
|
@@ -95,13 +114,30 @@ export interface MiniappSessionOptions extends CreateTransportOptions {
|
|
|
95
114
|
connectTimeoutMs?: number
|
|
96
115
|
}
|
|
97
116
|
|
|
117
|
+
/** Distance/temperature unit family. Mirrors the host's "Use Metric System" toggle. */
|
|
118
|
+
export type MiniappUnitSystem = "metric" | "imperial"
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Host user preferences a miniapp should follow by default (Settings >
|
|
122
|
+
* Appearance). Sent in CONNECT_ACK and pushed on change. Miniapps may still
|
|
123
|
+
* offer their own override on top.
|
|
124
|
+
*/
|
|
125
|
+
export interface MiniappPreferences {
|
|
126
|
+
unitSystem: MiniappUnitSystem
|
|
127
|
+
/** True for 12-hour (AM/PM) clocks, false for 24-hour. */
|
|
128
|
+
twelveHourTime: boolean
|
|
129
|
+
}
|
|
130
|
+
|
|
98
131
|
export interface ConnectAckPayload {
|
|
99
132
|
type: MiniappResponseType.CONNECT_ACK
|
|
100
133
|
userId: string
|
|
101
134
|
packageName: string
|
|
102
135
|
capabilities: GlassesCapabilities | null
|
|
136
|
+
/** Absent on runtimes older than the preferences surface. */
|
|
137
|
+
preferences?: MiniappPreferences
|
|
103
138
|
visibility?: MiniappVisibility
|
|
104
139
|
colorScheme?: MiniappColorScheme
|
|
140
|
+
launchSource?: MiniappLaunchSource
|
|
105
141
|
/**
|
|
106
142
|
* Manifest-declared permission record. Mirrors cloud SDK v3's PermissionRecord:
|
|
107
143
|
* `{location, microphone, camera, notifications, calendar, apiKeys}` —
|
|
@@ -114,7 +150,7 @@ export interface ConnectAckPayload {
|
|
|
114
150
|
}
|
|
115
151
|
|
|
116
152
|
export interface MiniappAuthState {
|
|
117
|
-
|
|
153
|
+
userId: string
|
|
118
154
|
oemId?: string
|
|
119
155
|
token: string
|
|
120
156
|
expiresAt: number
|
|
@@ -143,6 +179,7 @@ export type PermissionType =
|
|
|
143
179
|
| "memory"
|
|
144
180
|
| "ai"
|
|
145
181
|
| "speakers"
|
|
182
|
+
| "displayMirror"
|
|
146
183
|
export type PermissionRecord = Record<PermissionType, boolean>
|
|
147
184
|
|
|
148
185
|
const ALL_PERMISSION_TYPES: readonly PermissionType[] = [
|
|
@@ -155,6 +192,7 @@ const ALL_PERMISSION_TYPES: readonly PermissionType[] = [
|
|
|
155
192
|
"memory",
|
|
156
193
|
"ai",
|
|
157
194
|
"speakers",
|
|
195
|
+
"displayMirror",
|
|
158
196
|
] as const
|
|
159
197
|
|
|
160
198
|
export class NotConnectedError extends Error {
|
|
@@ -224,6 +262,7 @@ type SessionEmitterEvents = {
|
|
|
224
262
|
disconnect: (reason: string) => void
|
|
225
263
|
visibility: (v: MiniappVisibility) => void
|
|
226
264
|
capabilities: (cap: GlassesCapabilities | null) => void
|
|
265
|
+
preferences: (prefs: MiniappPreferences) => void
|
|
227
266
|
colorScheme: (scheme: MiniappColorScheme) => void
|
|
228
267
|
permissions: (perms: PermissionRecord) => void
|
|
229
268
|
speakerState: (event: import("./modules/speaker").SpeakerStateEvent) => void
|
|
@@ -236,6 +275,7 @@ type SessionEmitterEvents = {
|
|
|
236
275
|
|
|
237
276
|
export class MiniappSession<TChannels extends object = any> {
|
|
238
277
|
public readonly auth: AuthModule
|
|
278
|
+
public readonly mirror: MirrorModule
|
|
239
279
|
public readonly display: DisplayManager
|
|
240
280
|
/**
|
|
241
281
|
* Internal subscription registry + escape hatch.
|
|
@@ -251,8 +291,9 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
251
291
|
public readonly cloud: CloudModule
|
|
252
292
|
public readonly dashboard: DashboardAPI
|
|
253
293
|
public readonly glasses: GlassesModule
|
|
254
|
-
public readonly heading: HeadingModule
|
|
255
294
|
public readonly imu: ImuModule
|
|
295
|
+
public readonly lightSensor: LightSensorModule
|
|
296
|
+
public readonly compass: CompassModule
|
|
256
297
|
public readonly input: InputModule
|
|
257
298
|
/**
|
|
258
299
|
* User-supplied provider API keys (Settings > API Keys). Requires the
|
|
@@ -286,6 +327,11 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
286
327
|
public readonly navigation: NavigationModule
|
|
287
328
|
public readonly permissions: PermissionsModule
|
|
288
329
|
public readonly phone: PhoneModule
|
|
330
|
+
/**
|
|
331
|
+
* The engine's settings store behind an allowlist. SYSTEM-only — calls
|
|
332
|
+
* reject with NOT_PERMITTED unless this miniapp is a system app.
|
|
333
|
+
*/
|
|
334
|
+
public readonly settings: SettingsModule
|
|
289
335
|
public readonly storage: SimpleStorage
|
|
290
336
|
/**
|
|
291
337
|
* Phone-local persistent BINARY storage (`session.blob`) — the binary
|
|
@@ -318,9 +364,13 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
318
364
|
|
|
319
365
|
/** Phone-declared glasses capabilities. Null until CONNECT_ACK arrives. */
|
|
320
366
|
public capabilities: GlassesCapabilities | null = null
|
|
367
|
+
/** Host user preferences. Null until CONNECT_ACK arrives (or on runtimes that don't send them). */
|
|
368
|
+
public preferences: MiniappPreferences | null = null
|
|
321
369
|
public userId = ""
|
|
322
370
|
public packageName = ""
|
|
323
371
|
public visibility: MiniappVisibility = "foreground"
|
|
372
|
+
/** Where the user started this session from. Null until CONNECT_ACK arrives. */
|
|
373
|
+
public launchSource: MiniappLaunchSource | null = null
|
|
324
374
|
/** Host color scheme. Seeded from window.Glassly, updated via session events. */
|
|
325
375
|
public colorScheme: MiniappColorScheme = "light"
|
|
326
376
|
|
|
@@ -359,13 +409,14 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
359
409
|
memory: false,
|
|
360
410
|
ai: false,
|
|
361
411
|
speakers: false,
|
|
412
|
+
displayMirror: false,
|
|
362
413
|
}
|
|
363
414
|
|
|
364
415
|
constructor(options: MiniappSessionOptions = {}) {
|
|
365
416
|
this.transport = createTransport(options)
|
|
366
417
|
this.connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS
|
|
367
418
|
|
|
368
|
-
const injected =
|
|
419
|
+
const injected = getHostGlobals()
|
|
369
420
|
this.packageName = options.packageName ?? injected.packageName ?? ""
|
|
370
421
|
if (injected.colorScheme === "light" || injected.colorScheme === "dark") {
|
|
371
422
|
this.colorScheme = injected.colorScheme
|
|
@@ -377,10 +428,12 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
377
428
|
this.camera = new CameraModule(this)
|
|
378
429
|
this.cloud = new CloudModule(this)
|
|
379
430
|
this.dashboard = new DashboardAPI(this)
|
|
431
|
+
this.mirror = new MirrorModule(this)
|
|
380
432
|
this.display = new DisplayManager(this)
|
|
381
433
|
this.glasses = new GlassesModule(this)
|
|
382
|
-
this.heading = new HeadingModule(this)
|
|
383
434
|
this.imu = new ImuModule(this)
|
|
435
|
+
this.lightSensor = new LightSensorModule(this)
|
|
436
|
+
this.compass = new CompassModule(this)
|
|
384
437
|
this.input = new InputModule(this)
|
|
385
438
|
this.ai = new AiModule(this)
|
|
386
439
|
this.keys = new KeysModule(this)
|
|
@@ -392,6 +445,7 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
392
445
|
this.navigation = new NavigationModule(this)
|
|
393
446
|
this.permissions = new PermissionsModule(this)
|
|
394
447
|
this.phone = new PhoneModule(this)
|
|
448
|
+
this.settings = new SettingsModule(this)
|
|
395
449
|
this.storage = new SimpleStorage(this)
|
|
396
450
|
this.blob = new BlobModule(this)
|
|
397
451
|
this.stream = new StreamModule(this)
|
|
@@ -646,6 +700,10 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
646
700
|
return this.on("capabilities", handler)
|
|
647
701
|
}
|
|
648
702
|
|
|
703
|
+
onPreferencesChange(handler: (prefs: MiniappPreferences) => void): () => void {
|
|
704
|
+
return this.on("preferences", handler)
|
|
705
|
+
}
|
|
706
|
+
|
|
649
707
|
onColorSchemeChange(handler: (scheme: MiniappColorScheme) => void): () => void {
|
|
650
708
|
return this.on("colorScheme", handler)
|
|
651
709
|
}
|
|
@@ -691,13 +749,15 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
691
749
|
this.userId = ack.userId ?? ""
|
|
692
750
|
if (ack.packageName) this.packageName = ack.packageName
|
|
693
751
|
this.capabilities = ack.capabilities ?? null
|
|
752
|
+
if (ack.preferences) this.preferences = ack.preferences
|
|
694
753
|
if (ack.visibility) this.visibility = ack.visibility
|
|
754
|
+
if (ack.launchSource) this.launchSource = ack.launchSource
|
|
695
755
|
if (ack.colorScheme === "light" || ack.colorScheme === "dark") {
|
|
696
756
|
this.colorScheme = ack.colorScheme
|
|
697
757
|
}
|
|
698
758
|
if (ack.auth) {
|
|
699
759
|
this.applyAuth(ack.auth)
|
|
700
|
-
if (!this.userId) this.userId = ack.auth.
|
|
760
|
+
if (!this.userId) this.userId = ack.auth.userId
|
|
701
761
|
}
|
|
702
762
|
// Populate the manifest-declared permission cache. Older runtimes
|
|
703
763
|
// that don't send `permissions` leave the all-false default in place
|
|
@@ -714,7 +774,7 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
714
774
|
const next = (payload as unknown as AuthUpdatePayload).auth
|
|
715
775
|
if (next) {
|
|
716
776
|
this.applyAuth(next)
|
|
717
|
-
if (!this.userId) this.userId = next.
|
|
777
|
+
if (!this.userId) this.userId = next.userId
|
|
718
778
|
}
|
|
719
779
|
return
|
|
720
780
|
}
|
|
@@ -785,6 +845,14 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
785
845
|
return
|
|
786
846
|
}
|
|
787
847
|
|
|
848
|
+
case MiniappResponseType.PREFERENCES_UPDATE: {
|
|
849
|
+
const prefs = payload.preferences as MiniappPreferences | undefined
|
|
850
|
+
if (!prefs) return
|
|
851
|
+
this.preferences = prefs
|
|
852
|
+
this.emitter.emit("preferences", prefs)
|
|
853
|
+
return
|
|
854
|
+
}
|
|
855
|
+
|
|
788
856
|
case MiniappResponseType.VISIBILITY_CHANGE: {
|
|
789
857
|
const next = payload.visibility as MiniappVisibility | undefined
|
|
790
858
|
if (next === "foreground" || next === "background") {
|
|
@@ -956,6 +1024,8 @@ function manifestKeyToCanonical(manifestKey: string): PermissionType | null {
|
|
|
956
1024
|
return "memory"
|
|
957
1025
|
case "AI":
|
|
958
1026
|
return "ai"
|
|
1027
|
+
case "DISPLAY_MIRROR":
|
|
1028
|
+
return "displayMirror"
|
|
959
1029
|
case "SPEAKERS":
|
|
960
1030
|
return "speakers"
|
|
961
1031
|
default:
|
package/src/transport/auto.ts
CHANGED
|
@@ -24,12 +24,12 @@ export interface CreateTransportOptions {
|
|
|
24
24
|
*
|
|
25
25
|
* 1. **DispatchTransport** — when running in a per-miniapp JSContext
|
|
26
26
|
* (no DOM, but `__dispatch` is installed on `globalThis` by the
|
|
27
|
-
*
|
|
27
|
+
* JSRuntime runtime). This is the production path.
|
|
28
28
|
* 2. **PostMessageTransport** — inside a Glassly WebView
|
|
29
29
|
* (`window.ReactNativeWebView` defined). This is the existing UI
|
|
30
30
|
* layer path and the only transport miniapp UI bundles need.
|
|
31
31
|
* 3. **MockTransport** — explicit opt-in via `?glassly=mock` or
|
|
32
|
-
* `localStorage.
|
|
32
|
+
* `localStorage.MINIAPP_MOCK=1`. Useful for Storybook / unit tests.
|
|
33
33
|
* 4. **LocalSocketWithMockFallback** — external browser, races a
|
|
34
34
|
* `ws://127.0.0.1` LocalSocketTransport open against a 500ms timeout
|
|
35
35
|
* and falls back to MockTransport so the page doesn't hang.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview DispatchTransport — Transport implementation that rides
|
|
3
3
|
* the native `__dispatch(iface, method, argsJson)` bridge exposed by the
|
|
4
|
-
*
|
|
4
|
+
* JSRuntime runtime (per-miniapp JSContext on iOS-JSC, Zipline/QuickJS
|
|
5
5
|
* context on Android).
|
|
6
6
|
*
|
|
7
7
|
* The existing `MiniappSession` (session.ts) is transport-agnostic — it
|
package/src/transport/mock.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Activates when:
|
|
5
5
|
* - `window.ReactNativeWebView` is undefined (not in Glassly WebView), AND
|
|
6
6
|
* - The first LocalSocketTransport connection attempt fails fast, OR
|
|
7
|
-
* - The author opts in via `?glassly=mock` query param / `localStorage.
|
|
7
|
+
* - The author opts in via `?glassly=mock` query param / `localStorage.MINIAPP_MOCK = "1"`.
|
|
8
8
|
*
|
|
9
9
|
* Behaviors:
|
|
10
10
|
* - On `open()`: synthesize a CONNECT_ACK envelope so `session.connect()` resolves.
|
|
@@ -12,20 +12,32 @@
|
|
|
12
12
|
* auto-reply with synthetic results for any request that needs one.
|
|
13
13
|
* - Does NOT emit any glasses events. Subscribing succeeds silently.
|
|
14
14
|
*
|
|
15
|
-
* This is the Stage-1 stopgap from `agents/miniapp-quick-fixes-spec.md` #6.
|
|
15
|
+
* This is the Stage-1 stopgap from `notes/archive/agents/miniapp-quick-fixes-spec.md` #6.
|
|
16
16
|
* The full simulator (event injection, glasses-display preview, hardware bridge)
|
|
17
|
-
* is Stage 2 — see `agents/miniapp-browser-testing-simulator-spec.md`.
|
|
17
|
+
* is Stage 2 — see `notes/archive/agents/miniapp-browser-testing-simulator-spec.md`.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import {parseEnvelope, serializeEnvelope, type MiniappEnvelope} from "../envelope"
|
|
21
|
-
import {MiniappRequestType, MiniappResponseType} from "../protocol"
|
|
21
|
+
import {MiniappRequestType, MiniappResponseType, MiniappStreamType} from "../protocol"
|
|
22
22
|
import type {Transport, TransportDisconnectHandler, TransportMessageHandler} from "./types"
|
|
23
23
|
|
|
24
|
+
const mockMirror = () => ({
|
|
25
|
+
revision: 0,
|
|
26
|
+
updatedAt: 0,
|
|
27
|
+
connected: false,
|
|
28
|
+
model: null,
|
|
29
|
+
canvas: null,
|
|
30
|
+
view: null,
|
|
31
|
+
appId: null,
|
|
32
|
+
content: {kind: "unavailable", reason: "mock-host"},
|
|
33
|
+
glyphWidths: {},
|
|
34
|
+
})
|
|
35
|
+
|
|
24
36
|
const LOG_PREFIX = "[mock-transport]"
|
|
25
37
|
|
|
26
38
|
/**
|
|
27
39
|
* Returns true if the current environment requested the mock transport
|
|
28
|
-
* explicitly. Checks `?glassly=mock` query param and `localStorage.
|
|
40
|
+
* explicitly. Checks `?glassly=mock` query param and `localStorage.MINIAPP_MOCK`.
|
|
29
41
|
*/
|
|
30
42
|
export function isMockExplicitlyRequested(): boolean {
|
|
31
43
|
if (typeof window === "undefined") return false
|
|
@@ -38,7 +50,7 @@ export function isMockExplicitlyRequested(): boolean {
|
|
|
38
50
|
// ignore
|
|
39
51
|
}
|
|
40
52
|
try {
|
|
41
|
-
if (typeof localStorage !== "undefined" && localStorage.getItem("
|
|
53
|
+
if (typeof localStorage !== "undefined" && localStorage.getItem("MINIAPP_MOCK") === "1") {
|
|
42
54
|
return true
|
|
43
55
|
}
|
|
44
56
|
} catch {
|
|
@@ -105,6 +117,19 @@ export class MockTransport implements Transport {
|
|
|
105
117
|
return
|
|
106
118
|
|
|
107
119
|
case MiniappRequestType.SUBSCRIBE:
|
|
120
|
+
if (Array.isArray(payload.subscriptions) && payload.subscriptions.includes(MiniappStreamType.MIRROR_UPDATE)) {
|
|
121
|
+
queueMicrotask(() =>
|
|
122
|
+
this.messageHandler?.(
|
|
123
|
+
serializeEnvelope({
|
|
124
|
+
payload: {
|
|
125
|
+
type: MiniappResponseType.EVENT,
|
|
126
|
+
streamType: MiniappStreamType.MIRROR_UPDATE,
|
|
127
|
+
data: mockMirror(),
|
|
128
|
+
},
|
|
129
|
+
}),
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
}
|
|
108
133
|
// Subscribe is fire-and-forget; no response expected. Stage 1 emits no
|
|
109
134
|
// events. Future Stage 2 simulator can synthesize events here.
|
|
110
135
|
return
|
|
@@ -149,7 +174,7 @@ export class MockTransport implements Transport {
|
|
|
149
174
|
visibility: "foreground",
|
|
150
175
|
colorScheme: "light",
|
|
151
176
|
auth: {
|
|
152
|
-
|
|
177
|
+
userId: this.userId,
|
|
153
178
|
oemId: "mock",
|
|
154
179
|
token: this.authToken,
|
|
155
180
|
expiresAt: Date.now() + 60 * 60 * 1000,
|
|
@@ -195,10 +220,10 @@ function syntheticDataFor(requestId: string, requestType: string, requestPayload
|
|
|
195
220
|
requestPayload.preset === "narrow"
|
|
196
221
|
? 82
|
|
197
222
|
: requestPayload.preset === "wide"
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
? 118
|
|
224
|
+
: requestPayload.preset === "standard"
|
|
225
|
+
? 102
|
|
226
|
+
: undefined
|
|
202
227
|
const fov = typeof requestPayload.fov === "number" ? requestPayload.fov : (presetFov ?? 102)
|
|
203
228
|
const roi = requestPayload.roiPosition
|
|
204
229
|
const roiPosition = roi === "bottom" ? "bottom" : roi === "top" ? "top" : "center"
|
|
@@ -221,6 +246,9 @@ function syntheticDataFor(requestId: string, requestType: string, requestPayload
|
|
|
221
246
|
case MiniappRequestType.RGB_LED:
|
|
222
247
|
return {type: "rgb_led_control_response", state: "success", requestId}
|
|
223
248
|
|
|
249
|
+
case MiniappRequestType.MIRROR_GET:
|
|
250
|
+
return mockMirror()
|
|
251
|
+
|
|
224
252
|
case MiniappRequestType.LOCATION_POLL:
|
|
225
253
|
// San Francisco fallback — using 0,0 puts dev sessions in the
|
|
226
254
|
// Atlantic, which makes maps/navigation unusable in the WebView.
|
|
@@ -246,6 +274,9 @@ function syntheticDataFor(requestId: string, requestType: string, requestPayload
|
|
|
246
274
|
case MiniappRequestType.SET_WIFI_ADB_STATE:
|
|
247
275
|
return {ok: true}
|
|
248
276
|
|
|
277
|
+
case MiniappRequestType.DISPLAY_DIAGNOSTICS:
|
|
278
|
+
return {enabled: false, generatedAt: Date.now(), records: []}
|
|
279
|
+
|
|
249
280
|
case MiniappRequestType.SCAN_QR:
|
|
250
281
|
return {cancelled: true}
|
|
251
282
|
|