@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.
Files changed (45) hide show
  1. package/dist/app/server/index.d.ts +3 -12
  2. package/dist/app/server/index.d.ts.map +1 -1
  3. package/dist/display-utils.js +102 -102
  4. package/dist/display-utils.js.map +3 -3
  5. package/dist/index.js +163 -117
  6. package/dist/index.js.map +16 -16
  7. package/dist/internal/_SessionManager.d.ts.map +1 -1
  8. package/dist/session/MentraSession.d.ts.map +1 -1
  9. package/dist/session/internal/_V2CameraShim.d.ts +0 -1
  10. package/dist/session/internal/_V2CameraShim.d.ts.map +1 -1
  11. package/dist/session/internal/_V2EventManagerShim.d.ts +0 -1
  12. package/dist/session/internal/_V2EventManagerShim.d.ts.map +1 -1
  13. package/dist/session/internal/_V2SessionShim.d.ts +0 -4
  14. package/dist/session/internal/_V2SessionShim.d.ts.map +1 -1
  15. package/dist/session/managers/CameraManager.d.ts +0 -1
  16. package/dist/session/managers/CameraManager.d.ts.map +1 -1
  17. package/dist/session/managers/DeviceManager.d.ts +1 -17
  18. package/dist/session/managers/DeviceManager.d.ts.map +1 -1
  19. package/dist/session/managers/LedManager.d.ts +19 -4
  20. package/dist/session/managers/LedManager.d.ts.map +1 -1
  21. package/dist/session/managers/LocationManager.d.ts +41 -10
  22. package/dist/session/managers/LocationManager.d.ts.map +1 -1
  23. package/dist/session/managers/PermissionsManager.d.ts +43 -0
  24. package/dist/session/managers/PermissionsManager.d.ts.map +1 -1
  25. package/dist/session/managers/PhoneManager.d.ts +1 -57
  26. package/dist/session/managers/PhoneManager.d.ts.map +1 -1
  27. package/dist/session/managers/SpeakerManager.d.ts.map +1 -1
  28. package/dist/session.js +145 -87
  29. package/dist/session.js.map +10 -10
  30. package/node_modules/@mentra/types/src/applet.ts +55 -0
  31. package/node_modules/@mentra/types/src/capabilities/even-realities-g1.ts +63 -0
  32. package/node_modules/@mentra/types/src/capabilities/even-realities-g2.ts +70 -0
  33. package/node_modules/@mentra/types/src/capabilities/mentra-display.ts +63 -0
  34. package/node_modules/@mentra/types/src/capabilities/mentra-live.ts +103 -0
  35. package/node_modules/@mentra/types/src/capabilities/none.ts +76 -0
  36. package/node_modules/@mentra/types/src/capabilities/simulated-glasses.ts +76 -0
  37. package/node_modules/@mentra/types/src/capabilities/vuzix-z100.ts +60 -0
  38. package/node_modules/@mentra/types/src/cli.ts +169 -0
  39. package/node_modules/@mentra/types/src/device.ts +43 -0
  40. package/node_modules/@mentra/types/src/enums.ts +43 -0
  41. package/node_modules/@mentra/types/src/hardware.ts +179 -0
  42. package/node_modules/@mentra/types/src/index.ts +64 -0
  43. package/node_modules/@mentra/types/tsconfig.json +22 -0
  44. package/node_modules/@mentra/types/tsconfig.tsbuildinfo +1 -0
  45. 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 = "development";
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({ direct: options.rtmpUrl, video: options.video, audio: options.audio, stream: options.stream, sound: options.sound });
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.deps.logger.info(`DeviceManager: Capabilities ${caps ? "updated" : "cleared"}`);
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, onTimeMs) {
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: onTimeMs ?? 1000,
2396
- offtime: 0,
2397
- count: 1
2390
+ ontime,
2391
+ offtime,
2392
+ count
2398
2393
  };
2399
2394
  this.deps.sendMessage(message);
2400
- this.deps.logger.debug({ requestId, color, ontime: message.ontime }, "\uD83D\uDCA1 LED setColor request sent");
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
- onUpdate(handler, accuracy) {
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: accuracy ?? "standard" }, `[LocationManager] Subscribed to "${streamKey}".`);
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(accuracy) {
2502
+ requestUpdate() {
2498
2503
  const correlationId = generateCorrelationId();
2499
- const message = {
2500
- type: "location_poll_request" /* LOCATION_POLL_REQUEST */,
2501
- correlationId,
2502
- packageName: this.deps.getPackageName(),
2503
- sessionId: this.deps.getSessionId(),
2504
- accuracy: accuracy ?? "standard"
2505
- };
2506
- this.deps.sendMessage(message);
2507
- this.deps.logger.debug({ correlationId, accuracy: message.accuracy }, "\uD83D\uDCCD Location poll request sent");
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.sendBinaryFrame(chunk);
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 = createMp3Encoder(this.options.channels, this.options.sampleRate, this.options.bitrate);
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 = toInt16Array(data);
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 createMp3Encoder(channels, sampleRate, bitrate) {
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 toInt16Array(data) {
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.log("[auth.middleware] User ID verified from signed user token:", userId);
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.log("[auth.middleware] User ID verified from temporary token:", userId);
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.log("[auth.middleware] User ID verified from frontend user token:", userId);
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
- verbose: config.verbose,
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
- await this.onSession(session, sessionId, userId);
8923
- return c.json({ status: "success" });
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
- await this.invokeSessionHandler(created.compatSession, request.sessionId);
9931
- return { status: "success" };
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=11051307E83217F164756E2164756E21
10323
+ //# debugId=69C890D7C0BEBFE864756E2164756E21