@mentra/sdk 1.1.19
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/README.md +102 -0
- package/dist/constants/index.d.ts +14 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js +16 -0
- package/dist/examples/rtmp-streaming-example.d.ts +2 -0
- package/dist/examples/rtmp-streaming-example.d.ts.map +1 -0
- package/dist/examples/rtmp-streaming-example.js +102 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/logging/logger.d.ts +3 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +79 -0
- package/dist/tpa/index.d.ts +6 -0
- package/dist/tpa/index.d.ts.map +1 -0
- package/dist/tpa/index.js +24 -0
- package/dist/tpa/server/index.d.ts +193 -0
- package/dist/tpa/server/index.d.ts.map +1 -0
- package/dist/tpa/server/index.js +436 -0
- package/dist/tpa/session/api-client.d.ts +49 -0
- package/dist/tpa/session/api-client.d.ts.map +1 -0
- package/dist/tpa/session/api-client.js +101 -0
- package/dist/tpa/session/dashboard.d.ts +52 -0
- package/dist/tpa/session/dashboard.d.ts.map +1 -0
- package/dist/tpa/session/dashboard.js +149 -0
- package/dist/tpa/session/events.d.ts +178 -0
- package/dist/tpa/session/events.d.ts.map +1 -0
- package/dist/tpa/session/events.js +294 -0
- package/dist/tpa/session/index.d.ts +391 -0
- package/dist/tpa/session/index.d.ts.map +1 -0
- package/dist/tpa/session/index.js +1452 -0
- package/dist/tpa/session/layouts.d.ts +150 -0
- package/dist/tpa/session/layouts.d.ts.map +1 -0
- package/dist/tpa/session/layouts.js +282 -0
- package/dist/tpa/session/modules/streaming.d.ts +100 -0
- package/dist/tpa/session/modules/streaming.d.ts.map +1 -0
- package/dist/tpa/session/modules/streaming.js +270 -0
- package/dist/tpa/session/settings.d.ts +202 -0
- package/dist/tpa/session/settings.d.ts.map +1 -0
- package/dist/tpa/session/settings.js +361 -0
- package/dist/tpa/token/index.d.ts +7 -0
- package/dist/tpa/token/index.d.ts.map +1 -0
- package/dist/tpa/token/index.js +22 -0
- package/dist/tpa/token/utils.d.ts +69 -0
- package/dist/tpa/token/utils.d.ts.map +1 -0
- package/dist/tpa/token/utils.js +144 -0
- package/dist/tpa/webview/index.d.ts +47 -0
- package/dist/tpa/webview/index.d.ts.map +1 -0
- package/dist/tpa/webview/index.js +344 -0
- package/dist/types/dashboard/index.d.ts +128 -0
- package/dist/types/dashboard/index.d.ts.map +1 -0
- package/dist/types/dashboard/index.js +12 -0
- package/dist/types/enums.d.ts +57 -0
- package/dist/types/enums.d.ts.map +1 -0
- package/dist/types/enums.js +72 -0
- package/dist/types/index.d.ts +38 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +87 -0
- package/dist/types/layouts.d.ts +51 -0
- package/dist/types/layouts.d.ts.map +1 -0
- package/dist/types/layouts.js +3 -0
- package/dist/types/message-types.d.ts +109 -0
- package/dist/types/message-types.d.ts.map +1 -0
- package/dist/types/message-types.js +189 -0
- package/dist/types/messages/base.d.ts +12 -0
- package/dist/types/messages/base.d.ts.map +1 -0
- package/dist/types/messages/base.js +3 -0
- package/dist/types/messages/cloud-to-glasses.d.ts +126 -0
- package/dist/types/messages/cloud-to-glasses.d.ts.map +1 -0
- package/dist/types/messages/cloud-to-glasses.js +60 -0
- package/dist/types/messages/cloud-to-tpa.d.ts +228 -0
- package/dist/types/messages/cloud-to-tpa.d.ts.map +1 -0
- package/dist/types/messages/cloud-to-tpa.js +61 -0
- package/dist/types/messages/glasses-to-cloud.d.ts +219 -0
- package/dist/types/messages/glasses-to-cloud.d.ts.map +1 -0
- package/dist/types/messages/glasses-to-cloud.js +88 -0
- package/dist/types/messages/tpa-to-cloud.d.ts +146 -0
- package/dist/types/messages/tpa-to-cloud.d.ts.map +1 -0
- package/dist/types/messages/tpa-to-cloud.js +67 -0
- package/dist/types/models.d.ts +165 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/models.js +84 -0
- package/dist/types/rtmp-stream.d.ts +68 -0
- package/dist/types/rtmp-stream.d.ts.map +1 -0
- package/dist/types/rtmp-stream.js +3 -0
- package/dist/types/streams.d.ts +138 -0
- package/dist/types/streams.d.ts.map +1 -0
- package/dist/types/streams.js +251 -0
- package/dist/types/token.d.ts +41 -0
- package/dist/types/token.d.ts.map +1 -0
- package/dist/types/token.js +7 -0
- package/dist/types/user-session.d.ts +73 -0
- package/dist/types/user-session.d.ts.map +1 -0
- package/dist/types/user-session.js +17 -0
- package/dist/types/webhooks.d.ts +107 -0
- package/dist/types/webhooks.d.ts.map +1 -0
- package/dist/types/webhooks.js +55 -0
- package/dist/utils/resource-tracker.d.ts +94 -0
- package/dist/utils/resource-tracker.d.ts.map +1 -0
- package/dist/utils/resource-tracker.js +153 -0
- package/package.json +50 -0
@@ -0,0 +1,436 @@
|
|
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.TpaServer = void 0;
|
7
|
+
/**
|
8
|
+
* 🚀 TPA Server Module
|
9
|
+
*
|
10
|
+
* Creates and manages a server for Third Party Apps (TPAs) in the AugmentOS ecosystem.
|
11
|
+
* Handles webhook endpoints, session management, and cleanup.
|
12
|
+
*/
|
13
|
+
const express_1 = __importDefault(require("express"));
|
14
|
+
const path_1 = __importDefault(require("path"));
|
15
|
+
const session_1 = require("../session");
|
16
|
+
const webview_1 = require("../webview");
|
17
|
+
const types_1 = require("../../types");
|
18
|
+
const logger_1 = require("../../logging/logger");
|
19
|
+
/**
|
20
|
+
* 🎯 TPA Server Implementation
|
21
|
+
*
|
22
|
+
* Base class for creating TPA servers. Handles:
|
23
|
+
* - 🔄 Session lifecycle management
|
24
|
+
* - 📡 Webhook endpoints for AugmentOS Cloud
|
25
|
+
* - 📂 Static file serving
|
26
|
+
* - ❤️ Health checks
|
27
|
+
* - 🧹 Cleanup on shutdown
|
28
|
+
*
|
29
|
+
* @example
|
30
|
+
* ```typescript
|
31
|
+
* class MyAppServer extends TpaServer {
|
32
|
+
* protected async onSession(session: TpaSession, sessionId: string, userId: string) {
|
33
|
+
* // Handle new user sessions here
|
34
|
+
* session.events.onTranscription((data) => {
|
35
|
+
* session.layouts.showTextWall(data.text);
|
36
|
+
* });
|
37
|
+
* }
|
38
|
+
* }
|
39
|
+
*
|
40
|
+
* const server = new MyAppServer({
|
41
|
+
* packageName: 'org.example.myapp',
|
42
|
+
* apiKey: 'your_api_key',
|
43
|
+
* publicDir: "/public",
|
44
|
+
* });
|
45
|
+
*
|
46
|
+
* await server.start();
|
47
|
+
* ```
|
48
|
+
*/
|
49
|
+
class TpaServer {
|
50
|
+
constructor(config) {
|
51
|
+
this.config = config;
|
52
|
+
/** Map of active user sessions by sessionId */
|
53
|
+
this.activeSessions = new Map();
|
54
|
+
/** Array of cleanup handlers to run on shutdown */
|
55
|
+
this.cleanupHandlers = [];
|
56
|
+
/** TPA instructions string shown to the user */
|
57
|
+
this.tpaInstructions = null;
|
58
|
+
// Set defaults and merge with provided config
|
59
|
+
this.config = {
|
60
|
+
port: 7010,
|
61
|
+
webhookPath: '/webhook',
|
62
|
+
publicDir: false,
|
63
|
+
healthCheck: true,
|
64
|
+
...config
|
65
|
+
};
|
66
|
+
this.logger = logger_1.logger.child({ tpa: this.config.packageName, packageName: this.config.packageName, service: 'tpa-server' });
|
67
|
+
// Initialize Express app
|
68
|
+
this.app = (0, express_1.default)();
|
69
|
+
this.app.use(express_1.default.json());
|
70
|
+
const cookieParser = require('cookie-parser');
|
71
|
+
this.app.use(cookieParser(this.config.cookieSecret || `AOS_${this.config.packageName}_${this.config.apiKey.substring(0, 8)}`));
|
72
|
+
// Apply authentication middleware
|
73
|
+
this.app.use((0, webview_1.createAuthMiddleware)({
|
74
|
+
apiKey: this.config.apiKey,
|
75
|
+
packageName: this.config.packageName,
|
76
|
+
cookieSecret: this.config.cookieSecret || `AOS_${this.config.packageName}_${this.config.apiKey.substring(0, 8)}`
|
77
|
+
}));
|
78
|
+
this.tpaInstructions = config.tpaInstructions || null;
|
79
|
+
// Setup server features
|
80
|
+
this.setupWebhook();
|
81
|
+
this.setupSettingsEndpoint();
|
82
|
+
this.setupHealthCheck();
|
83
|
+
this.setupToolCallEndpoint();
|
84
|
+
this.setupPublicDir();
|
85
|
+
this.setupShutdown();
|
86
|
+
}
|
87
|
+
// Expose Express app for custom routes.
|
88
|
+
// This is useful for adding custom API routes or middleware.
|
89
|
+
getExpressApp() {
|
90
|
+
return this.app;
|
91
|
+
}
|
92
|
+
/**
|
93
|
+
* 👥 Session Handler
|
94
|
+
* Override this method to handle new TPA sessions.
|
95
|
+
* This is where you implement your app's core functionality.
|
96
|
+
*
|
97
|
+
* @param session - TPA session instance for the user
|
98
|
+
* @param sessionId - Unique identifier for this session
|
99
|
+
* @param userId - User's identifier
|
100
|
+
*/
|
101
|
+
async onSession(session, sessionId, userId) {
|
102
|
+
this.logger.info(`🚀 Starting new session handling for session ${sessionId} and user ${userId}`);
|
103
|
+
// Core session handling logic (onboarding removed)
|
104
|
+
this.logger.info(`✅ Session handling completed for session ${sessionId} and user ${userId}`);
|
105
|
+
}
|
106
|
+
/**
|
107
|
+
* 👥 Stop Handler
|
108
|
+
* Override this method to handle stop requests.
|
109
|
+
* This is where you can clean up resources when a session is stopped.
|
110
|
+
*
|
111
|
+
* @param sessionId - Unique identifier for this session
|
112
|
+
* @param userId - User's identifier
|
113
|
+
* @param reason - Reason for stopping
|
114
|
+
*/
|
115
|
+
async onStop(sessionId, userId, reason) {
|
116
|
+
this.logger.debug(`Session ${sessionId} stopped for user ${userId}. Reason: ${reason}`);
|
117
|
+
// Default implementation: close the session if it exists
|
118
|
+
const session = this.activeSessions.get(sessionId);
|
119
|
+
if (session) {
|
120
|
+
session.disconnect();
|
121
|
+
this.activeSessions.delete(sessionId);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
/**
|
125
|
+
* 🛠️ Tool Call Handler
|
126
|
+
* Override this method to handle tool calls from AugmentOS Cloud.
|
127
|
+
* This is where you implement your app's tool functionality.
|
128
|
+
*
|
129
|
+
* @param toolCall - The tool call request containing tool details and parameters
|
130
|
+
* @returns Optional string response that will be sent back to AugmentOS Cloud
|
131
|
+
*/
|
132
|
+
async onToolCall(toolCall) {
|
133
|
+
this.logger.debug(`Tool call received: ${toolCall.toolId}`);
|
134
|
+
this.logger.debug(`Parameters: ${JSON.stringify(toolCall.toolParameters)}`);
|
135
|
+
return undefined;
|
136
|
+
}
|
137
|
+
/**
|
138
|
+
* 🚀 Start the Server
|
139
|
+
* Starts listening for incoming connections and webhook calls.
|
140
|
+
*
|
141
|
+
* @returns Promise that resolves when server is ready
|
142
|
+
*/
|
143
|
+
start() {
|
144
|
+
return new Promise((resolve) => {
|
145
|
+
this.app.listen(this.config.port, () => {
|
146
|
+
this.logger.info(`🎯 TPA server running at http://localhost:${this.config.port}`);
|
147
|
+
if (this.config.publicDir) {
|
148
|
+
this.logger.info(`📂 Serving static files from ${this.config.publicDir}`);
|
149
|
+
}
|
150
|
+
resolve();
|
151
|
+
});
|
152
|
+
});
|
153
|
+
}
|
154
|
+
/**
|
155
|
+
* 🛑 Stop the Server
|
156
|
+
* Gracefully shuts down the server and cleans up all sessions.
|
157
|
+
*/
|
158
|
+
stop() {
|
159
|
+
this.logger.info('\n🛑 Shutting down...');
|
160
|
+
this.cleanup();
|
161
|
+
process.exit(0);
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* 🔐 Generate a TPA token for a user
|
165
|
+
* This should be called when handling a session webhook request.
|
166
|
+
*
|
167
|
+
* @param userId - User identifier
|
168
|
+
* @param sessionId - Session identifier
|
169
|
+
* @param secretKey - Secret key for signing the token
|
170
|
+
* @returns JWT token string
|
171
|
+
*/
|
172
|
+
generateToken(userId, sessionId, secretKey) {
|
173
|
+
const { createToken } = require('../token/utils');
|
174
|
+
return createToken({
|
175
|
+
userId,
|
176
|
+
packageName: this.config.packageName,
|
177
|
+
sessionId
|
178
|
+
}, { secretKey });
|
179
|
+
}
|
180
|
+
/**
|
181
|
+
* 🧹 Add Cleanup Handler
|
182
|
+
* Register a function to be called during server shutdown.
|
183
|
+
*
|
184
|
+
* @param handler - Function to call during cleanup
|
185
|
+
*/
|
186
|
+
addCleanupHandler(handler) {
|
187
|
+
this.cleanupHandlers.push(handler);
|
188
|
+
}
|
189
|
+
/**
|
190
|
+
* 🎯 Setup Webhook Endpoint
|
191
|
+
* Creates the webhook endpoint that AugmentOS Cloud calls to start new sessions.
|
192
|
+
*/
|
193
|
+
setupWebhook() {
|
194
|
+
if (!this.config.webhookPath) {
|
195
|
+
this.logger.error('❌ Webhook path not set');
|
196
|
+
throw new Error('Webhook path not set');
|
197
|
+
}
|
198
|
+
this.app.post(this.config.webhookPath, async (req, res) => {
|
199
|
+
try {
|
200
|
+
const webhookRequest = req.body;
|
201
|
+
// Handle session request
|
202
|
+
if ((0, types_1.isSessionWebhookRequest)(webhookRequest)) {
|
203
|
+
await this.handleSessionRequest(webhookRequest, res);
|
204
|
+
}
|
205
|
+
// Handle stop request
|
206
|
+
else if ((0, types_1.isStopWebhookRequest)(webhookRequest)) {
|
207
|
+
await this.handleStopRequest(webhookRequest, res);
|
208
|
+
}
|
209
|
+
// Unknown webhook type
|
210
|
+
else {
|
211
|
+
this.logger.error('❌ Unknown webhook request type');
|
212
|
+
res.status(400).json({
|
213
|
+
status: 'error',
|
214
|
+
message: 'Unknown webhook request type'
|
215
|
+
});
|
216
|
+
}
|
217
|
+
}
|
218
|
+
catch (error) {
|
219
|
+
this.logger.error(error, '❌ Error handling webhook: ' + error.message);
|
220
|
+
res.status(500).json({
|
221
|
+
status: 'error',
|
222
|
+
message: 'Error handling webhook: ' + error.message
|
223
|
+
});
|
224
|
+
}
|
225
|
+
});
|
226
|
+
}
|
227
|
+
/**
|
228
|
+
* 🛠️ Setup Tool Call Endpoint
|
229
|
+
* Creates a /tool endpoint for handling tool calls from AugmentOS Cloud.
|
230
|
+
*/
|
231
|
+
setupToolCallEndpoint() {
|
232
|
+
this.app.post('/tool', async (req, res) => {
|
233
|
+
try {
|
234
|
+
const toolCall = req.body;
|
235
|
+
this.logger.info({ body: req.body }, `🔧 Received tool call: ${toolCall.toolId}`);
|
236
|
+
// Call the onToolCall handler and get the response
|
237
|
+
const response = await this.onToolCall(toolCall);
|
238
|
+
// Send back the response if one was provided
|
239
|
+
if (response !== undefined) {
|
240
|
+
res.json({ status: 'success', reply: response });
|
241
|
+
}
|
242
|
+
else {
|
243
|
+
res.json({ status: 'success', reply: null });
|
244
|
+
}
|
245
|
+
}
|
246
|
+
catch (error) {
|
247
|
+
this.logger.error(error, '❌ Error handling tool call:');
|
248
|
+
res.status(500).json({
|
249
|
+
status: 'error',
|
250
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred calling tool'
|
251
|
+
});
|
252
|
+
}
|
253
|
+
});
|
254
|
+
this.app.get('/tool', async (req, res) => {
|
255
|
+
res.json({ status: 'success', reply: 'Hello, world!' });
|
256
|
+
});
|
257
|
+
}
|
258
|
+
/**
|
259
|
+
* Handle a session request webhook
|
260
|
+
*/
|
261
|
+
async handleSessionRequest(request, res) {
|
262
|
+
const { sessionId, userId, augmentOSWebsocketUrl } = request;
|
263
|
+
this.logger.info({ userId }, `🗣️ Received session request for user ${userId}, session ${sessionId}\n\n`);
|
264
|
+
// Create new TPA session
|
265
|
+
const session = new session_1.TpaSession({
|
266
|
+
packageName: this.config.packageName,
|
267
|
+
apiKey: this.config.apiKey,
|
268
|
+
augmentOSWebsocketUrl, // The websocket URL for the specific AugmentOS server that this userSession is connecting to.
|
269
|
+
tpaServer: this,
|
270
|
+
userId,
|
271
|
+
});
|
272
|
+
// Setup session event handlers
|
273
|
+
const cleanupDisconnect = session.events.onDisconnected((info) => {
|
274
|
+
// Handle different disconnect info formats (string or object)
|
275
|
+
if (typeof info === 'string') {
|
276
|
+
this.logger.info(`👋 Session ${sessionId} disconnected: ${info}`);
|
277
|
+
}
|
278
|
+
else {
|
279
|
+
// It's an object with detailed disconnect information
|
280
|
+
this.logger.info(`👋 Session ${sessionId} disconnected: ${info.message} (code: ${info.code}, reason: ${info.reason})`);
|
281
|
+
// Check if this is a permanent disconnection after exhausted reconnection attempts
|
282
|
+
if (info.permanent === true) {
|
283
|
+
this.logger.info(`🛑 Permanent disconnection detected for session ${sessionId}, calling onStop`);
|
284
|
+
// Keep track of the original session before removal
|
285
|
+
const session = this.activeSessions.get(sessionId);
|
286
|
+
// Call onStop with a reconnection failure reason
|
287
|
+
this.onStop(sessionId, userId, `Connection permanently lost: ${info.reason}`).catch(error => {
|
288
|
+
this.logger.error(error, `❌ Error in onStop handler for permanent disconnection:`);
|
289
|
+
});
|
290
|
+
}
|
291
|
+
}
|
292
|
+
// Remove the session from active sessions in all cases
|
293
|
+
this.activeSessions.delete(sessionId);
|
294
|
+
});
|
295
|
+
const cleanupError = session.events.onError((error) => {
|
296
|
+
this.logger.error(error, `❌ [Session ${sessionId}] Error:`);
|
297
|
+
});
|
298
|
+
// Start the session
|
299
|
+
try {
|
300
|
+
await session.connect(sessionId);
|
301
|
+
this.activeSessions.set(sessionId, session);
|
302
|
+
await this.onSession(session, sessionId, userId);
|
303
|
+
res.status(200).json({ status: 'success' });
|
304
|
+
}
|
305
|
+
catch (error) {
|
306
|
+
this.logger.error(error, '❌ Failed to connect:');
|
307
|
+
cleanupDisconnect();
|
308
|
+
cleanupError();
|
309
|
+
res.status(500).json({
|
310
|
+
status: 'error',
|
311
|
+
message: 'Failed to connect'
|
312
|
+
});
|
313
|
+
}
|
314
|
+
}
|
315
|
+
/**
|
316
|
+
* Handle a stop request webhook
|
317
|
+
*/
|
318
|
+
async handleStopRequest(request, res) {
|
319
|
+
const { sessionId, userId, reason } = request;
|
320
|
+
this.logger.info(`\n\n🛑 Received stop request for user ${userId}, session ${sessionId}, reason: ${reason}\n\n`);
|
321
|
+
try {
|
322
|
+
await this.onStop(sessionId, userId, reason);
|
323
|
+
res.status(200).json({ status: 'success' });
|
324
|
+
}
|
325
|
+
catch (error) {
|
326
|
+
this.logger.error(error, '❌ Error handling stop request:');
|
327
|
+
res.status(500).json({
|
328
|
+
status: 'error',
|
329
|
+
message: 'Failed to process stop request'
|
330
|
+
});
|
331
|
+
}
|
332
|
+
}
|
333
|
+
/**
|
334
|
+
* ❤️ Setup Health Check Endpoint
|
335
|
+
* Creates a /health endpoint for monitoring server status.
|
336
|
+
*/
|
337
|
+
setupHealthCheck() {
|
338
|
+
if (this.config.healthCheck) {
|
339
|
+
this.app.get('/health', (req, res) => {
|
340
|
+
res.json({
|
341
|
+
status: 'healthy',
|
342
|
+
app: this.config.packageName,
|
343
|
+
activeSessions: this.activeSessions.size
|
344
|
+
});
|
345
|
+
});
|
346
|
+
}
|
347
|
+
}
|
348
|
+
/**
|
349
|
+
* ⚙️ Setup Settings Endpoint
|
350
|
+
* Creates a /settings endpoint that the AugmentOS Cloud can use to update settings.
|
351
|
+
*/
|
352
|
+
setupSettingsEndpoint() {
|
353
|
+
this.app.post('/settings', async (req, res) => {
|
354
|
+
try {
|
355
|
+
const { userIdForSettings, settings } = req.body;
|
356
|
+
if (!userIdForSettings || !Array.isArray(settings)) {
|
357
|
+
return res.status(400).json({
|
358
|
+
status: 'error',
|
359
|
+
message: 'Missing userId or settings array in request body'
|
360
|
+
});
|
361
|
+
}
|
362
|
+
this.logger.info(`⚙️ Received settings update for user ${userIdForSettings}`);
|
363
|
+
// Find all active sessions for this user
|
364
|
+
const userSessions = [];
|
365
|
+
// Look through all active sessions
|
366
|
+
this.activeSessions.forEach((session, sessionId) => {
|
367
|
+
// Check if the session has this userId (not directly accessible)
|
368
|
+
// We're relying on the webhook handler to have already verified this
|
369
|
+
if (sessionId.includes(userIdForSettings)) {
|
370
|
+
userSessions.push(session);
|
371
|
+
}
|
372
|
+
});
|
373
|
+
if (userSessions.length === 0) {
|
374
|
+
this.logger.warn(`⚠️ No active sessions found for user ${userIdForSettings}`);
|
375
|
+
}
|
376
|
+
else {
|
377
|
+
this.logger.info(`🔄 Updating settings for ${userSessions.length} active sessions`);
|
378
|
+
}
|
379
|
+
// Update settings for all of the user's sessions
|
380
|
+
for (const session of userSessions) {
|
381
|
+
session.updateSettingsForTesting(settings);
|
382
|
+
}
|
383
|
+
// Allow subclasses to handle settings updates if they implement the method
|
384
|
+
if (typeof this.onSettingsUpdate === 'function') {
|
385
|
+
await this.onSettingsUpdate(userIdForSettings, settings);
|
386
|
+
}
|
387
|
+
res.json({
|
388
|
+
status: 'success',
|
389
|
+
message: 'Settings updated successfully',
|
390
|
+
sessionsUpdated: userSessions.length
|
391
|
+
});
|
392
|
+
}
|
393
|
+
catch (error) {
|
394
|
+
this.logger.error(error, '❌ Error handling settings update:');
|
395
|
+
res.status(500).json({
|
396
|
+
status: 'error',
|
397
|
+
message: 'Internal server error processing settings update'
|
398
|
+
});
|
399
|
+
}
|
400
|
+
});
|
401
|
+
}
|
402
|
+
/**
|
403
|
+
* 📂 Setup Static File Serving
|
404
|
+
* Configures Express to serve static files from the specified directory.
|
405
|
+
*/
|
406
|
+
setupPublicDir() {
|
407
|
+
if (this.config.publicDir) {
|
408
|
+
const publicPath = path_1.default.resolve(this.config.publicDir);
|
409
|
+
this.app.use(express_1.default.static(publicPath));
|
410
|
+
this.logger.info(`📂 Serving static files from ${publicPath}`);
|
411
|
+
}
|
412
|
+
}
|
413
|
+
/**
|
414
|
+
* 🛑 Setup Shutdown Handlers
|
415
|
+
* Registers process signal handlers for graceful shutdown.
|
416
|
+
*/
|
417
|
+
setupShutdown() {
|
418
|
+
process.on('SIGTERM', () => this.stop());
|
419
|
+
process.on('SIGINT', () => this.stop());
|
420
|
+
}
|
421
|
+
/**
|
422
|
+
* 🧹 Cleanup
|
423
|
+
* Closes all active sessions and runs cleanup handlers.
|
424
|
+
*/
|
425
|
+
cleanup() {
|
426
|
+
// Close all active sessions
|
427
|
+
for (const [sessionId, session] of this.activeSessions) {
|
428
|
+
this.logger.info(`👋 Closing session ${sessionId}`);
|
429
|
+
session.disconnect();
|
430
|
+
}
|
431
|
+
this.activeSessions.clear();
|
432
|
+
// Run cleanup handlers
|
433
|
+
this.cleanupHandlers.forEach(handler => handler());
|
434
|
+
}
|
435
|
+
}
|
436
|
+
exports.TpaServer = TpaServer;
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/**
|
2
|
+
* 🔌 API Client Module
|
3
|
+
*
|
4
|
+
* Provides HTTP API access to AugmentOS Cloud services.
|
5
|
+
* Automatically uses the correct server URL derived from the WebSocket URL.
|
6
|
+
*/
|
7
|
+
/**
|
8
|
+
* Convert a WebSocket URL to a HTTP/HTTPS URL
|
9
|
+
*
|
10
|
+
* @param wsUrl WebSocket URL to convert
|
11
|
+
* @returns HTTP URL equivalent
|
12
|
+
*/
|
13
|
+
export declare function wsUrlToHttpUrl(wsUrl?: string): string | undefined;
|
14
|
+
/**
|
15
|
+
* API client class for making HTTP requests to AugmentOS Cloud
|
16
|
+
*/
|
17
|
+
export declare class ApiClient {
|
18
|
+
private baseUrl;
|
19
|
+
private packageName;
|
20
|
+
private userId;
|
21
|
+
/**
|
22
|
+
* Create a new API client
|
23
|
+
*
|
24
|
+
* @param packageName TPA package name
|
25
|
+
* @param wsUrl WebSocket URL (optional, can be set later)
|
26
|
+
* @param userId User ID (optional, for authenticated requests)
|
27
|
+
*/
|
28
|
+
constructor(packageName: string, wsUrl?: string, userId?: string);
|
29
|
+
/**
|
30
|
+
* Set the WebSocket URL to derive the HTTP base URL
|
31
|
+
*
|
32
|
+
* @param wsUrl WebSocket URL
|
33
|
+
*/
|
34
|
+
setWebSocketUrl(wsUrl: string): void;
|
35
|
+
/**
|
36
|
+
* Set the user ID for authenticated requests
|
37
|
+
*
|
38
|
+
* @param userId User ID
|
39
|
+
*/
|
40
|
+
setUserId(userId: string): void;
|
41
|
+
/**
|
42
|
+
* Fetch settings from AugmentOS Cloud
|
43
|
+
*
|
44
|
+
* @returns Promise resolving to settings array
|
45
|
+
* @throws Error if client is not configured correctly or if request fails
|
46
|
+
*/
|
47
|
+
fetchSettings(): Promise<any[]>;
|
48
|
+
}
|
49
|
+
//# sourceMappingURL=api-client.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../../src/tpa/session/api-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBjE;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAqB;IAEnC;;;;;;OAMG;gBACS,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAShE;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;CA+BtC"}
|
@@ -0,0 +1,101 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* 🔌 API Client Module
|
4
|
+
*
|
5
|
+
* Provides HTTP API access to AugmentOS 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 AugmentOS Cloud
|
35
|
+
*/
|
36
|
+
class ApiClient {
|
37
|
+
/**
|
38
|
+
* Create a new API client
|
39
|
+
*
|
40
|
+
* @param packageName TPA 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 AugmentOS 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}/tpasettings/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;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/**
|
2
|
+
* Dashboard API Implementation
|
3
|
+
*
|
4
|
+
* Provides dashboard functionality for TPAs, allowing them to write content
|
5
|
+
* to the dashboard and respond to dashboard mode changes.
|
6
|
+
*/
|
7
|
+
import { DashboardAPI, DashboardContentAPI, DashboardMode, DashboardSystemAPI } from '../../types/dashboard';
|
8
|
+
import { EventManager } from './events';
|
9
|
+
import type { TpaSession } from './index';
|
10
|
+
import { TpaToCloudMessage } from 'src/types';
|
11
|
+
/**
|
12
|
+
* Implementation of DashboardSystemAPI interface for system dashboard TPA
|
13
|
+
*/
|
14
|
+
export declare class DashboardSystemManager implements DashboardSystemAPI {
|
15
|
+
private session;
|
16
|
+
private packageName;
|
17
|
+
private send;
|
18
|
+
constructor(session: TpaSession, packageName: string, send: (message: any) => void);
|
19
|
+
setTopLeft(content: string): void;
|
20
|
+
setTopRight(content: string): void;
|
21
|
+
setBottomLeft(content: string): void;
|
22
|
+
setBottomRight(content: string): void;
|
23
|
+
setViewMode(mode: DashboardMode): void;
|
24
|
+
private updateSystemSection;
|
25
|
+
}
|
26
|
+
/**
|
27
|
+
* Implementation of DashboardContentAPI interface for all TPAs
|
28
|
+
*/
|
29
|
+
export declare class DashboardContentManager implements DashboardContentAPI {
|
30
|
+
private session;
|
31
|
+
private packageName;
|
32
|
+
private send;
|
33
|
+
private events;
|
34
|
+
private currentMode;
|
35
|
+
constructor(session: TpaSession, packageName: string, send: (message: any) => void, events: EventManager);
|
36
|
+
write(content: string, targets?: DashboardMode[]): void;
|
37
|
+
writeToMain(content: string): void;
|
38
|
+
writeToExpanded(content: string): void;
|
39
|
+
getCurrentMode(): Promise<DashboardMode | 'none'>;
|
40
|
+
onModeChange(callback: (mode: DashboardMode | 'none') => void): () => void;
|
41
|
+
setCurrentMode(mode: DashboardMode | 'none'): void;
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Dashboard Manager - Main class that manages dashboard functionality
|
45
|
+
* Each TpaSession instance gets its own DashboardManager instance
|
46
|
+
*/
|
47
|
+
export declare class DashboardManager implements DashboardAPI {
|
48
|
+
readonly content: DashboardContentAPI;
|
49
|
+
readonly system?: DashboardSystemAPI;
|
50
|
+
constructor(session: TpaSession, send: (message: TpaToCloudMessage) => void);
|
51
|
+
}
|
52
|
+
//# sourceMappingURL=dashboard.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/tpa/session/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAO9C;;GAEG;AACH,qBAAa,sBAAuB,YAAW,kBAAkB;IAE7D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,IAAI;gBAFJ,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI;IAGtC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIrC,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAWtC,OAAO,CAAC,mBAAmB;CAW5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IAK/D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,WAAW,CAAkC;gBAI3C,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,EAC5B,MAAM,EAAE,YAAY;IAG9B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAa,EAAyB,GAAG,IAAI;IAY7E,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAgBhC,cAAc,IAAI,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC;IAQvD,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAe1E,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI;CASnD;AAED;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,SAAgB,OAAO,EAAE,mBAAmB,CAAC;IAC7C,SAAgB,MAAM,CAAC,EAAE,kBAAkB,CAAC;gBAEhC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI;CAe5E"}
|