Adds debugging utilities in dev/beta environments
This commit is contained in:
parent
ac50af52d2
commit
86488b97b9
13 changed files with 73 additions and 146 deletions
|
@ -246,8 +246,8 @@ export async function startApp(): Promise<void> {
|
||||||
},
|
},
|
||||||
|
|
||||||
requestChallenge(request) {
|
requestChallenge(request) {
|
||||||
if (window.Signal.CI) {
|
if (window.SignalCI) {
|
||||||
window.Signal.CI.handleEvent('challenge', request);
|
window.SignalCI.handleEvent('challenge', request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.sendChallengeRequest(request);
|
window.sendChallengeRequest(request);
|
||||||
|
|
|
@ -520,7 +520,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
status === 'viewed')
|
status === 'viewed')
|
||||||
) {
|
) {
|
||||||
const delta = Date.now() - timestamp;
|
const delta = Date.now() - timestamp;
|
||||||
window.Signal.CI?.handleEvent('message:send-complete', {
|
window.SignalCI?.handleEvent('message:send-complete', {
|
||||||
timestamp,
|
timestamp,
|
||||||
delta,
|
delta,
|
||||||
});
|
});
|
||||||
|
|
|
@ -266,7 +266,7 @@ export class MessageReceipts extends Collection<MessageReceiptModel> {
|
||||||
|
|
||||||
// We want the above call to not be delayed when testing with
|
// We want the above call to not be delayed when testing with
|
||||||
// CI.
|
// CI.
|
||||||
window.Signal.CI
|
window.SignalCI
|
||||||
? deleteSentProtoBatcher.flushAndWait()
|
? deleteSentProtoBatcher.flushAndWait()
|
||||||
: Promise.resolve(),
|
: Promise.resolve(),
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -5529,7 +5529,7 @@ export class ConversationModel extends window.Backbone
|
||||||
const delta = now - startedAt;
|
const delta = now - startedAt;
|
||||||
|
|
||||||
log.info(`conversation ${this.idForLogging()} open took ${delta}ms`);
|
log.info(`conversation ${this.idForLogging()} open took ${delta}ms`);
|
||||||
window.Signal.CI?.handleEvent('conversation:open', { delta });
|
window.SignalCI?.handleEvent('conversation:open', { delta });
|
||||||
}
|
}
|
||||||
|
|
||||||
async flushDebouncedUpdates(): Promise<void> {
|
async flushDebouncedUpdates(): Promise<void> {
|
||||||
|
|
|
@ -276,7 +276,7 @@ export class CallingClass {
|
||||||
|
|
||||||
private reduxInterface?: CallingReduxInterface;
|
private reduxInterface?: CallingReduxInterface;
|
||||||
|
|
||||||
private sfuUrl?: string;
|
public _sfuUrl?: string;
|
||||||
|
|
||||||
private lastMediaDeviceSettings?: MediaDeviceSettings;
|
private lastMediaDeviceSettings?: MediaDeviceSettings;
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ export class CallingClass {
|
||||||
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
throw new Error('CallingClass.initialize: Invalid uxActions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sfuUrl = sfuUrl;
|
this._sfuUrl = sfuUrl;
|
||||||
|
|
||||||
this.previousAudioDeviceModule = parseAudioDeviceModule(
|
this.previousAudioDeviceModule = parseAudioDeviceModule(
|
||||||
window.storage.get('previousAudioDeviceModule')
|
window.storage.get('previousAudioDeviceModule')
|
||||||
|
@ -610,7 +610,7 @@ export class CallingClass {
|
||||||
return statefulPeekInfo;
|
return statefulPeekInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.sfuUrl) {
|
if (!this._sfuUrl) {
|
||||||
throw new Error('Missing SFU URL; not peeking group call');
|
throw new Error('Missing SFU URL; not peeking group call');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +633,7 @@ export class CallingClass {
|
||||||
const membershipProof = Bytes.fromString(proof);
|
const membershipProof = Bytes.fromString(proof);
|
||||||
|
|
||||||
return RingRTC.peekGroupCall(
|
return RingRTC.peekGroupCall(
|
||||||
this.sfuUrl,
|
this._sfuUrl,
|
||||||
Buffer.from(membershipProof),
|
Buffer.from(membershipProof),
|
||||||
this.getGroupCallMembers(conversationId)
|
this.getGroupCallMembers(conversationId)
|
||||||
);
|
);
|
||||||
|
@ -669,7 +669,7 @@ export class CallingClass {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.sfuUrl) {
|
if (!this._sfuUrl) {
|
||||||
throw new Error('Missing SFU URL; not connecting group call');
|
throw new Error('Missing SFU URL; not connecting group call');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ export class CallingClass {
|
||||||
|
|
||||||
const outerGroupCall = RingRTC.getGroupCall(
|
const outerGroupCall = RingRTC.getGroupCall(
|
||||||
groupIdBuffer,
|
groupIdBuffer,
|
||||||
this.sfuUrl,
|
this._sfuUrl,
|
||||||
Buffer.alloc(0),
|
Buffer.alloc(0),
|
||||||
AUDIO_LEVEL_INTERVAL_MS,
|
AUDIO_LEVEL_INTERVAL_MS,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1733,8 +1733,8 @@ async function sync(
|
||||||
// We now know that we've successfully completed a storage service fetch
|
// We now know that we've successfully completed a storage service fetch
|
||||||
await window.storage.put('storageFetchComplete', true);
|
await window.storage.put('storageFetchComplete', true);
|
||||||
|
|
||||||
if (window.Signal.CI) {
|
if (window.SignalCI) {
|
||||||
window.Signal.CI.handleEvent('storageServiceComplete', {
|
window.SignalCI.handleEvent('storageServiceComplete', {
|
||||||
manifestVersion: version,
|
manifestVersion: version,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,9 +164,9 @@ export function SmartInstallScreen(): ReactElement {
|
||||||
}
|
}
|
||||||
onQrCodeScanned();
|
onQrCodeScanned();
|
||||||
|
|
||||||
if (window.Signal.CI) {
|
if (window.SignalCI) {
|
||||||
chooseDeviceNamePromiseWrapperRef.current.resolve(
|
chooseDeviceNamePromiseWrapperRef.current.resolve(
|
||||||
window.Signal.CI.deviceName
|
window.SignalCI.deviceName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ export class App {
|
||||||
const window = await this.getWindow();
|
const window = await this.getWindow();
|
||||||
|
|
||||||
await window.evaluate(
|
await window.evaluate(
|
||||||
`window.Signal.CI.solveChallenge(${JSON.stringify(response)})`
|
`window.SignalCI.solveChallenge(${JSON.stringify(response)})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ export class App {
|
||||||
const window = await this.getWindow();
|
const window = await this.getWindow();
|
||||||
|
|
||||||
const result = await window.evaluate(
|
const result = await window.evaluate(
|
||||||
`window.Signal.CI.waitForEvent(${JSON.stringify(event)})`
|
`window.SignalCI.waitForEvent(${JSON.stringify(event)})`
|
||||||
);
|
);
|
||||||
|
|
||||||
return result as T;
|
return result as T;
|
||||||
|
|
|
@ -224,7 +224,7 @@ export default class AccountManager extends EventTarget {
|
||||||
}
|
}
|
||||||
const url = getProvisioningUrl(uuid, pubKey);
|
const url = getProvisioningUrl(uuid, pubKey);
|
||||||
|
|
||||||
window.Signal.CI?.setProvisioningURL(url);
|
window.SignalCI?.setProvisioningURL(url);
|
||||||
|
|
||||||
setProvisioningUrl(url);
|
setProvisioningUrl(url);
|
||||||
request.respond(200, 'OK');
|
request.respond(200, 'OK');
|
||||||
|
|
24
ts/window.d.ts
vendored
24
ts/window.d.ts
vendored
|
@ -93,6 +93,15 @@ export type IPCType = {
|
||||||
updateTrayIcon: (count: number) => void;
|
updateTrayIcon: (count: number) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FeatureFlagType = {
|
||||||
|
GV2_ENABLE_SINGLE_CHANGE_PROCESSING: boolean;
|
||||||
|
GV2_ENABLE_CHANGE_PROCESSING: boolean;
|
||||||
|
GV2_ENABLE_STATE_PROCESSING: boolean;
|
||||||
|
GV2_ENABLE_PRE_JOIN_FETCH: boolean;
|
||||||
|
GV2_MIGRATION_DISABLE_ADD: boolean;
|
||||||
|
GV2_MIGRATION_DISABLE_INVITE: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type SignalCoreType = {
|
export type SignalCoreType = {
|
||||||
Crypto: typeof Crypto;
|
Crypto: typeof Crypto;
|
||||||
Curve: typeof Curve;
|
Curve: typeof Curve;
|
||||||
|
@ -128,9 +137,6 @@ export type SignalCoreType = {
|
||||||
};
|
};
|
||||||
conversationControllerStart: () => void;
|
conversationControllerStart: () => void;
|
||||||
challengeHandler?: ChallengeHandler;
|
challengeHandler?: ChallengeHandler;
|
||||||
|
|
||||||
// Test only
|
|
||||||
CI?: CIType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -214,14 +220,7 @@ declare global {
|
||||||
reduxStore: Store<StateType>;
|
reduxStore: Store<StateType>;
|
||||||
|
|
||||||
// Feature Flags
|
// Feature Flags
|
||||||
Flags: {
|
Flags: FeatureFlagType;
|
||||||
GV2_ENABLE_SINGLE_CHANGE_PROCESSING: boolean;
|
|
||||||
GV2_ENABLE_CHANGE_PROCESSING: boolean;
|
|
||||||
GV2_ENABLE_STATE_PROCESSING: boolean;
|
|
||||||
GV2_ENABLE_PRE_JOIN_FETCH: boolean;
|
|
||||||
GV2_MIGRATION_DISABLE_ADD: boolean;
|
|
||||||
GV2_MIGRATION_DISABLE_INVITE: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
BasePaths: {
|
BasePaths: {
|
||||||
|
@ -231,6 +230,9 @@ declare global {
|
||||||
temp: string;
|
temp: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Test only
|
||||||
|
SignalCI?: CIType;
|
||||||
|
|
||||||
// TODO DESKTOP-4801
|
// TODO DESKTOP-4801
|
||||||
SignalContext: SignalContextType;
|
SignalContext: SignalContextType;
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,5 @@ if (config.environment === 'test') {
|
||||||
if (config.enableCI) {
|
if (config.enableCI) {
|
||||||
console.log('Importing CI infrastructure...');
|
console.log('Importing CI infrastructure...');
|
||||||
const { getCI } = require('../../CI');
|
const { getCI } = require('../../CI');
|
||||||
window.Signal.CI = getCI(window.getTitle());
|
window.SignalCI = getCI(window.getTitle());
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import { sync } from 'fast-glob';
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
import { getSignalProtocolStore } from '../../SignalProtocolStore';
|
||||||
|
|
||||||
window.assert = assert;
|
window.assert = assert;
|
||||||
|
|
||||||
// This is a hack to let us run TypeScript tests in the renderer process. See the
|
// This is a hack to let us run TypeScript tests in the renderer process. See the
|
||||||
|
@ -26,3 +28,5 @@ window.testUtilities = {
|
||||||
}).forEach(require);
|
}).forEach(require);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.getSignalProtocolStore = getSignalProtocolStore;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright 2017 Signal Messenger, LLC
|
// Copyright 2017 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { clone } from 'lodash';
|
import { clone, has } from 'lodash';
|
||||||
import { contextBridge } from 'electron';
|
import { contextBridge } from 'electron';
|
||||||
|
|
||||||
import * as log from '../../logging/log';
|
import * as log from '../../logging/log';
|
||||||
import { SignalContext } from '../context';
|
|
||||||
|
|
||||||
import './phase1-ipc';
|
import './phase1-ipc';
|
||||||
import '../preload';
|
import '../preload';
|
||||||
|
@ -14,10 +13,11 @@ import './phase3-post-signal';
|
||||||
import './phase4-test';
|
import './phase4-test';
|
||||||
import '../../backbone/reliable_trigger';
|
import '../../backbone/reliable_trigger';
|
||||||
|
|
||||||
import { WebAudioRecorder } from '../../WebAudioRecorder';
|
import type { FeatureFlagType } from '../../window.d';
|
||||||
import { getSignalProtocolStore } from '../../SignalProtocolStore';
|
import type { StorageAccessType } from '../../types/Storage.d';
|
||||||
import { start as startConversationController } from '../../ConversationController';
|
import { start as startConversationController } from '../../ConversationController';
|
||||||
import { MessageController } from '../../util/MessageController';
|
import { MessageController } from '../../util/MessageController';
|
||||||
|
import { Environment, getEnvironment } from '../../environment';
|
||||||
|
|
||||||
window.addEventListener('contextmenu', e => {
|
window.addEventListener('contextmenu', e => {
|
||||||
const node = e.target as Element | null;
|
const node = e.target as Element | null;
|
||||||
|
@ -38,124 +38,45 @@ if (window.SignalContext.config.proxyUrl) {
|
||||||
log.info('Using provided proxy url');
|
log.info('Using provided proxy url');
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTestElectron = process.env.TEST_QUIT_ON_COMPLETE;
|
|
||||||
|
|
||||||
window.Whisper.events = clone(window.Backbone.Events);
|
window.Whisper.events = clone(window.Backbone.Events);
|
||||||
MessageController.install();
|
MessageController.install();
|
||||||
startConversationController();
|
startConversationController();
|
||||||
|
|
||||||
if (isTestElectron) {
|
if (getEnvironment() !== Environment.Production) {
|
||||||
window.getSignalProtocolStore = getSignalProtocolStore;
|
const SignalDebug = {
|
||||||
} else {
|
Data: window.Signal.Data,
|
||||||
contextBridge.exposeInMainWorld('SignalContext', SignalContext);
|
getConversation: (id: string) => window.ConversationController.get(id),
|
||||||
|
getMessageById: (id: string) => window.MessageController.getById(id),
|
||||||
|
getReduxState: () => window.reduxStore.getState(),
|
||||||
|
getSfuUrl: () => window.Signal.Services.calling._sfuUrl,
|
||||||
|
getStorageItem: (name: keyof StorageAccessType) => window.storage.get(name),
|
||||||
|
putStorageItem: <K extends keyof StorageAccessType>(
|
||||||
|
name: K,
|
||||||
|
value: StorageAccessType[K]
|
||||||
|
) => window.storage.put(name, value),
|
||||||
|
setFlag: (name: keyof FeatureFlagType, value: boolean) => {
|
||||||
|
if (!has(window.Flags, name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.Flags[name] = value;
|
||||||
|
},
|
||||||
|
setSfuUrl: (url: string) => {
|
||||||
|
window.Signal.Services.calling._sfuUrl = url;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('Backbone', window.Backbone);
|
contextBridge.exposeInMainWorld('SignalDebug', SignalDebug);
|
||||||
|
}
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('BasePaths', window.BasePaths);
|
if (getEnvironment() === Environment.Test) {
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'ConversationController',
|
|
||||||
window.ConversationController
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('Events', window.Events);
|
|
||||||
contextBridge.exposeInMainWorld('Flags', window.Flags);
|
|
||||||
contextBridge.exposeInMainWorld('IPC', window.IPC);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'SignalProtocolStore',
|
|
||||||
window.SignalProtocolStore
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getSignalProtocolStore',
|
|
||||||
getSignalProtocolStore
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'MessageController',
|
|
||||||
window.MessageController
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('WebAudioRecorder', WebAudioRecorder);
|
|
||||||
contextBridge.exposeInMainWorld('WebAPI', window.WebAPI);
|
|
||||||
contextBridge.exposeInMainWorld('Whisper', window.Whisper);
|
|
||||||
contextBridge.exposeInMainWorld('i18n', window.i18n);
|
|
||||||
contextBridge.exposeInMainWorld('reduxActions', window.reduxActions);
|
|
||||||
contextBridge.exposeInMainWorld('reduxStore', window.reduxStore);
|
|
||||||
contextBridge.exposeInMainWorld('startApp', window.startApp);
|
|
||||||
contextBridge.exposeInMainWorld('textsecure', window.textsecure);
|
|
||||||
|
|
||||||
// TODO DESKTOP-4801
|
|
||||||
contextBridge.exposeInMainWorld('ROOT_PATH', window.ROOT_PATH);
|
|
||||||
contextBridge.exposeInMainWorld('Signal', window.Signal);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'enterKeyboardMode',
|
|
||||||
window.enterKeyboardMode
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('enterMouseMode', window.enterMouseMode);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getAccountManager',
|
|
||||||
window.getAccountManager
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('getAppInstance', window.getAppInstance);
|
|
||||||
contextBridge.exposeInMainWorld('getBuildCreation', window.getBuildCreation);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getBuildExpiration',
|
|
||||||
window.getBuildExpiration
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('getConversations', window.getConversations);
|
|
||||||
contextBridge.exposeInMainWorld('getEnvironment', window.getEnvironment);
|
|
||||||
contextBridge.exposeInMainWorld('getHostName', window.getHostName);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getInteractionMode',
|
|
||||||
window.getInteractionMode
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('getLocale', window.getLocale);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getServerPublicParams',
|
|
||||||
window.getServerPublicParams
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'getServerTrustRoot',
|
|
||||||
window.getServerTrustRoot
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('getSfuUrl', window.getSfuUrl);
|
|
||||||
contextBridge.exposeInMainWorld('getSocketStatus', window.getSocketStatus);
|
|
||||||
contextBridge.exposeInMainWorld('getSyncRequest', window.getSyncRequest);
|
|
||||||
contextBridge.exposeInMainWorld('getTitle', window.getTitle);
|
|
||||||
contextBridge.exposeInMainWorld('getVersion', window.getVersion);
|
|
||||||
contextBridge.exposeInMainWorld('initialTheme', window.initialTheme);
|
|
||||||
contextBridge.exposeInMainWorld('isAfterVersion', window.isAfterVersion);
|
|
||||||
contextBridge.exposeInMainWorld('isBeforeVersion', window.isBeforeVersion);
|
|
||||||
contextBridge.exposeInMainWorld('isBehindProxy', window.isBehindProxy);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'libphonenumberFormat',
|
|
||||||
window.libphonenumberFormat
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'libphonenumberInstance',
|
|
||||||
window.libphonenumberInstance
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('localeMessages', window.localeMessages);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'logAuthenticatedConnect',
|
|
||||||
window.logAuthenticatedConnect
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('nodeSetImmediate', window.nodeSetImmediate);
|
|
||||||
contextBridge.exposeInMainWorld('platform', window.platform);
|
|
||||||
contextBridge.exposeInMainWorld('preloadedImages', window.preloadedImages);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'sendChallengeRequest',
|
|
||||||
window.sendChallengeRequest
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('setImmediate', window.setImmediate);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'showKeyboardShortcuts',
|
|
||||||
window.showKeyboardShortcuts
|
|
||||||
);
|
|
||||||
contextBridge.exposeInMainWorld('storage', window.storage);
|
|
||||||
contextBridge.exposeInMainWorld('systemTheme', window.systemTheme);
|
|
||||||
contextBridge.exposeInMainWorld(
|
|
||||||
'waitForEmptyEventQueue',
|
|
||||||
window.waitForEmptyEventQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('assert', window.assert);
|
|
||||||
contextBridge.exposeInMainWorld('RETRY_DELAY', window.RETRY_DELAY);
|
contextBridge.exposeInMainWorld('RETRY_DELAY', window.RETRY_DELAY);
|
||||||
|
contextBridge.exposeInMainWorld('assert', window.assert);
|
||||||
contextBridge.exposeInMainWorld('testUtilities', window.testUtilities);
|
contextBridge.exposeInMainWorld('testUtilities', window.testUtilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.SIGNAL_CI_CONFIG) {
|
||||||
|
contextBridge.exposeInMainWorld('SignalCI', window.SignalCI);
|
||||||
|
}
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('showDebugLog', window.IPC.showDebugLog);
|
||||||
|
contextBridge.exposeInMainWorld('startApp', window.startApp);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue