@flighthq/host-electron 0.5.1-next.920.da8f530 → 0.6.0
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/README.md +2 -2
- package/dist/contract.d.ts +19 -24
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +18 -24
- package/dist/contract.js.map +1 -1
- package/dist/electronApp.d.ts +62 -34
- package/dist/electronApp.d.ts.map +1 -1
- package/dist/electronApp.js +175 -234
- package/dist/electronApp.js.map +1 -1
- package/dist/electronClipboard.d.ts +7 -5
- package/dist/electronClipboard.d.ts.map +1 -1
- package/dist/electronClipboard.js +91 -66
- package/dist/electronClipboard.js.map +1 -1
- package/dist/electronDefaultHostGroups.d.ts +59 -0
- package/dist/electronDefaultHostGroups.d.ts.map +1 -0
- package/dist/electronDefaultHostGroups.js +109 -0
- package/dist/electronDefaultHostGroups.js.map +1 -0
- package/dist/electronDialog.d.ts +12 -9
- package/dist/electronDialog.d.ts.map +1 -1
- package/dist/electronDialog.js +28 -21
- package/dist/electronDialog.js.map +1 -1
- package/dist/electronIpc.d.ts +13 -11
- package/dist/electronIpc.d.ts.map +1 -1
- package/dist/electronIpc.js +32 -26
- package/dist/electronIpc.js.map +1 -1
- package/dist/electronMenu.d.ts +12 -6
- package/dist/electronMenu.d.ts.map +1 -1
- package/dist/electronMenu.js +41 -30
- package/dist/electronMenu.js.map +1 -1
- package/dist/electronMenuTemplate.d.ts +2 -1
- package/dist/electronMenuTemplate.d.ts.map +1 -1
- package/dist/electronMenuTemplate.js.map +1 -1
- package/dist/electronNotification.d.ts +25 -7
- package/dist/electronNotification.d.ts.map +1 -1
- package/dist/electronNotification.js +39 -16
- package/dist/electronNotification.js.map +1 -1
- package/dist/electronPlatform.d.ts +5 -3
- package/dist/electronPlatform.d.ts.map +1 -1
- package/dist/electronPlatform.js +9 -7
- package/dist/electronPlatform.js.map +1 -1
- package/dist/electronPower.d.ts +22 -11
- package/dist/electronPower.d.ts.map +1 -1
- package/dist/electronPower.js +48 -59
- package/dist/electronPower.js.map +1 -1
- package/dist/electronProtocol.d.ts +16 -8
- package/dist/electronProtocol.d.ts.map +1 -1
- package/dist/electronProtocol.js +45 -28
- package/dist/electronProtocol.js.map +1 -1
- package/dist/electronRegister.d.ts +5 -7
- package/dist/electronRegister.d.ts.map +1 -1
- package/dist/electronRegister.js +72 -99
- package/dist/electronRegister.js.map +1 -1
- package/dist/electronScreen.d.ts +7 -6
- package/dist/electronScreen.d.ts.map +1 -1
- package/dist/electronScreen.js +17 -14
- package/dist/electronScreen.js.map +1 -1
- package/dist/electronShell.d.ts +16 -8
- package/dist/electronShell.d.ts.map +1 -1
- package/dist/electronShell.js +50 -43
- package/dist/electronShell.js.map +1 -1
- package/dist/electronShortcut.d.ts +6 -4
- package/dist/electronShortcut.d.ts.map +1 -1
- package/dist/electronShortcut.js +16 -10
- package/dist/electronShortcut.js.map +1 -1
- package/dist/electronStorage.d.ts +5 -3
- package/dist/electronStorage.d.ts.map +1 -1
- package/dist/electronStorage.js +9 -7
- package/dist/electronStorage.js.map +1 -1
- package/dist/electronTray.d.ts +38 -21
- package/dist/electronTray.d.ts.map +1 -1
- package/dist/electronTray.js +110 -76
- package/dist/electronTray.js.map +1 -1
- package/dist/electronUpdater.d.ts +6 -3
- package/dist/electronUpdater.d.ts.map +1 -1
- package/dist/electronUpdater.js +10 -7
- package/dist/electronUpdater.js.map +1 -1
- package/dist/electronWindow.d.ts +23 -7
- package/dist/electronWindow.d.ts.map +1 -1
- package/dist/electronWindow.js +234 -152
- package/dist/electronWindow.js.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/types/ElectronApi.d.ts +393 -0
- package/dist/types/ElectronApi.d.ts.map +1 -0
- package/dist/types/ElectronApi.js +20 -0
- package/dist/types/ElectronApi.js.map +1 -0
- package/dist/types/ElectronAppCapabilitiesFor.d.ts +8 -0
- package/dist/types/ElectronAppCapabilitiesFor.d.ts.map +1 -0
- package/dist/types/ElectronAppCapabilitiesFor.js +2 -0
- package/dist/types/ElectronAppCapabilitiesFor.js.map +1 -0
- package/dist/types/ElectronHost.d.ts +43 -0
- package/dist/types/ElectronHost.d.ts.map +1 -0
- package/dist/types/ElectronHost.js +2 -0
- package/dist/types/ElectronHost.js.map +1 -0
- package/dist/types/ElectronHostGroups.d.ts +85 -0
- package/dist/types/ElectronHostGroups.d.ts.map +1 -0
- package/dist/types/ElectronHostGroups.js +2 -0
- package/dist/types/ElectronHostGroups.js.map +1 -0
- package/dist/types/ElectronHostOptions.d.ts +7 -0
- package/dist/types/ElectronHostOptions.d.ts.map +1 -0
- package/dist/types/ElectronHostOptions.js +2 -0
- package/dist/types/ElectronHostOptions.js.map +1 -0
- package/dist/types/ElectronProtocolCapabilities.d.ts +3 -0
- package/dist/types/ElectronProtocolCapabilities.d.ts.map +1 -0
- package/dist/types/ElectronProtocolCapabilities.js +2 -0
- package/dist/types/ElectronProtocolCapabilities.js.map +1 -0
- package/dist/types/ElectronTrayCapabilitiesFor.d.ts +7 -0
- package/dist/types/ElectronTrayCapabilitiesFor.d.ts.map +1 -0
- package/dist/types/ElectronTrayCapabilitiesFor.js +2 -0
- package/dist/types/ElectronTrayCapabilitiesFor.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +42 -21
- package/src/electronApp.test.ts +158 -131
- package/src/electronClipboard.test.ts +40 -13
- package/src/electronDefaultHostGroups.test.ts +148 -0
- package/src/electronDialog.test.ts +55 -53
- package/src/electronHostTreeShaking.test.ts +51 -0
- package/src/electronIpc.test.ts +47 -66
- package/src/electronMenu.test.ts +61 -47
- package/src/electronMenuTemplate.test.ts +1 -1
- package/src/electronNotification.test.ts +71 -21
- package/src/electronPlatform.test.ts +17 -12
- package/src/electronPower.test.ts +112 -88
- package/src/electronProtocol.test.ts +68 -35
- package/src/electronRegister.test.ts +280 -26
- package/src/electronScreen.test.ts +34 -25
- package/src/electronShell.test.ts +99 -59
- package/src/electronShortcut.test.ts +22 -19
- package/src/electronStorage.test.ts +26 -24
- package/src/electronTray.test.ts +225 -109
- package/src/electronUpdater.test.ts +26 -19
- package/src/electronWindow.test.ts +229 -101
|
@@ -1,13 +1,184 @@
|
|
|
1
|
-
import { getAppName } from '@flighthq/app
|
|
1
|
+
import { getAppName } from '@flighthq/app';
|
|
2
2
|
import { readClipboardText } from '@flighthq/clipboard/contract';
|
|
3
|
-
import { EntityRuntimeKey } from '@flighthq/
|
|
4
|
-
import type {
|
|
3
|
+
import { EntityRuntimeKey } from '@flighthq/entity/contract';
|
|
4
|
+
import type { EntityRaw, EntityRuntime } from '@flighthq/entity/contract';
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import * as contractApi from './contract.ts';
|
|
7
|
+
import { electronHost } from './electronRegister.ts';
|
|
8
|
+
import * as publicApi from './index.ts';
|
|
9
|
+
import type { ElectronApi } from './types/index.ts';
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
const GROUPS = [
|
|
12
|
+
['accessibility', 'electronHostAccessibilityGroup'],
|
|
13
|
+
['app', 'electronHostApp'],
|
|
14
|
+
['audio', 'electronHostAudioGroup'],
|
|
15
|
+
['audioDecode', 'electronHostAudioDecodeGroup'],
|
|
16
|
+
['bitmap', 'electronHostBitmapGroup'],
|
|
17
|
+
['canvas', 'electronHostCanvasGroup'],
|
|
18
|
+
['clipboard', 'electronHostClipboard'],
|
|
19
|
+
['compress', 'electronHostCompressGroup'],
|
|
20
|
+
['connectivity', 'electronHostConnectivityGroup'],
|
|
21
|
+
['decompress', 'electronHostDecompressGroup'],
|
|
22
|
+
['device', 'electronHostDeviceGroup'],
|
|
23
|
+
['dialog', 'electronHostDialog'],
|
|
24
|
+
['fileSystem', 'electronHostFileSystemGroup'],
|
|
25
|
+
['font', 'electronHostFontGroup'],
|
|
26
|
+
['fullscreen', 'electronHostFullscreenGroup'],
|
|
27
|
+
['geolocation', 'electronHostGeolocationGroup'],
|
|
28
|
+
['gl', 'electronHostGlGroup'],
|
|
29
|
+
['glyph', 'electronHostGlyphGroup'],
|
|
30
|
+
['haptics', 'electronHostHapticsGroup'],
|
|
31
|
+
['image', 'electronHostImageGroup'],
|
|
32
|
+
['imageDecode', 'electronHostImageDecodeGroup'],
|
|
33
|
+
['imageEncode', 'electronHostImageEncodeGroup'],
|
|
34
|
+
['input', 'electronHostInputGroup'],
|
|
35
|
+
['ipc', 'electronHostIpc'],
|
|
36
|
+
['lifecycle', 'electronHostLifecycleGroup'],
|
|
37
|
+
['mediaSession', 'electronHostMediaSessionGroup'],
|
|
38
|
+
['menu', 'electronHostMenu'],
|
|
39
|
+
['midi', 'electronHostMidiGroup'],
|
|
40
|
+
['net', 'electronHostNetGroup'],
|
|
41
|
+
['notification', 'electronHostNotification'],
|
|
42
|
+
['permissions', 'electronHostPermissionsGroup'],
|
|
43
|
+
['platform', 'electronHostPlatformGroup'],
|
|
44
|
+
['power', 'electronHostPower'],
|
|
45
|
+
['preferences', 'electronHostStorageGroup'],
|
|
46
|
+
['protocol', 'electronHostProtocol'],
|
|
47
|
+
['screen', 'electronHostScreen'],
|
|
48
|
+
['sensors', 'electronHostSensorsGroup'],
|
|
49
|
+
['share', 'electronHostShareGroup'],
|
|
50
|
+
['shell', 'electronHostShell'],
|
|
51
|
+
['shortcut', 'electronHostShortcut'],
|
|
52
|
+
['socket', 'electronHostSocketGroup'],
|
|
53
|
+
['softKeyboard', 'electronHostSoftKeyboardGroup'],
|
|
54
|
+
['statusBar', 'electronHostStatusBarGroup'],
|
|
55
|
+
['surface', 'electronHostSurfaceGroup'],
|
|
56
|
+
['textSegment', 'electronHostTextSegmentGroup'],
|
|
57
|
+
['textShaper', 'electronHostTextShaperGroup'],
|
|
58
|
+
['tray', 'electronHostTray'],
|
|
59
|
+
['updater', 'electronHostUpdater'],
|
|
60
|
+
['video', 'electronHostVideoGroup'],
|
|
61
|
+
['wgpu', 'electronHostWgpuGroup'],
|
|
62
|
+
['window', 'electronHostWindow'],
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
const LEAVES = [
|
|
66
|
+
'electronHostAppActivate',
|
|
67
|
+
'electronHostAppActivationPolicy',
|
|
68
|
+
'electronHostAppAllWindowsClosed',
|
|
69
|
+
'electronHostAppBadge',
|
|
70
|
+
'electronHostAppDock',
|
|
71
|
+
'electronHostAppFocus',
|
|
72
|
+
'electronHostAppHide',
|
|
73
|
+
'electronHostAppLocale',
|
|
74
|
+
'electronHostAppLoginItem',
|
|
75
|
+
'electronHostAppName',
|
|
76
|
+
'electronHostAppNameWrite',
|
|
77
|
+
'electronHostAppOpenFile',
|
|
78
|
+
'electronHostAppPath',
|
|
79
|
+
'electronHostAppQuit',
|
|
80
|
+
'electronHostAppQuitRequest',
|
|
81
|
+
'electronHostAppReady',
|
|
82
|
+
'electronHostAppRecentDocuments',
|
|
83
|
+
'electronHostAppRelaunch',
|
|
84
|
+
'electronHostAppSecondInstance',
|
|
85
|
+
'electronHostAppShow',
|
|
86
|
+
'electronHostAppSingleInstance',
|
|
87
|
+
'electronHostAppUserModelId',
|
|
88
|
+
'electronHostAppVersion',
|
|
89
|
+
'electronHostClipboardBookmark',
|
|
90
|
+
'electronHostClipboardFormats',
|
|
91
|
+
'electronHostClipboardImage',
|
|
92
|
+
'electronHostClipboardText',
|
|
93
|
+
'electronHostDirectoryOpenDialog',
|
|
94
|
+
'electronHostFileOpenDialog',
|
|
95
|
+
'electronHostFileSaveDialog',
|
|
96
|
+
'electronHostIpcHandle',
|
|
97
|
+
'electronHostIpcInvoke',
|
|
98
|
+
'electronHostIpcMessage',
|
|
99
|
+
'electronHostIpcSend',
|
|
100
|
+
'electronHostIpcTargetedSend',
|
|
101
|
+
'electronHostAppMenu',
|
|
102
|
+
'electronHostMenuPopup',
|
|
103
|
+
'electronHostMenuSelect',
|
|
104
|
+
'electronHostMessageDialog',
|
|
105
|
+
'electronHostNotificationAction',
|
|
106
|
+
'electronHostNotificationClick',
|
|
107
|
+
'electronHostNotificationClose',
|
|
108
|
+
'electronHostNotificationDelivery',
|
|
109
|
+
'electronHostNotificationDismiss',
|
|
110
|
+
'electronHostNotificationLifecycle',
|
|
111
|
+
'electronHostNotificationReceived',
|
|
112
|
+
'electronHostNotificationReply',
|
|
113
|
+
'electronHostPlatform',
|
|
114
|
+
'electronHostPowerBatteryHealth',
|
|
115
|
+
'electronHostPowerChange',
|
|
116
|
+
'electronHostPowerIdle',
|
|
117
|
+
'electronHostPowerKeepAwake',
|
|
118
|
+
'electronHostPowerSessionLock',
|
|
119
|
+
'electronHostPowerStatus',
|
|
120
|
+
'electronHostPowerSuspension',
|
|
121
|
+
'electronHostPowerThermal',
|
|
122
|
+
'electronHostProtocolDefault',
|
|
123
|
+
'electronHostProtocolOpen',
|
|
124
|
+
'electronHostProtocolRegistration',
|
|
125
|
+
'electronHostProtocolRegistrationQuery',
|
|
126
|
+
'electronHostProtocolUnregistration',
|
|
127
|
+
'electronHostScreenChange',
|
|
128
|
+
'electronHostScreenQuery',
|
|
129
|
+
'electronHostShellBeep',
|
|
130
|
+
'electronHostShellExternal',
|
|
131
|
+
'electronHostShellPathOpen',
|
|
132
|
+
'electronHostShellPathReveal',
|
|
133
|
+
'electronHostShellShortcutLink',
|
|
134
|
+
'electronHostShellTrash',
|
|
135
|
+
'electronHostShortcutQuery',
|
|
136
|
+
'electronHostShortcutTrigger',
|
|
137
|
+
'electronHostStorage',
|
|
138
|
+
'electronHostTrayBalloon',
|
|
139
|
+
'electronHostTrayBalloonEvents',
|
|
140
|
+
'electronHostTrayBounds',
|
|
141
|
+
'electronHostTrayDoubleClickPolicy',
|
|
142
|
+
'electronHostTrayDropEvents',
|
|
143
|
+
'electronHostTrayImage',
|
|
144
|
+
'electronHostTrayInteractionEvents',
|
|
145
|
+
'electronHostTrayLifecycle',
|
|
146
|
+
'electronHostTrayMenu',
|
|
147
|
+
'electronHostTrayMenuSelectionEvents',
|
|
148
|
+
'electronHostTrayPopupMenu',
|
|
149
|
+
'electronHostTrayPressedImage',
|
|
150
|
+
'electronHostTrayTemplateImage',
|
|
151
|
+
'electronHostTrayTitle',
|
|
152
|
+
'electronHostTrayTooltip',
|
|
153
|
+
'electronHostUpdaterCommand',
|
|
154
|
+
'electronHostWindowAppearance',
|
|
155
|
+
'electronHostWindowAttach',
|
|
156
|
+
'electronHostWindowAttention',
|
|
157
|
+
'electronHostWindowContentProtection',
|
|
158
|
+
'electronHostWindowFocus',
|
|
159
|
+
'electronHostWindowFullscreen',
|
|
160
|
+
'electronHostWindowGeometry',
|
|
161
|
+
'electronHostWindowHierarchy',
|
|
162
|
+
'electronHostWindowLifecycle',
|
|
163
|
+
'electronHostWindowProgress',
|
|
164
|
+
'electronHostWindowShadow',
|
|
165
|
+
'electronHostWindowShell',
|
|
166
|
+
'electronHostWindowSizeConstraints',
|
|
167
|
+
'electronHostWindowState',
|
|
168
|
+
'electronHostWindowVisibility',
|
|
169
|
+
'electronHostWindowZOrder',
|
|
170
|
+
] as const;
|
|
171
|
+
|
|
172
|
+
const AUXILIARY_EXPORTS = ['getAppWindowForElectronId', 'getElectronBrowserWindow', 'getElectronWindowId'] as const;
|
|
173
|
+
|
|
174
|
+
type EntityCompatibility = EntityRaw & { [EntityRuntimeKey]: EntityRuntime | undefined };
|
|
175
|
+
type ElectronLeafResult = ReturnType<(typeof publicApi)[(typeof LEAVES)[number]]>;
|
|
176
|
+
type ElectronLeafProvidersAreAllEntities =
|
|
177
|
+
Exclude<ElectronLeafResult, undefined> extends EntityCompatibility ? true : false;
|
|
178
|
+
type ElectronFullHostIsEntity = ReturnType<typeof publicApi.electronHost> extends EntityCompatibility ? true : false;
|
|
179
|
+
|
|
180
|
+
// A fake Electron API broad enough that every host constructor can close over its injected dependency
|
|
181
|
+
// without calling missing native operations during construction.
|
|
11
182
|
function fakeElectron(): ElectronApi {
|
|
12
183
|
const noop = () => {};
|
|
13
184
|
const off = () => () => {};
|
|
@@ -40,25 +211,56 @@ function fakeElectron(): ElectronApi {
|
|
|
40
211
|
dialog: {},
|
|
41
212
|
Menu: {
|
|
42
213
|
buildFromTemplate: () => ({ popup: noop }),
|
|
43
|
-
|
|
214
|
+
setAppMenu: noop,
|
|
44
215
|
},
|
|
45
216
|
// The remaining members are unused at registration time.
|
|
46
217
|
_off: off,
|
|
47
218
|
} as unknown as ElectronApi;
|
|
48
219
|
}
|
|
49
220
|
|
|
50
|
-
describe('
|
|
51
|
-
it('
|
|
52
|
-
|
|
221
|
+
describe('electronHost', () => {
|
|
222
|
+
it('exports exactly the canonical full, group, and supported leaf constructors from both lanes', () => {
|
|
223
|
+
const expected = [...new Set(['electronHost', ...GROUPS.map((entry) => entry[1]), ...LEAVES])].sort();
|
|
224
|
+
const expectedSurface = [...expected, ...AUXILIARY_EXPORTS].sort();
|
|
225
|
+
for (const api of [publicApi, contractApi]) {
|
|
226
|
+
expect(Object.keys(api).sort()).toEqual(expectedSurface);
|
|
227
|
+
const names = Object.keys(api)
|
|
228
|
+
.filter((name) => /^electronHost(?:$|[A-Z])/u.test(name))
|
|
229
|
+
.sort();
|
|
230
|
+
expect(names).toEqual(expected);
|
|
231
|
+
expect(
|
|
232
|
+
Object.keys(api).filter((name) =>
|
|
233
|
+
/^(?:createElectron|initializeElectron|makeElectron|registerElectron)/u.test(name),
|
|
234
|
+
),
|
|
235
|
+
).toEqual([]);
|
|
236
|
+
for (const name of names) expect(Reflect.get(api, name), name).toBeTypeOf('function');
|
|
237
|
+
}
|
|
238
|
+
for (const name of expected) expect(Reflect.get(publicApi, name)).toBe(Reflect.get(contractApi, name));
|
|
53
239
|
});
|
|
54
|
-
|
|
55
|
-
|
|
240
|
+
|
|
241
|
+
it('types the full host as an Entity and leaf capabilities as structural', () => {
|
|
242
|
+
expectTypeOf<ElectronFullHostIsEntity>().toEqualTypeOf<true>();
|
|
243
|
+
expectTypeOf<ElectronLeafProvidersAreAllEntities>().toEqualTypeOf<false>();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('constructs every Host group through explicit canonical boundaries', () => {
|
|
247
|
+
const host = electronHost(fakeElectron(), { platform: 'linux' }) as unknown as Record<string, unknown>;
|
|
248
|
+
const hostGroups = [...HOST_GROUP_NAMES];
|
|
249
|
+
expect(GROUPS.map((entry) => entry[0]).sort()).toEqual(hostGroups);
|
|
250
|
+
expect(
|
|
251
|
+
Object.keys(host)
|
|
252
|
+
.filter((key) => key !== String(EntityRuntimeKey))
|
|
253
|
+
.sort(),
|
|
254
|
+
).toEqual(hostGroups);
|
|
255
|
+
for (const [path] of GROUPS) expect(host[path], path).not.toBeUndefined();
|
|
256
|
+
});
|
|
257
|
+
|
|
56
258
|
it('routes capability seams to the Electron backends without throwing', async () => {
|
|
57
|
-
const host =
|
|
259
|
+
const host = electronHost(fakeElectron(), {
|
|
58
260
|
platform: 'linux',
|
|
59
261
|
});
|
|
60
|
-
expect(host.
|
|
61
|
-
expect(
|
|
262
|
+
expect(host.audio).toEqual({});
|
|
263
|
+
expect(host.video).toEqual({});
|
|
62
264
|
expect(host.dialog.directoryOpen.open).toBeTypeOf('function');
|
|
63
265
|
expect(host.dialog.fileOpen.open).toBeTypeOf('function');
|
|
64
266
|
expect(host.dialog.fileSave.save).toBeTypeOf('function');
|
|
@@ -68,26 +270,23 @@ describe('registerElectronBackends', () => {
|
|
|
68
270
|
expect(host.ipc.handle.handle).toBeTypeOf('function');
|
|
69
271
|
expect(host.ipc.message.subscribe).toBeTypeOf('function');
|
|
70
272
|
expect(host.ipc.targetedSend.send).toBeTypeOf('function');
|
|
71
|
-
expect(EntityRuntimeKey in host.shortcut.query).toBe(true);
|
|
72
|
-
expect(EntityRuntimeKey in host.shortcut.trigger).toBe(true);
|
|
73
|
-
expect(EntityRuntimeKey in host.updater.command).toBe(true);
|
|
74
273
|
expect(host.updater.command.check).toBeTypeOf('function');
|
|
75
274
|
expect(Object.keys(host.clipboard).sort()).toEqual(['bookmark', 'formats', 'image', 'text']);
|
|
76
275
|
expect(host.connectivity).toEqual({});
|
|
77
|
-
expect(host.
|
|
276
|
+
expect(host.preferences.local.getItem('missing')).toEqual({
|
|
78
277
|
reason: 'ok',
|
|
79
278
|
value: null,
|
|
80
279
|
});
|
|
81
|
-
expect(host.window.open).toBeTypeOf('function');
|
|
82
|
-
expect(getAppName(host)).toBe('ElectronApp');
|
|
83
|
-
expect(await readClipboardText(host)).toBe('ELECTRON-TEXT');
|
|
280
|
+
expect(host.window.lifecycle.open).toBeTypeOf('function');
|
|
281
|
+
expect(getAppName(host.app.name)).toBe('ElectronApp');
|
|
282
|
+
expect(await readClipboardText(host.clipboard.text)).toBe('ELECTRON-TEXT');
|
|
84
283
|
});
|
|
85
284
|
|
|
86
285
|
it('constructs the exact six Shell slots from an injected platform fact', () => {
|
|
87
|
-
const windowsHost =
|
|
286
|
+
const windowsHost = electronHost(fakeElectron(), {
|
|
88
287
|
platform: 'windows',
|
|
89
288
|
});
|
|
90
|
-
const linuxHost =
|
|
289
|
+
const linuxHost = electronHost(fakeElectron(), {
|
|
91
290
|
platform: 'linux',
|
|
92
291
|
});
|
|
93
292
|
expect(Object.keys(windowsHost.shell).sort()).toEqual([
|
|
@@ -99,6 +298,61 @@ describe('registerElectronBackends', () => {
|
|
|
99
298
|
'trash',
|
|
100
299
|
]);
|
|
101
300
|
expect(Object.keys(linuxHost.shell).sort()).toEqual(['beep', 'external', 'pathOpen', 'pathReveal', 'trash']);
|
|
102
|
-
for (const provider of Object.values(windowsHost.shell)) expect(EntityRuntimeKey in provider).toBe(true);
|
|
103
301
|
});
|
|
104
302
|
});
|
|
303
|
+
|
|
304
|
+
// The capability groups every provider host carries (D26: each provider declares its own; there is no
|
|
305
|
+
// aggregate Host to read them from).
|
|
306
|
+
const HOST_GROUP_NAMES = [
|
|
307
|
+
'accessibility',
|
|
308
|
+
'app',
|
|
309
|
+
'audio',
|
|
310
|
+
'audioDecode',
|
|
311
|
+
'bitmap',
|
|
312
|
+
'canvas',
|
|
313
|
+
'clipboard',
|
|
314
|
+
'compress',
|
|
315
|
+
'connectivity',
|
|
316
|
+
'decompress',
|
|
317
|
+
'device',
|
|
318
|
+
'dialog',
|
|
319
|
+
'fileSystem',
|
|
320
|
+
'font',
|
|
321
|
+
'fullscreen',
|
|
322
|
+
'geolocation',
|
|
323
|
+
'gl',
|
|
324
|
+
'glyph',
|
|
325
|
+
'haptics',
|
|
326
|
+
'image',
|
|
327
|
+
'imageDecode',
|
|
328
|
+
'imageEncode',
|
|
329
|
+
'input',
|
|
330
|
+
'ipc',
|
|
331
|
+
'lifecycle',
|
|
332
|
+
'mediaSession',
|
|
333
|
+
'menu',
|
|
334
|
+
'midi',
|
|
335
|
+
'net',
|
|
336
|
+
'notification',
|
|
337
|
+
'permissions',
|
|
338
|
+
'platform',
|
|
339
|
+
'power',
|
|
340
|
+
'preferences',
|
|
341
|
+
'protocol',
|
|
342
|
+
'screen',
|
|
343
|
+
'sensors',
|
|
344
|
+
'share',
|
|
345
|
+
'shell',
|
|
346
|
+
'shortcut',
|
|
347
|
+
'socket',
|
|
348
|
+
'softKeyboard',
|
|
349
|
+
'statusBar',
|
|
350
|
+
'surface',
|
|
351
|
+
'textSegment',
|
|
352
|
+
'textShaper',
|
|
353
|
+
'tray',
|
|
354
|
+
'updater',
|
|
355
|
+
'video',
|
|
356
|
+
'wgpu',
|
|
357
|
+
'window',
|
|
358
|
+
];
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { createScreenInfo } from '@flighthq/screen/contract';
|
|
2
|
+
import type { ScreenInfo } from '@flighthq/screen/contract';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
electronHostScreen,
|
|
6
|
+
electronHostScreenChange,
|
|
7
|
+
electronHostScreenQuery,
|
|
8
|
+
populateElectronHostScreenChange,
|
|
9
|
+
populateElectronHostScreenQuery,
|
|
10
|
+
} from './electronScreen.ts';
|
|
11
|
+
import type { ElectronApi, ElectronDisplay } from './types/index.ts';
|
|
10
12
|
|
|
11
13
|
function display(id: number, x: number): ElectronDisplay {
|
|
12
14
|
return {
|
|
@@ -46,16 +48,16 @@ function fakeElectron(): {
|
|
|
46
48
|
return { electron, listeners };
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
describe('
|
|
50
|
-
it('returns
|
|
51
|
-
const capabilities =
|
|
52
|
-
expect(
|
|
53
|
-
expect(
|
|
51
|
+
describe('electronHostScreen', () => {
|
|
52
|
+
it('returns query and change facets', () => {
|
|
53
|
+
const capabilities = electronHostScreen(fakeElectron().electron);
|
|
54
|
+
expect(capabilities.query).toBeDefined();
|
|
55
|
+
expect(capabilities.change).toBeDefined();
|
|
54
56
|
});
|
|
55
57
|
|
|
56
58
|
it('fills the primary screen into out', () => {
|
|
57
59
|
const { electron } = fakeElectron();
|
|
58
|
-
const backend =
|
|
60
|
+
const backend = electronHostScreen(electron).query;
|
|
59
61
|
const out = {} as ScreenInfo;
|
|
60
62
|
const result = backend.getPrimaryScreen(out);
|
|
61
63
|
expect(result).toBe(out);
|
|
@@ -70,12 +72,12 @@ describe('createElectronScreenCapabilities', () => {
|
|
|
70
72
|
scaleFactor: 2,
|
|
71
73
|
isPrimary: true,
|
|
72
74
|
});
|
|
73
|
-
expect(Object.keys(out).
|
|
75
|
+
expect(Object.keys(out).sort()).toEqual(Object.keys(createScreenInfo()).sort());
|
|
74
76
|
});
|
|
75
77
|
|
|
76
78
|
it('enumerates all screens marking the primary', () => {
|
|
77
79
|
const { electron } = fakeElectron();
|
|
78
|
-
const backend =
|
|
80
|
+
const backend = electronHostScreen(electron).query;
|
|
79
81
|
const out: ScreenInfo[] = [];
|
|
80
82
|
backend.getScreens(out);
|
|
81
83
|
expect(out).toHaveLength(2);
|
|
@@ -88,7 +90,7 @@ describe('createElectronScreenCapabilities', () => {
|
|
|
88
90
|
|
|
89
91
|
it('subscribes to all change events and unsubscribes from all', () => {
|
|
90
92
|
const fake = fakeElectron();
|
|
91
|
-
const backend =
|
|
93
|
+
const backend = electronHostScreen(fake.electron).change;
|
|
92
94
|
let count = 0;
|
|
93
95
|
const off = backend.subscribe(() => {
|
|
94
96
|
count++;
|
|
@@ -103,20 +105,27 @@ describe('createElectronScreenCapabilities', () => {
|
|
|
103
105
|
expect(fake.listeners.get('display-metrics-changed')).toHaveLength(0);
|
|
104
106
|
});
|
|
105
107
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
|
|
109
|
+
describe('electronHostScreenChange', () => {
|
|
110
|
+
it('constructs a screen change provider', () => {
|
|
111
|
+
expect(electronHostScreenChange(fakeElectron().electron)).toBeDefined();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('electronHostScreenQuery', () => {
|
|
116
|
+
it('constructs a screen query provider', () => {
|
|
117
|
+
expect(electronHostScreenQuery(fakeElectron().electron)).toBeDefined();
|
|
109
118
|
});
|
|
110
119
|
});
|
|
111
120
|
|
|
112
|
-
describe('
|
|
113
|
-
it('is the construction initializer of
|
|
114
|
-
expect(typeof
|
|
121
|
+
describe('populateElectronHostScreenChange', () => {
|
|
122
|
+
it('is the construction initializer of electronHostScreenChange', () => {
|
|
123
|
+
expect(typeof populateElectronHostScreenChange).toBe('function');
|
|
115
124
|
});
|
|
116
125
|
});
|
|
117
126
|
|
|
118
|
-
describe('
|
|
119
|
-
it('is the construction initializer of
|
|
120
|
-
expect(typeof
|
|
127
|
+
describe('populateElectronHostScreenQuery', () => {
|
|
128
|
+
it('is the construction initializer of electronHostScreenQuery', () => {
|
|
129
|
+
expect(typeof populateElectronHostScreenQuery).toBe('function');
|
|
121
130
|
});
|
|
122
131
|
});
|
|
@@ -1,58 +1,27 @@
|
|
|
1
|
-
import type { ElectronApi } from '@flighthq/types/contract';
|
|
2
|
-
import { EntityRuntimeKey } from '@flighthq/types/contract';
|
|
3
|
-
|
|
4
1
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
electronHostShell,
|
|
3
|
+
electronHostShellBeep,
|
|
4
|
+
electronHostShellExternal,
|
|
5
|
+
electronHostShellPathOpen,
|
|
6
|
+
electronHostShellPathReveal,
|
|
7
|
+
electronHostShellShortcutLink,
|
|
8
|
+
electronHostShellTrash,
|
|
9
|
+
populateElectronHostShellBeep,
|
|
10
|
+
populateElectronHostShellExternal,
|
|
11
|
+
populateElectronHostShellPathOpen,
|
|
12
|
+
populateElectronHostShellPathReveal,
|
|
13
|
+
populateElectronHostShellShortcutLink,
|
|
14
|
+
populateElectronHostShellTrash,
|
|
15
|
+
} from './electronShell.ts';
|
|
16
|
+
import type { ElectronApi } from './types/index.ts';
|
|
13
17
|
|
|
14
18
|
function fakeElectron(shell: Partial<ElectronApi['shell']>): ElectronApi {
|
|
15
19
|
return { shell } as unknown as ElectronApi;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
describe('
|
|
19
|
-
it('
|
|
20
|
-
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
describe('initializeShellExternalBackend', () => {
|
|
24
|
-
it('is the construction initializer of createShellExternalBackend', () => {
|
|
25
|
-
expect(typeof initializeShellExternalBackend).toBe('function');
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('initializeShellPathOpenBackend', () => {
|
|
30
|
-
it('is the construction initializer of createShellPathOpenBackend', () => {
|
|
31
|
-
expect(typeof initializeShellPathOpenBackend).toBe('function');
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('initializeShellPathRevealBackend', () => {
|
|
36
|
-
it('is the construction initializer of createShellPathRevealBackend', () => {
|
|
37
|
-
expect(typeof initializeShellPathRevealBackend).toBe('function');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('initializeShellShortcutLinkBackend', () => {
|
|
42
|
-
it('is the construction initializer of createShellShortcutLinkBackend', () => {
|
|
43
|
-
expect(typeof initializeShellShortcutLinkBackend).toBe('function');
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('initializeShellTrashBackend', () => {
|
|
48
|
-
it('is the construction initializer of createShellTrashBackend', () => {
|
|
49
|
-
expect(typeof initializeShellTrashBackend).toBe('function');
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('makeElectronShellCapabilities', () => {
|
|
54
|
-
it('constructs every Windows provider as an Entity', () => {
|
|
55
|
-
const capabilities = makeElectronShellCapabilities(fakeElectron({}), 'windows');
|
|
22
|
+
describe('electronHostShell', () => {
|
|
23
|
+
it('constructs every Windows provider', () => {
|
|
24
|
+
const capabilities = electronHostShell(fakeElectron({}), 'windows');
|
|
56
25
|
expect(Object.keys(capabilities).sort()).toEqual([
|
|
57
26
|
'beep',
|
|
58
27
|
'external',
|
|
@@ -61,11 +30,10 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
61
30
|
'shortcutLink',
|
|
62
31
|
'trash',
|
|
63
32
|
]);
|
|
64
|
-
for (const provider of Object.values(capabilities)) expect(EntityRuntimeKey in provider).toBe(true);
|
|
65
33
|
});
|
|
66
34
|
|
|
67
35
|
it('omits shortcutLink on an injected non-Windows platform', () => {
|
|
68
|
-
expect(Object.keys(
|
|
36
|
+
expect(Object.keys(electronHostShell(fakeElectron({}), 'linux')).sort()).toEqual([
|
|
69
37
|
'beep',
|
|
70
38
|
'external',
|
|
71
39
|
'pathOpen',
|
|
@@ -75,9 +43,9 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
75
43
|
});
|
|
76
44
|
|
|
77
45
|
it('maps awaited external completion and rejection', async () => {
|
|
78
|
-
const ok =
|
|
46
|
+
const ok = electronHostShell(fakeElectron({ openExternal: async () => {} }), 'linux');
|
|
79
47
|
await expect(ok.external?.open('https://example.test')).resolves.toEqual({ reason: 'ok' });
|
|
80
|
-
const failed =
|
|
48
|
+
const failed = electronHostShell(
|
|
81
49
|
fakeElectron({
|
|
82
50
|
openExternal: async () => {
|
|
83
51
|
throw new Error('denied');
|
|
@@ -89,9 +57,9 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
89
57
|
});
|
|
90
58
|
|
|
91
59
|
it('preserves an Electron path error string', async () => {
|
|
92
|
-
const success =
|
|
60
|
+
const success = electronHostShell(fakeElectron({ openPath: async () => '' }), 'linux');
|
|
93
61
|
await expect(success.pathOpen?.open('/a')).resolves.toEqual({ reason: 'ok' });
|
|
94
|
-
const failed =
|
|
62
|
+
const failed = electronHostShell(fakeElectron({ openPath: async () => 'no such file' }), 'linux');
|
|
95
63
|
await expect(failed.pathOpen?.open('/a')).resolves.toEqual({
|
|
96
64
|
message: 'no such file',
|
|
97
65
|
reason: 'operation-failed',
|
|
@@ -99,7 +67,7 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
99
67
|
});
|
|
100
68
|
|
|
101
69
|
it('does not turn an empty rejected path open into success', async () => {
|
|
102
|
-
const capabilities =
|
|
70
|
+
const capabilities = electronHostShell(
|
|
103
71
|
fakeElectron({
|
|
104
72
|
openPath: async () => {
|
|
105
73
|
throw new Error('');
|
|
@@ -112,7 +80,7 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
112
80
|
|
|
113
81
|
it('maps path reveal and trash outcomes', async () => {
|
|
114
82
|
let revealed = '';
|
|
115
|
-
const capabilities =
|
|
83
|
+
const capabilities = electronHostShell(
|
|
116
84
|
fakeElectron({
|
|
117
85
|
showItemInFolder(path) {
|
|
118
86
|
revealed = path;
|
|
@@ -127,7 +95,7 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
127
95
|
});
|
|
128
96
|
|
|
129
97
|
it('keeps shortcut read and write outcomes method-tight', async () => {
|
|
130
|
-
const capabilities =
|
|
98
|
+
const capabilities = electronHostShell(
|
|
131
99
|
fakeElectron({
|
|
132
100
|
readShortcutLink: () => ({ target: '/target' }),
|
|
133
101
|
writeShortcutLink: () => false,
|
|
@@ -145,7 +113,79 @@ describe('makeElectronShellCapabilities', () => {
|
|
|
145
113
|
|
|
146
114
|
it('dispatches beep synchronously', () => {
|
|
147
115
|
const beep = vi.fn();
|
|
148
|
-
|
|
116
|
+
electronHostShell(fakeElectron({ beep }), 'linux').beep?.beep();
|
|
149
117
|
expect(beep).toHaveBeenCalledOnce();
|
|
150
118
|
});
|
|
151
119
|
});
|
|
120
|
+
|
|
121
|
+
describe('electronHostShellBeep', () => {
|
|
122
|
+
it('constructs a shell beep provider', () => {
|
|
123
|
+
expect(electronHostShellBeep(fakeElectron({}))).toBeDefined();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('electronHostShellExternal', () => {
|
|
128
|
+
it('constructs a shell external provider', () => {
|
|
129
|
+
expect(electronHostShellExternal(fakeElectron({}))).toBeDefined();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('electronHostShellPathOpen', () => {
|
|
134
|
+
it('constructs a shell path open provider', () => {
|
|
135
|
+
expect(electronHostShellPathOpen(fakeElectron({}))).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('electronHostShellPathReveal', () => {
|
|
140
|
+
it('constructs a shell path reveal provider', () => {
|
|
141
|
+
expect(electronHostShellPathReveal(fakeElectron({}))).toBeDefined();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('electronHostShellShortcutLink', () => {
|
|
146
|
+
it('constructs a shell shortcut link provider', () => {
|
|
147
|
+
expect(electronHostShellShortcutLink(fakeElectron({}))).toBeDefined();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe('electronHostShellTrash', () => {
|
|
152
|
+
it('constructs a shell trash provider', () => {
|
|
153
|
+
expect(electronHostShellTrash(fakeElectron({}))).toBeDefined();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('populateElectronHostShellBeep', () => {
|
|
158
|
+
it('is the construction initializer of electronHostShellBeep', () => {
|
|
159
|
+
expect(typeof populateElectronHostShellBeep).toBe('function');
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('populateElectronHostShellExternal', () => {
|
|
164
|
+
it('is the construction initializer of electronHostShellExternal', () => {
|
|
165
|
+
expect(typeof populateElectronHostShellExternal).toBe('function');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('populateElectronHostShellPathOpen', () => {
|
|
170
|
+
it('is the construction initializer of electronHostShellPathOpen', () => {
|
|
171
|
+
expect(typeof populateElectronHostShellPathOpen).toBe('function');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('populateElectronHostShellPathReveal', () => {
|
|
176
|
+
it('is the construction initializer of electronHostShellPathReveal', () => {
|
|
177
|
+
expect(typeof populateElectronHostShellPathReveal).toBe('function');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('populateElectronHostShellShortcutLink', () => {
|
|
182
|
+
it('is the construction initializer of electronHostShellShortcutLink', () => {
|
|
183
|
+
expect(typeof populateElectronHostShellShortcutLink).toBe('function');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('populateElectronHostShellTrash', () => {
|
|
188
|
+
it('is the construction initializer of electronHostShellTrash', () => {
|
|
189
|
+
expect(typeof populateElectronHostShellTrash).toBe('function');
|
|
190
|
+
});
|
|
191
|
+
});
|