@glassnote/client 2.4.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.
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,61 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ version="1.1"
6
+ id="svg1"
7
+ width="346"
8
+ height="450"
9
+ viewBox="0 0 346 450"
10
+ sodipodi:docname="splash.svg"
11
+ inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
12
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
14
+ xmlns:xlink="http://www.w3.org/1999/xlink"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ xmlns:svg="http://www.w3.org/2000/svg">
17
+ <defs
18
+ id="defs1" />
19
+ <sodipodi:namedview
20
+ id="namedview1"
21
+ pagecolor="#ffffff"
22
+ bordercolor="#111111"
23
+ borderopacity="1"
24
+ inkscape:showpageshadow="0"
25
+ inkscape:pageopacity="0"
26
+ inkscape:pagecheckerboard="1"
27
+ inkscape:deskcolor="#d1d1d1"
28
+ inkscape:zoom="0.7835776"
29
+ inkscape:cx="62.533692"
30
+ inkscape:cy="186.96298"
31
+ inkscape:window-width="1920"
32
+ inkscape:window-height="1009"
33
+ inkscape:window-x="1912"
34
+ inkscape:window-y="-8"
35
+ inkscape:window-maximized="1"
36
+ inkscape:current-layer="g1" />
37
+ <g
38
+ inkscape:groupmode="layer"
39
+ inkscape:label="Image"
40
+ id="g1">
41
+ <image
42
+ width="346"
43
+ height="356"
44
+ preserveAspectRatio="none"
45
+ xlink:href="data:image/png;base64,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&#10;D1H8IjIWO4/4AAAAAElFTkSuQmCC&#10;"
46
+ id="image1"
47
+ x="0"
48
+ y="22" />
49
+ <text
50
+ xml:space="preserve"
51
+ style="font-size:43.7629px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.73518;fill:#333366;fill-opacity:0.90196079"
52
+ x="11.1488"
53
+ y="419.67566"
54
+ id="text1"><tspan
55
+ sodipodi:role="line"
56
+ id="tspan1"
57
+ x="11.1488"
58
+ y="419.67566"
59
+ style="stroke-width:2.73518;fill:#333366;fill-opacity:0.90196079">%VERSION%</tspan></text>
60
+ </g>
61
+ </svg>
package/localserver.js ADDED
@@ -0,0 +1,297 @@
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const { ipcMain } = require('electron');
4
+ const userData = require('./userData');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ // Get log file path from main process environment or use default
9
+ const logsDir = process.env.GLASSNOTE_LOGS_DIR || path.join(userData.getUserDataDir(), 'logs');
10
+ const logFilePath = process.env.GLASSNOTE_LOG_FILE || path.join(logsDir, `glassnote-${new Date().toISOString().split('T')[0]}.log`);
11
+
12
+ // Ensure logs directory exists
13
+ try {
14
+ if (!fs.existsSync(logsDir)) {
15
+ fs.mkdirSync(logsDir, { recursive: true });
16
+ }
17
+ } catch (dirError) {
18
+ console.error('Error creating logs directory:', dirError);
19
+ }
20
+
21
+ // General logging utility for all messages
22
+ function logToFile(level, message, additionalData = null) {
23
+ const timestamp = new Date().toISOString();
24
+ const logMessage = `[${timestamp}] [${level}] ${message}` +
25
+ (additionalData ? `\nAdditional data: ${JSON.stringify(additionalData, null, 2)}` : '') +
26
+ '\n';
27
+
28
+ try {
29
+ fs.appendFileSync(logFilePath, logMessage, 'utf8');
30
+ } catch (fileError) {
31
+ console.error('Error writing to log file:', fileError);
32
+ }
33
+ }
34
+
35
+ // Error logging utility with direct file writing
36
+ function logError(context, error, additionalInfo = {}) {
37
+ const timestamp = new Date().toISOString();
38
+ const errorMessage = `LocalServer Error [${context}]: ${error.message || error}`;
39
+ const errorDetails = {
40
+ context,
41
+ error: error.message || error,
42
+ stack: error.stack || 'No stack trace',
43
+ timestamp,
44
+ ...additionalInfo
45
+ };
46
+
47
+ // Write to log file using general logging utility
48
+ logToFile('ERROR', errorMessage, errorDetails);
49
+
50
+ // Also log to console for immediate visibility
51
+ console.error(`[${timestamp}] ${errorMessage}`);
52
+ }
53
+
54
+ class LocalServer {
55
+ constructor() {
56
+ if (LocalServer.instance) {
57
+ return LocalServer.instance;
58
+ }
59
+ LocalServer.instance = this;
60
+
61
+ this.mainWindow = null;
62
+ this.server = null;
63
+ this.retryTimer = null;
64
+ this.pendingResponses = new Map();
65
+ this.isRunning = false;
66
+
67
+ // Setup global error handlers for this instance
68
+ this.setupGlobalErrorHandlers();
69
+ }
70
+
71
+ setupGlobalErrorHandlers() {
72
+ // Handle uncaught exceptions specific to this server
73
+ if (!this.uncaughtExceptionHandler) {
74
+ this.uncaughtExceptionHandler = (error) => {
75
+ logError('UNCAUGHT_EXCEPTION', error, {
76
+ serverRunning: this.isRunning,
77
+ pendingResponsesCount: this.pendingResponses.size
78
+ });
79
+ };
80
+ process.on('uncaughtException', this.uncaughtExceptionHandler);
81
+ }
82
+
83
+ // Handle unhandled promise rejections
84
+ if (!this.unhandledRejectionHandler) {
85
+ this.unhandledRejectionHandler = (reason, promise) => {
86
+ logError('UNHANDLED_PROMISE_REJECTION', reason, {
87
+ promise: promise.toString(),
88
+ serverRunning: this.isRunning,
89
+ pendingResponsesCount: this.pendingResponses.size
90
+ });
91
+ };
92
+ process.on('unhandledRejection', this.unhandledRejectionHandler);
93
+ }
94
+ }
95
+
96
+ start(mainWindow) {
97
+ try {
98
+ this.mainWindow = mainWindow;
99
+
100
+ if (this.isRunning) {
101
+ const message = 'LocalServer is already running';
102
+ logToFile('INFO', message);
103
+ return;
104
+ }
105
+
106
+ // Create Express app
107
+ const app = express();
108
+
109
+ // Enable CORS for all routes
110
+ app.use(cors());
111
+
112
+ // Parse JSON bodies
113
+ app.use(express.json());
114
+
115
+ // Setup routes
116
+ app.get('/uuid', (req, res) => {
117
+ try {
118
+ const uuid = userData.getUUID();
119
+ res.json({ uuid });
120
+ } catch (error) {
121
+ logError('UUID_ENDPOINT', error);
122
+ res.status(500).json({ error: 'Internal Server Error' });
123
+ }
124
+ });
125
+
126
+ app.get('/code', (req, res) => {
127
+ try {
128
+ if (this.mainWindow && !this.mainWindow.isDestroyed()) {
129
+ this.mainWindow.webContents.send('show-code');
130
+ res.json({ show: true });
131
+ } else {
132
+ logError('MAINWINDOW_UNAVAILABLE', new Error('MainWindow not available for show-code'));
133
+ res.status(500).json({ error: 'Window unavailable' });
134
+ }
135
+ } catch (error) {
136
+ logError('CODE_ENDPOINT', error);
137
+ res.status(500).json({ error: 'Internal Server Error' });
138
+ }
139
+ });
140
+
141
+ app.get('/hidecode', (req, res) => {
142
+ try {
143
+ if (this.mainWindow && !this.mainWindow.isDestroyed()) {
144
+ this.mainWindow.webContents.send('hide-code');
145
+ res.json({ show: false });
146
+ } else {
147
+ logError('MAINWINDOW_UNAVAILABLE', new Error('MainWindow not available for hide-code'));
148
+ res.status(500).json({ error: 'Window unavailable' });
149
+ }
150
+ } catch (error) {
151
+ logError('HIDECODE_ENDPOINT', error);
152
+ res.status(500).json({ error: 'Internal Server Error' });
153
+ }
154
+ });
155
+
156
+ app.get('/iscodevisible', (req, res) => {
157
+ try {
158
+ if (this.mainWindow && !this.mainWindow.isDestroyed()) {
159
+ const requestId = Date.now();
160
+ this.pendingResponses.set(requestId, res);
161
+ this.mainWindow.webContents.send('check-code-visible', requestId);
162
+
163
+ // Set timeout for response (30 seconds)
164
+ setTimeout(() => {
165
+ if (this.pendingResponses.has(requestId)) {
166
+ logError('RESPONSE_TIMEOUT', new Error('Response timeout for check-code-visible'));
167
+ res.status(500).json({ error: 'Timeout' });
168
+ this.pendingResponses.delete(requestId);
169
+ }
170
+ }, 30000);
171
+ } else {
172
+ logError('MAINWINDOW_UNAVAILABLE', new Error('MainWindow not available for check-code-visible'));
173
+ res.status(500).json({ error: 'Window unavailable' });
174
+ }
175
+ } catch (error) {
176
+ logError('ISCODEVISIBLE_ENDPOINT', error);
177
+ res.status(500).json({ error: 'Internal Server Error' });
178
+ }
179
+ });
180
+
181
+ // Handle 404
182
+ app.use((req, res) => {
183
+ res.status(404).json({ error: 'Invalid endpoint' });
184
+ });
185
+
186
+ // Error handling middleware
187
+ app.use((error, req, res, next) => {
188
+ logError('EXPRESS_ERROR', error);
189
+ res.status(500).json({ error: 'Internal Server Error' });
190
+ });
191
+
192
+ // Start server
193
+ this.server = app.listen(48984, () => {
194
+ const message = 'Servidor escuchando en puerto 48984';
195
+ logToFile('INFO', message);
196
+ this.isRunning = true;
197
+ if (this.retryTimer) clearTimeout(this.retryTimer);
198
+ });
199
+
200
+ this.server.on('error', (err) => {
201
+ logError('SERVER_LISTEN', err, { port: 48984 });
202
+ const message = 'Error al iniciar servidor - Reintentando en 30 segundos';
203
+ logToFile('WARN', message);
204
+ this.isRunning = false;
205
+ this.retryTimer = setTimeout(() => this.start(mainWindow), 30000);
206
+ });
207
+
208
+ // Setup IPC handlers only once
209
+ if (!this.ipcHandlersSetup) {
210
+ try {
211
+ ipcMain.on(
212
+ 'check-code-visible-response',
213
+ (event, { requestId, isVisible }) => {
214
+ try {
215
+ const message = `check-code-visible-response ${requestId} ${isVisible}`;
216
+ logToFile('INFO', message);
217
+
218
+ const res = this.pendingResponses.get(requestId);
219
+ if (res) {
220
+ res.json({ show: isVisible });
221
+ this.pendingResponses.delete(requestId);
222
+ }
223
+ } catch (error) {
224
+ logError('IPC_RESPONSE', error, { requestId, isVisible });
225
+ }
226
+ }
227
+ );
228
+ this.ipcHandlersSetup = true;
229
+ } catch (error) {
230
+ logError('IPC_SETUP', error);
231
+ }
232
+ }
233
+ } catch (error) {
234
+ logError('START_METHOD', error);
235
+ }
236
+ }
237
+
238
+ stop() {
239
+ try {
240
+ if (this.server) {
241
+ this.server.close((error) => {
242
+ if (error) {
243
+ logError('SERVER_CLOSE', error);
244
+ } else {
245
+ const message = 'LocalServer stopped successfully';
246
+ logToFile('INFO', message);
247
+ }
248
+ });
249
+ }
250
+ if (this.retryTimer) {
251
+ clearTimeout(this.retryTimer);
252
+ this.retryTimer = null;
253
+ }
254
+
255
+ // Clean up pending responses
256
+ this.pendingResponses.forEach((res, requestId) => {
257
+ try {
258
+ if (!res.headersSent) {
259
+ res.status(500).json({ error: 'Server shutting down' });
260
+ }
261
+ } catch (error) {
262
+ logError('CLEANUP_RESPONSE', error, { requestId });
263
+ }
264
+ });
265
+ this.pendingResponses.clear();
266
+
267
+ // Clean up global error handlers
268
+ if (this.uncaughtExceptionHandler) {
269
+ process.removeListener('uncaughtException', this.uncaughtExceptionHandler);
270
+ this.uncaughtExceptionHandler = null;
271
+ }
272
+ if (this.unhandledRejectionHandler) {
273
+ process.removeListener('unhandledRejection', this.unhandledRejectionHandler);
274
+ this.unhandledRejectionHandler = null;
275
+ }
276
+
277
+ this.isRunning = false;
278
+ } catch (error) {
279
+ logError('STOP_METHOD', error);
280
+ }
281
+ }
282
+
283
+ updateMainWindow(mainWindow) {
284
+ try {
285
+ this.mainWindow = mainWindow;
286
+ const message = 'LocalServer mainWindow updated';
287
+ logToFile('INFO', message);
288
+ } catch (error) {
289
+ logError('UPDATE_MAIN_WINDOW', error);
290
+ }
291
+ }
292
+ }
293
+
294
+ // Singleton instance
295
+ LocalServer.instance = null;
296
+
297
+ module.exports = LocalServer;
@@ -0,0 +1,128 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Creates tail utility files in the logs directory for debugging
6
+ * Windows: tail_logs.bat
7
+ * macOS: tail_logs.sh
8
+ * @param {string} logsDir - Path to the logs directory
9
+ */
10
+ function createTailUtility(logsDir) {
11
+ try {
12
+ // Detect operating system
13
+ const platform = process.platform;
14
+
15
+ if (platform === 'win32') {
16
+ // Create Windows batch file
17
+ const tailBatPath = path.join(logsDir, 'tail_logs.bat');
18
+ const tailBatContent = `@echo off
19
+ setlocal enabledelayedexpansion
20
+
21
+ :: GlassNote Log Tail Utility - Auto-generated
22
+ :: Place this file in your logs directory and double-click to tail latest log
23
+
24
+ echo GlassNote Log Tail Utility
25
+ echo =========================
26
+ echo.
27
+
28
+ :: Find the most recent log file using PowerShell for reliable timestamp comparison
29
+ for /f "delims=" %%F in ('powershell -Command "Get-ChildItem *.log | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty Name"') do (
30
+ set LATEST_FILE=%%F
31
+ )
32
+
33
+ :: Check if we found a log file
34
+ if "!LATEST_FILE!"=="" (
35
+ echo No .log files found in this directory.
36
+ echo.
37
+ echo Please make sure GlassNote has been run at least once
38
+ pause
39
+ exit /b 1
40
+ )
41
+
42
+ :: Get file modification time using PowerShell
43
+ for /f "delims=" %%T in ('powershell -Command "(Get-Item '!LATEST_FILE!').LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss')"') do (
44
+ set FILE_TIME=%%T
45
+ )
46
+
47
+ echo Found latest log: !LATEST_FILE!
48
+ echo File modified: !FILE_TIME!
49
+ echo.
50
+ echo Showing last 50 lines (will update live):
51
+ echo Press CTRL+C to exit
52
+ echo.
53
+ echo =========================
54
+
55
+ :: Tail the latest log file
56
+ powershell -Command "Get-Content '!LATEST_FILE!' -Wait -Tail 50"
57
+ `;
58
+
59
+ // Only create if it doesn't exist or is different
60
+ if (!fs.existsSync(tailBatPath) || fs.readFileSync(tailBatPath, 'utf8') !== tailBatContent) {
61
+ fs.writeFileSync(tailBatPath, tailBatContent, 'utf8');
62
+ return true;
63
+ }
64
+ return false; // File already exists and is up to date
65
+
66
+ } else if (platform === 'darwin') {
67
+ // Create macOS shell script
68
+ const tailShPath = path.join(logsDir, 'tail_logs.sh');
69
+ const tailShContent = `#!/bin/bash
70
+
71
+ # GlassNote Log Tail Utility - Auto-generated
72
+ # Place this file in your logs directory and run: ./tail_logs.sh
73
+
74
+ echo "GlassNote Log Tail Utility"
75
+ echo "========================="
76
+ echo
77
+
78
+ # Find the most recent log file using macOS native commands
79
+ LATEST_FILE=$(ls -t *.log 2>/dev/null | head -n 1)
80
+
81
+ # Check if we found a log file
82
+ if [ -z "$LATEST_FILE" ]; then
83
+ echo "No .log files found in this directory."
84
+ echo
85
+ echo "Please make sure GlassNote has been run at least once"
86
+ exit 1
87
+ fi
88
+
89
+ # Get file modification time
90
+ FILE_TIME=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$LATEST_FILE")
91
+
92
+ echo "Found latest log: $LATEST_FILE"
93
+ echo "File modified: $FILE_TIME"
94
+ echo
95
+ echo "Showing last 50 lines (will update live):"
96
+ echo "Press CTRL+C to exit"
97
+ echo
98
+ echo "========================="
99
+
100
+ # Tail the latest log file
101
+ tail -n 50 -f "$LATEST_FILE"
102
+ `;
103
+
104
+ // Only create if it doesn't exist or is different
105
+ if (!fs.existsSync(tailShPath) || fs.readFileSync(tailShPath, 'utf8') !== tailShContent) {
106
+ fs.writeFileSync(tailShPath, tailShContent, 'utf8');
107
+ // Make the script executable
108
+ try {
109
+ fs.chmodSync(tailShPath, 0o755); // rwxr-xr-x
110
+ } catch (chmodError) {
111
+ console.warn('Could not set executable permissions on macOS script (may need manual chmod +x):', chmodError.message);
112
+ }
113
+ return true;
114
+ }
115
+ return false; // File already exists and is up to date
116
+
117
+ } else {
118
+ return false;
119
+ }
120
+ } catch (error) {
121
+ console.error('Error creating tail utility:', error);
122
+ return false;
123
+ }
124
+ }
125
+
126
+ module.exports = {
127
+ createTailUtility
128
+ };