@mentra/sdk 2.1.31-beta.4 โ 2.1.31-beta.6
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 +69 -5
- package/dist/app/server/index.d.ts.map +1 -1
- package/dist/app/session/modules/camera.d.ts +5 -43
- package/dist/app/session/modules/camera.d.ts.map +1 -1
- package/dist/index.js +142 -101
- package/dist/index.js.map +7 -7
- package/dist/types/message-types.d.ts +5 -2
- package/dist/types/message-types.d.ts.map +1 -1
- package/dist/types/messages/cloud-to-glasses.d.ts +10 -3
- package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -1
- package/dist/types/messages/glasses-to-cloud.d.ts +20 -2
- package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,23 @@ import { type Express } from "express";
|
|
|
8
8
|
import { AppSession } from "../session/index";
|
|
9
9
|
import { ToolCall } from "../../types";
|
|
10
10
|
import { Logger } from "pino";
|
|
11
|
+
import { PhotoData } from "../../types/photo-data";
|
|
11
12
|
export declare const GIVE_APP_CONTROL_OF_TOOL_RESPONSE: string;
|
|
13
|
+
/**
|
|
14
|
+
* Pending photo request stored at AppServer level
|
|
15
|
+
* This allows O(1) lookup when photo uploads arrive via HTTP,
|
|
16
|
+
* and survives session reconnections.
|
|
17
|
+
* See: cloud/issues/019-sdk-photo-request-architecture
|
|
18
|
+
*/
|
|
19
|
+
export interface PendingPhotoRequest {
|
|
20
|
+
userId: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
session: AppSession;
|
|
23
|
+
resolve: (photo: PhotoData) => void;
|
|
24
|
+
reject: (error: Error) => void;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
timeoutId?: NodeJS.Timeout;
|
|
27
|
+
}
|
|
12
28
|
/**
|
|
13
29
|
* ๐ง Configuration options for App Server
|
|
14
30
|
*
|
|
@@ -90,6 +106,16 @@ export declare class AppServer {
|
|
|
90
106
|
private cleanupHandlers;
|
|
91
107
|
/** App instructions string shown to the user */
|
|
92
108
|
private appInstructions;
|
|
109
|
+
/**
|
|
110
|
+
* Pending photo requests by requestId - owned by AppServer for HTTP endpoint access.
|
|
111
|
+
* This is the single source of truth for pending photo requests.
|
|
112
|
+
* Stored here (not on CameraModule) because:
|
|
113
|
+
* 1. Photo uploads arrive via HTTP to AppServer, not via WebSocket to session
|
|
114
|
+
* 2. Allows O(1) lookup by requestId instead of iterating all sessions
|
|
115
|
+
* 3. Survives session reconnections (session may be removed from activeSessions temporarily)
|
|
116
|
+
* See: cloud/issues/019-sdk-photo-request-architecture
|
|
117
|
+
*/
|
|
118
|
+
private pendingPhotoRequests;
|
|
93
119
|
readonly logger: Logger;
|
|
94
120
|
constructor(config: AppServerConfig);
|
|
95
121
|
getExpressApp(): Express;
|
|
@@ -192,7 +218,18 @@ export declare class AppServer {
|
|
|
192
218
|
/**
|
|
193
219
|
* ๐งน Cleanup
|
|
194
220
|
* Closes all active sessions and runs cleanup handlers.
|
|
195
|
-
*
|
|
221
|
+
* Does NOT release ownership - we want the cloud to resurrect when we come back up.
|
|
222
|
+
*
|
|
223
|
+
* OWNERSHIP_RELEASE should only be sent for:
|
|
224
|
+
* - switching_clouds: User moved to another cloud, don't compete
|
|
225
|
+
* - user_logout: User explicitly logged out
|
|
226
|
+
*
|
|
227
|
+
* NOT for clean_shutdown, because:
|
|
228
|
+
* - Server is restarting/redeploying
|
|
229
|
+
* - Cloud should resurrect the app (trigger webhook)
|
|
230
|
+
* - User expects their app to keep running
|
|
231
|
+
*
|
|
232
|
+
* See: cloud/issues/023-disposed-appsession-resurrection-bug
|
|
196
233
|
*/
|
|
197
234
|
private cleanup;
|
|
198
235
|
/**
|
|
@@ -200,15 +237,42 @@ export declare class AppServer {
|
|
|
200
237
|
* Creates a /photo-upload endpoint for receiving photos directly from ASG glasses
|
|
201
238
|
*/
|
|
202
239
|
private setupPhotoUploadEndpoint;
|
|
240
|
+
/**
|
|
241
|
+
* Register a pending photo request.
|
|
242
|
+
* Called by CameraModule when a photo is requested.
|
|
243
|
+
* Stores the request at AppServer level for O(1) lookup when HTTP response arrives.
|
|
244
|
+
*
|
|
245
|
+
* @param requestId - Unique identifier for this photo request
|
|
246
|
+
* @param request - Request details including session, resolve/reject callbacks
|
|
247
|
+
*/
|
|
248
|
+
registerPhotoRequest(requestId: string, request: Omit<PendingPhotoRequest, "timeoutId">): void;
|
|
249
|
+
/**
|
|
250
|
+
* Get a pending photo request by ID.
|
|
251
|
+
*
|
|
252
|
+
* @param requestId - The request ID to look up
|
|
253
|
+
* @returns The pending request, or undefined if not found
|
|
254
|
+
*/
|
|
255
|
+
getPhotoRequest(requestId: string): PendingPhotoRequest | undefined;
|
|
256
|
+
/**
|
|
257
|
+
* Complete a photo request (success or error).
|
|
258
|
+
* Clears the timeout and removes from the pending map.
|
|
259
|
+
*
|
|
260
|
+
* @param requestId - The request ID to complete
|
|
261
|
+
* @returns The pending request that was completed, or undefined if not found
|
|
262
|
+
*/
|
|
263
|
+
completePhotoRequest(requestId: string): PendingPhotoRequest | undefined;
|
|
264
|
+
/**
|
|
265
|
+
* Clean up all pending photo requests for a session.
|
|
266
|
+
* Called when a session permanently disconnects.
|
|
267
|
+
*
|
|
268
|
+
* @param sessionId - The session ID to clean up requests for
|
|
269
|
+
*/
|
|
270
|
+
cleanupPhotoRequestsForSession(sessionId: string): void;
|
|
203
271
|
/**
|
|
204
272
|
* ๐ Setup Mentra Auth Redirect Endpoint
|
|
205
273
|
* Creates a /mentra-auth endpoint that redirects to the MentraOS OAuth flow.
|
|
206
274
|
*/
|
|
207
275
|
private setupMentraAuthRedirect;
|
|
208
|
-
/**
|
|
209
|
-
* Find session that has a pending photo request for the given requestId
|
|
210
|
-
*/
|
|
211
|
-
private findSessionByPhotoRequestId;
|
|
212
276
|
}
|
|
213
277
|
/**
|
|
214
278
|
* @deprecated Use `AppServerConfig` instead. `TpaServerConfig` is deprecated and will be removed in a future version.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/app/server/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/app/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -74,8 +74,6 @@ export declare class CameraModule {
|
|
|
74
74
|
private packageName;
|
|
75
75
|
private sessionId;
|
|
76
76
|
private logger;
|
|
77
|
-
/** Map to store pending photo request promises */
|
|
78
|
-
private pendingPhotoRequests;
|
|
79
77
|
private isStreaming;
|
|
80
78
|
private currentStreamUrl?;
|
|
81
79
|
private currentStreamState?;
|
|
@@ -108,63 +106,27 @@ export declare class CameraModule {
|
|
|
108
106
|
* ```
|
|
109
107
|
*/
|
|
110
108
|
requestPhoto(options?: PhotoRequestOptions): Promise<PhotoData>;
|
|
111
|
-
/**
|
|
112
|
-
* ๐ฅ Handle photo received from /photo-upload endpoint
|
|
113
|
-
*
|
|
114
|
-
* This method is called internally when a photo response is received.
|
|
115
|
-
* It resolves the corresponding pending promise with the photo data.
|
|
116
|
-
*
|
|
117
|
-
* @param photoData - The photo data received
|
|
118
|
-
* @internal This method is used internally by AppSession
|
|
119
|
-
*/
|
|
120
|
-
handlePhotoReceived(photoData: PhotoData): void;
|
|
121
|
-
/**
|
|
122
|
-
* โ Handle photo error from /photo-upload endpoint
|
|
123
|
-
*
|
|
124
|
-
* This method is called internally when a photo error response is received.
|
|
125
|
-
* It rejects the corresponding pending promise with the error information.
|
|
126
|
-
*
|
|
127
|
-
* @param errorResponse - The error response received
|
|
128
|
-
* @internal This method is used internally by AppSession
|
|
129
|
-
*/
|
|
130
|
-
handlePhotoError(errorResponse: {
|
|
131
|
-
requestId: string;
|
|
132
|
-
success: false;
|
|
133
|
-
error: {
|
|
134
|
-
code: string;
|
|
135
|
-
message: string;
|
|
136
|
-
};
|
|
137
|
-
}): void;
|
|
138
109
|
/**
|
|
139
110
|
* ๐ Check if there's a pending photo request for the given request ID
|
|
111
|
+
* @deprecated Photo requests are now managed at AppServer level. This method delegates to AppServer.
|
|
140
112
|
*
|
|
141
113
|
* @param requestId - The request ID to check
|
|
142
114
|
* @returns true if there's a pending request
|
|
143
115
|
*/
|
|
144
116
|
hasPhotoPendingRequest(requestId: string): boolean;
|
|
145
|
-
/**
|
|
146
|
-
* ๐ Get the number of pending photo requests
|
|
147
|
-
*
|
|
148
|
-
* @returns Number of pending photo requests
|
|
149
|
-
*/
|
|
150
|
-
getPhotoPendingRequestCount(): number;
|
|
151
|
-
/**
|
|
152
|
-
* ๐ Get all pending photo request IDs
|
|
153
|
-
*
|
|
154
|
-
* @returns Array of pending request IDs
|
|
155
|
-
*/
|
|
156
|
-
getPhotoPendingRequestIds(): string[];
|
|
157
117
|
/**
|
|
158
118
|
* โ Cancel a pending photo request
|
|
119
|
+
* @deprecated Photo requests are now managed at AppServer level. This method delegates to AppServer.
|
|
159
120
|
*
|
|
160
121
|
* @param requestId - The request ID to cancel
|
|
161
122
|
* @returns true if the request was cancelled, false if it wasn't found
|
|
162
123
|
*/
|
|
163
124
|
cancelPhotoRequest(requestId: string): boolean;
|
|
164
125
|
/**
|
|
165
|
-
* ๐งน Cancel all pending photo requests
|
|
126
|
+
* ๐งน Cancel all pending photo requests for this session
|
|
127
|
+
* @deprecated Photo requests are now managed at AppServer level. Use AppServer.cleanupPhotoRequestsForSession() instead.
|
|
166
128
|
*
|
|
167
|
-
* @returns Number of requests that were cancelled
|
|
129
|
+
* @returns Number of requests that were cancelled (always 0, cleanup happens at AppServer level)
|
|
168
130
|
*/
|
|
169
131
|
cancelAllPhotoRequests(): number;
|
|
170
132
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/camera.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,SAAS,EAIT,gBAAgB,EAEhB,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../../../../src/app/session/modules/camera.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -326,6 +326,8 @@ var init_message_types = __esm(() => {
|
|
|
326
326
|
GlassesToCloudMessageType2["AUDIO_PLAY_RESPONSE"] = "audio_play_response";
|
|
327
327
|
GlassesToCloudMessageType2["RGB_LED_CONTROL_RESPONSE"] = "rgb_led_control_response";
|
|
328
328
|
GlassesToCloudMessageType2["LIVEKIT_INIT"] = "livekit_init";
|
|
329
|
+
GlassesToCloudMessageType2["UDP_REGISTER"] = "udp_register";
|
|
330
|
+
GlassesToCloudMessageType2["UDP_UNREGISTER"] = "udp_unregister";
|
|
329
331
|
})(GlassesToCloudMessageType ||= {});
|
|
330
332
|
((CloudToGlassesMessageType2) => {
|
|
331
333
|
CloudToGlassesMessageType2["CONNECTION_ACK"] = "connection_ack";
|
|
@@ -349,6 +351,7 @@ var init_message_types = __esm(() => {
|
|
|
349
351
|
CloudToGlassesMessageType2["REQUEST_SINGLE_LOCATION"] = "request_single_location";
|
|
350
352
|
CloudToGlassesMessageType2["WEBSOCKET_ERROR"] = "websocket_error";
|
|
351
353
|
CloudToGlassesMessageType2["LIVEKIT_INFO"] = "livekit_info";
|
|
354
|
+
CloudToGlassesMessageType2["UDP_PING_ACK"] = "udp_ping_ack";
|
|
352
355
|
})(CloudToGlassesMessageType ||= {});
|
|
353
356
|
((AppToCloudMessageType2) => {
|
|
354
357
|
AppToCloudMessageType2["CONNECTION_INIT"] = "tpa_connection_init";
|
|
@@ -737,6 +740,12 @@ function isAudioPlayResponse(message) {
|
|
|
737
740
|
function isLocalTranscription(message) {
|
|
738
741
|
return message.type === "local_transcription" /* LOCAL_TRANSCRIPTION */;
|
|
739
742
|
}
|
|
743
|
+
function isUdpRegister(message) {
|
|
744
|
+
return message.type === "udp_register" /* UDP_REGISTER */;
|
|
745
|
+
}
|
|
746
|
+
function isUdpUnregister(message) {
|
|
747
|
+
return message.type === "udp_unregister" /* UDP_UNREGISTER */;
|
|
748
|
+
}
|
|
740
749
|
// src/types/messages/cloud-to-glasses.ts
|
|
741
750
|
init_message_types();
|
|
742
751
|
function isResponse(message) {
|
|
@@ -2646,7 +2655,6 @@ class CameraModule {
|
|
|
2646
2655
|
packageName;
|
|
2647
2656
|
sessionId;
|
|
2648
2657
|
logger;
|
|
2649
|
-
pendingPhotoRequests = new Map;
|
|
2650
2658
|
isStreaming = false;
|
|
2651
2659
|
currentStreamUrl;
|
|
2652
2660
|
currentStreamState;
|
|
@@ -2663,9 +2671,15 @@ class CameraModule {
|
|
|
2663
2671
|
const baseUrl = this.session?.getHttpsServerUrl?.() || "";
|
|
2664
2672
|
cameraWarnLog(baseUrl, this.packageName, "requestPhoto");
|
|
2665
2673
|
try {
|
|
2666
|
-
console.log("DEBUG: requestPhoto options:", options);
|
|
2667
2674
|
const requestId = `photo_req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
2668
|
-
this.
|
|
2675
|
+
this.session.appServer.registerPhotoRequest(requestId, {
|
|
2676
|
+
userId: this.session.userId,
|
|
2677
|
+
sessionId: this.sessionId,
|
|
2678
|
+
session: this.session,
|
|
2679
|
+
resolve,
|
|
2680
|
+
reject: (error) => reject(error.message),
|
|
2681
|
+
timestamp: Date.now()
|
|
2682
|
+
});
|
|
2669
2683
|
const message = {
|
|
2670
2684
|
type: "photo_request" /* PHOTO_REQUEST */,
|
|
2671
2685
|
packageName: this.packageName,
|
|
@@ -2687,91 +2701,41 @@ class CameraModule {
|
|
|
2687
2701
|
}, `\uD83D\uDCF8 Photo request sent`);
|
|
2688
2702
|
if (options?.customWebhookUrl) {
|
|
2689
2703
|
this.logger.info({ requestId, customWebhookUrl: options.customWebhookUrl }, `\uD83D\uDCF8 Using custom webhook URL - resolving promise immediately since photo will be uploaded directly to custom endpoint`);
|
|
2690
|
-
const
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2704
|
+
const pending = this.session.appServer.completePhotoRequest(requestId);
|
|
2705
|
+
if (pending) {
|
|
2706
|
+
const mockPhotoData = {
|
|
2707
|
+
buffer: Buffer.from([]),
|
|
2708
|
+
mimeType: "image/jpeg",
|
|
2709
|
+
filename: "photo.jpg",
|
|
2710
|
+
requestId,
|
|
2711
|
+
size: 0,
|
|
2712
|
+
timestamp: new Date
|
|
2713
|
+
};
|
|
2714
|
+
pending.resolve(mockPhotoData);
|
|
2715
|
+
}
|
|
2700
2716
|
return;
|
|
2701
2717
|
}
|
|
2702
|
-
const timeoutMs = 30000;
|
|
2703
|
-
if (this.session && this.session.resources) {
|
|
2704
|
-
this.session.resources.setTimeout(() => {
|
|
2705
|
-
if (this.pendingPhotoRequests.has(requestId)) {
|
|
2706
|
-
this.pendingPhotoRequests.get(requestId).reject("Photo request timed out");
|
|
2707
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
2708
|
-
this.logger.warn({ requestId }, `\uD83D\uDCF8 Photo request timed out`);
|
|
2709
|
-
}
|
|
2710
|
-
}, timeoutMs);
|
|
2711
|
-
} else {
|
|
2712
|
-
setTimeout(() => {
|
|
2713
|
-
if (this.pendingPhotoRequests.has(requestId)) {
|
|
2714
|
-
this.pendingPhotoRequests.get(requestId).reject("Photo request timed out");
|
|
2715
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
2716
|
-
this.logger.warn({ requestId }, `\uD83D\uDCF8 Photo request timed out`);
|
|
2717
|
-
}
|
|
2718
|
-
}, timeoutMs);
|
|
2719
|
-
}
|
|
2720
2718
|
} catch (error) {
|
|
2721
2719
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2722
2720
|
reject(`Failed to request photo: ${errorMessage}`);
|
|
2723
2721
|
}
|
|
2724
2722
|
});
|
|
2725
2723
|
}
|
|
2726
|
-
handlePhotoReceived(photoData) {
|
|
2727
|
-
const { requestId } = photoData;
|
|
2728
|
-
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
|
2729
|
-
if (pendingRequest) {
|
|
2730
|
-
this.logger.info({ requestId }, `\uD83D\uDCF8 Photo received for request ${requestId}`);
|
|
2731
|
-
pendingRequest.resolve(photoData);
|
|
2732
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
2733
|
-
} else {
|
|
2734
|
-
this.logger.warn({ requestId }, `\uD83D\uDCF8 Received photo for unknown request ID: ${requestId}`);
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
|
-
handlePhotoError(errorResponse) {
|
|
2738
|
-
const { requestId, error } = errorResponse;
|
|
2739
|
-
const pendingRequest = this.pendingPhotoRequests.get(requestId);
|
|
2740
|
-
if (pendingRequest) {
|
|
2741
|
-
this.logger.error({ requestId, errorCode: error.code, errorMessage: error.message }, `\uD83D\uDCF8 Photo capture failed: ${error.code} - ${error.message}`);
|
|
2742
|
-
pendingRequest.reject(`${error.code}: ${error.message}`);
|
|
2743
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
2744
|
-
} else {
|
|
2745
|
-
this.logger.warn({ requestId, errorCode: error.code, errorMessage: error.message }, `\uD83D\uDCF8 Received photo error for unknown request ID: ${requestId}`);
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
2724
|
hasPhotoPendingRequest(requestId) {
|
|
2749
|
-
return this.
|
|
2750
|
-
}
|
|
2751
|
-
getPhotoPendingRequestCount() {
|
|
2752
|
-
return this.pendingPhotoRequests.size;
|
|
2753
|
-
}
|
|
2754
|
-
getPhotoPendingRequestIds() {
|
|
2755
|
-
return Array.from(this.pendingPhotoRequests.keys());
|
|
2725
|
+
return this.session.appServer.getPhotoRequest(requestId) !== undefined;
|
|
2756
2726
|
}
|
|
2757
2727
|
cancelPhotoRequest(requestId) {
|
|
2758
|
-
const
|
|
2759
|
-
if (
|
|
2760
|
-
|
|
2761
|
-
this.pendingPhotoRequests.delete(requestId);
|
|
2728
|
+
const pending = this.session.appServer.completePhotoRequest(requestId);
|
|
2729
|
+
if (pending) {
|
|
2730
|
+
pending.reject(new Error("Photo request cancelled"));
|
|
2762
2731
|
this.logger.info({ requestId }, `\uD83D\uDCF8 Photo request cancelled`);
|
|
2763
2732
|
return true;
|
|
2764
2733
|
}
|
|
2765
2734
|
return false;
|
|
2766
2735
|
}
|
|
2767
2736
|
cancelAllPhotoRequests() {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
reject("Photo request cancelled - session cleanup");
|
|
2771
|
-
this.logger.info({ requestId }, `\uD83D\uDCF8 Photo request cancelled during cleanup`);
|
|
2772
|
-
}
|
|
2773
|
-
this.pendingPhotoRequests.clear();
|
|
2774
|
-
return count;
|
|
2737
|
+
this.logger.debug(`\uD83D\uDCF8 cancelAllPhotoRequests called - cleanup now happens at AppServer level`);
|
|
2738
|
+
return 0;
|
|
2775
2739
|
}
|
|
2776
2740
|
async startStream(options) {
|
|
2777
2741
|
this.logger.info({ rtmpUrl: options.rtmpUrl }, `\uD83D\uDCF9 RTMP stream request starting`);
|
|
@@ -5072,6 +5036,7 @@ class AppServer {
|
|
|
5072
5036
|
activeSessionsByUserId = new Map;
|
|
5073
5037
|
cleanupHandlers = [];
|
|
5074
5038
|
appInstructions = null;
|
|
5039
|
+
pendingPhotoRequests = new Map;
|
|
5075
5040
|
logger;
|
|
5076
5041
|
constructor(config) {
|
|
5077
5042
|
this.config = config;
|
|
@@ -5246,6 +5211,23 @@ class AppServer {
|
|
|
5246
5211
|
this.logger.info({ userId }, `\uD83D\uDDE3๏ธ Received session request for user ${userId}, session ${sessionId}
|
|
5247
5212
|
|
|
5248
5213
|
`);
|
|
5214
|
+
const existingSession = this.activeSessions.get(sessionId);
|
|
5215
|
+
if (existingSession) {
|
|
5216
|
+
this.logger.info({ sessionId, userId }, `\uD83D\uDD04 Existing session found for ${sessionId} - sending OWNERSHIP_RELEASE and disconnecting before new connection`);
|
|
5217
|
+
try {
|
|
5218
|
+
await existingSession.releaseOwnership("switching_clouds");
|
|
5219
|
+
} catch (error) {
|
|
5220
|
+
this.logger.warn({ error, sessionId }, `โ ๏ธ Failed to send OWNERSHIP_RELEASE to old session - continuing anyway`);
|
|
5221
|
+
}
|
|
5222
|
+
try {
|
|
5223
|
+
existingSession.disconnect();
|
|
5224
|
+
} catch (error) {
|
|
5225
|
+
this.logger.warn({ error, sessionId }, `โ ๏ธ Failed to disconnect old session - continuing anyway`);
|
|
5226
|
+
}
|
|
5227
|
+
this.activeSessions.delete(sessionId);
|
|
5228
|
+
this.activeSessionsByUserId.delete(userId);
|
|
5229
|
+
this.logger.info({ sessionId, userId }, `โ
Old session cleaned up, proceeding with new connection`);
|
|
5230
|
+
}
|
|
5249
5231
|
const session = new AppSession({
|
|
5250
5232
|
packageName: this.config.packageName,
|
|
5251
5233
|
apiKey: this.config.apiKey,
|
|
@@ -5254,25 +5236,48 @@ class AppServer {
|
|
|
5254
5236
|
userId
|
|
5255
5237
|
});
|
|
5256
5238
|
const cleanupDisconnect = session.events.onDisconnected((info) => {
|
|
5239
|
+
let isPermanent = false;
|
|
5240
|
+
let reason = "unknown";
|
|
5257
5241
|
if (typeof info === "string") {
|
|
5258
5242
|
this.logger.info(`\uD83D\uDC4B Session ${sessionId} disconnected: ${info}`);
|
|
5243
|
+
reason = info;
|
|
5244
|
+
isPermanent = false;
|
|
5259
5245
|
} else {
|
|
5260
5246
|
this.logger.info(`\uD83D\uDC4B Session ${sessionId} disconnected: ${info.message} (code: ${info.code}, reason: ${info.reason})`);
|
|
5247
|
+
reason = info.reason || info.message;
|
|
5261
5248
|
if (info.sessionEnded === true) {
|
|
5262
5249
|
this.logger.info(`\uD83D\uDED1 User session ended for session ${sessionId}, calling onStop`);
|
|
5250
|
+
isPermanent = true;
|
|
5263
5251
|
this.onStop(sessionId, userId, "User session ended").catch((error) => {
|
|
5264
5252
|
this.logger.error(error, `โ Error in onStop handler for session end:`);
|
|
5265
5253
|
});
|
|
5266
5254
|
} else if (info.permanent === true) {
|
|
5267
5255
|
this.logger.info(`\uD83D\uDED1 Permanent disconnection detected for session ${sessionId}, calling onStop`);
|
|
5268
|
-
|
|
5256
|
+
isPermanent = true;
|
|
5269
5257
|
this.onStop(sessionId, userId, `Connection permanently lost: ${info.reason}`).catch((error) => {
|
|
5270
5258
|
this.logger.error(error, `โ Error in onStop handler for permanent disconnection:`);
|
|
5271
5259
|
});
|
|
5260
|
+
} else if (info.wasClean === true || info.code === 1000 || info.code === 1001) {
|
|
5261
|
+
this.logger.info(`\uD83D\uDED1 Clean WebSocket closure for session ${sessionId} (code: ${info.code}), treating as permanent`);
|
|
5262
|
+
isPermanent = true;
|
|
5263
|
+
this.onStop(sessionId, userId, `Clean disconnect: ${reason}`).catch((error) => {
|
|
5264
|
+
this.logger.error(error, `โ Error in onStop handler for clean disconnect:`);
|
|
5265
|
+
});
|
|
5272
5266
|
}
|
|
5273
5267
|
}
|
|
5274
|
-
|
|
5275
|
-
|
|
5268
|
+
if (isPermanent) {
|
|
5269
|
+
if (this.activeSessions.get(sessionId) === session) {
|
|
5270
|
+
this.activeSessions.delete(sessionId);
|
|
5271
|
+
} else {
|
|
5272
|
+
this.logger.debug({ sessionId }, `\uD83D\uDD04 Session ${sessionId} cleanup skipped - a newer session has taken over`);
|
|
5273
|
+
}
|
|
5274
|
+
if (this.activeSessionsByUserId.get(userId) === session) {
|
|
5275
|
+
this.activeSessionsByUserId.delete(userId);
|
|
5276
|
+
}
|
|
5277
|
+
this.cleanupPhotoRequestsForSession(sessionId);
|
|
5278
|
+
} else {
|
|
5279
|
+
this.logger.debug({ sessionId, reason }, `\uD83D\uDD04 Temporary disconnect for session ${sessionId}, keeping in maps for reconnection`);
|
|
5280
|
+
}
|
|
5276
5281
|
});
|
|
5277
5282
|
const cleanupError = session.events.onError((error) => {
|
|
5278
5283
|
this.logger.error(error, `โ [Session ${sessionId}] Error:`);
|
|
@@ -5376,12 +5381,12 @@ class AppServer {
|
|
|
5376
5381
|
process.on("SIGINT", () => this.stop());
|
|
5377
5382
|
}
|
|
5378
5383
|
async cleanup() {
|
|
5384
|
+
this.logger.info(`\uD83D\uDD27 [LOCAL SDK] cleanup() called - NOT sending OWNERSHIP_RELEASE`);
|
|
5379
5385
|
for (const [sessionId, session] of this.activeSessions) {
|
|
5380
|
-
this.logger.info(`\uD83D\uDC4B Closing session ${sessionId}
|
|
5386
|
+
this.logger.info(`\uD83D\uDC4B Closing session ${sessionId} (no ownership release - cloud will resurrect)`);
|
|
5381
5387
|
try {
|
|
5382
5388
|
await session.disconnect({
|
|
5383
|
-
releaseOwnership:
|
|
5384
|
-
reason: "clean_shutdown"
|
|
5389
|
+
releaseOwnership: false
|
|
5385
5390
|
});
|
|
5386
5391
|
} catch (error) {
|
|
5387
5392
|
this.logger.error(error, `Error during cleanup of session ${sessionId}`);
|
|
@@ -5413,7 +5418,6 @@ class AppServer {
|
|
|
5413
5418
|
try {
|
|
5414
5419
|
const { requestId, type, success, errorCode, errorMessage } = req.body;
|
|
5415
5420
|
const photoFile = req.file;
|
|
5416
|
-
console.log("Received photo response: ", req.body);
|
|
5417
5421
|
this.logger.info({ requestId, type, success, errorCode }, `\uD83D\uDCF8 Received photo response: ${requestId} (type: ${type})`);
|
|
5418
5422
|
if (!requestId) {
|
|
5419
5423
|
this.logger.error("No requestId in photo response");
|
|
@@ -5422,24 +5426,18 @@ class AppServer {
|
|
|
5422
5426
|
error: "No requestId provided"
|
|
5423
5427
|
});
|
|
5424
5428
|
}
|
|
5425
|
-
const
|
|
5426
|
-
if (!
|
|
5427
|
-
this.logger.warn({ requestId }, "No
|
|
5429
|
+
const pending = this.completePhotoRequest(requestId);
|
|
5430
|
+
if (!pending) {
|
|
5431
|
+
this.logger.warn({ requestId, pendingCount: this.pendingPhotoRequests.size }, "\uD83D\uDCF8 No pending request found for photo (may have timed out or session ended)");
|
|
5428
5432
|
return res.status(404).json({
|
|
5429
5433
|
success: false,
|
|
5430
|
-
error: "No
|
|
5434
|
+
error: "No pending request found for this photo (may have timed out or session ended)"
|
|
5431
5435
|
});
|
|
5432
5436
|
}
|
|
5433
5437
|
if (type === "photo_error" || success === false) {
|
|
5434
|
-
const
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
error: {
|
|
5438
|
-
code: errorCode || "UNKNOWN_ERROR",
|
|
5439
|
-
message: errorMessage || "Unknown error occurred"
|
|
5440
|
-
}
|
|
5441
|
-
};
|
|
5442
|
-
session.camera.handlePhotoError(errorResponse);
|
|
5438
|
+
const errorMsg = errorMessage || "Unknown error occurred";
|
|
5439
|
+
this.logger.info({ requestId, errorCode, errorMessage: errorMsg }, "\uD83D\uDCF8 Photo error received");
|
|
5440
|
+
pending.reject(new Error(`Photo capture failed: ${errorMsg} (code: ${errorCode || "UNKNOWN_ERROR"})`));
|
|
5443
5441
|
return res.json({
|
|
5444
5442
|
success: true,
|
|
5445
5443
|
requestId,
|
|
@@ -5448,6 +5446,7 @@ class AppServer {
|
|
|
5448
5446
|
}
|
|
5449
5447
|
if (!photoFile) {
|
|
5450
5448
|
this.logger.error({ requestId }, "No photo file in successful upload");
|
|
5449
|
+
pending.reject(new Error("No photo file provided for successful upload"));
|
|
5451
5450
|
return res.status(400).json({
|
|
5452
5451
|
success: false,
|
|
5453
5452
|
error: "No photo file provided for successful upload"
|
|
@@ -5461,7 +5460,8 @@ class AppServer {
|
|
|
5461
5460
|
size: photoFile.size,
|
|
5462
5461
|
timestamp: new Date
|
|
5463
5462
|
};
|
|
5464
|
-
|
|
5463
|
+
this.logger.info({ requestId, size: photoFile.size, mimeType: photoFile.mimetype }, "\uD83D\uDCF8 Photo received successfully, resolving promise");
|
|
5464
|
+
pending.resolve(photoData);
|
|
5465
5465
|
res.json({
|
|
5466
5466
|
success: true,
|
|
5467
5467
|
requestId,
|
|
@@ -5476,6 +5476,53 @@ class AppServer {
|
|
|
5476
5476
|
}
|
|
5477
5477
|
});
|
|
5478
5478
|
}
|
|
5479
|
+
registerPhotoRequest(requestId, request) {
|
|
5480
|
+
const timeoutMs = 30000;
|
|
5481
|
+
const timeoutId = setTimeout(() => {
|
|
5482
|
+
const pending = this.pendingPhotoRequests.get(requestId);
|
|
5483
|
+
if (pending) {
|
|
5484
|
+
pending.reject(new Error("Photo request timed out"));
|
|
5485
|
+
this.pendingPhotoRequests.delete(requestId);
|
|
5486
|
+
this.logger.warn({ requestId }, "\uD83D\uDCF8 Photo request timed out");
|
|
5487
|
+
}
|
|
5488
|
+
}, timeoutMs);
|
|
5489
|
+
this.pendingPhotoRequests.set(requestId, {
|
|
5490
|
+
...request,
|
|
5491
|
+
timeoutId
|
|
5492
|
+
});
|
|
5493
|
+
this.logger.debug({ requestId, userId: request.userId, sessionId: request.sessionId }, "\uD83D\uDCF8 Photo request registered at AppServer level");
|
|
5494
|
+
}
|
|
5495
|
+
getPhotoRequest(requestId) {
|
|
5496
|
+
return this.pendingPhotoRequests.get(requestId);
|
|
5497
|
+
}
|
|
5498
|
+
completePhotoRequest(requestId) {
|
|
5499
|
+
const pending = this.pendingPhotoRequests.get(requestId);
|
|
5500
|
+
if (pending) {
|
|
5501
|
+
if (pending.timeoutId) {
|
|
5502
|
+
clearTimeout(pending.timeoutId);
|
|
5503
|
+
}
|
|
5504
|
+
this.pendingPhotoRequests.delete(requestId);
|
|
5505
|
+
this.logger.debug({ requestId }, "\uD83D\uDCF8 Photo request completed");
|
|
5506
|
+
}
|
|
5507
|
+
return pending;
|
|
5508
|
+
}
|
|
5509
|
+
cleanupPhotoRequestsForSession(sessionId) {
|
|
5510
|
+
let cleanedCount = 0;
|
|
5511
|
+
for (const [requestId, pending] of this.pendingPhotoRequests) {
|
|
5512
|
+
if (pending.sessionId === sessionId) {
|
|
5513
|
+
if (pending.timeoutId) {
|
|
5514
|
+
clearTimeout(pending.timeoutId);
|
|
5515
|
+
}
|
|
5516
|
+
pending.reject(new Error("Session ended"));
|
|
5517
|
+
this.pendingPhotoRequests.delete(requestId);
|
|
5518
|
+
cleanedCount++;
|
|
5519
|
+
this.logger.debug({ requestId, sessionId }, "\uD83D\uDCF8 Photo request cleaned up (session ended)");
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
if (cleanedCount > 0) {
|
|
5523
|
+
this.logger.info({ sessionId, cleanedCount }, "\uD83D\uDCF8 Cleaned up photo requests for ended session");
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5479
5526
|
setupMentraAuthRedirect() {
|
|
5480
5527
|
this.app.get("/mentra-auth", (req, res) => {
|
|
5481
5528
|
const authUrl = `https://account.mentra.glass/auth?packagename=${encodeURIComponent(this.config.packageName)}`;
|
|
@@ -5483,14 +5530,6 @@ class AppServer {
|
|
|
5483
5530
|
res.redirect(302, authUrl);
|
|
5484
5531
|
});
|
|
5485
5532
|
}
|
|
5486
|
-
findSessionByPhotoRequestId(requestId) {
|
|
5487
|
-
for (const [_sessionId, session] of this.activeSessions) {
|
|
5488
|
-
if (session.camera.hasPhotoPendingRequest(requestId)) {
|
|
5489
|
-
return session;
|
|
5490
|
-
}
|
|
5491
|
-
}
|
|
5492
|
-
return;
|
|
5493
|
-
}
|
|
5494
5533
|
}
|
|
5495
5534
|
|
|
5496
5535
|
class TpaServer extends AppServer {
|
|
@@ -5511,6 +5550,8 @@ export {
|
|
|
5511
5550
|
isValidLanguageCode,
|
|
5512
5551
|
isVad,
|
|
5513
5552
|
isUpdate,
|
|
5553
|
+
isUdpUnregister,
|
|
5554
|
+
isUdpRegister,
|
|
5514
5555
|
isStreamStatusCheckResponse,
|
|
5515
5556
|
isStreamCategory,
|
|
5516
5557
|
isStopWebhookRequest,
|
|
@@ -5638,4 +5679,4 @@ export {
|
|
|
5638
5679
|
AnimationUtils
|
|
5639
5680
|
};
|
|
5640
5681
|
|
|
5641
|
-
//# debugId=
|
|
5682
|
+
//# debugId=82AABDD8D6AA68F464756E2164756E21
|