docs-combiner 0.1.17 → 0.1.19
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/dist/main.js +181 -6
- package/dist/preload.js +2 -0
- package/dist/renderer.js +1932 -556
- package/dist/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -48,6 +48,66 @@ const fs = __importStar(require("fs"));
|
|
|
48
48
|
const http = __importStar(require("http"));
|
|
49
49
|
const url = __importStar(require("url"));
|
|
50
50
|
let pendingGoogleAuth = null;
|
|
51
|
+
let mainWindow = null;
|
|
52
|
+
if (process.env.DOCS_COMBINER_DISABLE_GPU === '1') {
|
|
53
|
+
electron_1.app.disableHardwareAcceleration();
|
|
54
|
+
}
|
|
55
|
+
function getInspectableWindow() {
|
|
56
|
+
var _a, _b, _c;
|
|
57
|
+
return (_c = (_b = (_a = electron_1.BrowserWindow.getFocusedWindow()) !== null && _a !== void 0 ? _a : mainWindow) !== null && _b !== void 0 ? _b : electron_1.BrowserWindow.getAllWindows()[0]) !== null && _c !== void 0 ? _c : null;
|
|
58
|
+
}
|
|
59
|
+
function toggleDevToolsForWindow(win) {
|
|
60
|
+
if (!win || win.isDestroyed()) {
|
|
61
|
+
console.warn('[DevTools] No BrowserWindow available');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const webContents = win.webContents;
|
|
65
|
+
if (webContents.isDestroyed()) {
|
|
66
|
+
console.warn('[DevTools] WebContents is destroyed');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
if (webContents.isDevToolsOpened()) {
|
|
71
|
+
webContents.closeDevTools();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
webContents.openDevTools({ mode: 'detach', activate: true });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error('[DevTools] Failed to toggle DevTools:', e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function telegramSendMessageViaBot(botToken, chatId, text) {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
const apiUrl = `https://api.telegram.org/bot${encodeURIComponent(botToken)}/sendMessage`;
|
|
84
|
+
const safeText = text.length > 4096 ? `${text.slice(0, 4090)}…` : text;
|
|
85
|
+
try {
|
|
86
|
+
const res = yield fetch(apiUrl, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: { 'Content-Type': 'application/json' },
|
|
89
|
+
body: JSON.stringify({
|
|
90
|
+
chat_id: chatId,
|
|
91
|
+
text: safeText,
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
const data = (yield res.json());
|
|
95
|
+
if (!data.ok) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: data.description || `HTTP ${res.status}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return { ok: true };
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
error: e instanceof Error ? e.message : String(e),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
51
111
|
function abortPendingGoogleAuth(reason) {
|
|
52
112
|
const pending = pendingGoogleAuth;
|
|
53
113
|
if (!pending)
|
|
@@ -61,6 +121,52 @@ function abortPendingGoogleAuth(reason) {
|
|
|
61
121
|
}
|
|
62
122
|
pending.reject(new Error(reason));
|
|
63
123
|
}
|
|
124
|
+
function buildAppMenu() {
|
|
125
|
+
const isMac = process.platform === 'darwin';
|
|
126
|
+
const template = [];
|
|
127
|
+
if (isMac) {
|
|
128
|
+
template.push({ role: 'appMenu' });
|
|
129
|
+
// Cut/Copy/Paste/Select All — без этого Cmd+V в полях иногда не работает (Chromium + системное меню).
|
|
130
|
+
template.push({ role: 'editMenu' });
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
template.push({
|
|
134
|
+
label: 'File',
|
|
135
|
+
submenu: [{ role: 'quit' }],
|
|
136
|
+
});
|
|
137
|
+
template.push({
|
|
138
|
+
label: 'Edit',
|
|
139
|
+
submenu: [
|
|
140
|
+
{ role: 'undo' },
|
|
141
|
+
{ role: 'redo' },
|
|
142
|
+
{ type: 'separator' },
|
|
143
|
+
{ role: 'cut' },
|
|
144
|
+
{ role: 'copy' },
|
|
145
|
+
{ role: 'paste' },
|
|
146
|
+
{ role: 'delete' },
|
|
147
|
+
{ type: 'separator' },
|
|
148
|
+
{ role: 'selectAll' },
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
template.push({
|
|
153
|
+
label: 'View',
|
|
154
|
+
submenu: [
|
|
155
|
+
{ role: 'reload' },
|
|
156
|
+
{ role: 'forceReload' },
|
|
157
|
+
{
|
|
158
|
+
label: 'Toggle Developer Tools',
|
|
159
|
+
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
|
160
|
+
click: () => toggleDevToolsForWindow(getInspectableWindow()),
|
|
161
|
+
},
|
|
162
|
+
{ type: 'separator' },
|
|
163
|
+
{ role: 'resetZoom' },
|
|
164
|
+
{ role: 'zoomIn' },
|
|
165
|
+
{ role: 'zoomOut' },
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
electron_1.Menu.setApplicationMenu(electron_1.Menu.buildFromTemplate(template));
|
|
169
|
+
}
|
|
64
170
|
function createWindow() {
|
|
65
171
|
// Try to read theme preference from localStorage file
|
|
66
172
|
// In Electron, localStorage is stored in a specific location
|
|
@@ -74,7 +180,7 @@ function createWindow() {
|
|
|
74
180
|
catch (e) {
|
|
75
181
|
// Use default
|
|
76
182
|
}
|
|
77
|
-
|
|
183
|
+
mainWindow = new electron_1.BrowserWindow({
|
|
78
184
|
width: 1000,
|
|
79
185
|
height: 800,
|
|
80
186
|
backgroundColor: '#121212', // Set to dark by default, will be corrected by preload if light
|
|
@@ -86,10 +192,47 @@ function createWindow() {
|
|
|
86
192
|
sandbox: false
|
|
87
193
|
},
|
|
88
194
|
});
|
|
195
|
+
const win = mainWindow;
|
|
196
|
+
// Toggles from main: works when the page/React failed — handled before the renderer consumes the key.
|
|
197
|
+
// F12, Cmd+Shift+D (mac) / Ctrl+Shift+D (win/linux); also View → Toggle Developer Tools / Cmd+Option+I (see menu).
|
|
198
|
+
win.webContents.on('before-input-event', (event, input) => {
|
|
199
|
+
if (input.type !== 'keyDown') {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (input.key === 'F12' && !input.control && !input.meta && !input.alt) {
|
|
203
|
+
toggleDevToolsForWindow(win);
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (input.key.toLowerCase() !== 'd' || !input.shift || input.alt) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const isMac = process.platform === 'darwin';
|
|
211
|
+
const hasPrimaryMod = isMac ? input.meta === true : input.control === true;
|
|
212
|
+
if (hasPrimaryMod) {
|
|
213
|
+
toggleDevToolsForWindow(win);
|
|
214
|
+
event.preventDefault();
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
win.webContents.on('render-process-gone', (_event, details) => {
|
|
218
|
+
console.error(`[Renderer] render-process-gone: reason=${details.reason}, exitCode=${details.exitCode}`);
|
|
219
|
+
});
|
|
220
|
+
win.webContents.on('unresponsive', () => {
|
|
221
|
+
console.error('[Renderer] webContents became unresponsive');
|
|
222
|
+
});
|
|
223
|
+
win.webContents.on('responsive', () => {
|
|
224
|
+
console.log('[Renderer] webContents became responsive');
|
|
225
|
+
});
|
|
226
|
+
win.webContents.on('did-fail-load', (_event, errorCode, errorDescription, validatedURL) => {
|
|
227
|
+
console.error(`[Renderer] did-fail-load: ${errorCode} ${errorDescription} ${validatedURL}`);
|
|
228
|
+
});
|
|
229
|
+
win.webContents.on('console-message', (_event, level, message, line, sourceId) => {
|
|
230
|
+
console.log(`[Renderer console:${level}] ${message} (${sourceId}:${line})`);
|
|
231
|
+
});
|
|
89
232
|
// Show window only after page is ready to prevent white flash
|
|
90
|
-
|
|
233
|
+
win.webContents.once('did-finish-load', () => {
|
|
91
234
|
// Ensure theme is applied before showing
|
|
92
|
-
|
|
235
|
+
win.webContents.executeJavaScript(`
|
|
93
236
|
(function() {
|
|
94
237
|
const savedTheme = localStorage.getItem('themeMode');
|
|
95
238
|
const isDark = savedTheme === 'dark';
|
|
@@ -100,17 +243,21 @@ function createWindow() {
|
|
|
100
243
|
if (root) root.style.setProperty('background-color', bgColor, 'important');
|
|
101
244
|
})();
|
|
102
245
|
`).then(() => {
|
|
103
|
-
|
|
246
|
+
win.show();
|
|
104
247
|
}).catch(() => {
|
|
105
|
-
|
|
248
|
+
win.show();
|
|
106
249
|
});
|
|
107
250
|
});
|
|
108
251
|
// We need to point to the webpack output html
|
|
109
|
-
|
|
252
|
+
win.loadFile(path.join(__dirname, 'index.html'));
|
|
110
253
|
// DevTools disabled by default as requested
|
|
111
254
|
// mainWindow.webContents.openDevTools();
|
|
112
255
|
}
|
|
113
256
|
electron_1.app.whenReady().then(() => {
|
|
257
|
+
buildAppMenu();
|
|
258
|
+
electron_1.app.on('child-process-gone', (_event, details) => {
|
|
259
|
+
console.error(`[Electron] child-process-gone: type=${details.type}, reason=${details.reason}, exitCode=${details.exitCode}`);
|
|
260
|
+
});
|
|
114
261
|
const userDataPath = electron_1.app.getPath('userData');
|
|
115
262
|
if (!fs.existsSync(userDataPath)) {
|
|
116
263
|
fs.mkdirSync(userDataPath, { recursive: true });
|
|
@@ -137,6 +284,28 @@ electron_1.app.whenReady().then(() => {
|
|
|
137
284
|
return {};
|
|
138
285
|
}
|
|
139
286
|
}));
|
|
287
|
+
electron_1.ipcMain.handle('telegram-send-test', (_event, payload) => __awaiter(void 0, void 0, void 0, function* () {
|
|
288
|
+
var _a, _b;
|
|
289
|
+
const botToken = String((_a = payload === null || payload === void 0 ? void 0 : payload.botToken) !== null && _a !== void 0 ? _a : '').trim();
|
|
290
|
+
const chatId = String((_b = payload === null || payload === void 0 ? void 0 : payload.chatId) !== null && _b !== void 0 ? _b : '').trim();
|
|
291
|
+
if (!botToken || !chatId) {
|
|
292
|
+
return { ok: false, error: 'Укажите токен бота и ID чата.' };
|
|
293
|
+
}
|
|
294
|
+
return telegramSendMessageViaBot(botToken, chatId, 'Docs Combiner — тест оповещений.');
|
|
295
|
+
}));
|
|
296
|
+
electron_1.ipcMain.handle('telegram-send-message', (_event, payload) => __awaiter(void 0, void 0, void 0, function* () {
|
|
297
|
+
var _a, _b, _c;
|
|
298
|
+
const botToken = String((_a = payload === null || payload === void 0 ? void 0 : payload.botToken) !== null && _a !== void 0 ? _a : '').trim();
|
|
299
|
+
const chatId = String((_b = payload === null || payload === void 0 ? void 0 : payload.chatId) !== null && _b !== void 0 ? _b : '').trim();
|
|
300
|
+
const text = String((_c = payload === null || payload === void 0 ? void 0 : payload.text) !== null && _c !== void 0 ? _c : '');
|
|
301
|
+
if (!botToken || !chatId) {
|
|
302
|
+
return { ok: false, error: 'Укажите токен бота и ID чата.' };
|
|
303
|
+
}
|
|
304
|
+
if (!text.trim()) {
|
|
305
|
+
return { ok: false, error: 'Пустой текст сообщения.' };
|
|
306
|
+
}
|
|
307
|
+
return telegramSendMessageViaBot(botToken, chatId, text);
|
|
308
|
+
}));
|
|
140
309
|
electron_1.ipcMain.handle('save-file', (event, content, filename) => __awaiter(void 0, void 0, void 0, function* () {
|
|
141
310
|
const { canceled, filePath } = yield electron_1.dialog.showSaveDialog({
|
|
142
311
|
defaultPath: filename,
|
|
@@ -275,3 +444,9 @@ electron_1.app.whenReady().then(() => {
|
|
|
275
444
|
electron_1.app.on('window-all-closed', function () {
|
|
276
445
|
electron_1.app.quit();
|
|
277
446
|
});
|
|
447
|
+
process.on('uncaughtException', (err) => {
|
|
448
|
+
console.error('[Main] uncaughtException:', err);
|
|
449
|
+
});
|
|
450
|
+
process.on('unhandledRejection', (reason) => {
|
|
451
|
+
console.error('[Main] unhandledRejection:', reason);
|
|
452
|
+
});
|
package/dist/preload.js
CHANGED
|
@@ -59,4 +59,6 @@ electron_1.contextBridge.exposeInMainWorld('electronAPI', {
|
|
|
59
59
|
cancelPendingAuth: () => electron_1.ipcRenderer.invoke('cancel-pending-auth'),
|
|
60
60
|
openExternal: (url) => electron_1.ipcRenderer.invoke('open-external', url),
|
|
61
61
|
log: (level, ...args) => electron_1.ipcRenderer.invoke('log', level, ...args),
|
|
62
|
+
telegramSendTest: (botToken, chatId) => electron_1.ipcRenderer.invoke('telegram-send-test', { botToken, chatId }),
|
|
63
|
+
telegramSendMessage: (botToken, chatId, text) => electron_1.ipcRenderer.invoke('telegram-send-message', { botToken, chatId, text }),
|
|
62
64
|
});
|