@mentra/engine 3.2.0-dev.259 → 3.2.0-dev.262
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/build/facades/displayMirror.js +1 -1
- package/build/facades/displayMirror.js.map +1 -1
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/AcsMeetingService.d.ts +25 -1
- package/build/services/AcsMeetingService.d.ts.map +1 -1
- package/build/services/AcsMeetingService.js +41 -3
- package/build/services/AcsMeetingService.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts +1 -1
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +0 -4
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +2 -7
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +39 -24
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +293 -123
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/MentraJSRouter.d.ts +5 -9
- package/build/services/MentraJSRouter.d.ts.map +1 -1
- package/build/services/MentraJSRouter.js +5 -9
- package/build/services/MentraJSRouter.js.map +1 -1
- package/build/services/MentraUIRouter.d.ts +9 -12
- package/build/services/MentraUIRouter.d.ts.map +1 -1
- package/build/services/MentraUIRouter.js +9 -12
- package/build/services/MentraUIRouter.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts +6 -9
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +6 -9
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/MiniappLiveness.d.ts +11 -0
- package/build/services/MiniappLiveness.d.ts.map +1 -1
- package/build/services/MiniappLiveness.js +11 -0
- package/build/services/MiniappLiveness.js.map +1 -1
- package/build/services/PhoneLocationService.d.ts +2 -2
- package/build/services/PhoneLocationService.d.ts.map +1 -1
- package/build/services/PhoneLocationService.js +5 -9
- package/build/services/PhoneLocationService.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts +14 -3
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +28 -6
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/SoftapCallTransport.d.ts +87 -7
- package/build/services/SoftapCallTransport.d.ts.map +1 -1
- package/build/services/SoftapCallTransport.js +229 -28
- package/build/services/SoftapCallTransport.js.map +1 -1
- package/build/services/slimStreamStatus.d.ts +4 -1
- package/build/services/slimStreamStatus.d.ts.map +1 -1
- package/build/services/slimStreamStatus.js +4 -1
- package/build/services/slimStreamStatus.js.map +1 -1
- package/build/stores/apps.js +2 -2
- package/build/stores/apps.js.map +1 -1
- package/build/utils/miniappGlobals.d.ts +3 -5
- package/build/utils/miniappGlobals.d.ts.map +1 -1
- package/build/utils/miniappGlobals.js +16 -16
- package/build/utils/miniappGlobals.js.map +1 -1
- package/package.json +8 -8
- package/src/facades/displayMirror.ts +1 -1
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/services/AcsMeetingService.ts +51 -3
- package/src/services/DisplayProcessor.ts +1 -1
- package/src/services/LocalDisplayManager.ts +2 -7
- package/src/services/LocalMiniappRuntime.ts +305 -133
- package/src/services/MentraJSRouter.ts +5 -9
- package/src/services/MentraUIRouter.ts +9 -12
- package/src/services/MiniappLauncher.ts +6 -9
- package/src/services/MiniappLiveness.ts +18 -0
- package/src/services/PhoneLocationService.ts +5 -9
- package/src/services/PhoneStreamCoordinator.ts +28 -7
- package/src/services/SoftapCallTransport.ts +274 -32
- package/src/services/slimStreamStatus.ts +4 -1
- package/src/stores/apps.ts +2 -2
- package/src/utils/miniappGlobals.ts +16 -16
|
@@ -50,14 +50,13 @@ interface BoundWebView {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* push a fresh authoritative snapshot.
|
|
53
|
+
* The host mounts at most one miniapp UI WebView at a time. Its background
|
|
54
|
+
* JSContext runs separately on the phone and can remain alive after UI closure.
|
|
55
|
+
* UI closure unbinds the WebView and sends UI_CLOSE; on iOS the host also exits
|
|
56
|
+
* the UI when `onContentProcessDidTerminate` reports a content-process exit.
|
|
57
|
+
* The host may re-announce UI_OPEN after app resume or background dev respawn
|
|
58
|
+
* so the background can push a fresh snapshot. This router has no WebView
|
|
59
|
+
* heartbeat timeout.
|
|
61
60
|
*/
|
|
62
61
|
|
|
63
62
|
export class MentraUIRouter {
|
|
@@ -85,9 +84,8 @@ export class MentraUIRouter {
|
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
/**
|
|
88
|
-
* Called when the
|
|
89
|
-
*
|
|
90
|
-
* so handlers can flush state, then drops the binding.
|
|
87
|
+
* Called when the host tears down the WebView. Drops the binding and
|
|
88
|
+
* sends UI_CLOSE to the background so handlers can flush state.
|
|
91
89
|
*/
|
|
92
90
|
unbindWebView(packageName: string): void {
|
|
93
91
|
if (!this.bindings.has(packageName)) return
|
|
@@ -123,7 +121,6 @@ export class MentraUIRouter {
|
|
|
123
121
|
* Recognised envelope types from the WebView shim:
|
|
124
122
|
* - {type: "ready"} → fire UI_OPEN
|
|
125
123
|
* - {type: "msg", seq, channel, payload} → fire UI_MESSAGE
|
|
126
|
-
* - {type: "heartbeat", seq} → silently ack
|
|
127
124
|
*/
|
|
128
125
|
routeFromWebView(packageName: string, rawJson: string): void {
|
|
129
126
|
let env: {
|
|
@@ -317,12 +317,9 @@ class MiniappLauncher {
|
|
|
317
317
|
/**
|
|
318
318
|
* Re-spawn local miniapps that were running when the app was last killed.
|
|
319
319
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
* the phone's own JS engine — a host-process kill tears down their JSContext
|
|
324
|
-
* and there is no server to resurrect them, so without this they silently
|
|
325
|
-
* stay stopped on the next launch even though the user left them running.
|
|
320
|
+
* Every miniapp runs as local JavaScript in the Mentra App on the phone.
|
|
321
|
+
* A host-process kill tears down its JSContext, so without this restoration
|
|
322
|
+
* it stays stopped on the next launch even though the user left it running.
|
|
326
323
|
*
|
|
327
324
|
* Each local miniapp persists its running flag to disk on start/stop
|
|
328
325
|
* (`saveLocalAppRunningState`, via the applet's `onStart`/`onStop`). We read
|
|
@@ -331,9 +328,9 @@ class MiniappLauncher {
|
|
|
331
328
|
* tray/switcher project it as running, exactly as a normal start would. The
|
|
332
329
|
* WebView, if any, re-attaches lazily when the user opens the app.
|
|
333
330
|
*
|
|
334
|
-
* Idempotent and best-effort: skips already-spawned contexts
|
|
335
|
-
* persisted flag
|
|
336
|
-
*
|
|
331
|
+
* Idempotent and best-effort: skips already-spawned contexts and clears the
|
|
332
|
+
* persisted running flag if ensureRunning fails (for example, bundle resolution,
|
|
333
|
+
* deployment policy, or context spawning) so it does not retry every boot.
|
|
337
334
|
* Not compatibility-gated: a previously-running background app shouldn't be
|
|
338
335
|
* dropped just because glasses are momentarily disconnected at boot — it
|
|
339
336
|
* resumes when they reconnect, same as mid-session.
|
|
@@ -3,6 +3,24 @@ export interface MiniappPingLivenessDecision {
|
|
|
3
3
|
unansweredPingRounds: number
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* SoftAP join can spend a minute in native `prepareAgent` before the glasses
|
|
8
|
+
* hotspot even turns on. The JS bundle stays alive but may miss pongs while
|
|
9
|
+
* ACS is on the native thread. Unregistering for missed pings in that window
|
|
10
|
+
* cancels the join and leaves the UI stuck on the hotspot row.
|
|
11
|
+
*/
|
|
12
|
+
export function shouldHoldMiniappPingLiveness(args: {
|
|
13
|
+
packageName: string
|
|
14
|
+
softapPackageName?: string | null
|
|
15
|
+
softapCancelled?: boolean
|
|
16
|
+
}): boolean {
|
|
17
|
+
return Boolean(
|
|
18
|
+
args.softapPackageName &&
|
|
19
|
+
args.softapPackageName === args.packageName &&
|
|
20
|
+
!args.softapCancelled,
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
6
24
|
/**
|
|
7
25
|
* Advance liveness by one scheduled ping round.
|
|
8
26
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Phone location service — engine-owned. Owns the background phone-GPS task: the
|
|
3
3
|
* accuracy-tier control (`setLocationTier`), the accuracy mapping, and the
|
|
4
|
-
* `expo-task-manager` background task that
|
|
5
|
-
* local miniapps (`location_update`). Cloud upload was V1 (removed).
|
|
4
|
+
* `expo-task-manager` background task that forwards the first fix in each batch
|
|
5
|
+
* to subscribed local miniapps (`location_update`). Cloud upload was V1 (removed).
|
|
6
6
|
*
|
|
7
7
|
* This used to be the host-injected `locationTier` runtime hook + a MantleManager
|
|
8
8
|
* `TaskManager.defineTask`. It's device/OS plumbing (no UI), so it moved into engine:
|
|
@@ -21,8 +21,7 @@ import localMiniappRuntime from "./LocalMiniappRuntime"
|
|
|
21
21
|
|
|
22
22
|
export const LOCATION_TASK_NAME = "handleLocationUpdates"
|
|
23
23
|
|
|
24
|
-
// Background location task —
|
|
25
|
-
// miniapps. (The v1 SocketComms leg was already removed/commented before the move.)
|
|
24
|
+
// Background location task — forwards the first fix from each non-empty batch.
|
|
26
25
|
TaskManager.defineTask<{locations?: Location.LocationObject[]}>(LOCATION_TASK_NAME, async ({data, error}) => {
|
|
27
26
|
if (error) {
|
|
28
27
|
// OS-level failure (permission revoked, GPS unavailable, …) — log it so
|
|
@@ -36,11 +35,8 @@ TaskManager.defineTask<{locations?: Location.LocationObject[]}>(LOCATION_TASK_NA
|
|
|
36
35
|
return
|
|
37
36
|
}
|
|
38
37
|
const first = locs[0]!
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// Local miniapps get the update directly (the cloud relay never reaches
|
|
42
|
-
// __phone__). The Cloud V1 upload that used to run here was removed with the
|
|
43
|
-
// V1 ripout (issue #3392); a V2 location channel is separate product work.
|
|
38
|
+
// Deliver directly to local miniapps. The Cloud V1 upload that used to run
|
|
39
|
+
// here was removed with the V1 ripout (issue #3392).
|
|
44
40
|
localMiniappRuntime.forwardEvent("location_update", {
|
|
45
41
|
lat: first.coords.latitude,
|
|
46
42
|
lng: first.coords.longitude,
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
*
|
|
24
24
|
* Important: this is the ONLY place that mints `streamId`s for phone-owned
|
|
25
25
|
* streams. We use a `phone-` prefix so they're trivially distinguishable from
|
|
26
|
-
* cloud-minted IDs in logs
|
|
27
|
-
* the legacy path.
|
|
26
|
+
* cloud-minted managed-stream resource IDs in logs.
|
|
28
27
|
*
|
|
29
28
|
* BLE link loss is a SUSPENDED state, not a failure:
|
|
30
29
|
* ASG owns the ten-second phone/controller liveness deadline. The coordinator
|
|
@@ -231,9 +230,12 @@ export class PhoneStreamCoordinator {
|
|
|
231
230
|
* A stream was torn down while the BLE link was down, so the glasses never
|
|
232
231
|
* got `stopStream`. Sent on the next reconnect (if no new stream has claimed
|
|
233
232
|
* the slot) so a publisher that outlived its input does not keep pushing
|
|
234
|
-
* until its own watchdog fires.
|
|
233
|
+
* until its own watchdog fires. `generation` belongs to the publisher that
|
|
234
|
+
* queued it; a later SoftAP media hop must not inherit this stop.
|
|
235
235
|
*/
|
|
236
|
-
private pendingBleStop: {streamId: string; hotspot?: boolean} | null = null
|
|
236
|
+
private pendingBleStop: {streamId: string; hotspot?: boolean; generation: number; discarded?: boolean} | null = null
|
|
237
|
+
/** Bumped each time an unmanaged/managed publisher claims the slot. */
|
|
238
|
+
private publisherGeneration = 0
|
|
237
239
|
/**
|
|
238
240
|
* Serializes state transitions (start, stop, teardown). Without it, a
|
|
239
241
|
* second `start*` racing with the first can pass the `this.current === null`
|
|
@@ -364,6 +366,7 @@ export class PhoneStreamCoordinator {
|
|
|
364
366
|
}
|
|
365
367
|
|
|
366
368
|
const streamId = this.mintId("u")
|
|
369
|
+
++this.publisherGeneration
|
|
367
370
|
const entry: UnmanagedEntry = {
|
|
368
371
|
kind: "unmanaged",
|
|
369
372
|
streamId,
|
|
@@ -462,6 +465,7 @@ export class PhoneStreamCoordinator {
|
|
|
462
465
|
// and joins instead of double-provisioning.
|
|
463
466
|
const provision = await provisionManagedStream(opts.restreamDestinations)
|
|
464
467
|
const streamId = this.mintId("m")
|
|
468
|
+
++this.publisherGeneration
|
|
465
469
|
let ingestUrl: string
|
|
466
470
|
try {
|
|
467
471
|
ingestUrl = pickIngestUrl(provision, opts.ingest)
|
|
@@ -514,7 +518,7 @@ export class PhoneStreamCoordinator {
|
|
|
514
518
|
},
|
|
515
519
|
() => this.linkSource.isConnected(),
|
|
516
520
|
() => {
|
|
517
|
-
this.pendingBleStop = {streamId, hotspot: true}
|
|
521
|
+
this.pendingBleStop = {streamId, hotspot: true, generation: this.publisherGeneration}
|
|
518
522
|
this.attachLink()
|
|
519
523
|
},
|
|
520
524
|
)
|
|
@@ -616,6 +620,22 @@ export class PhoneStreamCoordinator {
|
|
|
616
620
|
})
|
|
617
621
|
}
|
|
618
622
|
|
|
623
|
+
/**
|
|
624
|
+
* Drop a deferred BLE `stopStream` that belonged to a publisher that is gone.
|
|
625
|
+
*
|
|
626
|
+
* SoftAP recovery destroys generation N and rebuilds N+1. If failSuspended already
|
|
627
|
+
* tore the publisher down after `glassesGraceMs`, `stop()` is a no-op but a pending
|
|
628
|
+
* stop would still flush into the new hop on reconnect. Call this from SoftAP
|
|
629
|
+
* `stopPublishing` so the deferred command dies with its generation.
|
|
630
|
+
*/
|
|
631
|
+
discardPendingBleStop(): void {
|
|
632
|
+
const pending = this.pendingBleStop
|
|
633
|
+
if (!pending) return
|
|
634
|
+
pending.discarded = true
|
|
635
|
+
this.pendingBleStop = null
|
|
636
|
+
this.detachLinkIfIdle()
|
|
637
|
+
}
|
|
638
|
+
|
|
619
639
|
/**
|
|
620
640
|
* Called by MantleManager when a `stream_status` event arrives from glasses
|
|
621
641
|
* and the registry says it's phone-owned.
|
|
@@ -760,9 +780,10 @@ export class PhoneStreamCoordinator {
|
|
|
760
780
|
|
|
761
781
|
private async flushPendingBleStop(): Promise<void> {
|
|
762
782
|
const pending = this.pendingBleStop
|
|
763
|
-
if (!pending || this.current || !this.linkSource.isConnected()) return
|
|
783
|
+
if (!pending || pending.discarded || this.current || !this.linkSource.isConnected()) return
|
|
764
784
|
console.info("[STREAM] BLE link back; sending deferred stopStream", pending)
|
|
765
785
|
await BluetoothSdk.stopStream()
|
|
786
|
+
if (pending.discarded || this.pendingBleStop !== pending || this.current) return
|
|
766
787
|
if (pending.hotspot) {
|
|
767
788
|
const result = await BluetoothSdk.setHotspotState(false)
|
|
768
789
|
if (result.state !== "disabled") throw new Error("Deferred hotspot shutdown was not confirmed")
|
|
@@ -1010,7 +1031,7 @@ export class PhoneStreamCoordinator {
|
|
|
1010
1031
|
// lock for the native timeout). Defer it to the next reconnect instead.
|
|
1011
1032
|
const linkUp = this.linkSource.isConnected()
|
|
1012
1033
|
if (sendBleStop && !linkUp) {
|
|
1013
|
-
this.pendingBleStop = {streamId: entry.streamId, hotspot: entry.kind === "managed" && !!entry.relay}
|
|
1034
|
+
this.pendingBleStop = {streamId: entry.streamId, hotspot: entry.kind === "managed" && !!entry.relay, generation: this.publisherGeneration}
|
|
1014
1035
|
console.warn("[STREAM] BLE link down during teardown; stopStream deferred", {
|
|
1015
1036
|
streamId: entry.streamId,
|
|
1016
1037
|
reason,
|