Skip to content

Commit 589a74d

Browse files
committed
Merge master into dev
Brings master bug fixes into dev branch: - macOS Tahoe crash fix: null guards on Redux store functions + safeSelect - Screen picker race condition fixes with responseSentRef pattern - Remove redundant dialog.close() in Dialog hooks - Remove package-lock.json in favor of yarn.lock - i18n updates (Lingohub, Hungarian) Conflict resolution: - privacy.ts: Combined dev's circular reference detection with master's enabled privacy hook (dev had it disabled for debugging) - main.ts: Kept dev's stopOutlookCalendarSync import - en.i18n.json: Kept all dev i18n keys (sync interval, detailed logging) - yarn.lock: Regenerated from dev's dependencies
2 parents c9adbeb + 6c95653 commit 589a74d

File tree

14 files changed

+462
-23045
lines changed

14 files changed

+462
-23045
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Thumbs.db
99
/dist
1010
/Development.provisionprofile
1111

12+
# npm (this project uses yarn)
13+
/package-lock.json
14+
1215
# yarn
1316
.pnp.*
1417
.yarn/*

package-lock.json

Lines changed: 0 additions & 22835 deletions
This file was deleted.

src/i18n/de-DE.i18n.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,4 +432,4 @@
432432
"expiresOn": "Läuft ab am {{date}}"
433433
}
434434
}
435-
}
435+
}

src/i18n/en.i18n.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@
470470
"permissionDenied": "Screen Recording Permission Denied",
471471
"permissionRequired": "Screen recording permission is required to share your screen.",
472472
"permissionInstructions": "Please enable it in your system preferences and try again.",
473+
"openSystemPreferences": "Open System Preferences",
473474
"title": "Share your screen",
474475
"entireScreen": "Your entire screen",
475476
"applicationWindow": "Application window",

src/i18n/hu.i18n.json

Lines changed: 223 additions & 66 deletions
Large diffs are not rendered by default.

src/i18n/ja.i18n.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@
103103
}
104104
}
105105
},
106+
"settings": {
107+
"options": {
108+
"transparentWindow": {
109+
"title": "透明ウィンドウ効果",
110+
"description": "ウィンドウのネイティブなビブランシー/透明効果を有効にします。適用するには再起動が必要です。"
111+
},
112+
"themeAppearance": {
113+
"title": "テーマ",
114+
"description": "アプリケーションのカラーテーマを選択します。",
115+
"auto": "システムに従う",
116+
"light": "ライト",
117+
"dark": "ダーク"
118+
}
119+
}
120+
},
106121
"error": {
107122
"authNeeded": "認証が必要です。<strong>{{- auth}}</strong> を試してみてください。",
108123
"connectTimeout": "再接続がタイムアウトしました",
@@ -215,21 +230,6 @@
215230
"cancel": "キャンセル",
216231
"share": "共有"
217232
},
218-
"settings": {
219-
"options": {
220-
"transparentWindow": {
221-
"title": "透明ウィンドウ効果",
222-
"description": "ウィンドウのネイティブなビブランシー/透明効果を有効にします。適用するには再起動が必要です。"
223-
},
224-
"themeAppearance": {
225-
"title": "テーマ",
226-
"description": "アプリケーションのカラーテーマを選択します。",
227-
"auto": "システムに従う",
228-
"light": "ライト",
229-
"dark": "ダーク"
230-
}
231-
}
232-
},
233233
"serverInfo": {
234234
"title": "サーバー情報",
235235
"urlLabel": "URL:",
@@ -256,4 +256,4 @@
256256
"expiresOn": "{{date}}に期限切れ"
257257
}
258258
}
259-
}
259+
}

src/logging/privacy.ts

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ export const redactSensitiveData = (text: string): string => {
5656
return result;
5757
};
5858

59-
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- kept for re-enabling privacy hook
6059
const redactObject = (obj: any, seen = new WeakSet()): any => {
6160
if (obj === null || obj === undefined) return obj;
6261
if (typeof obj === 'string') return redactSensitiveData(obj);
@@ -98,28 +97,24 @@ const redactObject = (obj: any, seen = new WeakSet()): any => {
9897
return obj;
9998
};
10099

101-
// Privacy hook is currently disabled to allow raw log data during feature development.
102-
// Re-enable by uncommenting the redaction logic below when features are finalized.
103100
export const createPrivacyHook = () => {
104-
return (message: any, _transport: any, _transportName?: string) => message;
105-
106-
// TODO: Re-enable privacy redaction when Outlook calendar features are stable
107-
// return (message: any, _transport: any, _transportName?: string) => {
108-
// try {
109-
// const data = Array.isArray(message.data) ? message.data : [message.data];
110-
// const sanitizedData = data.map((item: any) => {
111-
// if (typeof item === 'string') return redactSensitiveData(item);
112-
// if (typeof item === 'object' && item !== null)
113-
// return redactObject(item);
114-
// return item;
115-
// });
116-
// return { ...message, data: sanitizedData };
117-
// } catch {
118-
// return {
119-
// level: message.level,
120-
// date: message.date,
121-
// data: ['[Privacy redaction failed]'],
122-
// };
123-
// }
124-
// };
101+
return (message: any, _transport: any, _transportName?: string) => {
102+
try {
103+
// Guard against non-array data
104+
const data = Array.isArray(message.data) ? message.data : [message.data];
105+
const sanitizedData = data.map((item: any) => {
106+
if (typeof item === 'string') return redactSensitiveData(item);
107+
if (typeof item === 'object' && item !== null)
108+
return redactObject(item);
109+
return item;
110+
});
111+
return { ...message, data: sanitizedData };
112+
} catch {
113+
// Don't emit raw data on failure - only safe placeholder
114+
return {
115+
...message,
116+
data: ['[Privacy redaction failed]'],
117+
};
118+
}
119+
};
125120
};

src/main.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,6 @@ const start = async (): Promise<void> => {
9999

100100
// Mark main window as stable - GPU crashes after this won't trigger fallback
101101
markMainWindowStable();
102-
103-
// React DevTools is currently incompatible with Electron 10
104-
// if (process.env.NODE_ENV === 'development') {
105-
// installDevTools();
106-
// }
107102
watchMachineTheme();
108103
setupNotifications();
109104
attentionDrawing.setUp();

src/servers/preload/internalVideoChatWindow.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { ipcRenderer } from 'electron';
22

3-
import { select } from '../../store';
3+
import { safeSelect } from '../../store';
44
import { openExternal } from '../../utils/browserLauncher';
55

66
export const getInternalVideoChatWindowEnabled = (): boolean =>
7-
select(({ isInternalVideoChatWindowEnabled }) => ({
8-
isInternalVideoChatWindowEnabled,
9-
})).isInternalVideoChatWindowEnabled;
7+
safeSelect(
8+
({ isInternalVideoChatWindowEnabled }) => isInternalVideoChatWindowEnabled
9+
) ?? false;
1010

1111
export type videoCallWindowOptions = {
1212
providerName?: string | undefined;

src/store/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ export const createRendererReduxStore = async (): Promise<Store> => {
3636
};
3737

3838
export const dispatch = <Action extends RootAction>(action: Action): void => {
39+
if (!reduxStore) return;
3940
reduxStore.dispatch(action);
4041
};
4142

4243
export const dispatchSingle = <Action extends RootAction>(
4344
action: Action
4445
): void => {
46+
if (!reduxStore) return;
4547
reduxStore.dispatch({
4648
...action,
4749
ipcMeta: { ...action.ipcMeta, scope: 'single' },
@@ -51,6 +53,7 @@ export const dispatchSingle = <Action extends RootAction>(
5153
export const dispatchLocal = <Action extends RootAction>(
5254
action: Action
5355
): void => {
56+
if (!reduxStore) return;
5457
reduxStore.dispatch({
5558
...action,
5659
ipcMeta: { ...action.ipcMeta, scope: 'local' },
@@ -63,10 +66,16 @@ type Selector<T> = (state: RootState) => T;
6366
export const select = <T>(selector: Selector<T>): T =>
6467
selector(reduxStore.getState());
6568

69+
export const safeSelect = <T>(selector: Selector<T>): T | undefined => {
70+
if (!reduxStore) return undefined;
71+
return selector(reduxStore.getState());
72+
};
73+
6674
export const watch = <T>(
6775
selector: Selector<T>,
6876
watcher: (curr: T, prev: T | undefined) => void
6977
): (() => void) => {
78+
if (!reduxStore) return () => undefined;
7079
const initial = select(selector);
7180
watcher(initial, undefined);
7281

@@ -98,6 +107,7 @@ export const listen: {
98107
typeOrPredicate: ActionType | ((action: RootAction) => action is Action),
99108
listener: (action: RootAction) => void
100109
): (() => void) => {
110+
if (!reduxStore) return () => undefined;
101111
const effectivePredicate =
102112
typeof typeOrPredicate === 'function'
103113
? typeOrPredicate
@@ -184,6 +194,11 @@ export const request = <
184194
...types: ResponseTypes
185195
): Promise<Response['payload']> =>
186196
new Promise((resolve, reject) => {
197+
if (!reduxStore) {
198+
reject(new Error('Store not initialized'));
199+
return;
200+
}
201+
187202
const id = Math.random().toString(36).slice(2);
188203

189204
const unsubscribe = listen(

0 commit comments

Comments
 (0)