nyxora 26.6.22-1 → 26.6.23

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 CHANGED
@@ -2,10 +2,11 @@
2
2
  **Your Personal Web3 Assistant.**
3
3
 
4
4
 
5
+ [![Status: Alpha](https://img.shields.io/badge/Status-Alpha-red.svg)](#)
5
6
  [![Built on Arbitrum](https://img.shields.io/badge/Built_on-Arbitrum-28A0F0?style=flat&logo=arbitrum&logoColor=white)](https://arbitrum.io/)
6
7
  [![MCP Supported](https://img.shields.io/badge/MCP-Supported-blue.svg)](#)
7
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
- [![Security: Production-Grade](https://img.shields.io/badge/Security-Production--Grade-blue.svg)](#️-advanced-security-threat-model)
9
+ [![Security: Defense-in-Depth](https://img.shields.io/badge/Security-Defense--in--Depth-blue.svg)](#️-advanced-security-threat-model)
9
10
  [![Execution: Cryptographic Approval](https://img.shields.io/badge/Execution-Cryptographic--Approval-orange.svg)](#️-advanced-security-threat-model)
10
11
  [![Privacy: Local-Only Keys](https://img.shields.io/badge/Privacy-Local--Only--Keys-success.svg)](#️-advanced-security-threat-model)
11
12
 
@@ -90,7 +91,7 @@ Within the AI Brain, the Web3 codebase is strictly divided to prevent the LLM fr
90
91
 
91
92
  ## 🛡️ Advanced Security & Threat Model
92
93
 
93
- To dive deeper into the technical details of our Zero-Knowledge security architecture, please visit the [Nyxora Security Blueprint](https://nyxoraai.github.io/Nyxora/).
94
+ To dive deeper into the technical details of our Zero-Knowledge security architecture, please visit the [Nyxora Security](https://nyxoraai.github.io/Nyxora/).
94
95
 
95
96
  ---
96
97
 
@@ -182,8 +183,6 @@ For complete technical deep-dives into our Cryptographic Architecture, please vi
182
183
 
183
184
  > **🔗 [Read the Full Nyxora Documentation Here](https://nyxoraai.github.io/Nyxora/)**
184
185
 
185
- *(Includes guides on Secure Wallet Imports, Architecture Blueprints, Troubleshooting, and Custom Skill Development).*
186
-
187
186
  ---
188
187
 
189
188
  **❤️ Support the Project**
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wsManager = exports.WebSocketManager = void 0;
4
+ exports.initWebSocket = initWebSocket;
5
+ const ws_1 = require("ws");
6
+ const state_1 = require("../utils/state");
7
+ class WebSocketManager {
8
+ wss;
9
+ clients = new Map();
10
+ ringBuffer = new Map();
11
+ constructor(server) {
12
+ this.wss = new ws_1.WebSocketServer({ noServer: true });
13
+ server.on('upgrade', async (request, socket, head) => {
14
+ try {
15
+ const url = new URL(request.url || '', `http://${request.headers.host}`);
16
+ if (url.pathname !== '/ws/stream') {
17
+ socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
18
+ socket.destroy();
19
+ return;
20
+ }
21
+ const traceId = url.searchParams.get('traceId');
22
+ const token = url.searchParams.get('token');
23
+ if (!traceId || !token) {
24
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
25
+ socket.destroy();
26
+ return;
27
+ }
28
+ // Validate Auth Token during Upgrade Handshake
29
+ if (!(0, state_1.validateToken)(token)) {
30
+ socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
31
+ socket.destroy();
32
+ return;
33
+ }
34
+ this.wss.handleUpgrade(request, socket, head, (ws) => {
35
+ this.wss.emit('connection', ws, request, traceId);
36
+ });
37
+ }
38
+ catch (e) {
39
+ socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n');
40
+ socket.destroy();
41
+ }
42
+ });
43
+ this.wss.on('connection', (ws, request, traceId) => {
44
+ this.clients.set(traceId, ws);
45
+ ws.on('close', () => {
46
+ this.clients.delete(traceId);
47
+ });
48
+ // Flush Ring Buffer if it exists
49
+ const buffer = this.ringBuffer.get(traceId);
50
+ if (buffer) {
51
+ clearTimeout(buffer.timeout);
52
+ for (const log of buffer.logs) {
53
+ ws.send(JSON.stringify(log));
54
+ }
55
+ this.ringBuffer.delete(traceId);
56
+ }
57
+ });
58
+ }
59
+ broadcast(traceId, message, level = 'info') {
60
+ const payload = { timestamp: Date.now(), message, level };
61
+ const ws = this.clients.get(traceId);
62
+ if (ws && ws.readyState === ws_1.WebSocket.OPEN) {
63
+ // Client is connected, send directly
64
+ ws.send(JSON.stringify(payload));
65
+ }
66
+ else {
67
+ // Client not connected yet, buffer the log (Anti-Race Condition)
68
+ let buffer = this.ringBuffer.get(traceId);
69
+ if (!buffer) {
70
+ buffer = {
71
+ logs: [],
72
+ timeout: setTimeout(() => {
73
+ // Drop buffer after 5 seconds if client never connects
74
+ this.ringBuffer.delete(traceId);
75
+ }, 5000)
76
+ };
77
+ this.ringBuffer.set(traceId, buffer);
78
+ }
79
+ buffer.logs.push(payload);
80
+ }
81
+ }
82
+ broadcastAll(message, level = 'info') {
83
+ const payload = { timestamp: Date.now(), message, level };
84
+ const payloadStr = JSON.stringify(payload);
85
+ for (const [_, ws] of this.clients) {
86
+ if (ws.readyState === ws_1.WebSocket.OPEN) {
87
+ ws.send(payloadStr);
88
+ }
89
+ }
90
+ }
91
+ }
92
+ exports.WebSocketManager = WebSocketManager;
93
+ // Global instance to be initialized in server.ts
94
+ exports.wsManager = null;
95
+ function initWebSocket(server) {
96
+ exports.wsManager = new WebSocketManager(server);
97
+ return exports.wsManager;
98
+ }
@@ -18,9 +18,11 @@ process.on('uncaughtException', (error) => {
18
18
  const path_1 = __importDefault(require("path"));
19
19
  const helmet_1 = __importDefault(require("helmet"));
20
20
  const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
21
+ const crypto_1 = __importDefault(require("crypto"));
21
22
  const os_1 = __importDefault(require("os"));
22
23
  const paths_1 = require("../config/paths");
23
24
  const state_1 = require("../utils/state");
25
+ const WebSocketManager_1 = require("./WebSocketManager");
24
26
  const fs_1 = __importDefault(require("fs"));
25
27
  const yaml_1 = __importDefault(require("yaml"));
26
28
  const reasoning_1 = require("../agent/reasoning");
@@ -850,6 +852,22 @@ function resetIdleTimer() {
850
852
  reflection_1.ReflectionEngine.runReflection();
851
853
  }, 3 * 60 * 1000); // 3 minutes idle
852
854
  }
855
+ app.post('/api/v1/trade', async (req, res) => {
856
+ try {
857
+ const { message, session_id } = req.body;
858
+ if (!message)
859
+ return res.status(400).json({ error: 'Message is required' });
860
+ const traceId = crypto_1.default.randomBytes(8).toString('hex');
861
+ // Asynchronous background execution
862
+ (0, reasoning_1.processUserInput)(message, session_id || traceId).catch(err => {
863
+ console.error(`[TradeAPI] Error:`, err);
864
+ });
865
+ res.status(200).json({ status: 'processing', traceId });
866
+ }
867
+ catch (error) {
868
+ res.status(500).json({ error: error.message });
869
+ }
870
+ });
853
871
  app.post('/api/chat', async (req, res) => {
854
872
  try {
855
873
  const { message, session_id } = req.body;
@@ -1000,6 +1018,8 @@ function startServer() {
1000
1018
  const PORT = Number(process.env.PORT || 3000);
1001
1019
  const server = app.listen(PORT, '127.0.0.1', () => {
1002
1020
  console.log(`🤖 Nyxora API Server running on port ${PORT}`);
1021
+ // Initialize WebSocket Manager
1022
+ (0, WebSocketManager_1.initWebSocket)(server);
1003
1023
  // Start the Telegram bot listener
1004
1024
  (0, telegram_1.startTelegramBot)();
1005
1025
  // Start Asynchronous Bridge Watcher
@@ -276,7 +276,7 @@ Provider: ${config.llm.provider}`;
276
276
  { value: 'gitManager', label: 'Git Operations (Commit/Push/Pull)' },
277
277
  { value: 'updateSecurityPolicy', label: 'Update policy.yaml rules', hint: 'safeguard' },
278
278
  { value: 'browseWeb', label: 'Browse & Scrape Webpages' },
279
- { value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave)', hint: 'Requires API Key' },
279
+ { value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave/DuckDuckGo)', hint: 'Optional API Key' },
280
280
  { value: 'googleWorkspace', label: 'Google Workspace (Gmail, Docs, Sheets, Forms)', hint: 'Requires OAuth' },
281
281
  { value: 'notionWorkspace', label: 'Notion Integration' },
282
282
  { value: 'xManager', label: 'X/Twitter Management' },
@@ -308,15 +308,18 @@ Provider: ${config.llm.provider}`;
308
308
  options: [
309
309
  { value: 'tavily', label: 'Tavily Search (Built for AI - 1000 free/mo)' },
310
310
  { value: 'brave', label: 'Brave Search (Privacy focused - 2000 free/mo)' },
311
+ { value: 'duckduckgo', label: 'DuckDuckGo (Free & Built-in)' },
311
312
  ],
312
313
  });
313
314
  if ((0, prompts_1.isCancel)(searchProvider))
314
315
  return process.exit(0);
315
- searchApiKey = (await (0, prompts_1.password)({
316
- message: `Enter API Key for ${searchProvider} (Get it free at ${searchProvider === 'tavily' ? 'tavily.com' : 'search.brave.com'}):`,
317
- }));
318
- if ((0, prompts_1.isCancel)(searchApiKey))
319
- return process.exit(0);
316
+ if (searchProvider !== 'duckduckgo') {
317
+ searchApiKey = (await (0, prompts_1.password)({
318
+ message: `Enter API Key for ${searchProvider} (Get it free at ${searchProvider === 'tavily' ? 'tavily.com' : 'search.brave.com'}):`,
319
+ }));
320
+ if ((0, prompts_1.isCancel)(searchApiKey))
321
+ return process.exit(0);
322
+ }
320
323
  }
321
324
  const setupTelegram = activeChannels.includes('telegram');
322
325
  let telegramToken = '';
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Tracker = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
+ const WebSocketManager_1 = require("./WebSocketManager");
8
9
  const paths_1 = require("../config/paths");
9
10
  const stats = {
10
11
  cost: 0,
@@ -97,6 +98,10 @@ exports.Tracker = {
97
98
  if (gatewayLogs.length > MAX_LOGS)
98
99
  gatewayLogs.pop();
99
100
  saveState();
101
+ // Broadcast terminal logs to Dashboard via WebSocket
102
+ if (WebSocketManager_1.wsManager) {
103
+ WebSocketManager_1.wsManager.broadcastAll(`[${formatTime()}] ${message}`, meta?.level || 'info');
104
+ }
100
105
  },
101
106
  getLogs: () => {
102
107
  return {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.searchWebToolDefinition = void 0;
4
4
  exports.searchWeb = searchWeb;
5
5
  const parser_1 = require("../../config/parser");
6
+ const duck_duck_scrape_1 = require("duck-duck-scrape");
6
7
  const SEARXNG_INSTANCES = [
7
8
  'https://search.mdosch.de',
8
9
  'https://searx.tiekoetter.com',
@@ -79,6 +80,25 @@ async function searchSearxng(query, depth = 1) {
79
80
  }
80
81
  throw new Error('[SearXNG Error] All decentralized instances failed.');
81
82
  }
83
+ async function searchDuckDuckGo(query, depth = 1) {
84
+ try {
85
+ const searchResults = await (0, duck_duck_scrape_1.search)(query, {
86
+ safeSearch: duck_duck_scrape_1.SafeSearchType.MODERATE
87
+ });
88
+ if (!searchResults.noResults && searchResults.results.length > 0) {
89
+ const maxResults = depth > 1 ? 15 : 8;
90
+ return searchResults.results.slice(0, maxResults).map(r => ({
91
+ title: r.title,
92
+ url: r.url,
93
+ content: r.description || r.title
94
+ }));
95
+ }
96
+ return [];
97
+ }
98
+ catch (e) {
99
+ throw new Error(`[DuckDuckGo Error] Failed to scrape: ${e.message}`);
100
+ }
101
+ }
82
102
  const searchCache = new Map();
83
103
  async function searchWeb(query, depth = 1) {
84
104
  // Auto-inject current year for time-sensitive queries
@@ -119,13 +139,25 @@ async function searchWeb(query, depth = 1) {
119
139
  results = await searchBrave(finalQuery, creds.brave_key, depth);
120
140
  }
121
141
  catch (e2) {
122
- console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to SearXNG Mesh...');
123
- results = await searchSearxng(finalQuery, depth);
142
+ console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to DuckDuckGo (L3)...');
143
+ try {
144
+ results = await searchDuckDuckGo(finalQuery, depth);
145
+ }
146
+ catch (e3) {
147
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
148
+ results = await searchSearxng(finalQuery, depth);
149
+ }
124
150
  }
125
151
  }
126
152
  else {
127
- console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
128
- results = await searchSearxng(finalQuery, depth);
153
+ console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
154
+ try {
155
+ results = await searchDuckDuckGo(finalQuery, depth);
156
+ }
157
+ catch (e3) {
158
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
159
+ results = await searchSearxng(finalQuery, depth);
160
+ }
129
161
  }
130
162
  }
131
163
  else {
@@ -145,13 +177,25 @@ async function searchWeb(query, depth = 1) {
145
177
  results = await searchTavily(finalQuery, creds.tavily_key, depth);
146
178
  }
147
179
  catch (e2) {
148
- console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to SearXNG Mesh...');
149
- results = await searchSearxng(finalQuery, depth);
180
+ console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to DuckDuckGo (L3)...');
181
+ try {
182
+ results = await searchDuckDuckGo(finalQuery, depth);
183
+ }
184
+ catch (e3) {
185
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
186
+ results = await searchSearxng(finalQuery, depth);
187
+ }
150
188
  }
151
189
  }
152
190
  else {
153
- console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
154
- results = await searchSearxng(finalQuery, depth);
191
+ console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
192
+ try {
193
+ results = await searchDuckDuckGo(finalQuery, depth);
194
+ }
195
+ catch (e3) {
196
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
197
+ results = await searchSearxng(finalQuery, depth);
198
+ }
155
199
  }
156
200
  }
157
201
  else {
@@ -159,6 +203,15 @@ async function searchWeb(query, depth = 1) {
159
203
  }
160
204
  }
161
205
  }
206
+ else if (provider === 'duckduckgo') {
207
+ try {
208
+ results = await searchDuckDuckGo(finalQuery, depth);
209
+ }
210
+ catch (e) {
211
+ console.warn('[WebSearch] Primary provider (DuckDuckGo) failed. Falling back to SearXNG Mesh...');
212
+ results = await searchSearxng(finalQuery, depth);
213
+ }
214
+ }
162
215
  else {
163
216
  results = await searchSearxng(finalQuery, depth);
164
217
  }
@@ -9,6 +9,8 @@ const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const os_1 = __importDefault(require("os"));
11
11
  const crypto_1 = __importDefault(require("crypto"));
12
+ const http_1 = __importDefault(require("http"));
13
+ const msgpackr_1 = require("msgpackr");
12
14
  function getInternalToken() {
13
15
  try {
14
16
  const tokenPath = path_1.default.join(os_1.default.homedir(), '.nyxora', 'auth', 'runtime.token');
@@ -21,19 +23,43 @@ function getInternalToken() {
21
23
  }
22
24
  async function getAddress() {
23
25
  const token = getInternalToken();
24
- try {
25
- const res = await fetch(`http://127.0.0.1:${process.env.POLICY_PORT || 3001}/address`, {
26
- headers: token ? { 'Authorization': `Bearer ${token}` } : {},
27
- signal: AbortSignal.timeout(30000)
26
+ return new Promise((resolve, reject) => {
27
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
28
+ const options = {
29
+ socketPath: fs_1.default.existsSync(POLICY_SOCKET) ? POLICY_SOCKET : undefined,
30
+ host: fs_1.default.existsSync(POLICY_SOCKET) ? undefined : '127.0.0.1',
31
+ port: fs_1.default.existsSync(POLICY_SOCKET) ? undefined : (process.env.POLICY_PORT || 3001),
32
+ path: '/address',
33
+ method: 'GET',
34
+ headers: {
35
+ ...(token ? { 'Authorization': `Bearer ${token}` } : {})
36
+ }
37
+ };
38
+ const req = http_1.default.request(options, (res) => {
39
+ let data = '';
40
+ res.on('data', chunk => data += chunk);
41
+ res.on('end', () => {
42
+ try {
43
+ if (res.statusCode !== 200) {
44
+ reject(new Error(data));
45
+ return;
46
+ }
47
+ const parsed = JSON.parse(data);
48
+ resolve(parsed.address);
49
+ }
50
+ catch (e) {
51
+ reject(new Error(`Failed to get address from vault: ${e.message}`));
52
+ }
53
+ });
28
54
  });
29
- if (!res.ok)
30
- throw new Error(await res.text());
31
- const data = await res.json();
32
- return data.address;
33
- }
34
- catch (error) {
35
- throw new Error(`Failed to get address from vault: ${error.message}`);
36
- }
55
+ req.on('error', (error) => {
56
+ reject(new Error(`Failed to get address from vault: ${error.message}`));
57
+ });
58
+ req.setTimeout(30000, () => {
59
+ req.destroy(new Error('Timeout'));
60
+ });
61
+ req.end();
62
+ });
37
63
  }
38
64
  async function submitTransaction(txPayload) {
39
65
  const token = getInternalToken();
@@ -45,25 +71,49 @@ async function submitTransaction(txPayload) {
45
71
  const secret = getInternalToken() || '';
46
72
  txPayload.internalSignature = crypto_1.default.createHmac('sha256', secret).update(txPayload.chainName + amountWei).digest('hex');
47
73
  }
48
- try {
49
- const res = await fetch(`http://127.0.0.1:${process.env.POLICY_PORT || 3001}/request-tx`, {
74
+ return new Promise((resolve, reject) => {
75
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
76
+ const payloadBuffer = (0, msgpackr_1.pack)(txPayload);
77
+ const options = {
78
+ socketPath: fs_1.default.existsSync(POLICY_SOCKET) ? POLICY_SOCKET : undefined,
79
+ host: fs_1.default.existsSync(POLICY_SOCKET) ? undefined : '127.0.0.1',
80
+ port: fs_1.default.existsSync(POLICY_SOCKET) ? undefined : (process.env.POLICY_PORT || 3001),
81
+ path: '/request-tx',
50
82
  method: 'POST',
51
83
  headers: {
52
- 'Content-Type': 'application/json',
84
+ 'Content-Type': 'application/msgpack',
85
+ 'Content-Length': payloadBuffer.length,
53
86
  ...(token ? { 'Authorization': `Bearer ${token}` } : {})
54
- },
55
- body: JSON.stringify(txPayload),
56
- signal: AbortSignal.timeout(30000)
87
+ }
88
+ };
89
+ const req = http_1.default.request(options, (res) => {
90
+ let data = '';
91
+ res.on('data', chunk => data += chunk);
92
+ res.on('end', () => {
93
+ try {
94
+ const parsed = JSON.parse(data);
95
+ if (res.statusCode !== 200) {
96
+ reject(new Error(parsed.error || 'Failed to submit transaction'));
97
+ return;
98
+ }
99
+ if (parsed.status === 'pending') {
100
+ resolve(`Pending (ID: ${parsed.txId})`);
101
+ return;
102
+ }
103
+ resolve(parsed.signedHash || parsed.hash || parsed.txHash || parsed.status || 'Transaction executed successfully (No Hash returned)');
104
+ }
105
+ catch (e) {
106
+ reject(new Error(`Failed to parse vault response: ${e.message}`));
107
+ }
108
+ });
57
109
  });
58
- const data = await res.json();
59
- if (!res.ok)
60
- throw new Error(data.error || 'Failed to submit transaction');
61
- if (data.status === 'pending') {
62
- return `Pending (ID: ${data.txId})`;
63
- }
64
- return data.signedHash || data.hash || data.txHash || data.status || 'Transaction executed successfully (No Hash returned)';
65
- }
66
- catch (error) {
67
- throw new Error(`Transaction submission failed: ${error.message}`);
68
- }
110
+ req.on('error', (error) => {
111
+ reject(new Error(`Transaction submission failed: ${error.message}`));
112
+ });
113
+ req.setTimeout(30000, () => {
114
+ req.destroy(new Error('Timeout'));
115
+ });
116
+ req.write(payloadBuffer);
117
+ req.end();
118
+ });
69
119
  }
@@ -15,6 +15,7 @@ const zod_1 = require("zod");
15
15
  const path_1 = __importDefault(require("path"));
16
16
  const crypto_1 = __importDefault(require("crypto"));
17
17
  const os_1 = __importDefault(require("os"));
18
+ const msgpackr_1 = require("msgpackr");
18
19
  process.on('unhandledRejection', (reason, promise) => {
19
20
  console.error('[Anti-Crash] Unhandled Rejection at:', promise, 'reason:', reason);
20
21
  });
@@ -35,6 +36,25 @@ catch (e) {
35
36
  const SIGNER_SOCKET = process.env.SIGNER_SOCKET_PATH || '/tmp/nyxora-signer.sock';
36
37
  const app = (0, express_1.default)();
37
38
  app.use(express_1.default.json());
39
+ // MessagePack Parser Middleware for Hyper-Optimized IPC
40
+ app.use((req, res, next) => {
41
+ if (req.headers['content-type'] === 'application/msgpack') {
42
+ let chunks = [];
43
+ req.on('data', chunk => chunks.push(chunk));
44
+ req.on('end', () => {
45
+ try {
46
+ req.body = (0, msgpackr_1.unpack)(Buffer.concat(chunks));
47
+ next();
48
+ }
49
+ catch (e) {
50
+ res.status(400).json({ error: 'Invalid MessagePack payload' });
51
+ }
52
+ });
53
+ }
54
+ else {
55
+ next();
56
+ }
57
+ });
38
58
  const TxRequestSchema = zod_1.z.object({
39
59
  type: zod_1.z.enum(['transfer', 'swap', 'bridge', 'mint', 'custom']),
40
60
  chainName: zod_1.z.string(),
@@ -237,6 +257,7 @@ app.post('/approve-tx/:id', (req, res) => {
237
257
  signerReq.write(requestPayload);
238
258
  signerReq.end();
239
259
  });
260
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
240
261
  const server = app.listen(Number(PORT), '127.0.0.1', () => {
241
262
  console.log(`[Policy Engine] Listening on 127.0.0.1:${PORT} (Secured Local Loopback)`);
242
263
  });
@@ -250,3 +271,10 @@ server.on('error', (e) => {
250
271
  process.exit(1);
251
272
  }
252
273
  });
274
+ // Start UDS Server for Hyper-Optimized IPC
275
+ const udsServer = http_1.default.createServer(app);
276
+ if (fs_1.default.existsSync(POLICY_SOCKET))
277
+ fs_1.default.unlinkSync(POLICY_SOCKET);
278
+ udsServer.listen(POLICY_SOCKET, () => {
279
+ console.log(`[Policy Engine] Listening on UDS ${POLICY_SOCKET} (Hyper-Optimized IPC)`);
280
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nyxora",
3
- "version": "26.6.22-1",
3
+ "version": "26.6.23",
4
4
  "description": "Your Personal Web3 Assistant",
5
5
  "keywords": [
6
6
  "web3",
@@ -60,6 +60,7 @@
60
60
  "dotenv": "^17.4.2",
61
61
  "duck-duck-scrape": "^2.2.7",
62
62
  "express": "^5.2.1",
63
+ "msgpackr": "^2.0.4",
63
64
  "express-rate-limit": "^7.5.0",
64
65
  "helmet": "^8.0.0",
65
66
  "isolated-vm": "^6.1.2",
@@ -79,6 +80,7 @@
79
80
  "typescript": "^6.0.3",
80
81
  "viem": "^2.51.0",
81
82
  "write-excel-file": "^4.1.1",
83
+ "ws": "^8.21.0",
82
84
  "yaml": "^2.9.0",
83
85
  "zod": "^3.23.8"
84
86
  },
@@ -98,6 +100,7 @@
98
100
  },
99
101
  "devDependencies": {
100
102
  "@types/jsonwebtoken": "^9.0.5",
103
+ "@types/ws": "^8.5.10",
101
104
  "@types/node": "^25.9.1",
102
105
  "@types/node-cron": "^3.0.11",
103
106
  "concurrently": "^10.0.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nyxora-agent-core",
3
- "version": "26.6.22-1",
3
+ "version": "26.6.23",
4
4
  "private": true,
5
5
  "main": "src/gateway/server.ts",
6
6
  "dependencies": {
@@ -14,6 +14,7 @@
14
14
  "express-rate-limit": "^7.5.0",
15
15
  "helmet": "^8.0.0",
16
16
  "mammoth": "^1.12.0",
17
+ "msgpackr": "^2.0.4",
17
18
  "multer": "^2.2.0",
18
19
  "node-cron": "^4.4.1",
19
20
  "open": "^11.0.0",
@@ -24,6 +25,7 @@
24
25
  "telegraf": "^4.16.3",
25
26
  "twitter-api-v2": "^1.29.0",
26
27
  "write-excel-file": "^4.1.1",
28
+ "ws": "^8.21.0",
27
29
  "yaml": "^2.9.0",
28
30
  "zod": "^3.25.76"
29
31
  },
@@ -32,6 +34,7 @@
32
34
  "@types/node": "^25.9.2",
33
35
  "@types/node-cron": "^3.0.11",
34
36
  "@types/pdf-parse": "^1.1.5",
37
+ "@types/ws": "^8.18.1",
35
38
  "vitest": "^4.1.8"
36
39
  },
37
40
  "scripts": {
@@ -115,7 +115,7 @@ export interface NyxoraConfig {
115
115
  credentials?: any; // Deprecated, kept for parsing during migration
116
116
  };
117
117
  web_search?: {
118
- provider: 'tavily' | 'brave' | 'mesh';
118
+ provider: 'tavily' | 'brave' | 'duckduckgo' | 'mesh';
119
119
  enabled: boolean;
120
120
  };
121
121
  credentials?: {
@@ -0,0 +1,114 @@
1
+ import { WebSocketServer, WebSocket } from 'ws';
2
+ import http from 'http';
3
+ import { validateToken } from '../utils/state';
4
+ import { IncomingMessage } from 'http';
5
+
6
+ interface BufferedLog {
7
+ timestamp: number;
8
+ message: string;
9
+ level: string;
10
+ }
11
+
12
+ export class WebSocketManager {
13
+ private wss: WebSocketServer;
14
+ private clients: Map<string, WebSocket> = new Map();
15
+ private ringBuffer: Map<string, { logs: BufferedLog[]; timeout: NodeJS.Timeout }> = new Map();
16
+
17
+ constructor(server: http.Server) {
18
+ this.wss = new WebSocketServer({ noServer: true });
19
+
20
+ server.on('upgrade', async (request: IncomingMessage, socket, head) => {
21
+ try {
22
+ const url = new URL(request.url || '', `http://${request.headers.host}`);
23
+ if (url.pathname !== '/ws/stream') {
24
+ socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
25
+ socket.destroy();
26
+ return;
27
+ }
28
+
29
+ const traceId = url.searchParams.get('traceId');
30
+ const token = url.searchParams.get('token');
31
+
32
+ if (!traceId || !token) {
33
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
34
+ socket.destroy();
35
+ return;
36
+ }
37
+
38
+ // Validate Auth Token during Upgrade Handshake
39
+ if (!validateToken(token)) {
40
+ socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
41
+ socket.destroy();
42
+ return;
43
+ }
44
+
45
+ this.wss.handleUpgrade(request, socket, head, (ws) => {
46
+ this.wss.emit('connection', ws, request, traceId);
47
+ });
48
+ } catch (e) {
49
+ socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n');
50
+ socket.destroy();
51
+ }
52
+ });
53
+
54
+ this.wss.on('connection', (ws: WebSocket, request: IncomingMessage, traceId: string) => {
55
+ this.clients.set(traceId, ws);
56
+
57
+ ws.on('close', () => {
58
+ this.clients.delete(traceId);
59
+ });
60
+
61
+ // Flush Ring Buffer if it exists
62
+ const buffer = this.ringBuffer.get(traceId);
63
+ if (buffer) {
64
+ clearTimeout(buffer.timeout);
65
+ for (const log of buffer.logs) {
66
+ ws.send(JSON.stringify(log));
67
+ }
68
+ this.ringBuffer.delete(traceId);
69
+ }
70
+ });
71
+ }
72
+
73
+ public broadcast(traceId: string, message: string, level: string = 'info') {
74
+ const payload = { timestamp: Date.now(), message, level };
75
+ const ws = this.clients.get(traceId);
76
+
77
+ if (ws && ws.readyState === WebSocket.OPEN) {
78
+ // Client is connected, send directly
79
+ ws.send(JSON.stringify(payload));
80
+ } else {
81
+ // Client not connected yet, buffer the log (Anti-Race Condition)
82
+ let buffer = this.ringBuffer.get(traceId);
83
+ if (!buffer) {
84
+ buffer = {
85
+ logs: [],
86
+ timeout: setTimeout(() => {
87
+ // Drop buffer after 5 seconds if client never connects
88
+ this.ringBuffer.delete(traceId);
89
+ }, 5000)
90
+ };
91
+ this.ringBuffer.set(traceId, buffer);
92
+ }
93
+ buffer.logs.push(payload);
94
+ }
95
+ }
96
+
97
+ public broadcastAll(message: string, level: string = 'info') {
98
+ const payload = { timestamp: Date.now(), message, level };
99
+ const payloadStr = JSON.stringify(payload);
100
+ for (const [_, ws] of this.clients) {
101
+ if (ws.readyState === WebSocket.OPEN) {
102
+ ws.send(payloadStr);
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ // Global instance to be initialized in server.ts
109
+ export let wsManager: WebSocketManager | null = null;
110
+
111
+ export function initWebSocket(server: http.Server) {
112
+ wsManager = new WebSocketManager(server);
113
+ return wsManager;
114
+ }
@@ -21,6 +21,7 @@ import os from 'os';
21
21
  import { getPath } from '../config/paths';
22
22
  import { validateToken, getSessionToken } from '../utils/state';
23
23
 
24
+ import { initWebSocket } from './WebSocketManager';
24
25
  import fs from 'fs';
25
26
  import yaml from 'yaml';
26
27
  import { processUserInput, logger } from '../agent/reasoning';
@@ -910,6 +911,24 @@ function resetIdleTimer() {
910
911
  }, 3 * 60 * 1000); // 3 minutes idle
911
912
  }
912
913
 
914
+ app.post('/api/v1/trade', async (req, res) => {
915
+ try {
916
+ const { message, session_id } = req.body;
917
+ if (!message) return res.status(400).json({ error: 'Message is required' });
918
+
919
+ const traceId = crypto.randomBytes(8).toString('hex');
920
+
921
+ // Asynchronous background execution
922
+ processUserInput(message, session_id || traceId).catch(err => {
923
+ console.error(`[TradeAPI] Error:`, err);
924
+ });
925
+
926
+ res.status(200).json({ status: 'processing', traceId });
927
+ } catch (error: any) {
928
+ res.status(500).json({ error: error.message });
929
+ }
930
+ });
931
+
913
932
  app.post('/api/chat', async (req, res) => {
914
933
  try {
915
934
  const { message, session_id } = req.body;
@@ -1069,6 +1088,9 @@ export function startServer() {
1069
1088
  const server = app.listen(PORT, '127.0.0.1', () => {
1070
1089
  console.log(`🤖 Nyxora API Server running on port ${PORT}`);
1071
1090
 
1091
+ // Initialize WebSocket Manager
1092
+ initWebSocket(server);
1093
+
1072
1094
  // Start the Telegram bot listener
1073
1095
  startTelegramBot();
1074
1096
 
@@ -288,7 +288,7 @@ Provider: ${config.llm.provider}`;
288
288
  { value: 'gitManager', label: 'Git Operations (Commit/Push/Pull)' },
289
289
  { value: 'updateSecurityPolicy', label: 'Update policy.yaml rules', hint: 'safeguard' },
290
290
  { value: 'browseWeb', label: 'Browse & Scrape Webpages' },
291
- { value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave)', hint: 'Requires API Key' },
291
+ { value: 'searchWeb', label: 'Smart Web Search (Tavily/Brave/DuckDuckGo)', hint: 'Optional API Key' },
292
292
  { value: 'googleWorkspace', label: 'Google Workspace (Gmail, Docs, Sheets, Forms)', hint: 'Requires OAuth' },
293
293
  { value: 'notionWorkspace', label: 'Notion Integration' },
294
294
  { value: 'xManager', label: 'X/Twitter Management' },
@@ -320,14 +320,17 @@ Provider: ${config.llm.provider}`;
320
320
  options: [
321
321
  { value: 'tavily', label: 'Tavily Search (Built for AI - 1000 free/mo)' },
322
322
  { value: 'brave', label: 'Brave Search (Privacy focused - 2000 free/mo)' },
323
+ { value: 'duckduckgo', label: 'DuckDuckGo (Free & Built-in)' },
323
324
  ],
324
325
  });
325
326
  if (isCancel(searchProvider)) return process.exit(0);
326
327
 
327
- searchApiKey = (await password({
328
- message: `Enter API Key for ${searchProvider} (Get it free at ${searchProvider === 'tavily' ? 'tavily.com' : 'search.brave.com'}):`,
329
- })) as string;
330
- if (isCancel(searchApiKey)) return process.exit(0);
328
+ if (searchProvider !== 'duckduckgo') {
329
+ searchApiKey = (await password({
330
+ message: `Enter API Key for ${searchProvider} (Get it free at ${searchProvider === 'tavily' ? 'tavily.com' : 'search.brave.com'}):`,
331
+ })) as string;
332
+ if (isCancel(searchApiKey)) return process.exit(0);
333
+ }
331
334
  }
332
335
 
333
336
  const setupTelegram = activeChannels.includes('telegram');
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { wsManager } from './WebSocketManager';
3
4
  import { getPath } from '../config/paths';
4
5
 
5
6
  interface Stats {
@@ -114,6 +115,11 @@ export const Tracker = {
114
115
  gatewayLogs.unshift({ timestamp: formatTime(), message, meta });
115
116
  if (gatewayLogs.length > MAX_LOGS) gatewayLogs.pop();
116
117
  saveState();
118
+
119
+ // Broadcast terminal logs to Dashboard via WebSocket
120
+ if (wsManager) {
121
+ wsManager.broadcastAll(`[${formatTime()}] ${message}`, meta?.level || 'info');
122
+ }
117
123
  },
118
124
 
119
125
  getLogs: () => {
@@ -1,4 +1,5 @@
1
1
  import { loadConfig, loadApiKeys } from '../../config/parser';
2
+ import { search, SafeSearchType } from 'duck-duck-scrape';
2
3
 
3
4
  interface SearchQueryResult {
4
5
  title: string;
@@ -90,6 +91,26 @@ async function searchSearxng(query: string, depth: number = 1): Promise<SearchQu
90
91
  throw new Error('[SearXNG Error] All decentralized instances failed.');
91
92
  }
92
93
 
94
+ async function searchDuckDuckGo(query: string, depth: number = 1): Promise<SearchQueryResult[]> {
95
+ try {
96
+ const searchResults = await search(query, {
97
+ safeSearch: SafeSearchType.MODERATE
98
+ });
99
+
100
+ if (!searchResults.noResults && searchResults.results.length > 0) {
101
+ const maxResults = depth > 1 ? 15 : 8;
102
+ return searchResults.results.slice(0, maxResults).map(r => ({
103
+ title: r.title,
104
+ url: r.url,
105
+ content: r.description || r.title
106
+ }));
107
+ }
108
+ return [];
109
+ } catch (e: any) {
110
+ throw new Error(`[DuckDuckGo Error] Failed to scrape: ${e.message}`);
111
+ }
112
+ }
113
+
93
114
  const searchCache = new Map<string, {data: SearchQueryResult[], timestamp: number}>();
94
115
 
95
116
  export async function searchWeb(query: string, depth: number = 1): Promise<string> {
@@ -134,12 +155,22 @@ export async function searchWeb(query: string, depth: number = 1): Promise<strin
134
155
  try {
135
156
  results = await searchBrave(finalQuery, creds.brave_key, depth);
136
157
  } catch (e2: any) {
137
- console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to SearXNG Mesh...');
138
- results = await searchSearxng(finalQuery, depth);
158
+ console.warn('[WebSearch] Backup provider (Brave) failed. Falling back to DuckDuckGo (L3)...');
159
+ try {
160
+ results = await searchDuckDuckGo(finalQuery, depth);
161
+ } catch (e3) {
162
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
163
+ results = await searchSearxng(finalQuery, depth);
164
+ }
139
165
  }
140
166
  } else {
141
- console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
142
- results = await searchSearxng(finalQuery, depth);
167
+ console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
168
+ try {
169
+ results = await searchDuckDuckGo(finalQuery, depth);
170
+ } catch (e3) {
171
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
172
+ results = await searchSearxng(finalQuery, depth);
173
+ }
143
174
  }
144
175
  } else {
145
176
  throw e;
@@ -155,17 +186,34 @@ export async function searchWeb(query: string, depth: number = 1): Promise<strin
155
186
  try {
156
187
  results = await searchTavily(finalQuery, creds.tavily_key, depth);
157
188
  } catch (e2: any) {
158
- console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to SearXNG Mesh...');
159
- results = await searchSearxng(finalQuery, depth);
189
+ console.warn('[WebSearch] Backup provider (Tavily) failed. Falling back to DuckDuckGo (L3)...');
190
+ try {
191
+ results = await searchDuckDuckGo(finalQuery, depth);
192
+ } catch (e3) {
193
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
194
+ results = await searchSearxng(finalQuery, depth);
195
+ }
160
196
  }
161
197
  } else {
162
- console.warn('[WebSearch] No backup provider found. Falling back to SearXNG Mesh...');
163
- results = await searchSearxng(finalQuery, depth);
198
+ console.warn('[WebSearch] No backup premium provider found. Falling back to DuckDuckGo (L3)...');
199
+ try {
200
+ results = await searchDuckDuckGo(finalQuery, depth);
201
+ } catch (e3) {
202
+ console.warn('[WebSearch] DuckDuckGo failed. Falling back to SearXNG Mesh...');
203
+ results = await searchSearxng(finalQuery, depth);
204
+ }
164
205
  }
165
206
  } else {
166
207
  throw e;
167
208
  }
168
209
  }
210
+ } else if (provider === 'duckduckgo') {
211
+ try {
212
+ results = await searchDuckDuckGo(finalQuery, depth);
213
+ } catch (e: any) {
214
+ console.warn('[WebSearch] Primary provider (DuckDuckGo) failed. Falling back to SearXNG Mesh...');
215
+ results = await searchSearxng(finalQuery, depth);
216
+ }
169
217
  } else {
170
218
  results = await searchSearxng(finalQuery, depth);
171
219
  }
@@ -2,6 +2,8 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
4
  import crypto from 'crypto';
5
+ import http from 'http';
6
+ import { pack } from 'msgpackr';
5
7
 
6
8
  function getInternalToken(): string | undefined {
7
9
  try {
@@ -15,17 +17,46 @@ function getInternalToken(): string | undefined {
15
17
 
16
18
  export async function getAddress(): Promise<string> {
17
19
  const token = getInternalToken();
18
- try {
19
- const res = await fetch(`http://127.0.0.1:${process.env.POLICY_PORT || 3001}/address`, {
20
- headers: token ? { 'Authorization': `Bearer ${token}` } : {},
21
- signal: AbortSignal.timeout(30000)
20
+ return new Promise((resolve, reject) => {
21
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
22
+ const options = {
23
+ socketPath: fs.existsSync(POLICY_SOCKET) ? POLICY_SOCKET : undefined,
24
+ host: fs.existsSync(POLICY_SOCKET) ? undefined : '127.0.0.1',
25
+ port: fs.existsSync(POLICY_SOCKET) ? undefined : (process.env.POLICY_PORT || 3001),
26
+ path: '/address',
27
+ method: 'GET',
28
+ headers: {
29
+ ...(token ? { 'Authorization': `Bearer ${token}` } : {})
30
+ }
31
+ };
32
+
33
+ const req = http.request(options, (res) => {
34
+ let data = '';
35
+ res.on('data', chunk => data += chunk);
36
+ res.on('end', () => {
37
+ try {
38
+ if (res.statusCode !== 200) {
39
+ reject(new Error(data));
40
+ return;
41
+ }
42
+ const parsed = JSON.parse(data);
43
+ resolve(parsed.address);
44
+ } catch (e: any) {
45
+ reject(new Error(`Failed to get address from vault: ${e.message}`));
46
+ }
47
+ });
22
48
  });
23
- if (!res.ok) throw new Error(await res.text());
24
- const data = await res.json();
25
- return data.address;
26
- } catch (error: any) {
27
- throw new Error(`Failed to get address from vault: ${error.message}`);
28
- }
49
+
50
+ req.on('error', (error) => {
51
+ reject(new Error(`Failed to get address from vault: ${error.message}`));
52
+ });
53
+
54
+ req.setTimeout(30000, () => {
55
+ req.destroy(new Error('Timeout'));
56
+ });
57
+
58
+ req.end();
59
+ });
29
60
  }
30
61
 
31
62
  export async function submitTransaction(txPayload: any): Promise<string> {
@@ -39,25 +70,54 @@ export async function submitTransaction(txPayload: any): Promise<string> {
39
70
  const secret = getInternalToken() || '';
40
71
  txPayload.internalSignature = crypto.createHmac('sha256', secret).update(txPayload.chainName + amountWei).digest('hex');
41
72
  }
42
- try {
43
- const res = await fetch(`http://127.0.0.1:${process.env.POLICY_PORT || 3001}/request-tx`, {
73
+ return new Promise((resolve, reject) => {
74
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
75
+ const payloadBuffer = pack(txPayload);
76
+
77
+ const options = {
78
+ socketPath: fs.existsSync(POLICY_SOCKET) ? POLICY_SOCKET : undefined,
79
+ host: fs.existsSync(POLICY_SOCKET) ? undefined : '127.0.0.1',
80
+ port: fs.existsSync(POLICY_SOCKET) ? undefined : (process.env.POLICY_PORT || 3001),
81
+ path: '/request-tx',
44
82
  method: 'POST',
45
83
  headers: {
46
- 'Content-Type': 'application/json',
84
+ 'Content-Type': 'application/msgpack',
85
+ 'Content-Length': payloadBuffer.length,
47
86
  ...(token ? { 'Authorization': `Bearer ${token}` } : {})
48
- },
49
- body: JSON.stringify(txPayload),
50
- signal: AbortSignal.timeout(30000)
87
+ }
88
+ };
89
+
90
+ const req = http.request(options, (res) => {
91
+ let data = '';
92
+ res.on('data', chunk => data += chunk);
93
+ res.on('end', () => {
94
+ try {
95
+ const parsed = JSON.parse(data);
96
+ if (res.statusCode !== 200) {
97
+ reject(new Error(parsed.error || 'Failed to submit transaction'));
98
+ return;
99
+ }
100
+ if (parsed.status === 'pending') {
101
+ resolve(`Pending (ID: ${parsed.txId})`);
102
+ return;
103
+ }
104
+ resolve(parsed.signedHash || parsed.hash || parsed.txHash || parsed.status || 'Transaction executed successfully (No Hash returned)');
105
+ } catch (e: any) {
106
+ reject(new Error(`Failed to parse vault response: ${e.message}`));
107
+ }
108
+ });
51
109
  });
52
- const data = await res.json();
53
- if (!res.ok) throw new Error(data.error || 'Failed to submit transaction');
54
-
55
- if (data.status === 'pending') {
56
- return `Pending (ID: ${data.txId})`;
57
- }
58
- return data.signedHash || data.hash || data.txHash || data.status || 'Transaction executed successfully (No Hash returned)';
59
- } catch (error: any) {
60
- throw new Error(`Transaction submission failed: ${error.message}`);
61
- }
110
+
111
+ req.on('error', (error) => {
112
+ reject(new Error(`Transaction submission failed: ${error.message}`));
113
+ });
114
+
115
+ req.setTimeout(30000, () => {
116
+ req.destroy(new Error('Timeout'));
117
+ });
118
+
119
+ req.write(payloadBuffer);
120
+ req.end();
121
+ });
62
122
  }
63
123
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nyxora-dashboard",
3
3
  "private": true,
4
- "version": "26.6.22-1",
4
+ "version": "26.6.23",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nyxora-mcp-server",
3
- "version": "26.6.22-1",
3
+ "version": "26.6.23",
4
4
  "description": "Nyxora MCP Subserver, for external AI clients",
5
5
  "main": "dist/server.js",
6
6
  "scripts": {
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "nyxora-policy-engine",
3
- "version": "26.6.22-1",
3
+ "version": "26.6.23",
4
4
  "private": true,
5
5
  "main": "src/server.ts",
6
6
  "dependencies": {
7
7
  "express": "^5.2.1",
8
- "zod": "^3.23.8",
9
8
  "jsonwebtoken": "^9.0.2",
10
- "yaml": "^2.9.0"
9
+ "msgpackr": "^2.0.4",
10
+ "yaml": "^2.9.0",
11
+ "zod": "^3.23.8"
11
12
  }
12
13
  }
@@ -11,6 +11,7 @@ import { z } from 'zod';
11
11
  import path from 'path';
12
12
  import crypto from 'crypto';
13
13
  import os from 'os';
14
+ import { unpack } from 'msgpackr';
14
15
 
15
16
  process.on('unhandledRejection', (reason, promise) => {
16
17
  console.error('[Anti-Crash] Unhandled Rejection at:', promise, 'reason:', reason);
@@ -36,6 +37,24 @@ const SIGNER_SOCKET = process.env.SIGNER_SOCKET_PATH || '/tmp/nyxora-signer.sock
36
37
  const app = express();
37
38
  app.use(express.json());
38
39
 
40
+ // MessagePack Parser Middleware for Hyper-Optimized IPC
41
+ app.use((req, res, next) => {
42
+ if (req.headers['content-type'] === 'application/msgpack') {
43
+ let chunks: Buffer[] = [];
44
+ req.on('data', chunk => chunks.push(chunk));
45
+ req.on('end', () => {
46
+ try {
47
+ req.body = unpack(Buffer.concat(chunks));
48
+ next();
49
+ } catch (e) {
50
+ res.status(400).json({ error: 'Invalid MessagePack payload' });
51
+ }
52
+ });
53
+ } else {
54
+ next();
55
+ }
56
+ });
57
+
39
58
  const TxRequestSchema = z.object({
40
59
  type: z.enum(['transfer', 'swap', 'bridge', 'mint', 'custom']),
41
60
  chainName: z.string(),
@@ -261,6 +280,8 @@ app.post('/approve-tx/:id', (req, res) => {
261
280
  signerReq.end();
262
281
  });
263
282
 
283
+ const POLICY_SOCKET = '/tmp/nyxora-policy.sock';
284
+
264
285
  const server = app.listen(Number(PORT), '127.0.0.1', () => {
265
286
  console.log(`[Policy Engine] Listening on 127.0.0.1:${PORT} (Secured Local Loopback)`);
266
287
  });
@@ -274,3 +295,10 @@ server.on('error', (e: any) => {
274
295
  process.exit(1);
275
296
  }
276
297
  });
298
+
299
+ // Start UDS Server for Hyper-Optimized IPC
300
+ const udsServer = http.createServer(app);
301
+ if (fs.existsSync(POLICY_SOCKET)) fs.unlinkSync(POLICY_SOCKET);
302
+ udsServer.listen(POLICY_SOCKET, () => {
303
+ console.log(`[Policy Engine] Listening on UDS ${POLICY_SOCKET} (Hyper-Optimized IPC)`);
304
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nyxora-signer",
3
- "version": "26.6.22-1",
3
+ "version": "26.6.23",
4
4
  "private": true,
5
5
  "main": "src/server.ts",
6
6
  "dependencies": {