Repository navigation
Expand file tree
/
Copy pathprotocol.ts
More file actions
559 lines (483 loc) · 23.5 KB
/
Copy pathprotocol.ts
File metadata and controls
559 lines (483 loc) · 23.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
/**
* @fileoverview Wire protocol for @mentra/miniapp.
*
* Fresh miniapp-naming enum values. No legacy tpa_/app_/applet_ prefixes.
* These values are the contract between @mentra/miniapp and LocalMiniappRuntime,
* both running locally in the Mentra App on the phone.
*
* This file has no runtime dependency on the retired cloud SDK.
*/
// ============================================================================
// Miniapp → phone (request, via bridge envelope)
// ============================================================================
export enum MiniappRequestType {
/** Handshake: miniapp announces itself and asks phone to bind the session. */
CONNECT = "miniapp_connect",
/**
* One-shot: the background's `registerMiniapp` handler has settled, so its
* `session.ui.handle` handlers exist. Sent only to hosts advertising
* `hostFeatures.initReady`; the host keeps the UI closed until it arrives.
*/
READY = "miniapp_ready",
/** Request a fresh miniapp-scoped backend auth token. */
AUTH_REFRESH = "miniapp_auth_refresh",
/** Update the set of streams the miniapp is subscribed to. */
SUBSCRIBE = "miniapp_subscribe",
/**
* Push a legacy display layout to the glasses. The SDK no longer emits this
* (render()/RENDER replaced it); hosts keep accepting it from bundles packed
* with older SDKs and from cloud-shaped layouts.
*/
DISPLAY = "miniapp_display",
/** Render a whole scene of positioned elements (replace-the-frame). */
RENDER = "miniapp_render",
/** Play an arbitrary audio URL through the phone's audio playback service. */
PLAY_AUDIO = "miniapp_play_audio",
/** Stop any audio playback this miniapp initiated. */
STOP_AUDIO = "miniapp_stop_audio",
/** Speak text via cloud TTS — phone constructs the URL. */
SPEAK = "miniapp_speak",
/**
* Live PCM output stream to the phone's audio playback service
* (speaker.createStream). OPEN provisions a native chunk player; WRITE
* appends base64 PCM (replies with {bufferedMs} for backpressure); CLOSE
* drains and finishes; ABORT drops immediately.
*/
SPEAKER_STREAM_OPEN = "miniapp_speaker_stream_open",
SPEAKER_STREAM_WRITE = "miniapp_speaker_stream_write",
SPEAKER_STREAM_CLOSE = "miniapp_speaker_stream_close",
SPEAKER_STREAM_ABORT = "miniapp_speaker_stream_abort",
/** Control the glasses RGB LED. */
RGB_LED = "miniapp_rgb_led",
/** One-shot location poll. */
LOCATION_POLL = "miniapp_location_poll",
/** Read a bounded snapshot of phone calendar events. */
CALENDAR_LIST_EVENTS = "miniapp_calendar_list_events",
/** Start a turn-by-turn navigation trip. Android only. */
NAVIGATION_START = "miniapp_navigation_start",
/** Stop the active navigation trip (if any). */
NAVIGATION_STOP = "miniapp_navigation_stop",
/** Dev-only: nudge the simulator off-route to test rerouting. Android sim only. */
NAVIGATION_DEVIATE = "miniapp_navigation_deviate",
/** Dev-only: lock simulated locations to the wrong sidewalk for pivot-trigger testing. */
NAVIGATION_SET_WRONG_SIDEWALK = "miniapp_navigation_set_wrong_sidewalk",
/** Dev-only: take over the simulator and walk a polyline with crossings stripped. */
NAVIGATION_SET_SKIP_CROSSINGS = "miniapp_navigation_set_skip_crossings",
/** Snapshot of the active trip (or null). Lets a miniapp opening mid-trip hydrate. */
NAVIGATION_GET_STATE = "miniapp_navigation_get_state",
/** Compute a route without starting a trip. Replaces hand-rolled Directions calls. */
NAVIGATION_COMPUTE_ROUTE = "miniapp_navigation_compute_route",
/** Reverse-geocode a coordinate to a short road name + full formatted
* address. `road` backs the engine's fallback for pivots whose Routes-API
* instruction didn't include a parseable road; `address` backs UI labels for
* dropped pins / POI taps. Resolved in the v2 cloud maps service (Mapbox
* today) via the host bridge — the miniapp never holds a maps token. */
NAVIGATION_REVERSE_GEOCODE = "miniapp_navigation_reverse_geocode",
/** Type-ahead place search (autocomplete). Resolved in the v2 cloud maps
* service (Mapbox Search Box today) via the host bridge — the miniapp never
* holds a maps token. Pairs with NAVIGATION_PLACE_DETAILS via a sessionToken. */
NAVIGATION_PLACE_AUTOCOMPLETE = "miniapp_navigation_place_autocomplete",
/** Resolve an autocomplete suggestion (placeId + sessionToken) to coordinates,
* in the v2 cloud maps service via the host bridge. */
NAVIGATION_PLACE_DETAILS = "miniapp_navigation_place_details",
/** Trigger the Google Nav SDK T&C dialog up-front so start() doesn't have to. */
NAVIGATION_REQUEST_PERMISSION = "miniapp_navigation_request_permission",
/** Phone-local simple storage. */
STORAGE_GET = "miniapp_storage_get",
STORAGE_SET = "miniapp_storage_set",
STORAGE_DELETE = "miniapp_storage_delete",
STORAGE_LIST = "miniapp_storage_list",
STORAGE_CLEAR = "miniapp_storage_clear",
STORAGE_HAS = "miniapp_storage_has",
STORAGE_GET_ALL = "miniapp_storage_get_all",
STORAGE_SET_MULTIPLE = "miniapp_storage_set_multiple",
STORAGE_FLUSH = "miniapp_storage_flush",
/** Write camera FOV settings. */
CAMERA_FOV = "miniapp_camera_fov",
/** Pre-warm the glasses camera so the next takePhoto() is near-instant. */
CAMERA_WARM_UP = "miniapp_camera_warm_up",
/**
* Enable/disable raw accelerometer (IMU) streaming on the glasses. The
* accel stream also auto-enables on subscribe; this is an explicit override
* for callers who want to control the sensor directly. G2 only today.
*/
IMU_SET_ENABLED = "miniapp_imu_set_enabled",
/** Explicitly enable/disable glasses-side VAD (GX8002). Mirrors the app's mic settings toggle. */
MIC_SET_VAD_ENABLED = "miniapp_mic_set_vad_enabled",
/** Explicitly enable/disable the center-mic loudness gate ("Barrier"). */
MIC_SET_LOUDNESS_GATE_ENABLED = "miniapp_mic_set_loudness_gate_enabled",
/**
* Take a semantic microphone session. The host decides what the use case
* requires of the hardware; the caller never names a gain or a threshold.
* Host-gated per use case — see `MicModule.acquire`.
*/
MIC_ACQUIRE = "miniapp_mic_acquire",
/** Release a session taken with MIC_ACQUIRE. */
MIC_RELEASE = "miniapp_mic_release",
/**
* Enable or disable Wi-Fi ADB (wireless debugging) on Mentra Live.
* SYSTEM-only — host rejects with NOT_PERMITTED for non-system callers.
*/
SET_WIFI_ADB_STATE = "miniapp_set_wifi_adb_state",
/** Share content via the OS share sheet. */
SHARE = "miniapp_share",
/** Open a URL in the system browser. */
OPEN_URL = "miniapp_open_url",
/** Copy text to the system clipboard. */
COPY_CLIPBOARD = "miniapp_copy_clipboard",
/** Download a file (triggers OS share sheet for save location). */
DOWNLOAD = "miniapp_download",
/**
* Open a phone-camera QR scanner overlay. Host must not unmount the miniapp
* (clearing foreground fires UI_CLOSE and can hang up live sessions).
*/
SCAN_QR = "miniapp_scan_qr",
/**
* Phone-local persistent binary blob storage, scoped to (userId, packageName).
* Unlike STORAGE_* (small string KV in MMKV), blobs are arbitrary bytes written
* to the phone filesystem. Large payloads are moved in chunks (BLOB_WRITE /
* BLOB_READ) so a single bridge message never carries a multi-MB string.
*/
BLOB_CREATE = "miniapp_blob_create",
BLOB_WRITE = "miniapp_blob_write",
BLOB_COMMIT = "miniapp_blob_commit",
BLOB_ABORT = "miniapp_blob_abort",
BLOB_GET = "miniapp_blob_get",
BLOB_LIST = "miniapp_blob_list",
BLOB_DELETE = "miniapp_blob_delete",
BLOB_CLEAR = "miniapp_blob_clear",
BLOB_USAGE = "miniapp_blob_usage",
BLOB_OPEN_READ = "miniapp_blob_open_read",
BLOB_READ = "miniapp_blob_read",
BLOB_CLOSE_READ = "miniapp_blob_close_read",
/** Download a URL straight into a blob, host-side (no bytes cross the bridge). */
BLOB_SET_FROM_URL = "miniapp_blob_set_from_url",
/** Open the OS file picker and import the chosen file into a blob, host-side. */
BLOB_IMPORT = "miniapp_blob_import",
/** Share a stored blob from disk via the OS share sheet (no bytes cross the bridge). */
BLOB_SHARE = "miniapp_blob_share",
/** Phone → miniapp liveness probe. Miniapp SDK auto-replies with PONG. */
PING = "miniapp_ping",
/**
* Apply transcription configuration (language hints, vocabulary, diarization).
* Phone forwards to the cloud STT layer. Fire-and-forget; cached client-side
* so future reconnect logic can re-send.
*/
TRANSCRIPTION_CONFIG = "miniapp_transcription_config",
// ----- Deferred in v1 -----
/** Dashboard content update. Noop in v1. */
DASHBOARD_CONTENT_UPDATE = "miniapp_dashboard_content_update",
// ----- Photos, streaming -----
PHOTO = "miniapp_photo",
VIDEO_RECORDING_START = "miniapp_video_recording_start",
VIDEO_RECORDING_STOP = "miniapp_video_recording_stop",
STREAM_START = "miniapp_stream_start",
STREAM_STOP = "miniapp_stream_stop",
MANAGED_STREAM_START = "miniapp_managed_stream_start",
MANAGED_STREAM_STOP = "miniapp_managed_stream_stop",
/**
* Take the single raw decoded-frame preview lease on a source. See
* `session.stream.preview()`. Replies `{handleId, previewTraceId, source}`.
*/
STREAM_PREVIEW_START = "miniapp_stream_preview_start",
/** Release a preview lease by `handleId`. */
STREAM_PREVIEW_STOP = "miniapp_stream_preview_stop",
/** Ask the host to open the glasses Wi-Fi setup flow (mirrors the cloud SDK's requestWifiSetup). */
REQUEST_WIFI_SETUP = "miniapp_request_wifi_setup",
/** Read the phone's Wi-Fi radio state (null when the platform cannot determine it). */
PHONE_IS_WIFI_ENABLED = "miniapp_phone_is_wifi_enabled",
/** Ask the host to help the user enable phone Wi-Fi, then recheck on return. */
PHONE_REQUEST_WIFI_ENABLE = "miniapp_phone_request_wifi_enable",
// ----- Inter-miniapp interop (SYSTEM apps only) -----
/** List installed miniapps (compatibility-filtered, with declared actions). */
MINIAPPS_LIST = "miniapp_apps_list",
/** Start another miniapp (user-tap semantics). */
MINIAPPS_START = "miniapp_apps_start",
/** Stop another miniapp. */
MINIAPPS_STOP = "miniapp_apps_stop",
/** Install/update an approved bundle. Bundled host-trusted Stores only. */
MINIAPPS_INSTALL = "miniapp_apps_install",
/** Preflight a release's host/SDK/hardware requirements without downloading it. */
MINIAPPS_INSTALL_CHECK = "miniapp_apps_install_check",
/** Uninstall a package owned by the calling Store. Bundled host-trusted Stores only. */
MINIAPPS_UNINSTALL = "miniapp_apps_uninstall",
/** Invoke a declared action on another miniapp; headless-wakes it if stopped. */
ACTION_INVOKE = "miniapp_action_invoke",
/** Target → host: the result of a delivered ACTION_CALL, correlated by callId. */
ACTION_RESULT = "miniapp_action_result",
/**
* Phone-native meeting (ACS Teams). Join/leave/mute live in the MentraOS
* host so the miniapp never holds the ACS Calling SDK.
*/
MEETING_GET_IDENTITY = "miniapp_meeting_get_identity",
MEETING_GET_CONFIGURATION = "miniapp_meeting_get_configuration",
MEETING_CREATE = "miniapp_meeting_create",
MEETING_RETIRE = "miniapp_meeting_retire",
MEETING_JOIN = "miniapp_meeting_join",
MEETING_LEAVE = "miniapp_meeting_leave",
/** Terminate the meeting for everyone, not just this device. See `meeting.end()`. */
MEETING_END = "miniapp_meeting_end",
/** Admit one waiting participant, when the host has Teams lobby permission. */
MEETING_ADMIT = "miniapp_meeting_admit",
MEETING_SET_MUTED = "miniapp_meeting_set_muted",
/** Stop or resume the glasses camera the meeting receives, without leaving. */
MEETING_SET_VIDEO_ENABLED = "miniapp_meeting_set_video_enabled",
MEETING_UPDATE_VIDEO_SOURCE = "miniapp_meeting_update_video_source",
MEETING_GET_STATE = "miniapp_meeting_get_state",
/** Stop the glasses publisher for a photo. The meeting, hotspot, and audio stay up. */
MEETING_PAUSE_VIDEO_PUBLISHER = "miniapp_meeting_pause_video_publisher",
MEETING_RESUME_VIDEO_PUBLISHER = "miniapp_meeting_resume_video_publisher",
/** Full-frame "Taking a photo..." card on the outgoing video. Resolves after the first card frame. */
MEETING_SHOW_CARD = "miniapp_meeting_show_card",
/** Replace the card with a still. `durationMs` is counted by the caller from `shownAt`. */
MEETING_SHOW_IMAGE = "miniapp_meeting_show_image",
/** Stop holding a card or still so glasses frames reach Teams again. */
MEETING_SHOW_LIVE = "miniapp_meeting_show_live",
/**
* Direct link only: card, full-size glasses photo, still, and live again, all run by the host
* without stopping the glasses publisher. Resolves after the still has been held `durationMs`.
*/
MEETING_CAPTURE_STILL = "miniapp_meeting_capture_still",
}
// ============================================================================
// Phone → miniapp (response or push)
// ============================================================================
export enum MiniappResponseType {
/** Response to CONNECT carrying userId, packageName, capabilities. */
CONNECT_ACK = "miniapp_connect_ack",
/** Push: a streamed event for a subscribed stream. */
EVENT = "miniapp_event",
/** Response to any request that needs a result (matched by requestId). */
REQUEST_RESULT = "miniapp_request_result",
/** Push: glasses capabilities changed. */
CAPABILITIES_UPDATE = "miniapp_capabilities_update",
/** Push: miniapp's foreground/background state changed. */
VISIBILITY_CHANGE = "miniapp_visibility_change",
/** Push: host color scheme (light/dark) changed. */
COLOR_SCHEME_CHANGE = "miniapp_color_scheme_change",
/** Push: a Store installation moved to another host-side phase. */
MINIAPPS_INSTALL_PROGRESS = "miniapp_apps_install_progress",
/**
* Push: speaker playback state transitioned. Per-miniapp; the runtime sends
* to the owning miniapp only. Carries {state, errorCode?, errorMessage?,
* durationMs?}. See SpeakerModule.onStateChange().
*/
SPEAKER_STATE = "miniapp_speaker_state",
/**
* Push: manifest-declared permissions changed (e.g. dev miniapp re-scanned
* with updated manifest). Carries a full PermissionRecord. SDK caches it
* and fires session.permissions.onUpdate handlers.
*/
PERMISSIONS_UPDATE = "miniapp_permissions_update",
/**
* Push: miniapp-scoped backend auth token changed. Carries a token minted for
* this packageName only; it is never a Core or runtime access token.
*/
AUTH_UPDATE = "miniapp_auth_update",
/** Reply to PING. SDK auto-handles this; developers never see it. */
PONG = "miniapp_pong",
/**
* Host → target: deliver an action call (from another miniapp's
* session.actions.invoke) to this miniapp's session.actions.handle handler.
* Carries {callId, actionId, params, callerPackageName}. The SDK runs the
* handler and replies with an ACTION_RESULT request keyed by callId.
*/
ACTION_CALL = "miniapp_action_call",
/**
* Push: native meeting state changed. Carries {state, muted?, error?}.
* See MeetingModule.onState().
*/
MEETING_STATE = "miniapp_meeting_state",
/**
* Push: a photo pause hit its ceiling and the publisher was started again.
* Carries {pauseId, status: "expired"}. A resume the miniapp sends itself is not this event.
*/
MEETING_VIDEO_PUBLISHER = "miniapp_meeting_video_publisher",
/**
* Push: progress of one `meeting.captureStill`. Carries {stillId, phase} with phase `card`
* (card on the tile), `uploading` (the glasses captured and are uploading), or `shown` (the
* still is on the tile). The request result still settles the call.
*/
MEETING_STILL = "miniapp_meeting_still",
/**
* Push: a preview lease changed state. Carries {handleId, state: "held" | "ended", reason?}.
* See PreviewHandle.onStatus().
*/
STREAM_PREVIEW_STATUS = "miniapp_stream_preview_status",
/**
* Push: phone is about to tear down the miniapp's session. Gives the SDK
* a brief window (~50ms grace on the phone side) to fire one last
* `sendOneShot` before the transport closes — used to flush final
* cleanup like `display.render([])`. Synchronous handlers only.
*/
WILL_DISCONNECT = "miniapp_will_disconnect",
/** Async error not tied to a specific request. */
ERROR = "miniapp_error",
}
// ============================================================================
// Stream types a miniapp can subscribe to
// ============================================================================
export enum MiniappStreamType {
// Hardware / input events
BUTTON_PRESS = "button_press",
TOUCH_EVENT = "touch_event",
HEAD_POSITION = "head_position",
/**
* Raw accelerometer reading from the glasses IMU — `{x, y, z}` in g, plus a
* timestamp. G2 only today. A richer combined IMU stream (accel + gyro +
* magnetometer) is future work; this is the single-sensor precursor.
*/
ACCEL_DATA = "accel_data",
// Status
GLASSES_BATTERY = "glasses_battery",
PHONE_BATTERY = "phone_battery",
GLASSES_CONNECTION = "glasses_connection",
/** Glasses Wi-Fi state (connected/ssid). Glasses with Wi-Fi only; needed for streaming. */
GLASSES_WIFI = "glasses_wifi",
// Speech / audio (cloud or local)
TRANSCRIPTION = "transcription", // language variant: "transcription:en-US"
TRANSLATION = "translation", // language variant: "translation:en-US"
AUDIO_CHUNK = "audio_chunk",
VAD = "vad",
// Phone sensors
LOCATION_UPDATE = "location_update",
/** Compass heading in degrees (0=N, 90=E). Android only. */
HEADING_UPDATE = "heading_update",
/** Turn-by-turn navigation event (maneuver / rerouting / arrived / error). */
NAVIGATION_UPDATE = "navigation_update",
/** Active navigation route polyline — full path, fired once per route build. */
NAVIGATION_ROUTE = "navigation_route",
PHONE_NOTIFICATION = "phone_notification",
/**
* A previously-posted notification was dismissed by the user.
*
* Android-only today. iOS does not expose dismiss callbacks to apps
* (Apple privacy restriction); subscribing on iOS succeeds but no events
* fire. See agents/miniapp-speaker-state-and-notif-dismissed-plan.md.
*/
PHONE_NOTIFICATION_DISMISSED = "phone_notification_dismissed",
// Photos, streaming
PHOTO_TAKEN = "photo_taken",
STREAM_STATUS = "stream_status",
}
// ============================================================================
// Error codes
// ============================================================================
export enum MiniappErrorCode {
/** Request arguments failed host-side validation. */
INVALID_ARGUMENT = "INVALID_ARGUMENT",
/** The miniapp subscribed to a stream whose required permission wasn't in its manifest. */
PERMISSION_NOT_DECLARED = "PERMISSION_NOT_DECLARED",
/** The required phone OS permission is not currently granted. */
PERMISSION_DENIED = "PERMISSION_DENIED",
/** Request routed to a method that isn't supported yet. */
NOT_IMPLEMENTED = "NOT_IMPLEMENTED",
/** Request timed out or the session was torn down before it could complete. */
REQUEST_ABORTED = "REQUEST_ABORTED",
/** Phone-side code path threw. Check `message`. */
INTERNAL = "INTERNAL",
/** Cloud TTS returned a non-2xx for a SPEAK request. */
TTS_TEXT_TOO_LONG = "TTS_TEXT_TOO_LONG",
TTS_INVALID_VOICE = "TTS_INVALID_VOICE",
TTS_UPSTREAM_ERROR = "TTS_UPSTREAM_ERROR",
/** `speak({forceLocal: true})` but the on-device offline TTS model isn't downloaded/ready. */
TTS_LOCAL_UNAVAILABLE = "TTS_LOCAL_UNAVAILABLE",
/** Not connected / pre-ACK and transport closed. */
NOT_CONNECTED = "NOT_CONNECTED",
/** A meeting join needs a microphone session the caller does not hold. */
MIC_SESSION_REQUIRED = "MIC_SESSION_REQUIRED",
/** A different microphone source is already live; only one can be pinned. */
MIC_SOURCE_CONFLICT = "MIC_SOURCE_CONFLICT",
// ----- Inter-miniapp interop -----
/**
* Caller is not a system app — SYSTEM-only APIs (interop list/start/stop/invoke,
* setWifiAdbState) reject with this code.
*/
NOT_PERMITTED = "NOT_PERMITTED",
/** Target miniapp is not installed. */
APP_NOT_FOUND = "APP_NOT_FOUND",
/** Target miniapp is incompatible with the connected glasses. */
APP_NOT_COMPATIBLE = "APP_NOT_COMPATIBLE",
/** Bundle download, validation, or activation failed. */
INSTALL_FAILED = "INSTALL_FAILED",
/** Another Store installation is already in progress for the same package. */
INSTALL_IN_PROGRESS = "INSTALL_IN_PROGRESS",
/** An automatic update was deferred because the target is running or starting. */
APP_RUNNING = "APP_RUNNING",
/** Another Store owns the installed package's update provenance. */
STORE_OWNERSHIP_CONFLICT = "STORE_OWNERSHIP_CONFLICT",
/** Target miniapp does not declare the requested action. */
ACTION_NOT_FOUND = "ACTION_NOT_FOUND",
/** Target connected but never registered a handler for the action (within the buffer window). */
NO_ACTION_HANDLER = "NO_ACTION_HANDLER",
/** Target failed to wake / complete its CONNECT handshake for an invoke. */
WAKE_FAILED = "WAKE_FAILED",
/** Action handler did not return within the caller's timeout. */
ACTION_TIMEOUT = "ACTION_TIMEOUT",
/** Action params or result exceeded the 256 KB size cap. */
PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE",
// ----- Blob storage / recorder -----
/** No blob with the given id in this miniapp's namespace. */
BLOB_NOT_FOUND = "BLOB_NOT_FOUND",
/** Writing this blob would exceed the per-app blob quota. */
BLOB_QUOTA_EXCEEDED = "BLOB_QUOTA_EXCEEDED",
/** Blob is larger than the requested in-memory read can hold. */
BLOB_TOO_LARGE = "BLOB_TOO_LARGE",
/** Write/read handle is unknown, already settled, or belongs to another app. */
BLOB_HANDLE_INVALID = "BLOB_HANDLE_INVALID",
/** Filesystem write failed (out of disk, permissions, etc.). */
BLOB_WRITE_FAILED = "BLOB_WRITE_FAILED",
/** `blob.setFromUrl` could not download the URL (network / non-2xx). */
BLOB_DOWNLOAD_FAILED = "BLOB_DOWNLOAD_FAILED",
/** `blob.importFile` failed (not the user cancelling — that resolves to null). */
BLOB_IMPORT_FAILED = "BLOB_IMPORT_FAILED",
}
// ============================================================================
// Stream preview
// ============================================================================
/**
* Where a raw preview comes from. `"call"` is the decoded video of the phone-native meeting the
* caller owns. `"glasses"` is reserved and currently rejects with `unsupported`.
*/
export type PreviewSource = "call" | "glasses"
/**
* Typed preview failures and non-terminal statuses, shared by the background handle, the UI
* component and the host. `waiting_for_lease` and `paused_background` are statuses, not errors.
*/
export type PreviewErrorCode =
| "permission_denied"
| "not_meeting_owner"
| "preview_busy"
| "waiting_for_lease"
| "source_ended"
| "unsupported"
| "ack_timeout"
| "transport_failed"
| "pack_failed"
| "paused_background"
| "diagnostics_disabled"
export const PREVIEW_ERROR_CODES: readonly PreviewErrorCode[] = [
"permission_denied",
"not_meeting_owner",
"preview_busy",
"waiting_for_lease",
"source_ended",
"unsupported",
"ack_timeout",
"transport_failed",
"pack_failed",
"paused_background",
"diagnostics_disabled",
]
export function isPreviewErrorCode(value: unknown): value is PreviewErrorCode {
return typeof value === "string" && (PREVIEW_ERROR_CODES as readonly string[]).includes(value)
}
/** Lease state pushed to the background with `STREAM_PREVIEW_STATUS`. */
export interface PreviewStatus {
handleId: string
state: "held" | "ended"
/** Why the lease ended: `stopped`, `source_ended`, `runtime_stopped`, ... */
reason?: string
}
/** The single reserved UI channel the host answers itself for preview control. */
export const PREVIEW_UI_CHANNEL = "_preview"