@mentra/sdk 3.0.0-alpha.1 → 3.0.0-alpha.4
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/dist/app/server/index.d.ts +3 -12
- package/dist/app/server/index.d.ts.map +1 -1
- package/dist/display-utils.js +102 -102
- package/dist/display-utils.js.map +3 -3
- package/dist/index.js +163 -117
- package/dist/index.js.map +16 -16
- package/dist/internal/_SessionManager.d.ts.map +1 -1
- package/dist/session/MentraSession.d.ts.map +1 -1
- package/dist/session/internal/_V2CameraShim.d.ts +0 -1
- package/dist/session/internal/_V2CameraShim.d.ts.map +1 -1
- package/dist/session/internal/_V2EventManagerShim.d.ts +0 -1
- package/dist/session/internal/_V2EventManagerShim.d.ts.map +1 -1
- package/dist/session/internal/_V2SessionShim.d.ts +0 -4
- package/dist/session/internal/_V2SessionShim.d.ts.map +1 -1
- package/dist/session/managers/CameraManager.d.ts +0 -1
- package/dist/session/managers/CameraManager.d.ts.map +1 -1
- package/dist/session/managers/DeviceManager.d.ts +1 -17
- package/dist/session/managers/DeviceManager.d.ts.map +1 -1
- package/dist/session/managers/LedManager.d.ts +19 -4
- package/dist/session/managers/LedManager.d.ts.map +1 -1
- package/dist/session/managers/LocationManager.d.ts +41 -10
- package/dist/session/managers/LocationManager.d.ts.map +1 -1
- package/dist/session/managers/PermissionsManager.d.ts +43 -0
- package/dist/session/managers/PermissionsManager.d.ts.map +1 -1
- package/dist/session/managers/PhoneManager.d.ts +1 -57
- package/dist/session/managers/PhoneManager.d.ts.map +1 -1
- package/dist/session/managers/SpeakerManager.d.ts.map +1 -1
- package/dist/session.js +145 -87
- package/dist/session.js.map +10 -10
- package/node_modules/@mentra/types/src/applet.ts +55 -0
- package/node_modules/@mentra/types/src/capabilities/even-realities-g1.ts +63 -0
- package/node_modules/@mentra/types/src/capabilities/even-realities-g2.ts +70 -0
- package/node_modules/@mentra/types/src/capabilities/mentra-display.ts +63 -0
- package/node_modules/@mentra/types/src/capabilities/mentra-live.ts +103 -0
- package/node_modules/@mentra/types/src/capabilities/none.ts +76 -0
- package/node_modules/@mentra/types/src/capabilities/simulated-glasses.ts +76 -0
- package/node_modules/@mentra/types/src/capabilities/vuzix-z100.ts +60 -0
- package/node_modules/@mentra/types/src/cli.ts +169 -0
- package/node_modules/@mentra/types/src/device.ts +43 -0
- package/node_modules/@mentra/types/src/enums.ts +43 -0
- package/node_modules/@mentra/types/src/hardware.ts +179 -0
- package/node_modules/@mentra/types/src/index.ts +64 -0
- package/node_modules/@mentra/types/tsconfig.json +22 -0
- package/node_modules/@mentra/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -164,7 +164,7 @@ function tryCreateBetterStackTransport() {
|
|
|
164
164
|
}
|
|
165
165
|
function createLogger(config) {
|
|
166
166
|
const { pinoLevel, verbose } = resolveConfig(config);
|
|
167
|
-
const NODE_ENV = "
|
|
167
|
+
const NODE_ENV = "isaiah";
|
|
168
168
|
const PORTER_APP_NAME = process.env.PORTER_APP_NAME || "cloud-local";
|
|
169
169
|
const streams = [];
|
|
170
170
|
if (pinoLevel !== "silent") {
|
|
@@ -1613,21 +1613,6 @@ class CameraManager {
|
|
|
1613
1613
|
}
|
|
1614
1614
|
});
|
|
1615
1615
|
}
|
|
1616
|
-
onPhotoTaken(handler) {
|
|
1617
|
-
const streamKey = "photo_taken" /* PHOTO_TAKEN */;
|
|
1618
|
-
this.deps.addSubscription(streamKey);
|
|
1619
|
-
const routerCleanup = this.deps.router.on(streamKey, (_streamType, data) => {
|
|
1620
|
-
try {
|
|
1621
|
-
handler(normalisePhotoData(data));
|
|
1622
|
-
} catch (err) {
|
|
1623
|
-
this.deps.logger.error("[CameraManager] Error in onPhotoTaken handler:", err);
|
|
1624
|
-
}
|
|
1625
|
-
});
|
|
1626
|
-
return () => {
|
|
1627
|
-
routerCleanup();
|
|
1628
|
-
this.deps.removeSubscription(streamKey);
|
|
1629
|
-
};
|
|
1630
|
-
}
|
|
1631
1616
|
async startStream(options) {
|
|
1632
1617
|
const opts = options ?? {};
|
|
1633
1618
|
if (opts.direct) {
|
|
@@ -1734,7 +1719,13 @@ class CameraManager {
|
|
|
1734
1719
|
});
|
|
1735
1720
|
}
|
|
1736
1721
|
async startDirectStream(options) {
|
|
1737
|
-
return this._startDirectStream({
|
|
1722
|
+
return this._startDirectStream({
|
|
1723
|
+
direct: options.rtmpUrl,
|
|
1724
|
+
video: options.video,
|
|
1725
|
+
audio: options.audio,
|
|
1726
|
+
stream: options.stream,
|
|
1727
|
+
sound: options.sound
|
|
1728
|
+
});
|
|
1738
1729
|
}
|
|
1739
1730
|
async startManagedStream(options = {}) {
|
|
1740
1731
|
return this._startManagedStream({
|
|
@@ -1927,15 +1918,6 @@ class CameraManager {
|
|
|
1927
1918
|
this.isManagedStreaming = false;
|
|
1928
1919
|
}
|
|
1929
1920
|
}
|
|
1930
|
-
function normalisePhotoData(raw) {
|
|
1931
|
-
return {
|
|
1932
|
-
url: raw.photoUrl ?? raw.url ?? "",
|
|
1933
|
-
width: raw.width ?? 0,
|
|
1934
|
-
height: raw.height ?? 0,
|
|
1935
|
-
timestamp: raw.timestamp ? new Date(raw.timestamp).getTime() : Date.now(),
|
|
1936
|
-
savedToGallery: raw.savedToGallery ?? false
|
|
1937
|
-
};
|
|
1938
|
-
}
|
|
1939
1921
|
|
|
1940
1922
|
// src/session/managers/DashboardManager.ts
|
|
1941
1923
|
init_message_types();
|
|
@@ -2114,6 +2096,20 @@ class DeviceManager {
|
|
|
2114
2096
|
});
|
|
2115
2097
|
}
|
|
2116
2098
|
onTouchEvent(gestureOrHandler, handler) {
|
|
2099
|
+
if (Array.isArray(gestureOrHandler)) {
|
|
2100
|
+
const gestures = gestureOrHandler;
|
|
2101
|
+
const cleanups = [];
|
|
2102
|
+
for (const gesture2 of gestures) {
|
|
2103
|
+
const gestureStream2 = `${"touch_event" /* TOUCH_EVENT */}:${gesture2}`;
|
|
2104
|
+
cleanups.push(this.addStreamHandler(gestureStream2, (_st, data) => {
|
|
2105
|
+
handler(normaliseTouchEvent(data));
|
|
2106
|
+
}));
|
|
2107
|
+
}
|
|
2108
|
+
return () => {
|
|
2109
|
+
for (const fn of cleanups)
|
|
2110
|
+
fn();
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2117
2113
|
if (typeof gestureOrHandler === "function") {
|
|
2118
2114
|
return this.addStreamHandler("touch_event" /* TOUCH_EVENT */, (_st, data) => {
|
|
2119
2115
|
gestureOrHandler(normaliseTouchEvent(data));
|
|
@@ -2125,19 +2121,6 @@ class DeviceManager {
|
|
|
2125
2121
|
handler(normaliseTouchEvent(data));
|
|
2126
2122
|
});
|
|
2127
2123
|
}
|
|
2128
|
-
subscribeToGestures(gestures) {
|
|
2129
|
-
const cleanupFns = [];
|
|
2130
|
-
for (const gesture of gestures) {
|
|
2131
|
-
const gestureStream = `${"touch_event" /* TOUCH_EVENT */}:${gesture}`;
|
|
2132
|
-
const cleanup = this.addStreamHandler(gestureStream, () => {});
|
|
2133
|
-
cleanupFns.push(cleanup);
|
|
2134
|
-
}
|
|
2135
|
-
return () => {
|
|
2136
|
-
for (const fn of cleanupFns) {
|
|
2137
|
-
fn();
|
|
2138
|
-
}
|
|
2139
|
-
};
|
|
2140
|
-
}
|
|
2141
2124
|
onBatteryUpdate(handler) {
|
|
2142
2125
|
return this.addStreamHandler("glasses_battery_update" /* GLASSES_BATTERY_UPDATE */, (_st, data) => {
|
|
2143
2126
|
if (data.level !== undefined) {
|
|
@@ -2180,7 +2163,6 @@ class DeviceManager {
|
|
|
2180
2163
|
this.deps.logger.debug("DeviceManager: Received empty device_state_update");
|
|
2181
2164
|
return;
|
|
2182
2165
|
}
|
|
2183
|
-
this.deps.logger.debug("DeviceManager: Processing device state update");
|
|
2184
2166
|
if (state.connected !== undefined)
|
|
2185
2167
|
this._connected.setValue(state.connected);
|
|
2186
2168
|
if (state.modelName !== undefined)
|
|
@@ -2218,7 +2200,8 @@ class DeviceManager {
|
|
|
2218
2200
|
}
|
|
2219
2201
|
setCapabilities(caps) {
|
|
2220
2202
|
this.capabilities = caps;
|
|
2221
|
-
this.
|
|
2203
|
+
const model = this._modelName.value;
|
|
2204
|
+
this.deps.logger.info({ model: model ?? undefined, hasCamera: !!caps?.camera, hasMicrophone: !!caps?.microphone }, `Glasses capabilities ${caps ? "received" : "cleared"}${model ? ` (${model})` : ""}`);
|
|
2222
2205
|
for (const listener of this.capabilitiesListeners) {
|
|
2223
2206
|
try {
|
|
2224
2207
|
listener(caps);
|
|
@@ -2382,8 +2365,20 @@ class LedManager {
|
|
|
2382
2365
|
constructor(deps) {
|
|
2383
2366
|
this.deps = deps;
|
|
2384
2367
|
}
|
|
2385
|
-
setColor(color,
|
|
2368
|
+
setColor(color, durationOrOptions) {
|
|
2386
2369
|
const requestId = generateRequestId2();
|
|
2370
|
+
let ontime;
|
|
2371
|
+
let offtime;
|
|
2372
|
+
let count;
|
|
2373
|
+
if (typeof durationOrOptions === "object" && durationOrOptions !== null) {
|
|
2374
|
+
ontime = durationOrOptions.onTime;
|
|
2375
|
+
offtime = durationOrOptions.offTime;
|
|
2376
|
+
count = durationOrOptions.count;
|
|
2377
|
+
} else {
|
|
2378
|
+
ontime = durationOrOptions ?? 1000;
|
|
2379
|
+
offtime = 0;
|
|
2380
|
+
count = 1;
|
|
2381
|
+
}
|
|
2387
2382
|
const message = {
|
|
2388
2383
|
type: "rgb_led_control" /* RGB_LED_CONTROL */,
|
|
2389
2384
|
packageName: this.deps.getPackageName(),
|
|
@@ -2392,12 +2387,12 @@ class LedManager {
|
|
|
2392
2387
|
timestamp: new Date,
|
|
2393
2388
|
action: "on",
|
|
2394
2389
|
color,
|
|
2395
|
-
ontime
|
|
2396
|
-
offtime
|
|
2397
|
-
count
|
|
2390
|
+
ontime,
|
|
2391
|
+
offtime,
|
|
2392
|
+
count
|
|
2398
2393
|
};
|
|
2399
2394
|
this.deps.sendMessage(message);
|
|
2400
|
-
this.deps.logger.debug({ requestId, color, ontime
|
|
2395
|
+
this.deps.logger.debug({ requestId, color, ontime, offtime, count }, "\uD83D\uDCA1 LED setColor request sent");
|
|
2401
2396
|
}
|
|
2402
2397
|
off() {
|
|
2403
2398
|
const requestId = generateRequestId2();
|
|
@@ -2421,6 +2416,7 @@ class LedManager {
|
|
|
2421
2416
|
init_types();
|
|
2422
2417
|
var LOCATION_STREAM = "location_stream" /* LOCATION_STREAM */;
|
|
2423
2418
|
var LOCATION_UPDATE = "location_update" /* LOCATION_UPDATE */;
|
|
2419
|
+
var POLL_TIMEOUT_MS = 15000;
|
|
2424
2420
|
function generateCorrelationId() {
|
|
2425
2421
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
2426
2422
|
return `poll_${crypto.randomUUID()}`;
|
|
@@ -2446,19 +2442,27 @@ class LocationManager {
|
|
|
2446
2442
|
_accuracy = null;
|
|
2447
2443
|
_timestamp = null;
|
|
2448
2444
|
_hasPermission = true;
|
|
2445
|
+
_config = {};
|
|
2446
|
+
pendingPolls = new Map;
|
|
2449
2447
|
locationUpdateCleanup = null;
|
|
2450
2448
|
constructor(deps) {
|
|
2451
2449
|
this.deps = deps;
|
|
2452
2450
|
this.locationUpdateCleanup = this.deps.router.on(LOCATION_UPDATE, (_streamType, data, _message) => {
|
|
2453
2451
|
this.cacheLocation(data);
|
|
2452
|
+
this.resolvePendingPoll(data);
|
|
2454
2453
|
});
|
|
2455
2454
|
}
|
|
2456
|
-
|
|
2455
|
+
configure(config) {
|
|
2456
|
+
this._config = { ...this._config, ...config };
|
|
2457
|
+
}
|
|
2458
|
+
onUpdate(handler) {
|
|
2457
2459
|
const streamKey = LOCATION_STREAM;
|
|
2460
|
+
const accuracy = this._config.accuracy ?? "standard";
|
|
2458
2461
|
const routerCleanup = this.deps.router.on(streamKey, (_streamType, data, _message) => {
|
|
2459
2462
|
try {
|
|
2460
2463
|
const location = normalise(data);
|
|
2461
2464
|
this.cacheLocation(data);
|
|
2465
|
+
this.resolvePendingPoll(data);
|
|
2462
2466
|
handler(location);
|
|
2463
2467
|
} catch (err) {
|
|
2464
2468
|
this.deps.logger.error("[LocationManager] Error in onUpdate handler:", err);
|
|
@@ -2468,6 +2472,7 @@ class LocationManager {
|
|
|
2468
2472
|
try {
|
|
2469
2473
|
const location = normalise(data);
|
|
2470
2474
|
this.cacheLocation(data);
|
|
2475
|
+
this.resolvePendingPoll(data);
|
|
2471
2476
|
handler(location);
|
|
2472
2477
|
} catch (err) {
|
|
2473
2478
|
this.deps.logger.error("[LocationManager] Error in onUpdate handler (location_update):", err);
|
|
@@ -2478,7 +2483,7 @@ class LocationManager {
|
|
|
2478
2483
|
this.streamRefCount++;
|
|
2479
2484
|
if (this.streamRefCount === 1) {
|
|
2480
2485
|
this.deps.addSubscription(streamKey);
|
|
2481
|
-
this.deps.logger.debug({ accuracy
|
|
2486
|
+
this.deps.logger.debug({ accuracy }, `[LocationManager] Subscribed to "${streamKey}".`);
|
|
2482
2487
|
}
|
|
2483
2488
|
return () => {
|
|
2484
2489
|
if (!this.registrations.has(reg))
|
|
@@ -2494,17 +2499,31 @@ class LocationManager {
|
|
|
2494
2499
|
}
|
|
2495
2500
|
};
|
|
2496
2501
|
}
|
|
2497
|
-
requestUpdate(
|
|
2502
|
+
requestUpdate() {
|
|
2498
2503
|
const correlationId = generateCorrelationId();
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2504
|
+
const accuracy = this._config.accuracy ?? "standard";
|
|
2505
|
+
return new Promise((resolve, reject) => {
|
|
2506
|
+
const timeoutId = setTimeout(() => {
|
|
2507
|
+
this.pendingPolls.delete(correlationId);
|
|
2508
|
+
reject(new Error(`Location poll timed out after ${POLL_TIMEOUT_MS}ms (correlationId: ${correlationId})`));
|
|
2509
|
+
}, POLL_TIMEOUT_MS);
|
|
2510
|
+
this.pendingPolls.set(correlationId, { resolve, reject, timeoutId });
|
|
2511
|
+
const message = {
|
|
2512
|
+
type: "location_poll_request" /* LOCATION_POLL_REQUEST */,
|
|
2513
|
+
correlationId,
|
|
2514
|
+
packageName: this.deps.getPackageName(),
|
|
2515
|
+
sessionId: this.deps.getSessionId(),
|
|
2516
|
+
accuracy
|
|
2517
|
+
};
|
|
2518
|
+
try {
|
|
2519
|
+
this.deps.sendMessage(message);
|
|
2520
|
+
this.deps.logger.debug({ correlationId, accuracy }, "\uD83D\uDCCD Location poll request sent");
|
|
2521
|
+
} catch (err) {
|
|
2522
|
+
clearTimeout(timeoutId);
|
|
2523
|
+
this.pendingPolls.delete(correlationId);
|
|
2524
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
2525
|
+
}
|
|
2526
|
+
});
|
|
2508
2527
|
}
|
|
2509
2528
|
stop() {
|
|
2510
2529
|
const snapshot = Array.from(this.registrations);
|
|
@@ -2517,6 +2536,11 @@ class LocationManager {
|
|
|
2517
2536
|
this.deps.removeSubscription(LOCATION_STREAM);
|
|
2518
2537
|
}
|
|
2519
2538
|
this.streamRefCount = 0;
|
|
2539
|
+
for (const [id, pending] of this.pendingPolls) {
|
|
2540
|
+
clearTimeout(pending.timeoutId);
|
|
2541
|
+
pending.reject(new Error("LocationManager stopped while poll was pending"));
|
|
2542
|
+
this.pendingPolls.delete(id);
|
|
2543
|
+
}
|
|
2520
2544
|
this.deps.logger.debug("[LocationManager] All subscriptions stopped.");
|
|
2521
2545
|
}
|
|
2522
2546
|
get lat() {
|
|
@@ -2534,6 +2558,17 @@ class LocationManager {
|
|
|
2534
2558
|
get hasPermission() {
|
|
2535
2559
|
return this._hasPermission;
|
|
2536
2560
|
}
|
|
2561
|
+
resolvePendingPoll(raw) {
|
|
2562
|
+
const correlationId = raw?.correlationId;
|
|
2563
|
+
if (!correlationId)
|
|
2564
|
+
return;
|
|
2565
|
+
const pending = this.pendingPolls.get(correlationId);
|
|
2566
|
+
if (!pending)
|
|
2567
|
+
return;
|
|
2568
|
+
clearTimeout(pending.timeoutId);
|
|
2569
|
+
this.pendingPolls.delete(correlationId);
|
|
2570
|
+
pending.resolve(normalise(raw));
|
|
2571
|
+
}
|
|
2537
2572
|
cacheLocation(raw) {
|
|
2538
2573
|
if (typeof raw.lat === "number") {
|
|
2539
2574
|
this._lat = raw.lat;
|
|
@@ -2559,6 +2594,7 @@ class LocationManager {
|
|
|
2559
2594
|
this._lng = null;
|
|
2560
2595
|
this._accuracy = null;
|
|
2561
2596
|
this._timestamp = null;
|
|
2597
|
+
this._config = {};
|
|
2562
2598
|
this.deps.logger.debug("[LocationManager] Destroyed.");
|
|
2563
2599
|
}
|
|
2564
2600
|
}
|
|
@@ -2708,8 +2744,10 @@ class PermissionsManager {
|
|
|
2708
2744
|
permissions;
|
|
2709
2745
|
listeners = new Set;
|
|
2710
2746
|
logger;
|
|
2747
|
+
messageHandlers;
|
|
2711
2748
|
constructor(deps) {
|
|
2712
2749
|
this.logger = deps.logger;
|
|
2750
|
+
this.messageHandlers = deps.messageHandlers;
|
|
2713
2751
|
this.permissions = createDefaultPermissions();
|
|
2714
2752
|
}
|
|
2715
2753
|
has(permission) {
|
|
@@ -2724,6 +2762,26 @@ class PermissionsManager {
|
|
|
2724
2762
|
this.listeners.delete(handler);
|
|
2725
2763
|
};
|
|
2726
2764
|
}
|
|
2765
|
+
onPermissionError(handler) {
|
|
2766
|
+
const cleanup = this.messageHandlers.register("permission_error", (msg) => {
|
|
2767
|
+
try {
|
|
2768
|
+
handler({ message: msg.message ?? "Permission error", deniedPermissions: msg.deniedPermissions });
|
|
2769
|
+
} catch (err) {
|
|
2770
|
+
this.logger.error("[PermissionsManager] Error in onPermissionError handler:", err);
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
return cleanup;
|
|
2774
|
+
}
|
|
2775
|
+
onPermissionDenied(handler) {
|
|
2776
|
+
const cleanup = this.messageHandlers.register("permission_denied", (msg) => {
|
|
2777
|
+
try {
|
|
2778
|
+
handler({ message: msg.message ?? "Permission denied", permission: msg.permission, streamType: msg.streamType });
|
|
2779
|
+
} catch (err) {
|
|
2780
|
+
this.logger.error("[PermissionsManager] Error in onPermissionDenied handler:", err);
|
|
2781
|
+
}
|
|
2782
|
+
});
|
|
2783
|
+
return cleanup;
|
|
2784
|
+
}
|
|
2727
2785
|
updateFromSettings(settings) {
|
|
2728
2786
|
if (!settings) {
|
|
2729
2787
|
this.logger.debug("PermissionsManager: No settings provided, skipping update");
|
|
@@ -2894,7 +2952,6 @@ class PhoneManager {
|
|
|
2894
2952
|
deps;
|
|
2895
2953
|
permissions;
|
|
2896
2954
|
tracker;
|
|
2897
|
-
_battery = null;
|
|
2898
2955
|
constructor(deps) {
|
|
2899
2956
|
this.deps = deps;
|
|
2900
2957
|
this.permissions = deps.permissions;
|
|
@@ -2902,29 +2959,8 @@ class PhoneManager {
|
|
|
2902
2959
|
this.notifications = new NotificationSubManager(this.permissions, this.tracker, deps.logger);
|
|
2903
2960
|
this.calendar = new CalendarSubManager(this.permissions, this.tracker, deps.logger);
|
|
2904
2961
|
}
|
|
2905
|
-
get battery() {
|
|
2906
|
-
return this._battery;
|
|
2907
|
-
}
|
|
2908
|
-
onBatteryUpdate(handler) {
|
|
2909
|
-
return this.tracker.add("phone_battery_update" /* PHONE_BATTERY_UPDATE */, (_streamType, data) => {
|
|
2910
|
-
const level = data.level ?? data.batteryLevel ?? data.battery_level;
|
|
2911
|
-
if (level !== undefined) {
|
|
2912
|
-
this._battery = level;
|
|
2913
|
-
}
|
|
2914
|
-
try {
|
|
2915
|
-
handler({
|
|
2916
|
-
level: level ?? 0,
|
|
2917
|
-
charging: data.charging ?? false,
|
|
2918
|
-
timeRemaining: data.timeRemaining ?? data.time_remaining
|
|
2919
|
-
});
|
|
2920
|
-
} catch (err) {
|
|
2921
|
-
this.deps.logger.error(`PhoneManager: Error in battery handler: ${err instanceof Error ? err.message : String(err)}`);
|
|
2922
|
-
}
|
|
2923
|
-
});
|
|
2924
|
-
}
|
|
2925
2962
|
destroy() {
|
|
2926
2963
|
this.tracker.destroyAll();
|
|
2927
|
-
this._battery = null;
|
|
2928
2964
|
this.deps.logger.debug("PhoneManager: Destroyed.");
|
|
2929
2965
|
}
|
|
2930
2966
|
}
|
|
@@ -2934,6 +2970,20 @@ init_message_types();
|
|
|
2934
2970
|
var STREAM_ID_LENGTH = 36;
|
|
2935
2971
|
var STREAM_READY_TIMEOUT_MS = 1e4;
|
|
2936
2972
|
var PLAY_RESPONSE_TIMEOUT_MS = 60000;
|
|
2973
|
+
function createMp3Encoder(channels, sampleRate, bitrate) {
|
|
2974
|
+
globalThis.MPEGMode ??= __require("lamejs/src/js/MPEGMode.js");
|
|
2975
|
+
globalThis.Lame ??= __require("lamejs/src/js/Lame.js");
|
|
2976
|
+
globalThis.BitStream ??= __require("lamejs/src/js/BitStream.js");
|
|
2977
|
+
const lamejs = __require("lamejs");
|
|
2978
|
+
const Encoder = lamejs.Mp3Encoder ?? lamejs.default?.Mp3Encoder;
|
|
2979
|
+
return new Encoder(channels, sampleRate, bitrate);
|
|
2980
|
+
}
|
|
2981
|
+
function toInt16Array(data) {
|
|
2982
|
+
if (data instanceof Int16Array)
|
|
2983
|
+
return data;
|
|
2984
|
+
const buffer = data instanceof ArrayBuffer ? data : data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
2985
|
+
return new Int16Array(buffer);
|
|
2986
|
+
}
|
|
2937
2987
|
|
|
2938
2988
|
class AudioOutputStreamImpl {
|
|
2939
2989
|
id;
|
|
@@ -2943,6 +2993,7 @@ class AudioOutputStreamImpl {
|
|
|
2943
2993
|
options;
|
|
2944
2994
|
stateChangeHandlers = [];
|
|
2945
2995
|
streamUrl = null;
|
|
2996
|
+
encoder = null;
|
|
2946
2997
|
constructor(streamId, deps, opts = {}) {
|
|
2947
2998
|
this.id = streamId;
|
|
2948
2999
|
this.deps = deps;
|
|
@@ -2964,6 +3015,9 @@ class AudioOutputStreamImpl {
|
|
|
2964
3015
|
if (this._state !== "created") {
|
|
2965
3016
|
throw new Error(`Cannot open stream in state "${this._state}"`);
|
|
2966
3017
|
}
|
|
3018
|
+
if (this.options.format === "pcm16") {
|
|
3019
|
+
this.encoder = createMp3Encoder(this.options.channels, this.options.sampleRate, this.options.bitrate);
|
|
3020
|
+
}
|
|
2967
3021
|
const startMessage = {
|
|
2968
3022
|
type: "audio_stream_start" /* AUDIO_STREAM_START */,
|
|
2969
3023
|
packageName: this.deps.getPackageName(),
|
|
@@ -2996,7 +3050,15 @@ class AudioOutputStreamImpl {
|
|
|
2996
3050
|
}
|
|
2997
3051
|
if (chunk.length === 0)
|
|
2998
3052
|
return;
|
|
2999
|
-
this.
|
|
3053
|
+
if (this.options.format === "pcm16" && this.encoder) {
|
|
3054
|
+
const pcm = toInt16Array(chunk);
|
|
3055
|
+
const encoded = this.encoder.encodeBuffer(pcm);
|
|
3056
|
+
if (encoded.length === 0)
|
|
3057
|
+
return;
|
|
3058
|
+
this.sendBinaryFrame(new Uint8Array(encoded));
|
|
3059
|
+
} else {
|
|
3060
|
+
this.sendBinaryFrame(chunk);
|
|
3061
|
+
}
|
|
3000
3062
|
}
|
|
3001
3063
|
async end() {
|
|
3002
3064
|
if (this._state !== "streaming")
|
|
@@ -4263,7 +4325,7 @@ class MentraSession {
|
|
|
4263
4325
|
this.logger.error(error, "MentraSession transport error");
|
|
4264
4326
|
}
|
|
4265
4327
|
});
|
|
4266
|
-
this.permissions = new PermissionsManager({ logger: sdkLogger });
|
|
4328
|
+
this.permissions = new PermissionsManager({ logger: sdkLogger, messageHandlers: this._router.messageHandlers });
|
|
4267
4329
|
const deps = {
|
|
4268
4330
|
router: this._router.dataStreamRouter,
|
|
4269
4331
|
messageHandlers: this._router.messageHandlers,
|
|
@@ -4382,10 +4444,6 @@ class MentraSession {
|
|
|
4382
4444
|
}));
|
|
4383
4445
|
this.cleanupTasks.push(this._router.messageHandlers.register("capabilities_update" /* CAPABILITIES_UPDATE */, (message) => {
|
|
4384
4446
|
this.capabilities = message.capabilities ?? null;
|
|
4385
|
-
this.device.handleCapabilitiesUpdate(message);
|
|
4386
|
-
}));
|
|
4387
|
-
this.cleanupTasks.push(this._router.messageHandlers.register("device_state_update" /* DEVICE_STATE_UPDATE */, (message) => {
|
|
4388
|
-
this.device.handleDeviceStateUpdate(message);
|
|
4389
4447
|
}));
|
|
4390
4448
|
this.cleanupTasks.push(this._router.messageHandlers.register("app_stopped" /* APP_STOPPED */, (message) => {
|
|
4391
4449
|
const reason = message.reason ?? "unknown";
|
|
@@ -6167,7 +6225,7 @@ class AudioOutputStream extends EventEmitter5 {
|
|
|
6167
6225
|
throw new Error(`Cannot open stream in state "${this._state}"`);
|
|
6168
6226
|
}
|
|
6169
6227
|
if (this.options.format === "pcm16") {
|
|
6170
|
-
this.encoder =
|
|
6228
|
+
this.encoder = createMp3Encoder2(this.options.channels, this.options.sampleRate, this.options.bitrate);
|
|
6171
6229
|
}
|
|
6172
6230
|
const startMessage = {
|
|
6173
6231
|
type: "audio_stream_start" /* AUDIO_STREAM_START */,
|
|
@@ -6201,7 +6259,7 @@ class AudioOutputStream extends EventEmitter5 {
|
|
|
6201
6259
|
}
|
|
6202
6260
|
let mp3Data;
|
|
6203
6261
|
if (this.options.format === "pcm16" && this.encoder) {
|
|
6204
|
-
const pcm =
|
|
6262
|
+
const pcm = toInt16Array2(data);
|
|
6205
6263
|
const encoded = this.encoder.encodeBuffer(pcm);
|
|
6206
6264
|
if (encoded.length === 0)
|
|
6207
6265
|
return;
|
|
@@ -6296,7 +6354,7 @@ class AudioOutputStream extends EventEmitter5 {
|
|
|
6296
6354
|
});
|
|
6297
6355
|
}
|
|
6298
6356
|
}
|
|
6299
|
-
function
|
|
6357
|
+
function createMp3Encoder2(channels, sampleRate, bitrate) {
|
|
6300
6358
|
globalThis.MPEGMode ??= __require("lamejs/src/js/MPEGMode.js");
|
|
6301
6359
|
globalThis.Lame ??= __require("lamejs/src/js/Lame.js");
|
|
6302
6360
|
globalThis.BitStream ??= __require("lamejs/src/js/BitStream.js");
|
|
@@ -6312,7 +6370,7 @@ function toUint8Array(data) {
|
|
|
6312
6370
|
const buf = data;
|
|
6313
6371
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
6314
6372
|
}
|
|
6315
|
-
function
|
|
6373
|
+
function toInt16Array2(data) {
|
|
6316
6374
|
if (data instanceof Int16Array)
|
|
6317
6375
|
return data;
|
|
6318
6376
|
const bytes = toUint8Array(data);
|
|
@@ -8445,7 +8503,7 @@ function createAuthMiddleware(options) {
|
|
|
8445
8503
|
if (signedUserToken) {
|
|
8446
8504
|
const userId = await verifySignedUserToken(signedUserToken);
|
|
8447
8505
|
if (userId) {
|
|
8448
|
-
console.
|
|
8506
|
+
console.debug("[auth.middleware] Authenticated via signed user token");
|
|
8449
8507
|
return setAuthAndContinue(userId);
|
|
8450
8508
|
} else {
|
|
8451
8509
|
console.log("[auth.middleware] Signed user token invalid");
|
|
@@ -8465,7 +8523,7 @@ function createAuthMiddleware(options) {
|
|
|
8465
8523
|
}
|
|
8466
8524
|
}
|
|
8467
8525
|
const { userId } = await exchangeToken(cloudApiUrl, tempToken, apiKey, packageName);
|
|
8468
|
-
console.
|
|
8526
|
+
console.debug("[auth.middleware] Authenticated via temporary token");
|
|
8469
8527
|
return setAuthAndContinue(userId);
|
|
8470
8528
|
} catch (error) {
|
|
8471
8529
|
console.error("Webview token exchange failed:", error);
|
|
@@ -8474,7 +8532,7 @@ function createAuthMiddleware(options) {
|
|
|
8474
8532
|
if (frontendToken) {
|
|
8475
8533
|
const userId = verifyFrontendToken(frontendToken, apiKey);
|
|
8476
8534
|
if (userId) {
|
|
8477
|
-
console.
|
|
8535
|
+
console.debug("[auth.middleware] Authenticated via frontend token");
|
|
8478
8536
|
return setAuthAndContinue(userId);
|
|
8479
8537
|
} else {
|
|
8480
8538
|
console.log("[auth.middleware] Frontend token invalid");
|
|
@@ -8615,15 +8673,11 @@ class AppServer extends Hono2 {
|
|
|
8615
8673
|
healthCheck: true,
|
|
8616
8674
|
...config
|
|
8617
8675
|
};
|
|
8618
|
-
if (config.verbose !== undefined) {
|
|
8619
|
-
process.env.MENTRA_VERBOSE = config.verbose ? "true" : "false";
|
|
8620
|
-
}
|
|
8621
8676
|
if (config.logLevel !== undefined) {
|
|
8622
8677
|
process.env.MENTRA_LOG_LEVEL = config.logLevel;
|
|
8623
8678
|
}
|
|
8624
8679
|
this.logger = createLogger({
|
|
8625
|
-
|
|
8626
|
-
logLevel: config.logLevel
|
|
8680
|
+
logLevel: config.logLevel ?? "warn"
|
|
8627
8681
|
}).child({
|
|
8628
8682
|
app: this.config.packageName,
|
|
8629
8683
|
packageName: this.config.packageName,
|
|
@@ -8919,8 +8973,11 @@ class AppServer extends Hono2 {
|
|
|
8919
8973
|
try {
|
|
8920
8974
|
await session.connect(sessionId);
|
|
8921
8975
|
this.setActiveSession(sessionId, userId, session);
|
|
8922
|
-
|
|
8923
|
-
|
|
8976
|
+
const response = c.json({ status: "success" });
|
|
8977
|
+
this.onSession(session, sessionId, userId).catch((error) => {
|
|
8978
|
+
this.logger.error({ error, sessionId, userId }, "Error in onSession handler");
|
|
8979
|
+
});
|
|
8980
|
+
return response;
|
|
8924
8981
|
} catch (error) {
|
|
8925
8982
|
this.logger.error(error, "Failed to connect session");
|
|
8926
8983
|
cleanupDisconnect();
|
|
@@ -9386,9 +9443,6 @@ class _V2CameraShim {
|
|
|
9386
9443
|
takePhoto(options) {
|
|
9387
9444
|
return this.session.camera.takePhoto(options);
|
|
9388
9445
|
}
|
|
9389
|
-
onPhotoTaken(handler) {
|
|
9390
|
-
return this.session.camera.onPhotoTaken(handler);
|
|
9391
|
-
}
|
|
9392
9446
|
async requestPhoto(options) {
|
|
9393
9447
|
const bridge = this.config.photoRequestBridge;
|
|
9394
9448
|
const userId = this.session.userId;
|
|
@@ -9508,9 +9562,6 @@ class _V2EventManagerShim {
|
|
|
9508
9562
|
onVpsCoordinates(handler) {
|
|
9509
9563
|
return this.session.device.onVpsCoordinates(handler);
|
|
9510
9564
|
}
|
|
9511
|
-
onPhotoTaken(handler) {
|
|
9512
|
-
return this.session.camera.onPhotoTaken(handler);
|
|
9513
|
-
}
|
|
9514
9565
|
onAudioChunk(handler) {
|
|
9515
9566
|
return this.session.mic.onChunk((chunk) => {
|
|
9516
9567
|
handler({
|
|
@@ -9563,8 +9614,6 @@ class _V2EventManagerShim {
|
|
|
9563
9614
|
return this.onPhoneNotificationDismissed(handler);
|
|
9564
9615
|
case "vps_coordinates":
|
|
9565
9616
|
return this.onVpsCoordinates(handler);
|
|
9566
|
-
case "photo_taken":
|
|
9567
|
-
return this.onPhotoTaken(handler);
|
|
9568
9617
|
default:
|
|
9569
9618
|
return () => {};
|
|
9570
9619
|
}
|
|
@@ -9736,9 +9785,6 @@ class _V2SessionShim {
|
|
|
9736
9785
|
on(event, handler) {
|
|
9737
9786
|
return this.events.on(event, handler);
|
|
9738
9787
|
}
|
|
9739
|
-
subscribeToGestures(gestures) {
|
|
9740
|
-
return this.session.device.subscribeToGestures(gestures);
|
|
9741
|
-
}
|
|
9742
9788
|
onGlassesConnectionState(handler) {
|
|
9743
9789
|
return this.session.device.state.connected.onChange((connected) => {
|
|
9744
9790
|
handler({
|
|
@@ -9778,9 +9824,6 @@ class _V2SessionShim {
|
|
|
9778
9824
|
onVpsCoordinates(handler) {
|
|
9779
9825
|
return this.events.onVpsCoordinates(handler);
|
|
9780
9826
|
}
|
|
9781
|
-
onPhotoTaken(handler) {
|
|
9782
|
-
return this.events.onPhotoTaken(handler);
|
|
9783
|
-
}
|
|
9784
9827
|
_subscriptionSettingsHandler;
|
|
9785
9828
|
_subscriptionUpdateTriggers = [];
|
|
9786
9829
|
setSubscriptionSettings(options) {
|
|
@@ -9927,8 +9970,11 @@ class _SessionManager {
|
|
|
9927
9970
|
this.deleteIfSameSession(request.sessionId, created.session);
|
|
9928
9971
|
throw error;
|
|
9929
9972
|
}
|
|
9930
|
-
|
|
9931
|
-
|
|
9973
|
+
const response = { status: "success" };
|
|
9974
|
+
this.invokeSessionHandler(created.compatSession, request.sessionId).catch((error) => {
|
|
9975
|
+
this.logger.error({ error, sessionId: request.sessionId }, "Error in onSession handler");
|
|
9976
|
+
});
|
|
9977
|
+
return response;
|
|
9932
9978
|
}
|
|
9933
9979
|
async handleStopRequest(request) {
|
|
9934
9980
|
this.stopSuppression.add(request.sessionId);
|
|
@@ -10274,4 +10320,4 @@ export {
|
|
|
10274
10320
|
AnimationUtils
|
|
10275
10321
|
};
|
|
10276
10322
|
|
|
10277
|
-
//# debugId=
|
|
10323
|
+
//# debugId=69C890D7C0BEBFE864756E2164756E21
|