@superdangerous/app-framework 4.9.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.
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/api/logsRouter.d.ts +20 -0
- package/dist/api/logsRouter.d.ts.map +1 -0
- package/dist/api/logsRouter.js +515 -0
- package/dist/api/logsRouter.js.map +1 -0
- package/dist/cli/dev-server.d.ts +7 -0
- package/dist/cli/dev-server.d.ts.map +1 -0
- package/dist/cli/dev-server.js +640 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/StandardServer.d.ts +129 -0
- package/dist/core/StandardServer.d.ts.map +1 -0
- package/dist/core/StandardServer.js +453 -0
- package/dist/core/StandardServer.js.map +1 -0
- package/dist/core/apiResponse.d.ts +69 -0
- package/dist/core/apiResponse.d.ts.map +1 -0
- package/dist/core/apiResponse.js +127 -0
- package/dist/core/apiResponse.js.map +1 -0
- package/dist/core/healthCheck.d.ts +160 -0
- package/dist/core/healthCheck.d.ts.map +1 -0
- package/dist/core/healthCheck.js +398 -0
- package/dist/core/healthCheck.js.map +1 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +117 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +826 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/portUtils.d.ts +71 -0
- package/dist/core/portUtils.d.ts.map +1 -0
- package/dist/core/portUtils.js +240 -0
- package/dist/core/portUtils.js.map +1 -0
- package/dist/core/storageService.d.ts +119 -0
- package/dist/core/storageService.d.ts.map +1 -0
- package/dist/core/storageService.js +405 -0
- package/dist/core/storageService.js.map +1 -0
- package/dist/desktop/bundler.d.ts +40 -0
- package/dist/desktop/bundler.d.ts.map +1 -0
- package/dist/desktop/bundler.js +176 -0
- package/dist/desktop/bundler.js.map +1 -0
- package/dist/desktop/index.d.ts +25 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/index.js +15 -0
- package/dist/desktop/index.js.map +1 -0
- package/dist/desktop/native-modules.d.ts +66 -0
- package/dist/desktop/native-modules.d.ts.map +1 -0
- package/dist/desktop/native-modules.js +200 -0
- package/dist/desktop/native-modules.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/LogCategories.d.ts +87 -0
- package/dist/logging/LogCategories.d.ts.map +1 -0
- package/dist/logging/LogCategories.js +205 -0
- package/dist/logging/LogCategories.js.map +1 -0
- package/dist/middleware/aiErrorHandler.d.ts +31 -0
- package/dist/middleware/aiErrorHandler.d.ts.map +1 -0
- package/dist/middleware/aiErrorHandler.js +181 -0
- package/dist/middleware/aiErrorHandler.js.map +1 -0
- package/dist/middleware/auth.d.ts +101 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +230 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +56 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +123 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +13 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +85 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/fileUpload.d.ts +62 -0
- package/dist/middleware/fileUpload.d.ts.map +1 -0
- package/dist/middleware/fileUpload.js +175 -0
- package/dist/middleware/fileUpload.js.map +1 -0
- package/dist/middleware/health.d.ts +48 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +143 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/index.d.ts +20 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/openapi.d.ts +64 -0
- package/dist/middleware/openapi.d.ts.map +1 -0
- package/dist/middleware/openapi.js +258 -0
- package/dist/middleware/openapi.js.map +1 -0
- package/dist/middleware/requestLogging.d.ts +22 -0
- package/dist/middleware/requestLogging.d.ts.map +1 -0
- package/dist/middleware/requestLogging.js +61 -0
- package/dist/middleware/requestLogging.js.map +1 -0
- package/dist/middleware/session.d.ts +84 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +189 -0
- package/dist/middleware/session.js.map +1 -0
- package/dist/middleware/validation.d.ts +1337 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +483 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/services/aiService.d.ts +180 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +547 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/conversationStorage.d.ts +38 -0
- package/dist/services/conversationStorage.d.ts.map +1 -0
- package/dist/services/conversationStorage.js +158 -0
- package/dist/services/conversationStorage.js.map +1 -0
- package/dist/services/crossPlatformBuffer.d.ts +84 -0
- package/dist/services/crossPlatformBuffer.d.ts.map +1 -0
- package/dist/services/crossPlatformBuffer.js +246 -0
- package/dist/services/crossPlatformBuffer.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networkService.d.ts +81 -0
- package/dist/services/networkService.d.ts.map +1 -0
- package/dist/services/networkService.js +268 -0
- package/dist/services/networkService.js.map +1 -0
- package/dist/services/queueService.d.ts +112 -0
- package/dist/services/queueService.d.ts.map +1 -0
- package/dist/services/queueService.js +338 -0
- package/dist/services/queueService.js.map +1 -0
- package/dist/services/settingsService.d.ts +135 -0
- package/dist/services/settingsService.d.ts.map +1 -0
- package/dist/services/settingsService.js +425 -0
- package/dist/services/settingsService.js.map +1 -0
- package/dist/services/systemMonitor.d.ts +208 -0
- package/dist/services/systemMonitor.d.ts.map +1 -0
- package/dist/services/systemMonitor.js +693 -0
- package/dist/services/systemMonitor.js.map +1 -0
- package/dist/services/updateService.d.ts +78 -0
- package/dist/services/updateService.d.ts.map +1 -0
- package/dist/services/updateService.js +252 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/websocketEvents.d.ts +372 -0
- package/dist/services/websocketEvents.d.ts.map +1 -0
- package/dist/services/websocketEvents.js +338 -0
- package/dist/services/websocketEvents.js.map +1 -0
- package/dist/services/websocketServer.d.ts +80 -0
- package/dist/services/websocketServer.d.ts.map +1 -0
- package/dist/services/websocketServer.js +299 -0
- package/dist/services/websocketServer.js.map +1 -0
- package/dist/settings/SettingsSchema.d.ts +151 -0
- package/dist/settings/SettingsSchema.d.ts.map +1 -0
- package/dist/settings/SettingsSchema.js +424 -0
- package/dist/settings/SettingsSchema.js.map +1 -0
- package/dist/testing/TestServer.d.ts +69 -0
- package/dist/testing/TestServer.d.ts.map +1 -0
- package/dist/testing/TestServer.js +250 -0
- package/dist/testing/TestServer.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/appPaths.d.ts +74 -0
- package/dist/utils/appPaths.d.ts.map +1 -0
- package/dist/utils/appPaths.js +162 -0
- package/dist/utils/appPaths.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +50 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +114 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/standardConfig.d.ts +61 -0
- package/dist/utils/standardConfig.d.ts.map +1 -0
- package/dist/utils/standardConfig.js +109 -0
- package/dist/utils/standardConfig.js.map +1 -0
- package/dist/utils/startupBanner.d.ts +34 -0
- package/dist/utils/startupBanner.d.ts.map +1 -0
- package/dist/utils/startupBanner.js +169 -0
- package/dist/utils/startupBanner.js.map +1 -0
- package/dist/utils/startupLogger.d.ts +45 -0
- package/dist/utils/startupLogger.d.ts.map +1 -0
- package/dist/utils/startupLogger.js +200 -0
- package/dist/utils/startupLogger.js.map +1 -0
- package/package.json +151 -0
- package/src/api/logsRouter.ts +600 -0
- package/src/cli/dev-server.ts +803 -0
- package/src/cli/index.ts +31 -0
- package/src/core/StandardServer.ts +587 -0
- package/src/core/apiResponse.ts +202 -0
- package/src/core/healthCheck.ts +565 -0
- package/src/core/index.ts +80 -0
- package/src/core/logger.ts +1092 -0
- package/src/core/portUtils.ts +319 -0
- package/src/core/storageService.ts +595 -0
- package/src/desktop/bundler.ts +271 -0
- package/src/desktop/index.ts +18 -0
- package/src/desktop/native-modules.ts +289 -0
- package/src/index.ts +142 -0
- package/src/logging/LogCategories.ts +302 -0
- package/src/middleware/aiErrorHandler.ts +278 -0
- package/src/middleware/auth.ts +329 -0
- package/src/middleware/cors.ts +187 -0
- package/src/middleware/errorHandler.ts +103 -0
- package/src/middleware/fileUpload.ts +252 -0
- package/src/middleware/health.ts +206 -0
- package/src/middleware/index.ts +71 -0
- package/src/middleware/openapi.ts +305 -0
- package/src/middleware/requestLogging.ts +92 -0
- package/src/middleware/session.ts +238 -0
- package/src/middleware/validation.ts +603 -0
- package/src/services/aiService.ts +789 -0
- package/src/services/conversationStorage.ts +232 -0
- package/src/services/crossPlatformBuffer.ts +341 -0
- package/src/services/index.ts +47 -0
- package/src/services/networkService.ts +351 -0
- package/src/services/queueService.ts +446 -0
- package/src/services/settingsService.ts +549 -0
- package/src/services/systemMonitor.ts +936 -0
- package/src/services/updateService.ts +334 -0
- package/src/services/websocketEvents.ts +409 -0
- package/src/services/websocketServer.ts +394 -0
- package/src/settings/SettingsSchema.ts +664 -0
- package/src/testing/TestServer.ts +312 -0
- package/src/types/index.ts +154 -0
- package/src/utils/appPaths.ts +196 -0
- package/src/utils/fs-utils.ts +130 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/standardConfig.ts +178 -0
- package/src/utils/startupBanner.ts +287 -0
- package/src/utils/startupLogger.ts +268 -0
- package/ui/dist/index.d.mts +1221 -0
- package/ui/dist/index.d.ts +1221 -0
- package/ui/dist/index.js +73 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/index.mjs +73 -0
- package/ui/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File system utilities to replace fs-extra with native Node.js fs
|
|
3
|
+
* Provides cross-platform compatibility without ESM issues
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import { createReadStream, createWriteStream } from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Ensure a directory exists, creating it if necessary
|
|
12
|
+
*/
|
|
13
|
+
export async function ensureDir(dir: string): Promise<void> {
|
|
14
|
+
await fs.mkdir(dir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check if a path exists
|
|
19
|
+
*/
|
|
20
|
+
export async function pathExists(filePath: string): Promise<boolean> {
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(filePath);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Copy a file or directory
|
|
31
|
+
*/
|
|
32
|
+
export async function copy(src: string, dest: string): Promise<void> {
|
|
33
|
+
const stats = await fs.stat(src);
|
|
34
|
+
|
|
35
|
+
if (stats.isDirectory()) {
|
|
36
|
+
await ensureDir(dest);
|
|
37
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
38
|
+
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const destPath = path.join(dest, entry.name);
|
|
42
|
+
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
await copy(srcPath, destPath);
|
|
45
|
+
} else {
|
|
46
|
+
await fs.copyFile(srcPath, destPath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
await fs.copyFile(src, dest);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Move a file or directory
|
|
56
|
+
*/
|
|
57
|
+
export async function move(
|
|
58
|
+
src: string,
|
|
59
|
+
dest: string,
|
|
60
|
+
options?: { overwrite?: boolean },
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
const { overwrite = true } = options || {};
|
|
63
|
+
|
|
64
|
+
if (!overwrite && (await pathExists(dest))) {
|
|
65
|
+
throw new Error(`Destination already exists: ${dest}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await fs.rename(src, dest);
|
|
70
|
+
} catch (error: any) {
|
|
71
|
+
// If cross-device move, copy then delete
|
|
72
|
+
if (error.code === "EXDEV") {
|
|
73
|
+
await copy(src, dest);
|
|
74
|
+
await fs.rm(src, { recursive: true, force: true });
|
|
75
|
+
} else {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Remove a file or directory
|
|
83
|
+
*/
|
|
84
|
+
export async function remove(filePath: string): Promise<void> {
|
|
85
|
+
await fs.rm(filePath, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Read a JSON file
|
|
90
|
+
*/
|
|
91
|
+
export async function readJson(filePath: string): Promise<any> {
|
|
92
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
93
|
+
return JSON.parse(content);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Write a JSON file
|
|
98
|
+
*/
|
|
99
|
+
export async function writeJson(
|
|
100
|
+
filePath: string,
|
|
101
|
+
data: any,
|
|
102
|
+
options?: { spaces?: number },
|
|
103
|
+
): Promise<void> {
|
|
104
|
+
const { spaces = 2 } = options || {};
|
|
105
|
+
const content = JSON.stringify(data, null, spaces);
|
|
106
|
+
await fs.writeFile(filePath, content, "utf8");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Empty a directory without removing it
|
|
111
|
+
*/
|
|
112
|
+
export async function emptyDir(dir: string): Promise<void> {
|
|
113
|
+
if (await pathExists(dir)) {
|
|
114
|
+
const entries = await fs.readdir(dir);
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
await remove(path.join(dir, entry));
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
await ensureDir(dir);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Re-export native fs methods that don't need replacement
|
|
124
|
+
export { fs };
|
|
125
|
+
export { createReadStream, createWriteStream };
|
|
126
|
+
export const readFile = fs.readFile.bind(fs);
|
|
127
|
+
export const writeFile = fs.writeFile.bind(fs);
|
|
128
|
+
export const readdir = fs.readdir.bind(fs);
|
|
129
|
+
export const stat = fs.stat.bind(fs);
|
|
130
|
+
export const unlink = fs.unlink;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities Module Exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { default as startupLogger } from "./startupLogger.js";
|
|
6
|
+
export * from "../core/apiResponse.js";
|
|
7
|
+
export {
|
|
8
|
+
displayStartupBanner,
|
|
9
|
+
displayMinimalStartup,
|
|
10
|
+
} from "./startupBanner.js";
|
|
11
|
+
export type { StartupBannerOptions } from "./startupBanner.js";
|
|
12
|
+
export { loadStandardConfig, getDefaultPorts } from "./standardConfig.js";
|
|
13
|
+
export type { StandardAppConfig } from "./standardConfig.js";
|
|
14
|
+
export * from "./appPaths.js";
|
|
15
|
+
export * as fsUtils from "./fs-utils.js";
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Configuration Loader
|
|
3
|
+
* Provides consistent config loading across all SuperDangerous applications
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync, existsSync } from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
export interface StandardAppConfig {
|
|
10
|
+
app: {
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
};
|
|
16
|
+
server: {
|
|
17
|
+
port: number;
|
|
18
|
+
host: string;
|
|
19
|
+
webPort?: number;
|
|
20
|
+
websocketPort?: number;
|
|
21
|
+
};
|
|
22
|
+
ui?: {
|
|
23
|
+
theme?: "light" | "dark";
|
|
24
|
+
branding?: {
|
|
25
|
+
logo?: string;
|
|
26
|
+
primaryColor?: string;
|
|
27
|
+
secondaryColor?: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
logging?: {
|
|
31
|
+
level?: string;
|
|
32
|
+
directory?: string;
|
|
33
|
+
file_pattern?: string;
|
|
34
|
+
maxSize?: string;
|
|
35
|
+
maxFiles?: string;
|
|
36
|
+
console_level?: string;
|
|
37
|
+
};
|
|
38
|
+
desktop?: {
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
window?: {
|
|
41
|
+
width?: number;
|
|
42
|
+
height?: number;
|
|
43
|
+
minWidth?: number;
|
|
44
|
+
minHeight?: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
defaults?: {
|
|
48
|
+
timeout?: number;
|
|
49
|
+
retryAttempts?: number;
|
|
50
|
+
};
|
|
51
|
+
[key: string]: any; // Allow app-specific config
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load application configuration with environment variable overrides
|
|
56
|
+
*/
|
|
57
|
+
export function loadStandardConfig(dirname: string): StandardAppConfig {
|
|
58
|
+
// Load package.json for defaults
|
|
59
|
+
const packageJsonPath = path.join(dirname, "../package.json");
|
|
60
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
61
|
+
|
|
62
|
+
// Load app.json config if it exists
|
|
63
|
+
const configPath = path.join(dirname, "../data/config/app.json");
|
|
64
|
+
let appConfig: any = {};
|
|
65
|
+
|
|
66
|
+
if (existsSync(configPath)) {
|
|
67
|
+
appConfig = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Normalize config structure (handle different formats)
|
|
71
|
+
const normalizedConfig: StandardAppConfig = {
|
|
72
|
+
app: {
|
|
73
|
+
name:
|
|
74
|
+
process.env.APP_NAME ||
|
|
75
|
+
appConfig.app?.name ||
|
|
76
|
+
packageJson.name ||
|
|
77
|
+
"SuperDangerous App",
|
|
78
|
+
version: appConfig.app?.version || packageJson.version || "1.0.0",
|
|
79
|
+
title:
|
|
80
|
+
process.env.APP_TITLE ||
|
|
81
|
+
appConfig.app?.title ||
|
|
82
|
+
appConfig.app_title || // Legacy support
|
|
83
|
+
packageJson.displayName || // Some packages use displayName
|
|
84
|
+
packageJson.name
|
|
85
|
+
?.replace(/@[^/]+\//, "")
|
|
86
|
+
.replace(/-/g, " ")
|
|
87
|
+
.replace(/\b\w/g, (l: string) => l.toUpperCase()) ||
|
|
88
|
+
"SuperDangerous Application",
|
|
89
|
+
description:
|
|
90
|
+
process.env.APP_DESCRIPTION ||
|
|
91
|
+
appConfig.app?.description ||
|
|
92
|
+
packageJson.description,
|
|
93
|
+
},
|
|
94
|
+
server: {
|
|
95
|
+
port: Number(
|
|
96
|
+
process.env.PORT ||
|
|
97
|
+
process.env.API_PORT ||
|
|
98
|
+
appConfig.server?.port ||
|
|
99
|
+
appConfig.server?.api?.port ||
|
|
100
|
+
appConfig.api?.port ||
|
|
101
|
+
8080,
|
|
102
|
+
),
|
|
103
|
+
host:
|
|
104
|
+
process.env.HOST ||
|
|
105
|
+
appConfig.server?.host ||
|
|
106
|
+
appConfig.server?.api?.host ||
|
|
107
|
+
appConfig.api?.host ||
|
|
108
|
+
"0.0.0.0",
|
|
109
|
+
webPort: Number(
|
|
110
|
+
process.env.WEB_PORT ||
|
|
111
|
+
appConfig.server?.webPort ||
|
|
112
|
+
appConfig.server?.web?.port ||
|
|
113
|
+
appConfig.webPort ||
|
|
114
|
+
5173,
|
|
115
|
+
),
|
|
116
|
+
websocketPort: Number(
|
|
117
|
+
process.env.WEBSOCKET_PORT ||
|
|
118
|
+
appConfig.server?.websocketPort ||
|
|
119
|
+
appConfig.server?.websocket?.port ||
|
|
120
|
+
appConfig.webSocketPort ||
|
|
121
|
+
appConfig.server?.port ||
|
|
122
|
+
appConfig.api?.port,
|
|
123
|
+
),
|
|
124
|
+
},
|
|
125
|
+
ui: appConfig.ui || {},
|
|
126
|
+
logging: {
|
|
127
|
+
level: process.env.LOG_LEVEL || appConfig.logging?.level || "INFO",
|
|
128
|
+
directory: appConfig.logging?.directory || "logs",
|
|
129
|
+
file_pattern: appConfig.logging?.file_pattern || "app.log",
|
|
130
|
+
maxSize: appConfig.logging?.maxSize || "20m",
|
|
131
|
+
maxFiles: appConfig.logging?.maxFiles || "14d",
|
|
132
|
+
console_level:
|
|
133
|
+
process.env.CONSOLE_LOG_LEVEL ||
|
|
134
|
+
appConfig.logging?.console_level ||
|
|
135
|
+
"INFO",
|
|
136
|
+
},
|
|
137
|
+
desktop: {
|
|
138
|
+
enabled:
|
|
139
|
+
process.env.DESKTOP === "true" || appConfig.desktop?.enabled || false,
|
|
140
|
+
...appConfig.desktop,
|
|
141
|
+
},
|
|
142
|
+
defaults: appConfig.defaults || {
|
|
143
|
+
timeout: 5000,
|
|
144
|
+
retryAttempts: 3,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Merge in any app-specific config
|
|
149
|
+
Object.keys(appConfig).forEach((key) => {
|
|
150
|
+
if (
|
|
151
|
+
![
|
|
152
|
+
"app",
|
|
153
|
+
"server",
|
|
154
|
+
"api",
|
|
155
|
+
"ui",
|
|
156
|
+
"logging",
|
|
157
|
+
"desktop",
|
|
158
|
+
"defaults",
|
|
159
|
+
].includes(key)
|
|
160
|
+
) {
|
|
161
|
+
normalizedConfig[key] = appConfig[key];
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return normalizedConfig;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get default ports for an application
|
|
170
|
+
* Applications can override these by providing their own configuration
|
|
171
|
+
*/
|
|
172
|
+
export function getDefaultPorts(_appName: string): {
|
|
173
|
+
api: number;
|
|
174
|
+
web: number;
|
|
175
|
+
} {
|
|
176
|
+
// Return sensible defaults - applications should define their own ports
|
|
177
|
+
return { api: 8080, web: 3000 };
|
|
178
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized Startup Banner for SuperDangerous Applications
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
|
|
9
|
+
// Force colors to ensure consistent output
|
|
10
|
+
chalk.level = 3; // Full color support
|
|
11
|
+
|
|
12
|
+
// Get framework version dynamically
|
|
13
|
+
function getFrameworkVersion(): string {
|
|
14
|
+
// Try multiple strategies to find the framework version
|
|
15
|
+
const strategies = [
|
|
16
|
+
// Strategy 1: Check if we're in the framework itself (during development)
|
|
17
|
+
() => {
|
|
18
|
+
const localPkg = path.join(__dirname, "../../package.json");
|
|
19
|
+
if (fs.existsSync(localPkg)) {
|
|
20
|
+
const pkg = JSON.parse(fs.readFileSync(localPkg, "utf-8"));
|
|
21
|
+
if (pkg.name === "@superdangerous/app-framework") {
|
|
22
|
+
return pkg.version;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
},
|
|
27
|
+
// Strategy 2: Check node_modules in current working directory
|
|
28
|
+
() => {
|
|
29
|
+
const nodeModulesPath = path.join(
|
|
30
|
+
process.cwd(),
|
|
31
|
+
"node_modules",
|
|
32
|
+
"@superdangerous",
|
|
33
|
+
"app-framework",
|
|
34
|
+
"package.json",
|
|
35
|
+
);
|
|
36
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
37
|
+
const pkg = JSON.parse(fs.readFileSync(nodeModulesPath, "utf-8"));
|
|
38
|
+
return pkg.version;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
},
|
|
42
|
+
// Strategy 3: Try require.resolve to find the module
|
|
43
|
+
() => {
|
|
44
|
+
try {
|
|
45
|
+
const pkgPath = require.resolve(
|
|
46
|
+
"@superdangerous/app-framework/package.json",
|
|
47
|
+
{ paths: [process.cwd()] },
|
|
48
|
+
);
|
|
49
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
50
|
+
return pkg.version;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
for (const strategy of strategies) {
|
|
58
|
+
try {
|
|
59
|
+
const version = strategy();
|
|
60
|
+
if (version) return version;
|
|
61
|
+
} catch {
|
|
62
|
+
// Try next strategy
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return "unknown";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const version = getFrameworkVersion();
|
|
70
|
+
|
|
71
|
+
export interface BannerOptions {
|
|
72
|
+
appName: string;
|
|
73
|
+
appVersion: string;
|
|
74
|
+
environment?: string;
|
|
75
|
+
port?: number;
|
|
76
|
+
additionalInfo?: string[];
|
|
77
|
+
showTips?: boolean;
|
|
78
|
+
showCredits?: boolean;
|
|
79
|
+
color?: "blue" | "green" | "yellow" | "red";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface StartupBannerOptions extends BannerOptions {
|
|
83
|
+
appName: string;
|
|
84
|
+
appVersion: string;
|
|
85
|
+
packageName?: string; // Optional package name
|
|
86
|
+
description?: string;
|
|
87
|
+
port: number; // API port
|
|
88
|
+
webPort?: number; // Optional separate web UI port
|
|
89
|
+
webSocketPort?: number; // Optional WebSocket port
|
|
90
|
+
environment?: string;
|
|
91
|
+
startTime?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Display a standardized startup banner for SuperDangerous applications
|
|
96
|
+
* All apps should use this exact same format for consistency
|
|
97
|
+
*/
|
|
98
|
+
export function displayStartupBanner(options: StartupBannerOptions): void {
|
|
99
|
+
const {
|
|
100
|
+
appName,
|
|
101
|
+
appVersion,
|
|
102
|
+
description,
|
|
103
|
+
port,
|
|
104
|
+
webPort, // Use separate web port if provided
|
|
105
|
+
webSocketPort, // WebSocket port
|
|
106
|
+
environment = process.env.NODE_ENV || "development",
|
|
107
|
+
startTime,
|
|
108
|
+
} = options;
|
|
109
|
+
|
|
110
|
+
const width = 50; // Reduced width to match horizontal dividers
|
|
111
|
+
const border = "─".repeat(width); // Full width for top/bottom borders
|
|
112
|
+
|
|
113
|
+
// Calculate startup time if provided
|
|
114
|
+
const startupTime = startTime
|
|
115
|
+
? `${((Date.now() - startTime) / 1000).toFixed(1)}s`
|
|
116
|
+
: "0.0s";
|
|
117
|
+
|
|
118
|
+
// Helper to create a line with proper padding
|
|
119
|
+
const makeLine = (
|
|
120
|
+
content: string,
|
|
121
|
+
align: "center" | "left" = "center",
|
|
122
|
+
): string => {
|
|
123
|
+
// eslint-disable-next-line no-control-regex
|
|
124
|
+
const visibleLength = content.replace(/\x1b\[[0-9;]*m/g, "").length; // Strip ANSI codes for length calculation
|
|
125
|
+
if (align === "center") {
|
|
126
|
+
const leftPad = Math.max(0, Math.floor((width - visibleLength) / 2));
|
|
127
|
+
const rightPad = Math.max(0, width - visibleLength - leftPad);
|
|
128
|
+
return (
|
|
129
|
+
chalk.gray("│") +
|
|
130
|
+
" ".repeat(leftPad) +
|
|
131
|
+
content +
|
|
132
|
+
" ".repeat(rightPad) +
|
|
133
|
+
chalk.gray("│")
|
|
134
|
+
);
|
|
135
|
+
} else {
|
|
136
|
+
const padding = Math.max(0, width - visibleLength);
|
|
137
|
+
return chalk.gray("│") + content + " ".repeat(padding) + chalk.gray("│");
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Helper to wrap text
|
|
142
|
+
const wrapText = (text: string, maxWidth: number): string[] => {
|
|
143
|
+
const words = text.split(" ");
|
|
144
|
+
const lines: string[] = [];
|
|
145
|
+
let currentLine = "";
|
|
146
|
+
|
|
147
|
+
for (const word of words) {
|
|
148
|
+
if ((currentLine + " " + word).trim().length <= maxWidth) {
|
|
149
|
+
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
|
150
|
+
} else {
|
|
151
|
+
if (currentLine) lines.push(currentLine);
|
|
152
|
+
currentLine = word;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (currentLine) lines.push(currentLine);
|
|
156
|
+
|
|
157
|
+
return lines;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const emptyLine = chalk.gray("│") + " ".repeat(width) + chalk.gray("│");
|
|
161
|
+
const separator =
|
|
162
|
+
chalk.gray("│ ") + chalk.gray("─".repeat(width - 2)) + chalk.gray(" │");
|
|
163
|
+
|
|
164
|
+
// Build the banner
|
|
165
|
+
console.log("");
|
|
166
|
+
console.log(chalk.gray("╭" + border + "╮"));
|
|
167
|
+
console.log(chalk.gray(emptyLine));
|
|
168
|
+
|
|
169
|
+
// App name in light gray
|
|
170
|
+
console.log(makeLine(chalk.gray(appName)));
|
|
171
|
+
console.log(emptyLine);
|
|
172
|
+
|
|
173
|
+
// Version in amber to match Ctrl+C
|
|
174
|
+
console.log(makeLine(chalk.yellow(`v${appVersion}`)));
|
|
175
|
+
console.log(emptyLine);
|
|
176
|
+
|
|
177
|
+
// Description (wrapped if needed)
|
|
178
|
+
if (description) {
|
|
179
|
+
const wrappedLines = wrapText(description, width - 4);
|
|
180
|
+
for (const line of wrappedLines) {
|
|
181
|
+
console.log(makeLine(line));
|
|
182
|
+
}
|
|
183
|
+
console.log(emptyLine);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log(separator);
|
|
187
|
+
console.log(emptyLine);
|
|
188
|
+
|
|
189
|
+
// URLs - no emojis, keys dark gray, values light gray
|
|
190
|
+
if (webPort && webPort !== port) {
|
|
191
|
+
// Both web UI and API are configured on different ports
|
|
192
|
+
console.log(
|
|
193
|
+
makeLine(
|
|
194
|
+
`${chalk.gray(" Web UI :")} ${chalk.gray(`http://localhost:${webPort}`)}`,
|
|
195
|
+
"left",
|
|
196
|
+
),
|
|
197
|
+
);
|
|
198
|
+
console.log(
|
|
199
|
+
makeLine(
|
|
200
|
+
`${chalk.gray(" API :")} ${chalk.gray(`http://localhost:${port}/api`)}`,
|
|
201
|
+
"left",
|
|
202
|
+
),
|
|
203
|
+
);
|
|
204
|
+
} else if (webPort === port) {
|
|
205
|
+
// Web UI and API share the same port (production mode)
|
|
206
|
+
console.log(
|
|
207
|
+
makeLine(
|
|
208
|
+
`${chalk.gray(" Web UI :")} ${chalk.gray(`http://localhost:${port}`)}`,
|
|
209
|
+
"left",
|
|
210
|
+
),
|
|
211
|
+
);
|
|
212
|
+
console.log(
|
|
213
|
+
makeLine(
|
|
214
|
+
`${chalk.gray(" API :")} ${chalk.gray(`http://localhost:${port}/api`)}`,
|
|
215
|
+
"left",
|
|
216
|
+
),
|
|
217
|
+
);
|
|
218
|
+
} else {
|
|
219
|
+
// API-only mode
|
|
220
|
+
console.log(
|
|
221
|
+
makeLine(
|
|
222
|
+
`${chalk.gray(" API Server :")} ${chalk.gray(`http://localhost:${port}`)}`,
|
|
223
|
+
"left",
|
|
224
|
+
),
|
|
225
|
+
);
|
|
226
|
+
console.log(
|
|
227
|
+
makeLine(
|
|
228
|
+
`${chalk.gray(" Endpoints :")} ${chalk.gray(`http://localhost:${port}/api/*`)}`,
|
|
229
|
+
"left",
|
|
230
|
+
),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
console.log(
|
|
234
|
+
makeLine(
|
|
235
|
+
`${chalk.gray(" WebSocket :")} ${chalk.gray(`ws://localhost:${webSocketPort || port}`)}`,
|
|
236
|
+
"left",
|
|
237
|
+
),
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
console.log(emptyLine);
|
|
241
|
+
console.log(separator);
|
|
242
|
+
console.log(emptyLine);
|
|
243
|
+
|
|
244
|
+
// Status lines
|
|
245
|
+
console.log(
|
|
246
|
+
makeLine(`${chalk.gray(" Ready in")} ${chalk.green(startupTime)}`, "left"),
|
|
247
|
+
);
|
|
248
|
+
console.log(
|
|
249
|
+
makeLine(
|
|
250
|
+
`${chalk.gray(" Environment:")} ${chalk.gray(environment)}`,
|
|
251
|
+
"left",
|
|
252
|
+
),
|
|
253
|
+
);
|
|
254
|
+
console.log(
|
|
255
|
+
makeLine(
|
|
256
|
+
`${chalk.gray(" Framework:")} ${chalk.gray(`@superdangerous/app-framework v${version}`)}`,
|
|
257
|
+
"left",
|
|
258
|
+
),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
console.log(emptyLine);
|
|
262
|
+
console.log(separator);
|
|
263
|
+
console.log(emptyLine);
|
|
264
|
+
|
|
265
|
+
console.log(
|
|
266
|
+
makeLine(
|
|
267
|
+
`${chalk.gray(" Press")} ${chalk.yellow("Ctrl+C")} ${chalk.gray("to stop")}`,
|
|
268
|
+
"left",
|
|
269
|
+
),
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
console.log(chalk.gray(emptyLine));
|
|
273
|
+
console.log(chalk.gray("╰" + border + "╯"));
|
|
274
|
+
console.log("");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Display a minimal startup message (for silent mode)
|
|
279
|
+
*/
|
|
280
|
+
export function displayMinimalStartup(appName: string, port: number): void {
|
|
281
|
+
console.log(
|
|
282
|
+
chalk.green("✓"),
|
|
283
|
+
chalk.bold(appName),
|
|
284
|
+
"started on port",
|
|
285
|
+
chalk.cyan(port),
|
|
286
|
+
);
|
|
287
|
+
}
|