@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,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation Storage Service
|
|
3
|
+
* Provides persistent storage for AI conversations using lowdb
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Low } from "lowdb";
|
|
7
|
+
import { JSONFile } from "lowdb/node";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { ensureDir } from "fs-extra";
|
|
10
|
+
import { createLogger } from "../core/index.js";
|
|
11
|
+
let logger: any; // Will be initialized when needed
|
|
12
|
+
|
|
13
|
+
function ensureLogger() {
|
|
14
|
+
if (!logger) {
|
|
15
|
+
logger = createLogger("ConversationStorage");
|
|
16
|
+
}
|
|
17
|
+
return logger;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Message {
|
|
21
|
+
role: "user" | "assistant" | "system";
|
|
22
|
+
content: string;
|
|
23
|
+
timestamp?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface Conversation {
|
|
27
|
+
id: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
messages: Message[];
|
|
30
|
+
metadata?: Record<string, any>;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ConversationsDB {
|
|
36
|
+
conversations: Record<string, Conversation>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const defaultData: ConversationsDB = {
|
|
40
|
+
conversations: {},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class ConversationStorage {
|
|
44
|
+
private db: Low<ConversationsDB> | null = null;
|
|
45
|
+
private initialized: boolean = false;
|
|
46
|
+
|
|
47
|
+
async initialize(): Promise<void> {
|
|
48
|
+
if (this.initialized) return;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Ensure data directory exists
|
|
52
|
+
const dataDir = path.join(process.cwd(), "data");
|
|
53
|
+
await ensureDir(dataDir);
|
|
54
|
+
|
|
55
|
+
// Initialize lowdb with JSON file adapter
|
|
56
|
+
const dbPath = path.join(dataDir, "conversations.json");
|
|
57
|
+
const adapter = new JSONFile<ConversationsDB>(dbPath);
|
|
58
|
+
this.db = new Low<ConversationsDB>(adapter, defaultData);
|
|
59
|
+
|
|
60
|
+
// Read data from file
|
|
61
|
+
await this.db.read();
|
|
62
|
+
|
|
63
|
+
// Initialize with default data if file doesn't exist
|
|
64
|
+
if (!this.db.data) {
|
|
65
|
+
this.db.data = defaultData;
|
|
66
|
+
await this.db.write();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Ensure conversations object exists
|
|
70
|
+
if (!this.db.data.conversations) {
|
|
71
|
+
this.db.data.conversations = {};
|
|
72
|
+
await this.db.write();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.initialized = true;
|
|
76
|
+
ensureLogger().info("Conversation storage initialized");
|
|
77
|
+
} catch (_error) {
|
|
78
|
+
ensureLogger().error(
|
|
79
|
+
"Failed to initialize conversation storage:",
|
|
80
|
+
_error,
|
|
81
|
+
);
|
|
82
|
+
throw _error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async getConversation(conversationId: string): Promise<Conversation | null> {
|
|
87
|
+
await this.initialize();
|
|
88
|
+
return this.db!.data!.conversations[conversationId] || null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async saveConversation(
|
|
92
|
+
conversationId: string,
|
|
93
|
+
conversation: Partial<Conversation>,
|
|
94
|
+
): Promise<Conversation> {
|
|
95
|
+
await this.initialize();
|
|
96
|
+
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
const existing = this.db!.data!.conversations[conversationId];
|
|
99
|
+
const fullConversation: Conversation = {
|
|
100
|
+
...existing,
|
|
101
|
+
...conversation,
|
|
102
|
+
id: conversationId,
|
|
103
|
+
messages: conversation.messages ?? existing?.messages ?? [],
|
|
104
|
+
createdAt: existing?.createdAt ?? conversation.createdAt ?? now,
|
|
105
|
+
updatedAt: now,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
this.db!.data!.conversations[conversationId] = fullConversation;
|
|
109
|
+
await this.db!.write();
|
|
110
|
+
|
|
111
|
+
ensureLogger().debug(`Saved conversation: ${conversationId}`);
|
|
112
|
+
return fullConversation;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async deleteConversation(conversationId: string): Promise<boolean> {
|
|
116
|
+
await this.initialize();
|
|
117
|
+
|
|
118
|
+
if (this.db!.data!.conversations[conversationId]) {
|
|
119
|
+
delete this.db!.data!.conversations[conversationId];
|
|
120
|
+
await this.db!.write();
|
|
121
|
+
ensureLogger().debug(`Deleted conversation: ${conversationId}`);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async getAllConversations(): Promise<Conversation[]> {
|
|
129
|
+
await this.initialize();
|
|
130
|
+
return Object.values(this.db!.data!.conversations);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async getRecentConversations(limit: number = 10): Promise<Conversation[]> {
|
|
134
|
+
await this.initialize();
|
|
135
|
+
const conversations = Object.values(this.db!.data!.conversations);
|
|
136
|
+
|
|
137
|
+
return conversations
|
|
138
|
+
.sort(
|
|
139
|
+
(a, b) =>
|
|
140
|
+
new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
|
|
141
|
+
)
|
|
142
|
+
.slice(0, limit);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async addMessage(
|
|
146
|
+
conversationId: string,
|
|
147
|
+
message: Message,
|
|
148
|
+
): Promise<Conversation> {
|
|
149
|
+
await this.initialize();
|
|
150
|
+
|
|
151
|
+
let conversation = this.db!.data!.conversations[conversationId];
|
|
152
|
+
|
|
153
|
+
if (!conversation) {
|
|
154
|
+
conversation = {
|
|
155
|
+
id: conversationId,
|
|
156
|
+
messages: [],
|
|
157
|
+
createdAt: new Date().toISOString(),
|
|
158
|
+
updatedAt: new Date().toISOString(),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
message.timestamp = message.timestamp || new Date().toISOString();
|
|
163
|
+
conversation.messages.push(message);
|
|
164
|
+
conversation.updatedAt = new Date().toISOString();
|
|
165
|
+
|
|
166
|
+
this.db!.data!.conversations[conversationId] = conversation;
|
|
167
|
+
await this.db!.write();
|
|
168
|
+
|
|
169
|
+
return conversation;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async clearAllConversations(): Promise<void> {
|
|
173
|
+
await this.initialize();
|
|
174
|
+
this.db!.data!.conversations = {};
|
|
175
|
+
await this.db!.write();
|
|
176
|
+
ensureLogger().info("Cleared all conversations");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async exportConversations(): Promise<ConversationsDB> {
|
|
180
|
+
await this.initialize();
|
|
181
|
+
return { ...this.db!.data! };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async importConversations(data: ConversationsDB): Promise<void> {
|
|
185
|
+
await this.initialize();
|
|
186
|
+
this.db!.data = data;
|
|
187
|
+
await this.db!.write();
|
|
188
|
+
ensureLogger().info("Imported conversations");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async getConversationStats(): Promise<Record<string, any>> {
|
|
192
|
+
await this.initialize();
|
|
193
|
+
const conversations = Object.values(this.db!.data!.conversations);
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
total: conversations.length,
|
|
197
|
+
totalMessages: conversations.reduce(
|
|
198
|
+
(sum, c) => sum + c.messages.length,
|
|
199
|
+
0,
|
|
200
|
+
),
|
|
201
|
+
averageLength:
|
|
202
|
+
conversations.length > 0
|
|
203
|
+
? conversations.reduce((sum, c) => sum + c.messages.length, 0) /
|
|
204
|
+
conversations.length
|
|
205
|
+
: 0,
|
|
206
|
+
oldestConversation:
|
|
207
|
+
conversations.length > 0
|
|
208
|
+
? conversations.reduce((oldest, c) =>
|
|
209
|
+
new Date(c.createdAt) < new Date(oldest.createdAt) ? c : oldest,
|
|
210
|
+
).createdAt
|
|
211
|
+
: null,
|
|
212
|
+
newestConversation:
|
|
213
|
+
conversations.length > 0
|
|
214
|
+
? conversations.reduce((newest, c) =>
|
|
215
|
+
new Date(c.createdAt) > new Date(newest.createdAt) ? c : newest,
|
|
216
|
+
).createdAt
|
|
217
|
+
: null,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Singleton instance
|
|
223
|
+
let conversationStorage: ConversationStorage | null = null;
|
|
224
|
+
|
|
225
|
+
export function getConversationStorage(): ConversationStorage {
|
|
226
|
+
if (!conversationStorage) {
|
|
227
|
+
conversationStorage = new ConversationStorage();
|
|
228
|
+
}
|
|
229
|
+
return conversationStorage;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export default ConversationStorage;
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Platform Buffer Handling Module
|
|
3
|
+
*
|
|
4
|
+
* Ensures consistent data representation across ARM and x86 architectures
|
|
5
|
+
* by using explicit buffer operations that are not affected by processor endianness.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type Endianness = "LE" | "BE";
|
|
9
|
+
export type DataType =
|
|
10
|
+
| "uint16"
|
|
11
|
+
| "int16"
|
|
12
|
+
| "uint32"
|
|
13
|
+
| "int32"
|
|
14
|
+
| "float32"
|
|
15
|
+
| "float64"
|
|
16
|
+
| "bool";
|
|
17
|
+
|
|
18
|
+
export interface BufferOptions {
|
|
19
|
+
endian?: Endianness;
|
|
20
|
+
wordSwap?: boolean;
|
|
21
|
+
byteSwap?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class CrossPlatformBuffer {
|
|
25
|
+
private systemEndianness: Endianness;
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
// Detect system endianness for debugging/logging purposes
|
|
29
|
+
this.systemEndianness = this.detectSystemEndianness();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Detect system endianness (for logging/debugging only)
|
|
34
|
+
*/
|
|
35
|
+
private detectSystemEndianness(): Endianness {
|
|
36
|
+
const arrayBuffer = new ArrayBuffer(2);
|
|
37
|
+
const uint8Array = new Uint8Array(arrayBuffer);
|
|
38
|
+
const uint16Array = new Uint16Array(arrayBuffer);
|
|
39
|
+
|
|
40
|
+
uint16Array[0] = 0x1234;
|
|
41
|
+
|
|
42
|
+
if (uint8Array[0] === 0x12) {
|
|
43
|
+
return "BE"; // Big Endian
|
|
44
|
+
} else {
|
|
45
|
+
return "LE"; // Little Endian
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get system endianness
|
|
51
|
+
*/
|
|
52
|
+
getSystemEndianness(): Endianness {
|
|
53
|
+
return this.systemEndianness;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Convert float32 to two 16-bit registers with explicit endianness control
|
|
58
|
+
*/
|
|
59
|
+
float32ToRegisters(
|
|
60
|
+
value: number,
|
|
61
|
+
endian: Endianness = "LE",
|
|
62
|
+
wordSwap: boolean = false,
|
|
63
|
+
byteSwap: boolean = false,
|
|
64
|
+
): [number, number] {
|
|
65
|
+
// Create a buffer to hold the float32
|
|
66
|
+
const buffer = new ArrayBuffer(4);
|
|
67
|
+
const float32View = new Float32Array(buffer);
|
|
68
|
+
const dataView = new DataView(buffer);
|
|
69
|
+
|
|
70
|
+
// Write the float32 value
|
|
71
|
+
float32View[0] = value;
|
|
72
|
+
|
|
73
|
+
// Read as two 16-bit values with specified endianness
|
|
74
|
+
let reg1: number, reg2: number;
|
|
75
|
+
|
|
76
|
+
if (endian === "BE") {
|
|
77
|
+
// Big Endian: most significant word first
|
|
78
|
+
reg1 = dataView.getUint16(0, false); // Big endian read
|
|
79
|
+
reg2 = dataView.getUint16(2, false);
|
|
80
|
+
} else {
|
|
81
|
+
// Little Endian: least significant word first
|
|
82
|
+
reg1 = dataView.getUint16(0, true); // Little endian read
|
|
83
|
+
reg2 = dataView.getUint16(2, true);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Apply word swap if needed
|
|
87
|
+
if (wordSwap) {
|
|
88
|
+
[reg1, reg2] = [reg2, reg1];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Apply byte swap within each word if needed
|
|
92
|
+
if (byteSwap) {
|
|
93
|
+
reg1 = ((reg1 & 0xff) << 8) | ((reg1 >> 8) & 0xff);
|
|
94
|
+
reg2 = ((reg2 & 0xff) << 8) | ((reg2 >> 8) & 0xff);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [reg1, reg2];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Convert two 16-bit registers to float32 with explicit endianness control
|
|
102
|
+
*/
|
|
103
|
+
registersToFloat32(
|
|
104
|
+
reg1: number,
|
|
105
|
+
reg2: number,
|
|
106
|
+
endian: Endianness = "LE",
|
|
107
|
+
wordSwap: boolean = false,
|
|
108
|
+
byteSwap: boolean = false,
|
|
109
|
+
): number {
|
|
110
|
+
// Apply byte swap within each word if needed
|
|
111
|
+
if (byteSwap) {
|
|
112
|
+
reg1 = ((reg1 & 0xff) << 8) | ((reg1 >> 8) & 0xff);
|
|
113
|
+
reg2 = ((reg2 & 0xff) << 8) | ((reg2 >> 8) & 0xff);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Apply word swap if needed
|
|
117
|
+
if (wordSwap) {
|
|
118
|
+
[reg1, reg2] = [reg2, reg1];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Create a buffer and write the registers
|
|
122
|
+
const buffer = new ArrayBuffer(4);
|
|
123
|
+
const dataView = new DataView(buffer);
|
|
124
|
+
|
|
125
|
+
if (endian === "BE") {
|
|
126
|
+
// Big Endian: write as big endian
|
|
127
|
+
dataView.setUint16(0, reg1, false);
|
|
128
|
+
dataView.setUint16(2, reg2, false);
|
|
129
|
+
} else {
|
|
130
|
+
// Little Endian: write as little endian
|
|
131
|
+
dataView.setUint16(0, reg1, true);
|
|
132
|
+
dataView.setUint16(2, reg2, true);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Read as float32
|
|
136
|
+
const float32View = new Float32Array(buffer);
|
|
137
|
+
return float32View[0];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Convert int32 to two 16-bit registers
|
|
142
|
+
*/
|
|
143
|
+
int32ToRegisters(
|
|
144
|
+
value: number,
|
|
145
|
+
endian: Endianness = "LE",
|
|
146
|
+
wordSwap: boolean = false,
|
|
147
|
+
): [number, number] {
|
|
148
|
+
const buffer = new ArrayBuffer(4);
|
|
149
|
+
const dataView = new DataView(buffer);
|
|
150
|
+
|
|
151
|
+
// Write the int32 value
|
|
152
|
+
dataView.setInt32(0, value, endian === "LE");
|
|
153
|
+
|
|
154
|
+
// Read as two 16-bit values
|
|
155
|
+
let reg1 = dataView.getUint16(0, endian === "LE");
|
|
156
|
+
let reg2 = dataView.getUint16(2, endian === "LE");
|
|
157
|
+
|
|
158
|
+
if (wordSwap) {
|
|
159
|
+
[reg1, reg2] = [reg2, reg1];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return [reg1, reg2];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Convert two 16-bit registers to int32
|
|
167
|
+
*/
|
|
168
|
+
registersToInt32(
|
|
169
|
+
reg1: number,
|
|
170
|
+
reg2: number,
|
|
171
|
+
endian: Endianness = "LE",
|
|
172
|
+
wordSwap: boolean = false,
|
|
173
|
+
): number {
|
|
174
|
+
if (wordSwap) {
|
|
175
|
+
[reg1, reg2] = [reg2, reg1];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const buffer = new ArrayBuffer(4);
|
|
179
|
+
const dataView = new DataView(buffer);
|
|
180
|
+
|
|
181
|
+
dataView.setUint16(0, reg1, endian === "LE");
|
|
182
|
+
dataView.setUint16(2, reg2, endian === "LE");
|
|
183
|
+
|
|
184
|
+
return dataView.getInt32(0, endian === "LE");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Convert uint32 to two 16-bit registers
|
|
189
|
+
*/
|
|
190
|
+
uint32ToRegisters(
|
|
191
|
+
value: number,
|
|
192
|
+
endian: Endianness = "LE",
|
|
193
|
+
wordSwap: boolean = false,
|
|
194
|
+
): [number, number] {
|
|
195
|
+
const buffer = new ArrayBuffer(4);
|
|
196
|
+
const dataView = new DataView(buffer);
|
|
197
|
+
|
|
198
|
+
// Write the uint32 value
|
|
199
|
+
dataView.setUint32(0, value, endian === "LE");
|
|
200
|
+
|
|
201
|
+
// Read as two 16-bit values
|
|
202
|
+
let reg1 = dataView.getUint16(0, endian === "LE");
|
|
203
|
+
let reg2 = dataView.getUint16(2, endian === "LE");
|
|
204
|
+
|
|
205
|
+
if (wordSwap) {
|
|
206
|
+
[reg1, reg2] = [reg2, reg1];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return [reg1, reg2];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Convert two 16-bit registers to uint32
|
|
214
|
+
*/
|
|
215
|
+
registersToUint32(
|
|
216
|
+
reg1: number,
|
|
217
|
+
reg2: number,
|
|
218
|
+
endian: Endianness = "LE",
|
|
219
|
+
wordSwap: boolean = false,
|
|
220
|
+
): number {
|
|
221
|
+
if (wordSwap) {
|
|
222
|
+
[reg1, reg2] = [reg2, reg1];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const buffer = new ArrayBuffer(4);
|
|
226
|
+
const dataView = new DataView(buffer);
|
|
227
|
+
|
|
228
|
+
dataView.setUint16(0, reg1, endian === "LE");
|
|
229
|
+
dataView.setUint16(2, reg2, endian === "LE");
|
|
230
|
+
|
|
231
|
+
return dataView.getUint32(0, endian === "LE");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Convert boolean to register value
|
|
236
|
+
*/
|
|
237
|
+
boolToRegister(value: boolean): number {
|
|
238
|
+
return value ? 1 : 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Convert register value to boolean
|
|
243
|
+
*/
|
|
244
|
+
registerToBool(value: number): boolean {
|
|
245
|
+
return value !== 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Convert int16 to register with proper sign extension
|
|
250
|
+
*/
|
|
251
|
+
int16ToRegister(value: number): number {
|
|
252
|
+
// Ensure value is within int16 range
|
|
253
|
+
value = Math.max(-32768, Math.min(32767, value));
|
|
254
|
+
|
|
255
|
+
// Convert to unsigned representation
|
|
256
|
+
if (value < 0) {
|
|
257
|
+
return 0x10000 + value; // Two's complement
|
|
258
|
+
}
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Convert register to int16 with proper sign handling
|
|
264
|
+
*/
|
|
265
|
+
registerToInt16(value: number): number {
|
|
266
|
+
// Check if the sign bit is set
|
|
267
|
+
if (value & 0x8000) {
|
|
268
|
+
// Negative number in two's complement
|
|
269
|
+
return value - 0x10000;
|
|
270
|
+
}
|
|
271
|
+
return value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Convert string to register array
|
|
276
|
+
*/
|
|
277
|
+
stringToRegisters(str: string, maxLength: number = 32): number[] {
|
|
278
|
+
const registers: number[] = [];
|
|
279
|
+
const buffer = Buffer.from(str, "utf8");
|
|
280
|
+
|
|
281
|
+
// Pad with zeros to ensure even number of bytes
|
|
282
|
+
const paddedLength = Math.min(maxLength, Math.ceil(buffer.length / 2) * 2);
|
|
283
|
+
|
|
284
|
+
for (let i = 0; i < paddedLength; i += 2) {
|
|
285
|
+
const byte1 = buffer[i] || 0;
|
|
286
|
+
const byte2 = buffer[i + 1] || 0;
|
|
287
|
+
registers.push((byte1 << 8) | byte2);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return registers;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Convert register array to string
|
|
295
|
+
*/
|
|
296
|
+
registersToString(registers: number[]): string {
|
|
297
|
+
const bytes: number[] = [];
|
|
298
|
+
|
|
299
|
+
for (const reg of registers) {
|
|
300
|
+
bytes.push((reg >> 8) & 0xff); // High byte
|
|
301
|
+
bytes.push(reg & 0xff); // Low byte
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Remove trailing zeros
|
|
305
|
+
while (bytes.length > 0 && bytes[bytes.length - 1] === 0) {
|
|
306
|
+
bytes.pop();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return Buffer.from(bytes).toString("utf8");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Validate register value is within 16-bit range
|
|
314
|
+
*/
|
|
315
|
+
validateRegisterValue(value: number): boolean {
|
|
316
|
+
return Number.isInteger(value) && value >= 0 && value <= 0xffff;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Create a buffer configuration for consistent handling
|
|
321
|
+
*/
|
|
322
|
+
createBufferConfig(options: BufferOptions = {}): Required<BufferOptions> {
|
|
323
|
+
return {
|
|
324
|
+
endian: options.endian || "LE",
|
|
325
|
+
wordSwap: options.wordSwap || false,
|
|
326
|
+
byteSwap: options.byteSwap || false,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Singleton instance
|
|
332
|
+
let crossPlatformBuffer: CrossPlatformBuffer | null = null;
|
|
333
|
+
|
|
334
|
+
export function getCrossPlatformBuffer(): CrossPlatformBuffer {
|
|
335
|
+
if (!crossPlatformBuffer) {
|
|
336
|
+
crossPlatformBuffer = new CrossPlatformBuffer();
|
|
337
|
+
}
|
|
338
|
+
return crossPlatformBuffer;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export default CrossPlatformBuffer;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services Module Exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Configuration management - use SettingsService
|
|
6
|
+
|
|
7
|
+
// Other services
|
|
8
|
+
export { getConversationStorage } from "./conversationStorage.js";
|
|
9
|
+
export { CrossPlatformBuffer } from "./crossPlatformBuffer.js";
|
|
10
|
+
export { getNetworkService } from "./networkService.js";
|
|
11
|
+
export { getUpdateService } from "./updateService.js";
|
|
12
|
+
export {
|
|
13
|
+
createWebSocketServer,
|
|
14
|
+
getWebSocketServer,
|
|
15
|
+
} from "./websocketServer.js";
|
|
16
|
+
export {
|
|
17
|
+
SettingsService,
|
|
18
|
+
CommonSettingsCategories,
|
|
19
|
+
} from "./settingsService.js";
|
|
20
|
+
export type {
|
|
21
|
+
SettingsCategory,
|
|
22
|
+
SettingsField,
|
|
23
|
+
SettingsOptions,
|
|
24
|
+
} from "./settingsService.js";
|
|
25
|
+
|
|
26
|
+
// WebSocket events
|
|
27
|
+
export {
|
|
28
|
+
WebSocketEventManager,
|
|
29
|
+
TypedEventEmitter,
|
|
30
|
+
EventTypes,
|
|
31
|
+
EventPatterns,
|
|
32
|
+
} from "./websocketEvents.js";
|
|
33
|
+
export type { EventPayload, EventResponse } from "./websocketEvents.js";
|
|
34
|
+
|
|
35
|
+
// AI Service
|
|
36
|
+
export { aiService, AIService } from "./aiService.js";
|
|
37
|
+
export type {
|
|
38
|
+
AIConfig,
|
|
39
|
+
AIMessage,
|
|
40
|
+
AIResponse,
|
|
41
|
+
AIAnalysisOptions,
|
|
42
|
+
AIProvider,
|
|
43
|
+
} from "./aiService.js";
|
|
44
|
+
|
|
45
|
+
// Queue Service
|
|
46
|
+
export { default as QueueService } from "./queueService.js";
|
|
47
|
+
export type { QueueJob, QueueConfig, JobHandler } from "./queueService.js";
|