@itwin/core-electron 4.0.0-dev.28 → 4.0.0-dev.32

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.
Files changed (42) hide show
  1. package/lib/cjs/ElectronBackend.d.ts +1 -1
  2. package/lib/cjs/ElectronBackend.js +17 -17
  3. package/lib/cjs/ElectronBackend.js.map +1 -1
  4. package/lib/cjs/ElectronFrontend.d.ts +1 -1
  5. package/lib/cjs/ElectronFrontend.js +17 -17
  6. package/lib/cjs/ElectronFrontend.js.map +1 -1
  7. package/lib/cjs/__DOC_ONLY__.d.ts +3 -3
  8. package/lib/cjs/__DOC_ONLY__.js +22 -22
  9. package/lib/cjs/__DOC_ONLY__.js.map +1 -1
  10. package/lib/cjs/backend/ElectronHost.d.ts +104 -104
  11. package/lib/cjs/backend/ElectronHost.js +240 -240
  12. package/lib/cjs/backend/ElectronPreload.d.ts +1 -1
  13. package/lib/cjs/backend/ElectronPreload.js +39 -39
  14. package/lib/cjs/backend/ElectronPreload.js.map +1 -1
  15. package/lib/cjs/common/ElectronIpcInterface.d.ts +7 -7
  16. package/lib/cjs/common/ElectronIpcInterface.js +5 -5
  17. package/lib/cjs/common/ElectronIpcInterface.js.map +1 -1
  18. package/lib/cjs/common/ElectronIpcTransport.d.ts +44 -44
  19. package/lib/cjs/common/ElectronIpcTransport.js +186 -186
  20. package/lib/cjs/common/ElectronIpcTransport.js.map +1 -1
  21. package/lib/cjs/common/ElectronManagerLoggerCategory.d.ts +10 -10
  22. package/lib/cjs/common/ElectronManagerLoggerCategory.js +18 -18
  23. package/lib/cjs/common/ElectronManagerLoggerCategory.js.map +1 -1
  24. package/lib/cjs/common/ElectronPush.d.ts +20 -20
  25. package/lib/cjs/common/ElectronPush.js +48 -48
  26. package/lib/cjs/common/ElectronPush.js.map +1 -1
  27. package/lib/cjs/common/ElectronRpcManager.d.ts +26 -26
  28. package/lib/cjs/common/ElectronRpcManager.js +65 -65
  29. package/lib/cjs/common/ElectronRpcManager.js.map +1 -1
  30. package/lib/cjs/common/ElectronRpcProtocol.d.ts +34 -34
  31. package/lib/cjs/common/ElectronRpcProtocol.js +58 -58
  32. package/lib/cjs/common/ElectronRpcProtocol.js.map +1 -1
  33. package/lib/cjs/common/ElectronRpcRequest.d.ts +19 -19
  34. package/lib/cjs/common/ElectronRpcRequest.js +56 -56
  35. package/lib/cjs/common/ElectronRpcRequest.js.map +1 -1
  36. package/lib/cjs/common/ITwinElectronApi.d.ts +10 -10
  37. package/lib/cjs/common/ITwinElectronApi.js +6 -6
  38. package/lib/cjs/common/ITwinElectronApi.js.map +1 -1
  39. package/lib/cjs/frontend/ElectronApp.d.ts +35 -35
  40. package/lib/cjs/frontend/ElectronApp.js +73 -73
  41. package/lib/cjs/frontend/ElectronApp.js.map +1 -1
  42. package/package.json +14 -14
@@ -1,241 +1,241 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ElectronHost = void 0;
8
- const fs = require("fs");
9
- const path = require("path");
10
- const core_bentley_1 = require("@itwin/core-bentley");
11
- const core_backend_1 = require("@itwin/core-backend");
12
- const core_common_1 = require("@itwin/core-common");
13
- const ElectronRpcManager_1 = require("../common/ElectronRpcManager");
14
- const ElectronIpcInterface_1 = require("../common/ElectronIpcInterface");
15
- // cSpell:ignore signin devserver webcontents copyfile unmaximize eopt
16
- class ElectronIpc {
17
- addListener(channel, listener) {
18
- ElectronHost.ipcMain.addListener(channel, listener);
19
- return () => ElectronHost.ipcMain.removeListener(channel, listener);
20
- }
21
- removeListener(channel, listener) {
22
- ElectronHost.ipcMain.removeListener(channel, listener);
23
- }
24
- send(channel, ...args) {
25
- const window = ElectronHost.mainWindow ?? ElectronHost.electron.BrowserWindow.getAllWindows()[0];
26
- window?.webContents.send(channel, ...args);
27
- }
28
- handle(channel, listener) {
29
- ElectronHost.ipcMain.removeHandler(channel); // make sure there's not already a handler registered
30
- ElectronHost.ipcMain.handle(channel, listener);
31
- return () => ElectronHost.ipcMain.removeHandler(channel);
32
- }
33
- }
34
- /**
35
- * The backend for Electron-based desktop applications
36
- * @beta
37
- */
38
- class ElectronHost {
39
- constructor() { }
40
- static get ipcMain() { return this._electron?.ipcMain; }
41
- static get app() { return this._electron?.app; }
42
- static get electron() { return this._electron; }
43
- /**
44
- * Converts an "electron://frontend/" URL to an absolute file path.
45
- *
46
- * We use this protocol in production builds because our frontend must be built with absolute URLs,
47
- * however, since we're loading everything directly from the install directory, we cannot know the
48
- * absolute path at build time.
49
- */
50
- static parseElectronUrl(requestedUrl) {
51
- // Note that the "frontend/" path is arbitrary - this is just so we can handle *some* relative URLs...
52
- let assetPath = requestedUrl.substring(this._electronFrontend.length);
53
- if (assetPath.length === 0)
54
- assetPath = "index.html";
55
- assetPath = path.normalize(`${this.webResourcesPath}/${assetPath}`);
56
- // File protocols don't follow symlinks, so we need to resolve this to a real path.
57
- // However, if the file doesn't exist, it's fine to return an invalid path here - the request will just fail with net::ERR_FILE_NOT_FOUND
58
- try {
59
- assetPath = fs.realpathSync(assetPath);
60
- }
61
- catch (error) {
62
- // eslint-disable-next-line no-console
63
- // console.warn(`WARNING: Frontend requested "${requestedUrl}", but ${assetPath} does not exist`);
64
- }
65
- if (!assetPath.startsWith(this.webResourcesPath))
66
- throw new Error(`Access to files outside installation directory (${this.webResourcesPath}) is prohibited`);
67
- return assetPath;
68
- }
69
- static _openWindow(options) {
70
- const webPreferences = {
71
- ...options?.webPreferences,
72
- // These web preference variables should not be overriden by the ElectronHostWindowOptions
73
- preload: require.resolve(/* webpack: copyfile */ "./ElectronPreload.js"),
74
- experimentalFeatures: false,
75
- nodeIntegration: false,
76
- contextIsolation: true,
77
- sandbox: true,
78
- nodeIntegrationInWorker: false,
79
- nodeIntegrationInSubFrames: false,
80
- };
81
- const opts = {
82
- ...options,
83
- autoHideMenuBar: true,
84
- icon: this.appIconPath,
85
- webPreferences,
86
- };
87
- this._mainWindow = new (this.electron.BrowserWindow)(opts);
88
- ElectronRpcManager_1.ElectronRpcConfiguration.targetWindowId = this._mainWindow.id;
89
- this._mainWindow.on("closed", () => this._mainWindow = undefined);
90
- this._mainWindow.loadURL(this.frontendURL); // eslint-disable-line @typescript-eslint/no-floating-promises
91
- /** Monitors and saves main window size, position and maximized state */
92
- if (options?.storeWindowName) {
93
- const mainWindow = this._mainWindow;
94
- const name = options.storeWindowName;
95
- const saveWindowPosition = (key) => {
96
- const bounds = mainWindow.getBounds();
97
- core_backend_1.NativeHost.settingsStore.setData(`${key}-${name}`, JSON.stringify(bounds));
98
- };
99
- const saveMaximized = (maximized) => {
100
- if (!maximized)
101
- saveWindowPosition(this._deprecatedSizeAndPosStoreKey);
102
- core_backend_1.NativeHost.settingsStore.setData(`windowMaximized-${name}`, maximized);
103
- };
104
- mainWindow.on("maximize", () => saveMaximized(true));
105
- mainWindow.on("unmaximize", () => saveMaximized(false));
106
- saveMaximized(mainWindow.isMaximized());
107
- mainWindow.on("resized", () => saveWindowPosition(this._deprecatedSizeAndPosStoreKey));
108
- mainWindow.on("moved", () => saveWindowPosition(this._deprecatedSizeAndPosStoreKey));
109
- const debouncedSaveWindowSizeAndPos = debounce(() => saveWindowPosition(this._sizeAndPosStoreKey));
110
- mainWindow.on("resize", () => debouncedSaveWindowSizeAndPos());
111
- mainWindow.on("move", () => debouncedSaveWindowSizeAndPos());
112
- saveWindowPosition(this._sizeAndPosStoreKey);
113
- }
114
- }
115
- /** The "main" BrowserWindow for this application. */
116
- static get mainWindow() { return this._mainWindow; }
117
- /**
118
- * Gets window size and position for a window, by name, from settings file, if present.
119
- * @note Size and position values in the settings file will be updated differently depending on platform.
120
- * On Linux values are only updated on window "unmaximize".
121
- * On Windows and MacOS values are also updated on window manual resize or move.
122
- * To get consistent behavior across different platforms, use [[ElectronHost.getWindowSizeAndPositionSetting]].
123
- * @deprecated in 3.6. Use [[ElectronHost.getWindowSizeAndPositionSetting]].
124
- */
125
- static getWindowSizeSetting(windowName) {
126
- const saved = core_backend_1.NativeHost.settingsStore.getString(`${this._deprecatedSizeAndPosStoreKey}-${windowName}`);
127
- return saved ? JSON.parse(saved) : undefined;
128
- }
129
- /**
130
- * Gets window size and position for a window, by name, from settings file, if present.
131
- */
132
- static getWindowSizeAndPositionSetting(windowName) {
133
- const saved = core_backend_1.NativeHost.settingsStore.getString(`${this._sizeAndPosStoreKey}-${windowName}`);
134
- return saved ? JSON.parse(saved) : undefined;
135
- }
136
- /** Gets "window maximized" flag for a window, by name, from settings file if present */
137
- static getWindowMaximizedSetting(windowName) {
138
- return core_backend_1.NativeHost.settingsStore.getBoolean(`windowMaximized-${windowName}`);
139
- }
140
- /**
141
- * Open the main Window when the app is ready.
142
- * @param windowOptions Options for constructing the main BrowserWindow. See: https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
143
- */
144
- static async openMainWindow(windowOptions) {
145
- const app = this.app;
146
- // quit the application when all windows are closed (unless we're running on MacOS)
147
- app.on("window-all-closed", () => {
148
- if (process.platform !== "darwin")
149
- app.quit();
150
- });
151
- // re-open the main window if it was closed and the app is re-activated (this is the normal MacOS behavior)
152
- app.on("activate", () => {
153
- if (!this._mainWindow)
154
- this._openWindow(windowOptions);
155
- });
156
- if (this._developmentServer) {
157
- // Occasionally, the electron backend may start before the webpack devserver has even started.
158
- // If this happens, we'll just retry and keep reloading the page.
159
- app.on("web-contents-created", (_e, webcontents) => {
160
- webcontents.on("did-fail-load", async (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {
161
- // errorCode -102 is CONNECTION_REFUSED - see https://cs.chromium.org/chromium/src/net/base/net_error_list.h
162
- if (isMainFrame && errorCode === -102) {
163
- await core_bentley_1.BeDuration.wait(100);
164
- webcontents.reload();
165
- }
166
- });
167
- });
168
- }
169
- await app.whenReady();
170
- if (!this._developmentServer) {
171
- // handle any "electron://" requests and redirect them to "file://" URLs
172
- this.electron.protocol.registerFileProtocol("electron", (request, callback) => callback(this.parseElectronUrl(request.url))); // eslint-disable-line @typescript-eslint/no-var-requires
173
- }
174
- this._openWindow(windowOptions);
175
- }
176
- static get isValid() { return this._ipc !== undefined; }
177
- /**
178
- * Initialize the backend of an Electron app.
179
- * This method configures the backend for all of the inter-process communication (RPC and IPC) for an
180
- * Electron app. It should be called from your Electron main function.
181
- * @param opts Options that control aspects of your backend.
182
- * @note This method must only be called from the backend of an Electron app (i.e. when [ProcessDetector.isElectronAppBackend]($bentley) is `true`).
183
- */
184
- static async startup(opts) {
185
- if (!core_bentley_1.ProcessDetector.isElectronAppBackend)
186
- throw new Error("Not running under Electron");
187
- if (!this.isValid) {
188
- this._electron = require("electron");
189
- this._ipc = new ElectronIpc();
190
- const app = this.app;
191
- if (!app.isReady())
192
- this.electron.protocol.registerSchemesAsPrivileged([{
193
- scheme: "electron",
194
- privileges: {
195
- standard: true,
196
- secure: true,
197
- supportFetchAPI: true,
198
- },
199
- }]);
200
- const eopt = opts?.electronHost;
201
- this._developmentServer = eopt?.developmentServer ?? false;
202
- const frontendPort = eopt?.frontendPort ?? 3000;
203
- this.webResourcesPath = eopt?.webResourcesPath ?? "";
204
- this.frontendURL = eopt?.frontendURL ?? (this._developmentServer ? `http://localhost:${frontendPort}` : `${this._electronFrontend}index.html`);
205
- this.appIconPath = path.join(this.webResourcesPath, eopt?.iconName ?? "appicon.ico");
206
- this.rpcConfig = ElectronRpcManager_1.ElectronRpcManager.initializeBackend(this._ipc, eopt?.rpcInterfaces);
207
- }
208
- opts = opts ?? {};
209
- opts.ipcHost = opts.ipcHost ?? {};
210
- opts.ipcHost.socket = this._ipc;
211
- await core_backend_1.NativeHost.startup(opts);
212
- if (core_backend_1.IpcHost.isValid) {
213
- ElectronDialogHandler.register();
214
- opts.electronHost?.ipcHandlers?.forEach((ipc) => ipc.register());
215
- }
216
- }
217
- }
218
- exports.ElectronHost = ElectronHost;
219
- ElectronHost._deprecatedSizeAndPosStoreKey = "windowPos";
220
- ElectronHost._sizeAndPosStoreKey = "windowSizeAndPos";
221
- ElectronHost._electronFrontend = "electron://frontend/";
222
- class ElectronDialogHandler extends core_backend_1.IpcHandler {
223
- get channelName() { return ElectronIpcInterface_1.dialogChannel; }
224
- async callDialog(method, ...args) {
225
- const dialog = ElectronHost.electron.dialog;
226
- const dialogMethod = dialog[method];
227
- if (typeof dialogMethod !== "function")
228
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.FunctionNotFound, `illegal electron dialog method`);
229
- return dialogMethod.call(dialog, ...args);
230
- }
231
- }
232
- function debounce(func, ms = 200) {
233
- let timeout;
234
- return function (...args) {
235
- clearTimeout(timeout);
236
- timeout = setTimeout(() => {
237
- func.apply(this, args);
238
- }, ms);
239
- };
240
- }
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ElectronHost = void 0;
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+ const core_bentley_1 = require("@itwin/core-bentley");
11
+ const core_backend_1 = require("@itwin/core-backend");
12
+ const core_common_1 = require("@itwin/core-common");
13
+ const ElectronRpcManager_1 = require("../common/ElectronRpcManager");
14
+ const ElectronIpcInterface_1 = require("../common/ElectronIpcInterface");
15
+ // cSpell:ignore signin devserver webcontents copyfile unmaximize eopt
16
+ class ElectronIpc {
17
+ addListener(channel, listener) {
18
+ ElectronHost.ipcMain.addListener(channel, listener);
19
+ return () => ElectronHost.ipcMain.removeListener(channel, listener);
20
+ }
21
+ removeListener(channel, listener) {
22
+ ElectronHost.ipcMain.removeListener(channel, listener);
23
+ }
24
+ send(channel, ...args) {
25
+ const window = ElectronHost.mainWindow ?? ElectronHost.electron.BrowserWindow.getAllWindows()[0];
26
+ window?.webContents.send(channel, ...args);
27
+ }
28
+ handle(channel, listener) {
29
+ ElectronHost.ipcMain.removeHandler(channel); // make sure there's not already a handler registered
30
+ ElectronHost.ipcMain.handle(channel, listener);
31
+ return () => ElectronHost.ipcMain.removeHandler(channel);
32
+ }
33
+ }
34
+ /**
35
+ * The backend for Electron-based desktop applications
36
+ * @beta
37
+ */
38
+ class ElectronHost {
39
+ constructor() { }
40
+ static get ipcMain() { return this._electron?.ipcMain; }
41
+ static get app() { return this._electron?.app; }
42
+ static get electron() { return this._electron; }
43
+ /**
44
+ * Converts an "electron://frontend/" URL to an absolute file path.
45
+ *
46
+ * We use this protocol in production builds because our frontend must be built with absolute URLs,
47
+ * however, since we're loading everything directly from the install directory, we cannot know the
48
+ * absolute path at build time.
49
+ */
50
+ static parseElectronUrl(requestedUrl) {
51
+ // Note that the "frontend/" path is arbitrary - this is just so we can handle *some* relative URLs...
52
+ let assetPath = requestedUrl.substring(this._electronFrontend.length);
53
+ if (assetPath.length === 0)
54
+ assetPath = "index.html";
55
+ assetPath = path.normalize(`${this.webResourcesPath}/${assetPath}`);
56
+ // File protocols don't follow symlinks, so we need to resolve this to a real path.
57
+ // However, if the file doesn't exist, it's fine to return an invalid path here - the request will just fail with net::ERR_FILE_NOT_FOUND
58
+ try {
59
+ assetPath = fs.realpathSync(assetPath);
60
+ }
61
+ catch (error) {
62
+ // eslint-disable-next-line no-console
63
+ // console.warn(`WARNING: Frontend requested "${requestedUrl}", but ${assetPath} does not exist`);
64
+ }
65
+ if (!assetPath.startsWith(this.webResourcesPath))
66
+ throw new Error(`Access to files outside installation directory (${this.webResourcesPath}) is prohibited`);
67
+ return assetPath;
68
+ }
69
+ static _openWindow(options) {
70
+ const webPreferences = {
71
+ ...options?.webPreferences,
72
+ // These web preference variables should not be overriden by the ElectronHostWindowOptions
73
+ preload: require.resolve(/* webpack: copyfile */ "./ElectronPreload.js"),
74
+ experimentalFeatures: false,
75
+ nodeIntegration: false,
76
+ contextIsolation: true,
77
+ sandbox: true,
78
+ nodeIntegrationInWorker: false,
79
+ nodeIntegrationInSubFrames: false,
80
+ };
81
+ const opts = {
82
+ ...options,
83
+ autoHideMenuBar: true,
84
+ icon: this.appIconPath,
85
+ webPreferences,
86
+ };
87
+ this._mainWindow = new (this.electron.BrowserWindow)(opts);
88
+ ElectronRpcManager_1.ElectronRpcConfiguration.targetWindowId = this._mainWindow.id;
89
+ this._mainWindow.on("closed", () => this._mainWindow = undefined);
90
+ this._mainWindow.loadURL(this.frontendURL); // eslint-disable-line @typescript-eslint/no-floating-promises
91
+ /** Monitors and saves main window size, position and maximized state */
92
+ if (options?.storeWindowName) {
93
+ const mainWindow = this._mainWindow;
94
+ const name = options.storeWindowName;
95
+ const saveWindowPosition = (key) => {
96
+ const bounds = mainWindow.getBounds();
97
+ core_backend_1.NativeHost.settingsStore.setData(`${key}-${name}`, JSON.stringify(bounds));
98
+ };
99
+ const saveMaximized = (maximized) => {
100
+ if (!maximized)
101
+ saveWindowPosition(this._deprecatedSizeAndPosStoreKey);
102
+ core_backend_1.NativeHost.settingsStore.setData(`windowMaximized-${name}`, maximized);
103
+ };
104
+ mainWindow.on("maximize", () => saveMaximized(true));
105
+ mainWindow.on("unmaximize", () => saveMaximized(false));
106
+ saveMaximized(mainWindow.isMaximized());
107
+ mainWindow.on("resized", () => saveWindowPosition(this._deprecatedSizeAndPosStoreKey));
108
+ mainWindow.on("moved", () => saveWindowPosition(this._deprecatedSizeAndPosStoreKey));
109
+ const debouncedSaveWindowSizeAndPos = debounce(() => saveWindowPosition(this._sizeAndPosStoreKey));
110
+ mainWindow.on("resize", () => debouncedSaveWindowSizeAndPos());
111
+ mainWindow.on("move", () => debouncedSaveWindowSizeAndPos());
112
+ saveWindowPosition(this._sizeAndPosStoreKey);
113
+ }
114
+ }
115
+ /** The "main" BrowserWindow for this application. */
116
+ static get mainWindow() { return this._mainWindow; }
117
+ /**
118
+ * Gets window size and position for a window, by name, from settings file, if present.
119
+ * @note Size and position values in the settings file will be updated differently depending on platform.
120
+ * On Linux values are only updated on window "unmaximize".
121
+ * On Windows and MacOS values are also updated on window manual resize or move.
122
+ * To get consistent behavior across different platforms, use [[ElectronHost.getWindowSizeAndPositionSetting]].
123
+ * @deprecated in 3.6. Use [[ElectronHost.getWindowSizeAndPositionSetting]].
124
+ */
125
+ static getWindowSizeSetting(windowName) {
126
+ const saved = core_backend_1.NativeHost.settingsStore.getString(`${this._deprecatedSizeAndPosStoreKey}-${windowName}`);
127
+ return saved ? JSON.parse(saved) : undefined;
128
+ }
129
+ /**
130
+ * Gets window size and position for a window, by name, from settings file, if present.
131
+ */
132
+ static getWindowSizeAndPositionSetting(windowName) {
133
+ const saved = core_backend_1.NativeHost.settingsStore.getString(`${this._sizeAndPosStoreKey}-${windowName}`);
134
+ return saved ? JSON.parse(saved) : undefined;
135
+ }
136
+ /** Gets "window maximized" flag for a window, by name, from settings file if present */
137
+ static getWindowMaximizedSetting(windowName) {
138
+ return core_backend_1.NativeHost.settingsStore.getBoolean(`windowMaximized-${windowName}`);
139
+ }
140
+ /**
141
+ * Open the main Window when the app is ready.
142
+ * @param windowOptions Options for constructing the main BrowserWindow. See: https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
143
+ */
144
+ static async openMainWindow(windowOptions) {
145
+ const app = this.app;
146
+ // quit the application when all windows are closed (unless we're running on MacOS)
147
+ app.on("window-all-closed", () => {
148
+ if (process.platform !== "darwin")
149
+ app.quit();
150
+ });
151
+ // re-open the main window if it was closed and the app is re-activated (this is the normal MacOS behavior)
152
+ app.on("activate", () => {
153
+ if (!this._mainWindow)
154
+ this._openWindow(windowOptions);
155
+ });
156
+ if (this._developmentServer) {
157
+ // Occasionally, the electron backend may start before the webpack devserver has even started.
158
+ // If this happens, we'll just retry and keep reloading the page.
159
+ app.on("web-contents-created", (_e, webcontents) => {
160
+ webcontents.on("did-fail-load", async (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {
161
+ // errorCode -102 is CONNECTION_REFUSED - see https://cs.chromium.org/chromium/src/net/base/net_error_list.h
162
+ if (isMainFrame && errorCode === -102) {
163
+ await core_bentley_1.BeDuration.wait(100);
164
+ webcontents.reload();
165
+ }
166
+ });
167
+ });
168
+ }
169
+ await app.whenReady();
170
+ if (!this._developmentServer) {
171
+ // handle any "electron://" requests and redirect them to "file://" URLs
172
+ this.electron.protocol.registerFileProtocol("electron", (request, callback) => callback(this.parseElectronUrl(request.url))); // eslint-disable-line @typescript-eslint/no-var-requires
173
+ }
174
+ this._openWindow(windowOptions);
175
+ }
176
+ static get isValid() { return this._ipc !== undefined; }
177
+ /**
178
+ * Initialize the backend of an Electron app.
179
+ * This method configures the backend for all of the inter-process communication (RPC and IPC) for an
180
+ * Electron app. It should be called from your Electron main function.
181
+ * @param opts Options that control aspects of your backend.
182
+ * @note This method must only be called from the backend of an Electron app (i.e. when [ProcessDetector.isElectronAppBackend]($bentley) is `true`).
183
+ */
184
+ static async startup(opts) {
185
+ if (!core_bentley_1.ProcessDetector.isElectronAppBackend)
186
+ throw new Error("Not running under Electron");
187
+ if (!this.isValid) {
188
+ this._electron = require("electron");
189
+ this._ipc = new ElectronIpc();
190
+ const app = this.app;
191
+ if (!app.isReady())
192
+ this.electron.protocol.registerSchemesAsPrivileged([{
193
+ scheme: "electron",
194
+ privileges: {
195
+ standard: true,
196
+ secure: true,
197
+ supportFetchAPI: true,
198
+ },
199
+ }]);
200
+ const eopt = opts?.electronHost;
201
+ this._developmentServer = eopt?.developmentServer ?? false;
202
+ const frontendPort = eopt?.frontendPort ?? 3000;
203
+ this.webResourcesPath = eopt?.webResourcesPath ?? "";
204
+ this.frontendURL = eopt?.frontendURL ?? (this._developmentServer ? `http://localhost:${frontendPort}` : `${this._electronFrontend}index.html`);
205
+ this.appIconPath = path.join(this.webResourcesPath, eopt?.iconName ?? "appicon.ico");
206
+ this.rpcConfig = ElectronRpcManager_1.ElectronRpcManager.initializeBackend(this._ipc, eopt?.rpcInterfaces);
207
+ }
208
+ opts = opts ?? {};
209
+ opts.ipcHost = opts.ipcHost ?? {};
210
+ opts.ipcHost.socket = this._ipc;
211
+ await core_backend_1.NativeHost.startup(opts);
212
+ if (core_backend_1.IpcHost.isValid) {
213
+ ElectronDialogHandler.register();
214
+ opts.electronHost?.ipcHandlers?.forEach((ipc) => ipc.register());
215
+ }
216
+ }
217
+ }
218
+ exports.ElectronHost = ElectronHost;
219
+ ElectronHost._deprecatedSizeAndPosStoreKey = "windowPos";
220
+ ElectronHost._sizeAndPosStoreKey = "windowSizeAndPos";
221
+ ElectronHost._electronFrontend = "electron://frontend/";
222
+ class ElectronDialogHandler extends core_backend_1.IpcHandler {
223
+ get channelName() { return ElectronIpcInterface_1.dialogChannel; }
224
+ async callDialog(method, ...args) {
225
+ const dialog = ElectronHost.electron.dialog;
226
+ const dialogMethod = dialog[method];
227
+ if (typeof dialogMethod !== "function")
228
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.FunctionNotFound, `illegal electron dialog method`);
229
+ return dialogMethod.call(dialog, ...args);
230
+ }
231
+ }
232
+ function debounce(func, ms = 200) {
233
+ let timeout;
234
+ return function (...args) {
235
+ clearTimeout(timeout);
236
+ timeout = setTimeout(() => {
237
+ func.apply(this, args);
238
+ }, ms);
239
+ };
240
+ }
241
241
  //# sourceMappingURL=ElectronHost.js.map
@@ -1,2 +1,2 @@
1
- export {};
1
+ export {};
2
2
  //# sourceMappingURL=ElectronPreload.d.ts.map
@@ -1,40 +1,40 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /*---------------------------------------------------------------------------------------------
4
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
5
- * See LICENSE.md in the project root for license terms and full copyright notice.
6
- *--------------------------------------------------------------------------------------------*/
7
- const electron_1 = require("electron");
8
- /**
9
- * This file is loaded as an Electron preload script
10
- * (see https://www.electronjs.org/docs/api/browser-window#class-browserwindow) from ElectronMain.ts
11
- */
12
- function checkPrefix(channel) {
13
- if (!channel.startsWith("itwin."))
14
- throw new Error(`illegal channel name '${channel}'`);
15
- }
16
- /** the implementation of the private api between the frontend (renderer) and backend (main) iTwin.js processes in Electron. */
17
- const frontendApi = {
18
- send(channel, ...data) {
19
- checkPrefix(channel);
20
- electron_1.ipcRenderer.send(channel, ...data);
21
- },
22
- addListener(channel, listener) {
23
- checkPrefix(channel);
24
- return electron_1.ipcRenderer.addListener(channel, listener);
25
- },
26
- removeListener(channel, listener) {
27
- return electron_1.ipcRenderer.removeListener(channel, listener);
28
- },
29
- once(channel, listener) {
30
- checkPrefix(channel);
31
- return electron_1.ipcRenderer.once(channel, listener);
32
- },
33
- async invoke(channel, ...data) {
34
- checkPrefix(channel);
35
- return electron_1.ipcRenderer.invoke(channel, ...data);
36
- },
37
- };
38
- // this adds the frontendApi object under the name `window.itwinjs` in the frontend Electron process.
39
- electron_1.contextBridge.exposeInMainWorld("itwinjs", frontendApi);
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /*---------------------------------------------------------------------------------------------
4
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
5
+ * See LICENSE.md in the project root for license terms and full copyright notice.
6
+ *--------------------------------------------------------------------------------------------*/
7
+ const electron_1 = require("electron");
8
+ /**
9
+ * This file is loaded as an Electron preload script
10
+ * (see https://www.electronjs.org/docs/api/browser-window#class-browserwindow) from ElectronMain.ts
11
+ */
12
+ function checkPrefix(channel) {
13
+ if (!channel.startsWith("itwin."))
14
+ throw new Error(`illegal channel name '${channel}'`);
15
+ }
16
+ /** the implementation of the private api between the frontend (renderer) and backend (main) iTwin.js processes in Electron. */
17
+ const frontendApi = {
18
+ send(channel, ...data) {
19
+ checkPrefix(channel);
20
+ electron_1.ipcRenderer.send(channel, ...data);
21
+ },
22
+ addListener(channel, listener) {
23
+ checkPrefix(channel);
24
+ return electron_1.ipcRenderer.addListener(channel, listener);
25
+ },
26
+ removeListener(channel, listener) {
27
+ return electron_1.ipcRenderer.removeListener(channel, listener);
28
+ },
29
+ once(channel, listener) {
30
+ checkPrefix(channel);
31
+ return electron_1.ipcRenderer.once(channel, listener);
32
+ },
33
+ async invoke(channel, ...data) {
34
+ checkPrefix(channel);
35
+ return electron_1.ipcRenderer.invoke(channel, ...data);
36
+ },
37
+ };
38
+ // this adds the frontendApi object under the name `window.itwinjs` in the frontend Electron process.
39
+ electron_1.contextBridge.exposeInMainWorld("itwinjs", frontendApi);
40
40
  //# sourceMappingURL=ElectronPreload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronPreload.js","sourceRoot":"","sources":["../../../src/backend/ElectronPreload.ts"],"names":[],"mappings":";;AAAA;;;+FAG+F;AAC/F,uCAAsD;AAGtD;;;GAGG;AAEH,SAAS,WAAW,CAAC,OAAe;IAClC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,GAAG,CAAC,CAAC;AACzD,CAAC;AAED,+HAA+H;AAC/H,MAAM,WAAW,GAAqB;IACpC,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,sBAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,WAAW,CAAC,OAAe,EAAE,QAA0B;QACrD,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IACD,cAAc,CAAC,OAAe,EAAE,QAA0B;QACxD,OAAO,sBAAW,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAe,EAAE,QAA0B;QAC9C,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9C,CAAC;CACF,CAAC;AAEF,qGAAqG;AACrG,wBAAa,CAAC,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport { contextBridge, ipcRenderer } from \"electron\";\nimport type { ElectronListener, ITwinElectronApi } from \"../common/ITwinElectronApi\";\n\n/**\n * This file is loaded as an Electron preload script\n * (see https://www.electronjs.org/docs/api/browser-window#class-browserwindow) from ElectronMain.ts\n */\n\nfunction checkPrefix(channel: string) {\n if (!channel.startsWith(\"itwin.\"))\n throw new Error(`illegal channel name '${channel}'`);\n}\n\n/** the implementation of the private api between the frontend (renderer) and backend (main) iTwin.js processes in Electron. */\nconst frontendApi: ITwinElectronApi = {\n send(channel: string, ...data: any[]) {\n checkPrefix(channel);\n ipcRenderer.send(channel, ...data);\n },\n addListener(channel: string, listener: ElectronListener) {\n checkPrefix(channel);\n return ipcRenderer.addListener(channel, listener);\n },\n removeListener(channel: string, listener: ElectronListener) {\n return ipcRenderer.removeListener(channel, listener);\n },\n once(channel: string, listener: ElectronListener) {\n checkPrefix(channel);\n return ipcRenderer.once(channel, listener);\n },\n async invoke(channel: string, ...data: any[]): Promise<any> {\n checkPrefix(channel);\n return ipcRenderer.invoke(channel, ...data);\n },\n};\n\n// this adds the frontendApi object under the name `window.itwinjs` in the frontend Electron process.\ncontextBridge.exposeInMainWorld(\"itwinjs\", frontendApi);\n"]}
1
+ {"version":3,"file":"ElectronPreload.js","sourceRoot":"","sources":["../../../src/backend/ElectronPreload.ts"],"names":[],"mappings":";;AAAA;;;+FAG+F;AAC/F,uCAAsD;AAGtD;;;GAGG;AAEH,SAAS,WAAW,CAAC,OAAe;IAClC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,GAAG,CAAC,CAAC;AACzD,CAAC;AAED,+HAA+H;AAC/H,MAAM,WAAW,GAAqB;IACpC,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QAClC,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,sBAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,WAAW,CAAC,OAAe,EAAE,QAA0B;QACrD,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IACD,cAAc,CAAC,OAAe,EAAE,QAA0B;QACxD,OAAO,sBAAW,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,OAAe,EAAE,QAA0B;QAC9C,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,WAAW,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,sBAAW,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9C,CAAC;CACF,CAAC;AAEF,qGAAqG;AACrG,wBAAa,CAAC,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { contextBridge, ipcRenderer } from \"electron\";\r\nimport type { ElectronListener, ITwinElectronApi } from \"../common/ITwinElectronApi\";\r\n\r\n/**\r\n * This file is loaded as an Electron preload script\r\n * (see https://www.electronjs.org/docs/api/browser-window#class-browserwindow) from ElectronMain.ts\r\n */\r\n\r\nfunction checkPrefix(channel: string) {\r\n if (!channel.startsWith(\"itwin.\"))\r\n throw new Error(`illegal channel name '${channel}'`);\r\n}\r\n\r\n/** the implementation of the private api between the frontend (renderer) and backend (main) iTwin.js processes in Electron. */\r\nconst frontendApi: ITwinElectronApi = {\r\n send(channel: string, ...data: any[]) {\r\n checkPrefix(channel);\r\n ipcRenderer.send(channel, ...data);\r\n },\r\n addListener(channel: string, listener: ElectronListener) {\r\n checkPrefix(channel);\r\n return ipcRenderer.addListener(channel, listener);\r\n },\r\n removeListener(channel: string, listener: ElectronListener) {\r\n return ipcRenderer.removeListener(channel, listener);\r\n },\r\n once(channel: string, listener: ElectronListener) {\r\n checkPrefix(channel);\r\n return ipcRenderer.once(channel, listener);\r\n },\r\n async invoke(channel: string, ...data: any[]): Promise<any> {\r\n checkPrefix(channel);\r\n return ipcRenderer.invoke(channel, ...data);\r\n },\r\n};\r\n\r\n// this adds the frontendApi object under the name `window.itwinjs` in the frontend Electron process.\r\ncontextBridge.exposeInMainWorld(\"itwinjs\", frontendApi);\r\n"]}
@@ -1,8 +1,8 @@
1
- import { AsyncMethodsOf } from "@itwin/core-bentley";
2
- /** @internal */
3
- export declare const dialogChannel = "electron-dialog";
4
- /** Asynchronous methods of dialog module in an Electron app.
5
- * @beta
6
- */
7
- export declare type DialogModuleMethod = AsyncMethodsOf<Electron.Dialog>;
1
+ import { AsyncMethodsOf } from "@itwin/core-bentley";
2
+ /** @internal */
3
+ export declare const dialogChannel = "electron-dialog";
4
+ /** Asynchronous methods of dialog module in an Electron app.
5
+ * @beta
6
+ */
7
+ export declare type DialogModuleMethod = AsyncMethodsOf<Electron.Dialog>;
8
8
  //# sourceMappingURL=ElectronIpcInterface.d.ts.map
@@ -1,6 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dialogChannel = void 0;
4
- /** @internal */
5
- exports.dialogChannel = "electron-dialog";
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dialogChannel = void 0;
4
+ /** @internal */
5
+ exports.dialogChannel = "electron-dialog";
6
6
  //# sourceMappingURL=ElectronIpcInterface.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElectronIpcInterface.js","sourceRoot":"","sources":["../../../src/common/ElectronIpcInterface.ts"],"names":[],"mappings":";;;AAMA,gBAAgB;AACH,QAAA,aAAa,GAAG,iBAAiB,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport { AsyncMethodsOf } from \"@itwin/core-bentley\";\n\n/** @internal */\nexport const dialogChannel = \"electron-dialog\";\n\n/** Asynchronous methods of dialog module in an Electron app.\n * @beta\n */\nexport type DialogModuleMethod = AsyncMethodsOf<Electron.Dialog>;\n"]}
1
+ {"version":3,"file":"ElectronIpcInterface.js","sourceRoot":"","sources":["../../../src/common/ElectronIpcInterface.ts"],"names":[],"mappings":";;;AAMA,gBAAgB;AACH,QAAA,aAAa,GAAG,iBAAiB,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { AsyncMethodsOf } from \"@itwin/core-bentley\";\r\n\r\n/** @internal */\r\nexport const dialogChannel = \"electron-dialog\";\r\n\r\n/** Asynchronous methods of dialog module in an Electron app.\r\n * @beta\r\n */\r\nexport type DialogModuleMethod = AsyncMethodsOf<Electron.Dialog>;\r\n"]}