@superdangerous/app-framework 4.9.1 → 4.14.0

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.
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { Server } from "socket.io";
6
6
  import { createLogger } from "../core/index.js";
7
- let logger; // Will be initialized when needed
7
+ let logger = null;
8
8
  class WebSocketServer {
9
9
  io = null;
10
10
  httpServer;
@@ -24,7 +24,7 @@ class WebSocketServer {
24
24
  if (this.io) {
25
25
  if (opts?.broadcastHook) {
26
26
  this.broadcastHook = opts.broadcastHook;
27
- logger.debug("WebSocket broadcast hook updated");
27
+ logger?.debug("WebSocket broadcast hook updated");
28
28
  }
29
29
  return;
30
30
  }
@@ -39,7 +39,7 @@ class WebSocketServer {
39
39
  this.broadcastHook = opts.broadcastHook;
40
40
  }
41
41
  this.setupEventHandlers();
42
- logger.info("WebSocket server initialized");
42
+ logger?.info("WebSocket server initialized");
43
43
  }
44
44
  /**
45
45
  * Get the underlying Socket.IO server instance
@@ -53,7 +53,7 @@ class WebSocketServer {
53
53
  this.io.on("connection", (socket) => {
54
54
  // Only log in debug mode to avoid spam
55
55
  if (process.env.LOG_LEVEL?.toLowerCase() === "debug") {
56
- logger.debug(`Client connected: ${socket.id}`);
56
+ logger?.debug(`Client connected: ${socket.id}`);
57
57
  }
58
58
  this.clients.set(socket.id, {
59
59
  id: socket.id,
@@ -76,13 +76,13 @@ class WebSocketServer {
76
76
  socket.on("disconnect", () => {
77
77
  // Only log in debug mode to avoid spam
78
78
  if (process.env.LOG_LEVEL?.toLowerCase() === "debug") {
79
- logger.debug(`Client disconnected: ${socket.id}`);
79
+ logger?.debug(`Client disconnected: ${socket.id}`);
80
80
  }
81
81
  this.handleDisconnect(socket);
82
82
  });
83
83
  // Handle errors
84
- socket.on("error", (_error) => {
85
- logger.error(`Socket error for ${socket.id}:`, _error);
84
+ socket.on("error", (error) => {
85
+ logger?.error(`Socket error for ${socket.id}:`, error);
86
86
  });
87
87
  });
88
88
  }
@@ -102,7 +102,7 @@ class WebSocketServer {
102
102
  }
103
103
  // Join socket.io room for efficient broadcasting
104
104
  socket.join(`simulator:${simulatorId}`);
105
- logger.debug(`Client ${socket.id} subscribed to simulator ${simulatorId}`);
105
+ logger?.debug(`Client ${socket.id} subscribed to simulator ${simulatorId}`);
106
106
  }
107
107
  unsubscribeFromSimulator(socket, simulatorId) {
108
108
  const client = this.clients.get(socket.id);
@@ -120,7 +120,7 @@ class WebSocketServer {
120
120
  }
121
121
  // Leave socket.io room
122
122
  socket.leave(`simulator:${simulatorId}`);
123
- logger.debug(`Client ${socket.id} unsubscribed from simulator ${simulatorId}`);
123
+ logger?.debug(`Client ${socket.id} unsubscribed from simulator ${simulatorId}`);
124
124
  }
125
125
  handleDisconnect(socket) {
126
126
  const client = this.clients.get(socket.id);
@@ -179,7 +179,9 @@ class WebSocketServer {
179
179
  type: "data:update",
180
180
  data: {
181
181
  simulatorId: data.simulatorId,
182
- values: data.values || { [data.address]: data.value },
182
+ values: data.values || {
183
+ [data.address]: data.value,
184
+ },
183
185
  },
184
186
  };
185
187
  break;
@@ -189,13 +191,17 @@ class WebSocketServer {
189
191
  data: data,
190
192
  };
191
193
  }
192
- // Broadcast to all clients
193
- this.io.emit(event, message.data);
194
- // If simulator-specific, also send to room
194
+ // Broadcast: if simulator-specific, send only to room; otherwise broadcast globally
195
+ // This prevents duplicate events for subscribed clients
195
196
  if (data.simulatorId) {
196
197
  this.io.to(`simulator:${data.simulatorId}`).emit(event, message.data);
198
+ const subscriberCount = this.simulatorSubscriptions.get(data.simulatorId)?.size || 0;
199
+ logger?.debug(`Broadcast ${event} to ${subscriberCount} subscribers of simulator ${data.simulatorId}`);
200
+ }
201
+ else {
202
+ this.io.emit(event, message.data);
203
+ logger?.debug(`Broadcast ${event} to ${this.clients.size} clients`);
197
204
  }
198
- logger.debug(`Broadcast ${event} to ${this.clients.size} clients`);
199
205
  }
200
206
  /**
201
207
  * Send event to specific simulator subscribers
@@ -212,7 +218,7 @@ class WebSocketServer {
212
218
  };
213
219
  this.io.to(`simulator:${simulatorId}`).emit(event, message.data);
214
220
  const subscriberCount = this.simulatorSubscriptions.get(simulatorId)?.size || 0;
215
- logger.debug(`Broadcast ${event} to ${subscriberCount} subscribers of simulator ${simulatorId}`);
221
+ logger?.debug(`Broadcast ${event} to ${subscriberCount} subscribers of simulator ${simulatorId}`);
216
222
  }
217
223
  /**
218
224
  * Get statistics about connected clients
@@ -255,7 +261,7 @@ class WebSocketServer {
255
261
  // Close the server
256
262
  await new Promise((resolve) => {
257
263
  this.io.close(() => {
258
- logger.info("WebSocket server shut down");
264
+ logger?.info("WebSocket server shut down");
259
265
  resolve();
260
266
  });
261
267
  });
@@ -1 +1 @@
1
- {"version":3,"file":"websocketServer.js","sourceRoot":"","sources":["../../src/services/websocketServer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocketServer.js","sourceRoot":"","sources":["../../src/services/websocketServer.ts"],"names":[],"mappings":"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"}
@@ -83,7 +83,6 @@ export interface UpdateCheckResult {
83
83
  export interface ClientInfo {
84
84
  id: string;
85
85
  connectedAt: Date;
86
- lastActivity: Date;
87
86
  subscriptions: Set<string>;
88
87
  }
89
88
  /**
@@ -98,9 +97,9 @@ export interface Logger {
98
97
  /**
99
98
  * WebSocket message types
100
99
  */
101
- export interface WebSocketMessage {
100
+ export interface WebSocketMessage<T = unknown> {
102
101
  type: string;
103
- data: any;
102
+ data: T;
104
103
  }
105
104
  export interface SimulatorUpdateMessage extends WebSocketMessage {
106
105
  type: "simulator:started" | "simulator:stopped" | "simulator:data";
@@ -114,24 +113,24 @@ export interface DataUpdateMessage extends WebSocketMessage {
114
113
  type: "data:update";
115
114
  data: {
116
115
  simulatorId: string;
117
- values: Record<string, any>;
116
+ values: Record<string, unknown>;
118
117
  };
119
118
  }
120
119
  export interface Simulator {
121
120
  id: string;
122
121
  name: string;
123
122
  status: string;
124
- [key: string]: any;
123
+ [key: string]: unknown;
125
124
  }
126
125
  export interface Template {
127
126
  id: string;
128
127
  name: string;
129
- [key: string]: any;
128
+ [key: string]: unknown;
130
129
  }
131
130
  export interface AppConfig {
132
- [key: string]: any;
131
+ [key: string]: unknown;
133
132
  }
134
133
  export interface ValidationError extends Error {
135
- details?: any[];
134
+ details?: unknown[];
136
135
  }
137
136
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superdangerous/app-framework",
3
- "version": "4.9.1",
3
+ "version": "4.14.0",
4
4
  "description": "Opinionated TypeScript framework for structured vibecoding - building internal web and desktop apps with batteries included",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,6 @@
8
8
  "bin": {
9
9
  "app-framework": "dist/cli/index.js",
10
10
  "framework": "dist/cli/index.js",
11
- "build-sidecar": "dist/cli/build-sidecar.js",
12
11
  "dev-server": "dist/cli/dev-server.js"
13
12
  },
14
13
  "exports": {
@@ -120,6 +119,7 @@
120
119
  "@types/express": "^4.17.23",
121
120
  "@types/fs-extra": "^11.0.4",
122
121
  "@types/node": "^20.10.0",
122
+ "@types/supertest": "^6.0.3",
123
123
  "@types/swagger-jsdoc": "^6.0.4",
124
124
  "@types/swagger-ui-express": "^4.1.8",
125
125
  "@types/ws": "^8.18.1",
@@ -131,6 +131,7 @@
131
131
  "npm-run-all": "^4.1.5",
132
132
  "prettier": "^3.5.1",
133
133
  "socket.io-client": "^4.8.1",
134
+ "supertest": "^7.1.4",
134
135
  "ts-node": "^10.9.2",
135
136
  "tsx": "^4.20.4",
136
137
  "typedoc": "^0.28.12",
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Standardized Logging API Router
3
- * Provides consistent logging endpoints for all SuperDangerous applications
3
+ * Provides consistent logging endpoints for all EpiSensor applications
4
+ *
5
+ * SECURITY WARNING: This router exposes sensitive log files without authentication.
6
+ * Before production use, implement proper authentication middleware.
4
7
  */
5
8
 
6
9
  import express, { Request, Response } from "express";
@@ -26,13 +29,99 @@ export interface LogFile {
26
29
  path?: string;
27
30
  }
28
31
 
32
+ /**
33
+ * Validate and sanitize file path to prevent directory traversal
34
+ */
35
+ function validateFilePath(filename: string, baseDir: string): string | null {
36
+ if (!filename || typeof filename !== "string") {
37
+ return null;
38
+ }
39
+
40
+ // Normalize the filename and resolve path
41
+ const safeName = path.normalize(filename).replace(/^(\.\.[/\\])+/, "");
42
+ const resolvedPath = path.resolve(baseDir, safeName);
43
+ const resolvedBase = path.resolve(baseDir);
44
+
45
+ // Ensure the resolved path is within the base directory
46
+ if (
47
+ !resolvedPath.startsWith(resolvedBase + path.sep) &&
48
+ resolvedPath !== resolvedBase
49
+ ) {
50
+ return null;
51
+ }
52
+
53
+ return resolvedPath;
54
+ }
55
+
56
+ /**
57
+ * Safely parse integer with fallback
58
+ */
59
+ function parseIntSafe(value: any, defaultValue: number): number {
60
+ if (typeof value === "number") return Math.floor(value);
61
+ if (typeof value === "string") {
62
+ const parsed = parseInt(value, 10);
63
+ return isNaN(parsed) ? defaultValue : parsed;
64
+ }
65
+ return defaultValue;
66
+ }
67
+
68
+ // Helper function to format bytes
69
+ function formatBytes(bytes: number, decimals = 2): string {
70
+ if (bytes === 0) return "0 Bytes";
71
+ const k = 1024;
72
+ const dm = decimals < 0 ? 0 : decimals;
73
+ const sizes = ["Bytes", "KB", "MB", "GB"];
74
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
75
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
76
+ }
77
+
78
+ /**
79
+ * Helper to get log files from a directory
80
+ */
81
+ async function getLogFilesFromDir(
82
+ logsDir: string,
83
+ includeFullPath = false,
84
+ ): Promise<LogFile[]> {
85
+ if (!existsSync(logsDir)) {
86
+ return [];
87
+ }
88
+
89
+ const files = await fs.readdir(logsDir);
90
+ const logFiles: LogFile[] = [];
91
+
92
+ for (const file of files) {
93
+ if (
94
+ file.endsWith(".log") ||
95
+ file.endsWith(".txt") ||
96
+ file.endsWith(".gz")
97
+ ) {
98
+ const filePath = path.join(logsDir, file);
99
+ const stats = await fs.stat(filePath);
100
+
101
+ logFiles.push({
102
+ name: file,
103
+ size: stats.size,
104
+ modified: stats.mtime.toISOString(),
105
+ ...(includeFullPath && { path: filePath }),
106
+ });
107
+ }
108
+ }
109
+
110
+ // Sort by modified date, newest first
111
+ logFiles.sort(
112
+ (a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime(),
113
+ );
114
+
115
+ return logFiles;
116
+ }
117
+
29
118
  /**
30
119
  * Get recent log entries
31
120
  * GET /api/logs/entries?limit=100&level=info
32
121
  */
33
122
  router.get("/entries", async (req: Request, res: Response) => {
34
123
  try {
35
- const limit = parseInt(req.query.limit as string) || 100;
124
+ const limit = parseIntSafe(req.query.limit, 100);
36
125
  const level = (req.query.level as string) || "all";
37
126
 
38
127
  const logger = getLogger;
@@ -59,36 +148,7 @@ router.get("/entries", async (req: Request, res: Response) => {
59
148
  router.get("/files", async (_req: Request, res: Response) => {
60
149
  try {
61
150
  const logsDir = path.join(process.cwd(), "data", "logs");
62
-
63
- if (!existsSync(logsDir)) {
64
- res.json({
65
- success: true,
66
- files: [],
67
- });
68
- return;
69
- }
70
-
71
- const files = await fs.readdir(logsDir);
72
- const logFiles: LogFile[] = [];
73
-
74
- for (const file of files) {
75
- if (file.endsWith(".log") || file.endsWith(".txt")) {
76
- const filePath = path.join(logsDir, file);
77
- const stats = await fs.stat(filePath);
78
-
79
- logFiles.push({
80
- name: file,
81
- size: stats.size,
82
- modified: stats.mtime.toISOString(),
83
- path: filePath,
84
- });
85
- }
86
- }
87
-
88
- // Sort by modified date, newest first
89
- logFiles.sort(
90
- (a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime(),
91
- );
151
+ const logFiles = await getLogFilesFromDir(logsDir, true);
92
152
 
93
153
  res.json({
94
154
  success: true,
@@ -112,10 +172,10 @@ router.get("/download/:filename", async (req: Request, res: Response) => {
112
172
  try {
113
173
  const { filename } = req.params;
114
174
  const logsDir = path.join(process.cwd(), "data", "logs");
115
- const filePath = path.join(logsDir, filename);
116
175
 
117
176
  // Security check - prevent directory traversal
118
- if (!filePath.startsWith(logsDir)) {
177
+ const filePath = validateFilePath(filename, logsDir);
178
+ if (!filePath) {
119
179
  res.status(403).json({
120
180
  success: false,
121
181
  error: "Access denied",
@@ -149,10 +209,10 @@ router.get("/stream/:filename", async (req: Request, res: Response) => {
149
209
  try {
150
210
  const { filename } = req.params;
151
211
  const logsDir = path.join(process.cwd(), "data", "logs");
152
- const filePath = path.join(logsDir, filename);
153
212
 
154
- // Security check
155
- if (!filePath.startsWith(logsDir)) {
213
+ // Security check - prevent directory traversal
214
+ const filePath = validateFilePath(filename, logsDir);
215
+ if (!filePath) {
156
216
  res.status(403).json({
157
217
  success: false,
158
218
  error: "Access denied",
@@ -203,47 +263,21 @@ router.post("/clear", async (_req: Request, res: Response) => {
203
263
  });
204
264
 
205
265
  /**
206
- * Get archived log files
266
+ * Get archived log files (alias for /files for backward compatibility)
207
267
  * GET /api/logs/archives
208
268
  */
209
269
  router.get("/archives", async (_req: Request, res: Response) => {
210
270
  try {
211
271
  const logsDir = path.join(process.cwd(), "data", "logs");
272
+ const archives = await getLogFilesFromDir(logsDir);
212
273
 
213
- if (!existsSync(logsDir)) {
214
- return res.json({
215
- success: true,
216
- archives: [],
217
- });
218
- }
219
-
220
- const files = await fs.readdir(logsDir);
221
- const archives: LogFile[] = [];
222
-
223
- for (const file of files) {
224
- if (file.endsWith(".log") || file.endsWith(".txt")) {
225
- const filePath = path.join(logsDir, file);
226
- const stats = await fs.stat(filePath);
227
- archives.push({
228
- name: file,
229
- size: stats.size,
230
- modified: stats.mtime.toISOString(),
231
- });
232
- }
233
- }
234
-
235
- // Sort by modified date, newest first
236
- archives.sort(
237
- (a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime(),
238
- );
239
-
240
- return res.json({
274
+ res.json({
241
275
  success: true,
242
276
  archives,
243
277
  });
244
278
  } catch (_error) {
245
279
  console.error("Failed to fetch archives:", _error);
246
- return res.status(500).json({
280
+ res.status(500).json({
247
281
  success: false,
248
282
  error: "Failed to fetch archives",
249
283
  archives: [],
@@ -259,10 +293,10 @@ router.delete("/archive/:filename", async (req: Request, res: Response) => {
259
293
  try {
260
294
  const { filename } = req.params;
261
295
  const logsDir = path.join(process.cwd(), "data", "logs");
262
- const filePath = path.join(logsDir, filename);
263
296
 
264
- // Security check
265
- if (!filePath.startsWith(logsDir) || filename.includes("..")) {
297
+ // Security check - prevent directory traversal
298
+ const filePath = validateFilePath(filename, logsDir);
299
+ if (!filePath) {
266
300
  return res.status(403).json({
267
301
  success: false,
268
302
  error: "Access denied",
@@ -338,52 +372,14 @@ router.get("/export", async (req: Request, res: Response) => {
338
372
  */
339
373
  router.get("/stats", async (_req: Request, res: Response) => {
340
374
  try {
341
- const logsDir = path.join(process.cwd(), "data", "logs");
342
-
343
- if (!existsSync(logsDir)) {
344
- res.json({
345
- success: true,
346
- stats: {
347
- totalSize: 0,
348
- fileCount: 0,
349
- oldestLog: null,
350
- newestLog: null,
351
- },
352
- });
353
- return;
354
- }
355
-
356
- const files = await fs.readdir(logsDir);
357
- let totalSize = 0;
358
- let oldestTime: Date | null = null;
359
- let newestTime: Date | null = null;
360
- let fileCount = 0;
361
-
362
- for (const file of files) {
363
- if (file.endsWith(".log") || file.endsWith(".txt")) {
364
- const filePath = path.join(logsDir, file);
365
- const stats = await fs.stat(filePath);
366
-
367
- totalSize += stats.size;
368
- fileCount++;
369
-
370
- if (!oldestTime || stats.birthtime < oldestTime) {
371
- oldestTime = stats.birthtime;
372
- }
373
- if (!newestTime || stats.mtime > newestTime) {
374
- newestTime = stats.mtime;
375
- }
376
- }
377
- }
375
+ const logger = getLogger;
376
+ const stats = await logger.getLogStats();
378
377
 
379
378
  res.json({
380
379
  success: true,
381
380
  stats: {
382
- totalSize,
383
- totalSizeFormatted: formatBytes(totalSize),
384
- fileCount,
385
- oldestLog: oldestTime?.toISOString() || null,
386
- newestLog: newestTime?.toISOString() || null,
381
+ ...stats,
382
+ totalSizeFormatted: formatBytes(stats.totalSize || 0),
387
383
  },
388
384
  });
389
385
  } catch (_error) {
@@ -506,26 +502,21 @@ router.get(
506
502
  async (req: Request, res: Response) => {
507
503
  try {
508
504
  const { filename } = req.params;
509
-
510
- // Security: prevent directory traversal
511
- const safeName = path.basename(filename);
512
-
513
- // Check in logs directory first
514
505
  const logsDir = path.join(process.cwd(), "data", "logs");
515
- let filePath = path.join(logsDir, safeName);
516
506
 
517
- // If not found, check in archive directory
518
- if (!existsSync(filePath)) {
519
- filePath = path.join(logsDir, "archive", safeName);
520
- }
507
+ // Security: prevent directory traversal using proper validation
508
+ let filePath = validateFilePath(filename, logsDir);
521
509
 
522
- // If still not found and filename includes 'archive/', handle that case
523
- if (!existsSync(filePath) && filename.startsWith("archive/")) {
524
- const archiveName = filename.replace("archive/", "");
525
- filePath = path.join(logsDir, "archive", archiveName);
510
+ // If not found in main logs, try archive directory
511
+ if (!filePath || !existsSync(filePath)) {
512
+ const archiveDir = path.join(logsDir, "archive");
513
+ const archiveFilename = filename.startsWith("archive/")
514
+ ? filename.substring("archive/".length)
515
+ : filename;
516
+ filePath = validateFilePath(archiveFilename, archiveDir);
526
517
  }
527
518
 
528
- if (!existsSync(filePath)) {
519
+ if (!filePath || !existsSync(filePath)) {
529
520
  return res.status(404).json({
530
521
  success: false,
531
522
  error: "File not found",
@@ -540,7 +531,7 @@ router.get(
540
531
  res.setHeader("Content-Type", "text/plain");
541
532
  }
542
533
 
543
- return res.download(filePath, safeName);
534
+ return res.download(filePath, path.basename(filePath));
544
535
  } catch (_error) {
545
536
  return res.status(500).json({
546
537
  success: false,
@@ -587,14 +578,4 @@ router.post("/rotate", async (_req: Request, res: Response) => {
587
578
  }
588
579
  });
589
580
 
590
- // Helper function to format bytes
591
- function formatBytes(bytes: number, decimals = 2): string {
592
- if (bytes === 0) return "0 Bytes";
593
- const k = 1024;
594
- const dm = decimals < 0 ? 0 : decimals;
595
- const sizes = ["Bytes", "KB", "MB", "GB"];
596
- const i = Math.floor(Math.log(bytes) / Math.log(k));
597
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
598
- }
599
-
600
581
  export default router;
package/src/core/index.ts CHANGED
@@ -56,13 +56,14 @@ export interface Logger {
56
56
 
57
57
  export type LogLevel = "debug" | "info" | "warn" | "error";
58
58
 
59
- // Security
59
+ // Security & Storage
60
60
  export {
61
61
  getStorageService,
62
62
  StorageService,
63
63
  getSecureFileHandler,
64
64
  SecureFileHandler,
65
65
  } from "./storageService.js";
66
+ export type { FileInfo, SaveOptions, ReadOptions } from "./storageService.js";
66
67
 
67
68
  /**
68
69
  * Usage Example: