diff --git a/electron.js b/electron.js index 0a241af71d..6193e65a43 100644 --- a/electron.js +++ b/electron.js @@ -13,6 +13,10 @@ const Store = require('electron-store'); const suffix = app.isPackaged ? '' : 'dev'; const store = new Store({ name: [ 'localStorage', suffix ].join('-') }); +// gRPC DevTools extension ID +const GRPC_DEVTOOLS_ID = 'fohdnlaeecihjiendkfhifhlgldpeopm'; +const { installExtension } = require('@tomjs/electron-devtools-installer'); + // Fix notifications app name if (is.windows) { app.setAppUserModelId(app.name); @@ -182,7 +186,7 @@ function createWindow () { }); }; -app.on('ready', () => { +app.on('ready', async () => { session.defaultSession.webRequest.onHeadersReceived((details, callback) => { callback({ responseHeaders: { @@ -192,6 +196,21 @@ app.on('ready', () => { }); }); + // Load gRPC DevTools extension in development mode + if (is.development) { + try { + // Install the extension using electron-devtools-installer + const extension = await installExtension(GRPC_DEVTOOLS_ID, { + loadExtensionOptions: { + allowFileAccess: true + } + }); + console.log(`✅ gRPC DevTools extension installed`); + } catch (err) { + console.error('❌ Failed to install gRPC DevTools extension:', err.message); + } + } + ConfigManager.init(waitForLibraryAndCreateWindows); }); @@ -242,4 +261,4 @@ app.on('open-url', (e, url) => { Util.send(mainWindow, 'route', Util.getRouteFromUrl(url)); mainWindow.show(); }; -}); \ No newline at end of file +}); diff --git a/electron/json/cors.json b/electron/json/cors.json index 8439e360e2..0e414bc4ad 100644 --- a/electron/json/cors.json +++ b/electron/json/cors.json @@ -54,7 +54,8 @@ "https://s1.hdslb.com", "https://static.sketchfab.com", "https://*.diagrams.net", - "https://*.bstarstatic.com" + "https://*.bstarstatic.com", + "chrome-extension://fohdnlaeecihjiendkfhifhlgldpeopm/" ], "font-src": [ @@ -168,7 +169,8 @@ "https://*.bstarstatic.com", "https://*.googletagmanager.com", "https://*.facebook.net", - "https://*.diagrams.net" + "https://*.diagrams.net", + "chrome-extension://fohdnlaeecihjiendkfhifhlgldpeopm/" ], "frame-src": [ @@ -195,8 +197,9 @@ "https://cdpn.io", "https://kroki.io", "https://sketchfab.com", - "https://*.diagrams.net" - ], + "https://*.diagrams.net", + "chrome-extension://fohdnlaeecihjiendkfhifhlgldpeopm/" + ], "worker-src": [ "'self'", diff --git a/package-lock.json b/package-lock.json index 8454bf881a..20823971ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,6 +87,7 @@ "@rspack/cli": "^1.1.0", "@rspack/core": "^1.1.0", "@rspack/plugin-react-refresh": "^1.0.0", + "@tomjs/electron-devtools-installer": "^3.0.1", "@types/history": "^4.7.8", "@types/jquery": "^3.5.14", "@types/katex": "^0.14.0", @@ -2086,6 +2087,35 @@ "node": ">=10" } }, + "node_modules/@tomjs/electron-devtools-installer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@tomjs/electron-devtools-installer/-/electron-devtools-installer-3.0.1.tgz", + "integrity": "sha512-eFrCiDfA5KAkAQIDX8gzcPiFZ38YP+hhhIJuzVHQg0c58m8YsM/UJNFpiHuZgnCBkm2lgH85vYaprY6+cjxiwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tomjs/unzip-crx": "^1.1.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "electron": ">=12.0.0" + } + }, + "node_modules/@tomjs/unzip-crx": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@tomjs/unzip-crx/-/unzip-crx-1.1.3.tgz", + "integrity": "sha512-uqolp78TcG5q2ZBOZ57Nf7m7o3kaKAz1E9uFf4FCSO/nCI11HaDWpw7PaGUk1MImeIjNradiLpT2b9kTKSs4uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jszip": "^3.10.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -10610,6 +10640,76 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/jszip/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/katex": { "version": "0.16.22", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", @@ -18158,6 +18258,13 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", diff --git a/package.json b/package.json index 959a662930..b872ee0795 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@rspack/cli": "^1.1.0", "@rspack/core": "^1.1.0", "@rspack/plugin-react-refresh": "^1.0.0", + "@tomjs/electron-devtools-installer": "^3.0.1", "@types/history": "^4.7.8", "@types/jquery": "^3.5.14", "@types/katex": "^0.14.0", diff --git a/src/ts/lib/api/dispatcher.ts b/src/ts/lib/api/dispatcher.ts index 983eace42e..660d28e2e4 100644 --- a/src/ts/lib/api/dispatcher.ts +++ b/src/ts/lib/api/dispatcher.ts @@ -8,6 +8,7 @@ import Service from 'dist/lib/pb/protos/service/service_grpc_web_pb'; import { I, M, S, U, J, analytics, Renderer, Action, Dataview, Mapper, keyboard, Preview, focus } from 'Lib'; import * as Response from './response'; import { ClientReadableStream } from 'grpc-web'; +import { unaryInterceptors, streamInterceptors } from './grpc-devtools'; const SORT_IDS = [ 'BlockAdd', @@ -39,7 +40,10 @@ class Dispatcher { return; }; - this.service = new Service.ClientCommandsClient(address, null, null); + this.service = new Service.ClientCommandsClient(address, null, { + unaryInterceptors, + streamInterceptors, + }); }; startStream () { diff --git a/src/ts/lib/api/grpc-devtools.d.ts b/src/ts/lib/api/grpc-devtools.d.ts new file mode 100644 index 0000000000..e0b3e30176 --- /dev/null +++ b/src/ts/lib/api/grpc-devtools.d.ts @@ -0,0 +1,7 @@ +// Type augmentation for grpc-web to include interceptor options +declare module 'grpc-web' { + interface GrpcWebClientBaseOptions { + unaryInterceptors?: UnaryInterceptor[]; + streamInterceptors?: StreamInterceptor[]; + } +} \ No newline at end of file diff --git a/src/ts/lib/api/grpc-devtools.ts b/src/ts/lib/api/grpc-devtools.ts new file mode 100644 index 0000000000..81b3e9cfd6 --- /dev/null +++ b/src/ts/lib/api/grpc-devtools.ts @@ -0,0 +1,18 @@ +import type { UnaryInterceptor, StreamInterceptor } from 'grpc-web'; + +declare const __gRPC_devtools__: + | undefined + | { + gRPCWebUnaryInterceptor: UnaryInterceptor; + gRPCWebStreamInterceptor: StreamInterceptor; + }; + +export const unaryInterceptors = + typeof __gRPC_devtools__ === 'object' + ? [__gRPC_devtools__.gRPCWebUnaryInterceptor] + : []; + +export const streamInterceptors = + typeof __gRPC_devtools__ === 'object' + ? [__gRPC_devtools__.gRPCWebStreamInterceptor] + : []; \ No newline at end of file