@mentra/sdk 2.1.26 → 2.1.28

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 (97) hide show
  1. package/dist/app/session/api-client.d.ts.map +1 -1
  2. package/dist/app/session/dashboard.d.ts +5 -8
  3. package/dist/app/session/dashboard.d.ts.map +1 -1
  4. package/dist/app/session/events.d.ts +5 -2
  5. package/dist/app/session/events.d.ts.map +1 -1
  6. package/dist/app/session/index.d.ts +62 -3
  7. package/dist/app/session/index.d.ts.map +1 -1
  8. package/dist/app/session/modules/audio.d.ts +33 -4
  9. package/dist/app/session/modules/audio.d.ts.map +1 -1
  10. package/dist/app/session/modules/camera-managed-extension.d.ts +2 -3
  11. package/dist/app/session/modules/camera-managed-extension.d.ts.map +1 -1
  12. package/dist/app/session/modules/camera.d.ts +5 -5
  13. package/dist/app/session/modules/camera.d.ts.map +1 -1
  14. package/dist/app/session/modules/led.d.ts +141 -0
  15. package/dist/app/session/modules/led.d.ts.map +1 -0
  16. package/dist/app/session/modules/location.d.ts +1 -2
  17. package/dist/app/session/modules/location.d.ts.map +1 -1
  18. package/dist/app/session/modules/simple-storage.d.ts.map +1 -1
  19. package/dist/constants/log-messages/color.d.ts +5 -0
  20. package/dist/constants/log-messages/color.d.ts.map +1 -0
  21. package/dist/constants/log-messages/logos.d.ts +4 -0
  22. package/dist/constants/log-messages/logos.d.ts.map +1 -0
  23. package/dist/constants/{messages.d.ts → log-messages/updates.d.ts} +2 -3
  24. package/dist/constants/log-messages/updates.d.ts.map +1 -0
  25. package/dist/constants/log-messages/warning.d.ts +8 -0
  26. package/dist/constants/log-messages/warning.d.ts.map +1 -0
  27. package/dist/index.d.ts +7 -7
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5347 -112
  30. package/dist/index.js.map +45 -0
  31. package/dist/logging/logger.d.ts +2 -1
  32. package/dist/logging/logger.d.ts.map +1 -1
  33. package/dist/types/capabilities.d.ts +3 -0
  34. package/dist/types/capabilities.d.ts.map +1 -1
  35. package/dist/types/index.d.ts +4 -14
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/types/message-types.d.ts +12 -3
  38. package/dist/types/message-types.d.ts.map +1 -1
  39. package/dist/types/messages/app-to-cloud.d.ts +48 -2
  40. package/dist/types/messages/app-to-cloud.d.ts.map +1 -1
  41. package/dist/types/messages/cloud-to-app.d.ts +25 -6
  42. package/dist/types/messages/cloud-to-app.d.ts.map +1 -1
  43. package/dist/types/messages/cloud-to-glasses.d.ts +43 -1
  44. package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -1
  45. package/dist/types/messages/glasses-to-cloud.d.ts +32 -1
  46. package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
  47. package/dist/types/rtmp-stream.d.ts +1 -1
  48. package/dist/types/rtmp-stream.d.ts.map +1 -1
  49. package/dist/types/streams.d.ts +28 -1
  50. package/dist/types/streams.d.ts.map +1 -1
  51. package/dist/utils/permissions-utils.d.ts +8 -0
  52. package/dist/utils/permissions-utils.d.ts.map +1 -0
  53. package/package.json +12 -3
  54. package/dist/app/index.js +0 -24
  55. package/dist/app/server/index.js +0 -658
  56. package/dist/app/session/api-client.js +0 -101
  57. package/dist/app/session/dashboard.js +0 -149
  58. package/dist/app/session/events.js +0 -305
  59. package/dist/app/session/index.js +0 -1571
  60. package/dist/app/session/layouts.js +0 -372
  61. package/dist/app/session/modules/audio.js +0 -321
  62. package/dist/app/session/modules/camera-managed-extension.js +0 -310
  63. package/dist/app/session/modules/camera.js +0 -603
  64. package/dist/app/session/modules/index.js +0 -19
  65. package/dist/app/session/modules/location.js +0 -58
  66. package/dist/app/session/modules/simple-storage.js +0 -232
  67. package/dist/app/session/settings.js +0 -358
  68. package/dist/app/token/index.js +0 -22
  69. package/dist/app/token/utils.js +0 -144
  70. package/dist/app/webview/index.js +0 -382
  71. package/dist/constants/index.js +0 -16
  72. package/dist/constants/messages.d.ts.map +0 -1
  73. package/dist/constants/messages.js +0 -57
  74. package/dist/examples/managed-rtmp-streaming-example.js +0 -158
  75. package/dist/examples/managed-rtmp-streaming-with-restream-example.js +0 -124
  76. package/dist/examples/rtmp-streaming-example.js +0 -102
  77. package/dist/logging/logger.js +0 -79
  78. package/dist/types/capabilities.js +0 -9
  79. package/dist/types/dashboard/index.js +0 -12
  80. package/dist/types/enums.js +0 -75
  81. package/dist/types/index.js +0 -101
  82. package/dist/types/layouts.js +0 -3
  83. package/dist/types/message-types.js +0 -207
  84. package/dist/types/messages/app-to-cloud.js +0 -95
  85. package/dist/types/messages/base.js +0 -3
  86. package/dist/types/messages/cloud-to-app.js +0 -78
  87. package/dist/types/messages/cloud-to-glasses.js +0 -68
  88. package/dist/types/messages/glasses-to-cloud.js +0 -139
  89. package/dist/types/models.js +0 -101
  90. package/dist/types/photo-data.js +0 -2
  91. package/dist/types/rtmp-stream.js +0 -3
  92. package/dist/types/streams.js +0 -306
  93. package/dist/types/token.js +0 -7
  94. package/dist/types/webhooks.js +0 -28
  95. package/dist/utils/animation-utils.js +0 -340
  96. package/dist/utils/bitmap-utils.js +0 -475
  97. package/dist/utils/resource-tracker.js +0 -153
@@ -1,101 +0,0 @@
1
- "use strict";
2
- /**
3
- * 🔌 API Client Module
4
- *
5
- * Provides HTTP API access to MentraOS Cloud services.
6
- * Automatically uses the correct server URL derived from the WebSocket URL.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.ApiClient = void 0;
10
- exports.wsUrlToHttpUrl = wsUrlToHttpUrl;
11
- /**
12
- * Convert a WebSocket URL to a HTTP/HTTPS URL
13
- *
14
- * @param wsUrl WebSocket URL to convert
15
- * @returns HTTP URL equivalent
16
- */
17
- function wsUrlToHttpUrl(wsUrl) {
18
- if (!wsUrl)
19
- return undefined;
20
- try {
21
- // Parse the WebSocket URL
22
- const url = new URL(wsUrl);
23
- // Change protocol from ws/wss to http/https
24
- const protocol = url.protocol === 'wss:' ? 'https:' : 'http:';
25
- // Recreate the URL with the new protocol
26
- return `${protocol}//${url.host}`;
27
- }
28
- catch (error) {
29
- console.error('Error converting WebSocket URL to HTTP URL:', error);
30
- return undefined;
31
- }
32
- }
33
- /**
34
- * API client class for making HTTP requests to MentraOS Cloud
35
- */
36
- class ApiClient {
37
- /**
38
- * Create a new API client
39
- *
40
- * @param packageName App package name
41
- * @param wsUrl WebSocket URL (optional, can be set later)
42
- * @param userId User ID (optional, for authenticated requests)
43
- */
44
- constructor(packageName, wsUrl, userId) {
45
- this.packageName = packageName;
46
- this.userId = userId;
47
- if (wsUrl) {
48
- this.baseUrl = wsUrlToHttpUrl(wsUrl);
49
- }
50
- }
51
- /**
52
- * Set the WebSocket URL to derive the HTTP base URL
53
- *
54
- * @param wsUrl WebSocket URL
55
- */
56
- setWebSocketUrl(wsUrl) {
57
- this.baseUrl = wsUrlToHttpUrl(wsUrl);
58
- }
59
- /**
60
- * Set the user ID for authenticated requests
61
- *
62
- * @param userId User ID
63
- */
64
- setUserId(userId) {
65
- this.userId = userId;
66
- }
67
- /**
68
- * Fetch settings from MentraOS Cloud
69
- *
70
- * @returns Promise resolving to settings array
71
- * @throws Error if client is not configured correctly or if request fails
72
- */
73
- async fetchSettings() {
74
- if (!this.baseUrl) {
75
- throw new Error('API client is not configured with a base URL');
76
- }
77
- if (!this.userId) {
78
- throw new Error('User ID is required for fetching settings');
79
- }
80
- const url = `${this.baseUrl}/appsettings/user/${this.packageName}`;
81
- try {
82
- const response = await fetch(url, {
83
- method: 'GET',
84
- headers: {
85
- 'Authorization': `Bearer ${this.userId}`,
86
- 'Content-Type': 'application/json'
87
- }
88
- });
89
- if (!response.ok) {
90
- throw new Error(`Failed to fetch settings: ${response.status} ${response.statusText}`);
91
- }
92
- const data = await response.json();
93
- return data.settings || [];
94
- }
95
- catch (error) {
96
- console.error('Error fetching settings:', error);
97
- throw error;
98
- }
99
- }
100
- }
101
- exports.ApiClient = ApiClient;
@@ -1,149 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DashboardManager = exports.DashboardContentManager = exports.DashboardSystemManager = void 0;
7
- /**
8
- * Dashboard API Implementation
9
- *
10
- * Provides dashboard functionality for Apps, allowing them to write content
11
- * to the dashboard and respond to dashboard mode changes.
12
- */
13
- // import { systemApps } from '../../constants';
14
- const dashboard_1 = require("../../types/dashboard");
15
- const message_types_1 = require("../../types/message-types");
16
- const dotenv_1 = __importDefault(require("dotenv"));
17
- // Load environment variables from .env file
18
- dotenv_1.default.config();
19
- const SYSTEM_DASHBOARD_PACKAGE_NAME = process.env.SYSTEM_DASHBOARD_PACKAGE_NAME || "system.augmentos.dashboard";
20
- /**
21
- * Implementation of DashboardSystemAPI interface for system dashboard App
22
- */
23
- class DashboardSystemManager {
24
- constructor(session, packageName, send) {
25
- this.session = session;
26
- this.packageName = packageName;
27
- this.send = send;
28
- }
29
- setTopLeft(content) {
30
- this.updateSystemSection("topLeft", content);
31
- }
32
- setTopRight(content) {
33
- this.updateSystemSection("topRight", content);
34
- }
35
- setBottomLeft(content) {
36
- this.updateSystemSection("bottomLeft", content);
37
- }
38
- setBottomRight(content) {
39
- this.updateSystemSection("bottomRight", content);
40
- }
41
- setViewMode(mode) {
42
- const message = {
43
- type: message_types_1.AppToCloudMessageType.DASHBOARD_MODE_CHANGE,
44
- packageName: this.packageName,
45
- sessionId: `${this.session.getSessionId()}-${this.packageName}`,
46
- mode,
47
- timestamp: new Date(),
48
- };
49
- this.send(message);
50
- }
51
- updateSystemSection(section, content) {
52
- const message = {
53
- type: message_types_1.AppToCloudMessageType.DASHBOARD_SYSTEM_UPDATE,
54
- packageName: this.packageName,
55
- sessionId: `${this.session.getSessionId()}-${this.packageName}`,
56
- section,
57
- content,
58
- timestamp: new Date(),
59
- };
60
- this.send(message);
61
- }
62
- }
63
- exports.DashboardSystemManager = DashboardSystemManager;
64
- /**
65
- * Implementation of DashboardContentAPI interface for all Apps
66
- */
67
- class DashboardContentManager {
68
- // private alwaysOnEnabled: boolean = false;
69
- constructor(session, packageName, send, events) {
70
- this.session = session;
71
- this.packageName = packageName;
72
- this.send = send;
73
- this.events = events;
74
- this.currentMode = "none";
75
- }
76
- write(content, targets = [dashboard_1.DashboardMode.MAIN]) {
77
- const message = {
78
- type: message_types_1.AppToCloudMessageType.DASHBOARD_CONTENT_UPDATE,
79
- packageName: this.packageName,
80
- sessionId: `${this.session.getSessionId()}-${this.packageName}`,
81
- content,
82
- modes: targets,
83
- timestamp: new Date(),
84
- };
85
- this.send(message);
86
- }
87
- writeToMain(content) {
88
- this.write(content, [dashboard_1.DashboardMode.MAIN]);
89
- }
90
- writeToExpanded(content) {
91
- const message = {
92
- type: message_types_1.AppToCloudMessageType.DASHBOARD_CONTENT_UPDATE,
93
- packageName: this.packageName,
94
- sessionId: `${this.session.getSessionId()}-${this.packageName}`,
95
- content,
96
- modes: [dashboard_1.DashboardMode.EXPANDED],
97
- timestamp: new Date(),
98
- };
99
- this.send(message);
100
- }
101
- // writeToAlwaysOn(content: string): void {
102
- // this.write(content, [DashboardMode.ALWAYS_ON]);
103
- // }
104
- async getCurrentMode() {
105
- return this.currentMode;
106
- }
107
- // async isAlwaysOnEnabled(): Promise<boolean> {
108
- // return this.alwaysOnEnabled;
109
- // }
110
- onModeChange(callback) {
111
- return this.events.onDashboardModeChange((data) => {
112
- this.currentMode = data.mode;
113
- callback(data.mode);
114
- });
115
- }
116
- // onAlwaysOnChange(callback: (enabled: boolean) => void): () => void {
117
- // return this.events.onDashboardAlwaysOnChange((data) => {
118
- // this.alwaysOnEnabled = data.enabled;
119
- // callback(data.enabled);
120
- // });
121
- // }
122
- // Internal methods to update state
123
- setCurrentMode(mode) {
124
- this.currentMode = mode;
125
- this.events.emit("dashboard_mode_change", { mode });
126
- }
127
- }
128
- exports.DashboardContentManager = DashboardContentManager;
129
- /**
130
- * Dashboard Manager - Main class that manages dashboard functionality
131
- * Each AppSession instance gets its own DashboardManager instance
132
- */
133
- class DashboardManager {
134
- constructor(session, send) {
135
- const packageName = session.getPackageName();
136
- const events = session.events;
137
- // Create content API (available to all Apps)
138
- this.content = new DashboardContentManager(session, packageName, send, events);
139
- // Add system API if this is the system dashboard App
140
- if (packageName === SYSTEM_DASHBOARD_PACKAGE_NAME) {
141
- session.logger.info({ service: "SDK:DashboardManager" }, "Initializing system dashboard manager");
142
- this.system = new DashboardSystemManager(session, packageName, send);
143
- }
144
- else {
145
- session.logger.info({ service: "SDK:DashboardManager" }, `Not the system dashboard: ${packageName}`);
146
- }
147
- }
148
- }
149
- exports.DashboardManager = DashboardManager;
@@ -1,305 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.EventManager = void 0;
7
- /**
8
- * 🎮 Event Manager Module
9
- */
10
- const events_1 = __importDefault(require("events"));
11
- const types_1 = require("../../types");
12
- class EventManager {
13
- constructor(subscribe, unsubscribe) {
14
- this.subscribe = subscribe;
15
- this.unsubscribe = unsubscribe;
16
- this.emitter = new events_1.default();
17
- this.handlers = new Map();
18
- this.lastLanguageTranscriptioCleanupHandler = () => { };
19
- this.lastLanguageTranslationCleanupHandler = () => { };
20
- }
21
- // Convenience handlers for common event types
22
- onTranscription(handler) {
23
- // Default to en-US when using the generic transcription handler
24
- return this.addHandler((0, types_1.createTranscriptionStream)("en-US"), handler);
25
- }
26
- /**
27
- * 🎤 Listen for transcription events in a specific language
28
- * @param language - Language code (e.g., "en-US")
29
- * @param handler - Function to handle transcription data
30
- * @param disableLanguageIdentification - Optional flag to disable language identification (defaults to false/enabled)
31
- * @returns Cleanup function to remove the handler
32
- * @throws Error if language code is invalid
33
- */
34
- onTranscriptionForLanguage(language, handler, disableLanguageIdentification = false) {
35
- if (!(0, types_1.isValidLanguageCode)(language)) {
36
- throw new Error(`Invalid language code: ${language}`);
37
- }
38
- this.lastLanguageTranscriptioCleanupHandler();
39
- const streamType = (0, types_1.createTranscriptionStream)(language, {
40
- disableLanguageIdentification,
41
- });
42
- this.lastLanguageTranscriptioCleanupHandler = this.addHandler(streamType, handler);
43
- return this.lastLanguageTranscriptioCleanupHandler;
44
- }
45
- /**
46
- * 🌐 Listen for translation events for a specific language pair
47
- * @param sourceLanguage - Source language code (e.g., "es-ES")
48
- * @param targetLanguage - Target language code (e.g., "en-US")
49
- * @param handler - Function to handle translation data
50
- * @returns Cleanup function to remove the handler
51
- * @throws Error if language codes are invalid
52
- */
53
- ontranslationForLanguage(sourceLanguage, targetLanguage, handler) {
54
- if (!(0, types_1.isValidLanguageCode)(sourceLanguage)) {
55
- throw new Error(`Invalid source language code: ${sourceLanguage}`);
56
- }
57
- if (!(0, types_1.isValidLanguageCode)(targetLanguage)) {
58
- throw new Error(`Invalid target language code: ${targetLanguage}`);
59
- }
60
- this.lastLanguageTranslationCleanupHandler();
61
- const streamType = (0, types_1.createTranslationStream)(sourceLanguage, targetLanguage);
62
- this.lastLanguageTranslationCleanupHandler = this.addHandler(streamType, handler);
63
- return this.lastLanguageTranslationCleanupHandler;
64
- }
65
- onHeadPosition(handler) {
66
- return this.addHandler(types_1.StreamType.HEAD_POSITION, handler);
67
- }
68
- onButtonPress(handler) {
69
- return this.addHandler(types_1.StreamType.BUTTON_PRESS, handler);
70
- }
71
- onPhoneNotifications(handler) {
72
- return this.addHandler(types_1.StreamType.PHONE_NOTIFICATION, handler);
73
- }
74
- onPhoneNotificationDismissed(handler) {
75
- return this.addHandler(types_1.StreamType.PHONE_NOTIFICATION_DISMISSED, handler);
76
- }
77
- onGlassesBattery(handler) {
78
- return this.addHandler(types_1.StreamType.GLASSES_BATTERY_UPDATE, handler);
79
- }
80
- onPhoneBattery(handler) {
81
- return this.addHandler(types_1.StreamType.PHONE_BATTERY_UPDATE, handler);
82
- }
83
- onVoiceActivity(handler) {
84
- return this.addHandler(types_1.StreamType.VAD, handler);
85
- }
86
- onLocation(handler) {
87
- return this.addHandler(types_1.StreamType.LOCATION_UPDATE, handler);
88
- }
89
- onCalendarEvent(handler) {
90
- return this.addHandler(types_1.StreamType.CALENDAR_EVENT, handler);
91
- }
92
- /**
93
- * 🎤 Listen for audio chunk data
94
- * @param handler - Function to handle audio chunks
95
- * @returns Cleanup function to remove the handler
96
- */
97
- onAudioChunk(handler) {
98
- return this.addHandler(types_1.StreamType.AUDIO_CHUNK, handler);
99
- }
100
- // System event handlers
101
- onConnected(handler) {
102
- this.emitter.on("connected", handler);
103
- return () => this.emitter.off("connected", handler);
104
- }
105
- onDisconnected(handler) {
106
- this.emitter.on("disconnected", handler);
107
- return () => this.emitter.off("disconnected", handler);
108
- }
109
- onError(handler) {
110
- this.emitter.on("error", handler);
111
- return () => this.emitter.off("error", handler);
112
- }
113
- onSettingsUpdate(handler) {
114
- this.emitter.on("settings_update", handler);
115
- return () => this.emitter.off("settings_update", handler);
116
- }
117
- /**
118
- * 🔧 Listen for device capabilities updates
119
- * @param handler - Function to handle capabilities updates
120
- * @returns Cleanup function to remove the handler
121
- */
122
- onCapabilitiesUpdate(handler) {
123
- this.emitter.on("capabilities_update", handler);
124
- return () => this.emitter.off("capabilities_update", handler);
125
- }
126
- /**
127
- * 🌐 Listen for dashboard mode changes
128
- * @param handler - Function to handle dashboard mode changes
129
- * @returns Cleanup function to remove the handler
130
- */
131
- onDashboardModeChange(handler) {
132
- this.emitter.on("dashboard_mode_change", handler);
133
- return () => this.emitter.off("dashboard_mode_change", handler);
134
- }
135
- /**
136
- * 🌐 Listen for dashboard always-on mode changes
137
- * @param handler - Function to handle dashboard always-on mode changes
138
- * @returns Cleanup function to remove the handler
139
- */
140
- onDashboardAlwaysOnChange(handler) {
141
- this.emitter.on("dashboard_always_on_change", handler);
142
- return () => this.emitter.off("dashboard_always_on_change", handler);
143
- }
144
- /**
145
- * 🚫 Listen for permission errors when subscriptions are rejected
146
- * @param handler - Function to handle permission errors
147
- * @returns Cleanup function to remove the handler
148
- */
149
- onPermissionError(handler) {
150
- this.emitter.on("permission_error", handler);
151
- return () => this.emitter.off("permission_error", handler);
152
- }
153
- /**
154
- * 🚫 Listen for individual permission denied events for specific streams
155
- * @param handler - Function to handle permission denied events
156
- * @returns Cleanup function to remove the handler
157
- */
158
- onPermissionDenied(handler) {
159
- this.emitter.on("permission_denied", handler);
160
- return () => this.emitter.off("permission_denied", handler);
161
- }
162
- /**
163
- * 🔄 Listen for changes to a specific setting
164
- * @param key - Setting key to monitor
165
- * @param handler - Function to handle setting value changes
166
- * @returns Cleanup function to remove the handler
167
- */
168
- onSettingChange(key, handler) {
169
- let previousValue = undefined;
170
- const settingsHandler = (settings) => {
171
- try {
172
- const setting = settings.find((s) => s.key === key);
173
- if (setting) {
174
- // Only call handler if value has changed
175
- if (setting.value !== previousValue) {
176
- const newValue = setting.value;
177
- handler(newValue, previousValue);
178
- previousValue = newValue;
179
- }
180
- }
181
- }
182
- catch (error) {
183
- console.error(`Error in onSettingChange handler for key "${key}":`, error);
184
- }
185
- };
186
- this.emitter.on("settings_update", settingsHandler);
187
- this.emitter.on("connected", settingsHandler); // Also check when first connected
188
- return () => {
189
- this.emitter.off("settings_update", settingsHandler);
190
- this.emitter.off("connected", settingsHandler);
191
- };
192
- }
193
- /**
194
- * 🔄 Generic event handler
195
- *
196
- * Use this for stream types without specific handler methods
197
- */
198
- on(type, handler) {
199
- return this.addHandler(type, handler);
200
- }
201
- /**
202
- * ➕ Add an event handler and subscribe if needed
203
- */
204
- addHandler(type, handler) {
205
- const handlers = this.handlers.get(type) ?? new Set();
206
- if (handlers.size === 0) {
207
- this.handlers.set(type, handlers);
208
- this.subscribe(type);
209
- }
210
- handlers.add(handler);
211
- return () => this.removeHandler(type, handler);
212
- }
213
- /**
214
- * ➖ Remove an event handler
215
- */
216
- removeHandler(type, handler) {
217
- const handlers = this.handlers.get(type);
218
- if (!handlers)
219
- return;
220
- handlers.delete(handler);
221
- if (handlers.size === 0) {
222
- this.handlers.delete(type);
223
- this.unsubscribe(type);
224
- }
225
- }
226
- /**
227
- * 📡 Emit an event to all registered handlers with error isolation
228
- */
229
- emit(event, data) {
230
- try {
231
- // Emit to EventEmitter handlers (system events)
232
- // console.log(`#### Emitting to ${event}`);
233
- this.emitter.emit(event, data);
234
- // Emit to stream handlers if applicable
235
- const handlers = this.handlers.get(event);
236
- // console.log(`#### Handlers: ${JSON.stringify(handlers)}`);
237
- if (handlers) {
238
- // Create array of handlers to prevent modification during iteration
239
- const handlersArray = Array.from(handlers);
240
- // console.log(`((())) HandlersArray: ${JSON.stringify(handlersArray)}`);
241
- // Execute each handler in isolated try/catch to prevent one handler
242
- // from crashing the entire App
243
- handlersArray.forEach((handler) => {
244
- try {
245
- handler(data);
246
- }
247
- catch (handlerError) {
248
- // Log the error but don't let it propagate
249
- console.error(`Error in handler for event '${String(event)}':`, handlerError);
250
- // Emit an error event for tracking purposes
251
- if (event !== "error") {
252
- // Prevent infinite recursion
253
- const errorMessage = handlerError instanceof Error
254
- ? handlerError.message
255
- : String(handlerError);
256
- this.emitter.emit("error", new Error(`Handler error for event '${String(event)}': ${errorMessage}`));
257
- }
258
- }
259
- });
260
- }
261
- }
262
- catch (emitError) {
263
- // Catch any errors in the emission process itself
264
- console.error(`Fatal error emitting event '${String(event)}':`, emitError);
265
- // Try to emit an error event if we're not already handling an error
266
- if (event !== "error") {
267
- try {
268
- const errorMessage = emitError instanceof Error ? emitError.message : String(emitError);
269
- this.emitter.emit("error", new Error(`Event emission error for '${String(event)}': ${errorMessage}`));
270
- }
271
- catch (nestedError) {
272
- // If even this fails, just log it - nothing more we can do
273
- console.error("Failed to emit error event:", nestedError);
274
- }
275
- }
276
- }
277
- }
278
- /**
279
- * 📨 Listen for custom messages with a specific action
280
- * @param action - The action identifier to filter by
281
- * @param handler - Function to handle the message
282
- * @returns Cleanup function to remove the handler
283
- */
284
- onCustomMessage(action, handler) {
285
- const messageHandler = (message) => {
286
- if (message.action === action) {
287
- handler(message.payload);
288
- }
289
- };
290
- this.emitter.on("custom_message", messageHandler);
291
- return () => this.emitter.off("custom_message", messageHandler);
292
- }
293
- onVpsCoordinates(handler) {
294
- return this.addHandler(types_1.StreamType.VPS_COORDINATES, handler);
295
- }
296
- /**
297
- * 📸 Listen for photo responses
298
- * @param handler - Function to handle photo response data
299
- * @returns Cleanup function to remove the handler
300
- */
301
- onPhotoTaken(handler) {
302
- return this.addHandler(types_1.StreamType.PHOTO_TAKEN, handler);
303
- }
304
- }
305
- exports.EventManager = EventManager;