async handleAppInit(ws: WebSocket, initMessage: AppConnectionInit): Promise<void> {
const { packageName, apiKey, sessionId } = initMessage;
// Validate API key
const isValidApiKey = await developerService.validateApiKey(
packageName,
apiKey,
this.userSession
);
if (!isValidApiKey) {
this.resolvePendingConnectionWithError(
packageName,
"AUTHENTICATION",
"Invalid API key"
);
ws.close(1008, "Invalid API key");
return;
}
// Check app is in loading state
if (!this.userSession.loadingApps.has(packageName) &&
!this.userSession.runningApps.has(packageName)) {
ws.close(1008, "App not started for this session");
return;
}
// Store WebSocket connection
this.userSession.appWebsockets.set(packageName, ws);
// Set up close handler
ws.on("close", (code, reason) => {
this.handleAppConnectionClosed(packageName, code, reason.toString());
});
// Set up heartbeat
this.setupAppHeartbeat(packageName, ws);
// Update state
this.setAppConnectionState(packageName, AppConnectionState.RUNNING);
this.userSession.runningApps.add(packageName);
this.userSession.loadingApps.delete(packageName);
// Send connection acknowledgment
const connectionAck = {
type: CloudToAppMessageType.CONNECTION_ACK,
sessionId: `${this.userSession.userId}-${packageName}`,
userId: this.userSession.userId,
capabilities: this.userSession.capabilities,
timestamp: new Date()
};
ws.send(JSON.stringify(connectionAck));
// Resolve pending connection
this.resolvePendingConnection(packageName);
}