@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.
Files changed (137) hide show
  1. package/README.md +2 -2
  2. package/dist/contract.d.ts +19 -24
  3. package/dist/contract.d.ts.map +1 -1
  4. package/dist/contract.js +18 -24
  5. package/dist/contract.js.map +1 -1
  6. package/dist/electronApp.d.ts +62 -34
  7. package/dist/electronApp.d.ts.map +1 -1
  8. package/dist/electronApp.js +175 -234
  9. package/dist/electronApp.js.map +1 -1
  10. package/dist/electronClipboard.d.ts +7 -5
  11. package/dist/electronClipboard.d.ts.map +1 -1
  12. package/dist/electronClipboard.js +91 -66
  13. package/dist/electronClipboard.js.map +1 -1
  14. package/dist/electronDefaultHostGroups.d.ts +59 -0
  15. package/dist/electronDefaultHostGroups.d.ts.map +1 -0
  16. package/dist/electronDefaultHostGroups.js +109 -0
  17. package/dist/electronDefaultHostGroups.js.map +1 -0
  18. package/dist/electronDialog.d.ts +12 -9
  19. package/dist/electronDialog.d.ts.map +1 -1
  20. package/dist/electronDialog.js +28 -21
  21. package/dist/electronDialog.js.map +1 -1
  22. package/dist/electronIpc.d.ts +13 -11
  23. package/dist/electronIpc.d.ts.map +1 -1
  24. package/dist/electronIpc.js +32 -26
  25. package/dist/electronIpc.js.map +1 -1
  26. package/dist/electronMenu.d.ts +12 -6
  27. package/dist/electronMenu.d.ts.map +1 -1
  28. package/dist/electronMenu.js +41 -30
  29. package/dist/electronMenu.js.map +1 -1
  30. package/dist/electronMenuTemplate.d.ts +2 -1
  31. package/dist/electronMenuTemplate.d.ts.map +1 -1
  32. package/dist/electronMenuTemplate.js.map +1 -1
  33. package/dist/electronNotification.d.ts +25 -7
  34. package/dist/electronNotification.d.ts.map +1 -1
  35. package/dist/electronNotification.js +39 -16
  36. package/dist/electronNotification.js.map +1 -1
  37. package/dist/electronPlatform.d.ts +5 -3
  38. package/dist/electronPlatform.d.ts.map +1 -1
  39. package/dist/electronPlatform.js +9 -7
  40. package/dist/electronPlatform.js.map +1 -1
  41. package/dist/electronPower.d.ts +22 -11
  42. package/dist/electronPower.d.ts.map +1 -1
  43. package/dist/electronPower.js +48 -59
  44. package/dist/electronPower.js.map +1 -1
  45. package/dist/electronProtocol.d.ts +16 -8
  46. package/dist/electronProtocol.d.ts.map +1 -1
  47. package/dist/electronProtocol.js +45 -28
  48. package/dist/electronProtocol.js.map +1 -1
  49. package/dist/electronRegister.d.ts +5 -7
  50. package/dist/electronRegister.d.ts.map +1 -1
  51. package/dist/electronRegister.js +72 -99
  52. package/dist/electronRegister.js.map +1 -1
  53. package/dist/electronScreen.d.ts +7 -6
  54. package/dist/electronScreen.d.ts.map +1 -1
  55. package/dist/electronScreen.js +17 -14
  56. package/dist/electronScreen.js.map +1 -1
  57. package/dist/electronShell.d.ts +16 -8
  58. package/dist/electronShell.d.ts.map +1 -1
  59. package/dist/electronShell.js +50 -43
  60. package/dist/electronShell.js.map +1 -1
  61. package/dist/electronShortcut.d.ts +6 -4
  62. package/dist/electronShortcut.d.ts.map +1 -1
  63. package/dist/electronShortcut.js +16 -10
  64. package/dist/electronShortcut.js.map +1 -1
  65. package/dist/electronStorage.d.ts +5 -3
  66. package/dist/electronStorage.d.ts.map +1 -1
  67. package/dist/electronStorage.js +9 -7
  68. package/dist/electronStorage.js.map +1 -1
  69. package/dist/electronTray.d.ts +38 -21
  70. package/dist/electronTray.d.ts.map +1 -1
  71. package/dist/electronTray.js +110 -76
  72. package/dist/electronTray.js.map +1 -1
  73. package/dist/electronUpdater.d.ts +6 -3
  74. package/dist/electronUpdater.d.ts.map +1 -1
  75. package/dist/electronUpdater.js +10 -7
  76. package/dist/electronUpdater.js.map +1 -1
  77. package/dist/electronWindow.d.ts +23 -7
  78. package/dist/electronWindow.d.ts.map +1 -1
  79. package/dist/electronWindow.js +234 -152
  80. package/dist/electronWindow.js.map +1 -1
  81. package/dist/index.d.ts +19 -1
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +18 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/types/ElectronApi.d.ts +393 -0
  86. package/dist/types/ElectronApi.d.ts.map +1 -0
  87. package/dist/types/ElectronApi.js +20 -0
  88. package/dist/types/ElectronApi.js.map +1 -0
  89. package/dist/types/ElectronAppCapabilitiesFor.d.ts +8 -0
  90. package/dist/types/ElectronAppCapabilitiesFor.d.ts.map +1 -0
  91. package/dist/types/ElectronAppCapabilitiesFor.js +2 -0
  92. package/dist/types/ElectronAppCapabilitiesFor.js.map +1 -0
  93. package/dist/types/ElectronHost.d.ts +43 -0
  94. package/dist/types/ElectronHost.d.ts.map +1 -0
  95. package/dist/types/ElectronHost.js +2 -0
  96. package/dist/types/ElectronHost.js.map +1 -0
  97. package/dist/types/ElectronHostGroups.d.ts +85 -0
  98. package/dist/types/ElectronHostGroups.d.ts.map +1 -0
  99. package/dist/types/ElectronHostGroups.js +2 -0
  100. package/dist/types/ElectronHostGroups.js.map +1 -0
  101. package/dist/types/ElectronHostOptions.d.ts +7 -0
  102. package/dist/types/ElectronHostOptions.d.ts.map +1 -0
  103. package/dist/types/ElectronHostOptions.js +2 -0
  104. package/dist/types/ElectronHostOptions.js.map +1 -0
  105. package/dist/types/ElectronProtocolCapabilities.d.ts +3 -0
  106. package/dist/types/ElectronProtocolCapabilities.d.ts.map +1 -0
  107. package/dist/types/ElectronProtocolCapabilities.js +2 -0
  108. package/dist/types/ElectronProtocolCapabilities.js.map +1 -0
  109. package/dist/types/ElectronTrayCapabilitiesFor.d.ts +7 -0
  110. package/dist/types/ElectronTrayCapabilitiesFor.d.ts.map +1 -0
  111. package/dist/types/ElectronTrayCapabilitiesFor.js +2 -0
  112. package/dist/types/ElectronTrayCapabilitiesFor.js.map +1 -0
  113. package/dist/types/index.d.ts +7 -0
  114. package/dist/types/index.d.ts.map +1 -0
  115. package/dist/types/index.js +7 -0
  116. package/dist/types/index.js.map +1 -0
  117. package/package.json +42 -21
  118. package/src/electronApp.test.ts +158 -131
  119. package/src/electronClipboard.test.ts +40 -13
  120. package/src/electronDefaultHostGroups.test.ts +148 -0
  121. package/src/electronDialog.test.ts +55 -53
  122. package/src/electronHostTreeShaking.test.ts +51 -0
  123. package/src/electronIpc.test.ts +47 -66
  124. package/src/electronMenu.test.ts +61 -47
  125. package/src/electronMenuTemplate.test.ts +1 -1
  126. package/src/electronNotification.test.ts +71 -21
  127. package/src/electronPlatform.test.ts +17 -12
  128. package/src/electronPower.test.ts +112 -88
  129. package/src/electronProtocol.test.ts +68 -35
  130. package/src/electronRegister.test.ts +280 -26
  131. package/src/electronScreen.test.ts +34 -25
  132. package/src/electronShell.test.ts +99 -59
  133. package/src/electronShortcut.test.ts +22 -19
  134. package/src/electronStorage.test.ts +26 -24
  135. package/src/electronTray.test.ts +225 -109
  136. package/src/electronUpdater.test.ts +26 -19
  137. package/src/electronWindow.test.ts +229 -101
@@ -7,34 +7,49 @@ import {
7
7
  setTrayIconContextMenu,
8
8
  setTrayIconTemplate,
9
9
  } from '@flighthq/tray/contract';
10
+ import type { TrayIcon } from '@flighthq/tray/contract';
11
+ import { describe, expect, it, vi } from 'vitest';
12
+
13
+ import {
14
+ electronHostTray,
15
+ electronHostTrayBalloon,
16
+ electronHostTrayBalloonEvents,
17
+ electronHostTrayBounds,
18
+ electronHostTrayDoubleClickPolicy,
19
+ electronHostTrayDropEvents,
20
+ electronHostTrayImage,
21
+ electronHostTrayInteractionEvents,
22
+ electronHostTrayLifecycle,
23
+ electronHostTrayMenu,
24
+ electronHostTrayMenuSelectionEvents,
25
+ electronHostTrayPopupMenu,
26
+ electronHostTrayPressedImage,
27
+ electronHostTrayTemplateImage,
28
+ electronHostTrayTitle,
29
+ electronHostTrayTooltip,
30
+ populateElectronHostTrayBalloon,
31
+ populateElectronHostTrayBalloonEvents,
32
+ populateElectronHostTrayBounds,
33
+ populateElectronHostTrayDoubleClickPolicy,
34
+ populateElectronHostTrayDropEvents,
35
+ populateElectronHostTrayImage,
36
+ populateElectronHostTrayInteractionEvents,
37
+ populateElectronHostTrayLifecycle,
38
+ populateElectronHostTrayMenu,
39
+ populateElectronHostTrayMenuSelectionEvents,
40
+ populateElectronHostTrayPopupMenu,
41
+ populateElectronHostTrayPressedImage,
42
+ populateElectronHostTrayTemplateImage,
43
+ populateElectronHostTrayTitle,
44
+ populateElectronHostTrayTooltip,
45
+ } from './electronTray.ts';
10
46
  import type {
11
47
  ElectronApi,
12
48
  ElectronMenu,
13
49
  ElectronMenuItemOptions,
14
50
  ElectronNativeImage,
15
51
  ElectronTray,
16
- TrayIconForHost,
17
- } from '@flighthq/types/contract';
18
- import { describe, expect, it, vi } from 'vitest';
19
-
20
- import {
21
- createElectronTrayCapabilities,
22
- initializeTrayBalloonBackend,
23
- initializeTrayBalloonEventsBackend,
24
- initializeTrayBoundsBackend,
25
- initializeTrayDoubleClickPolicyBackend,
26
- initializeTrayDropEventsBackend,
27
- initializeTrayImageBackend,
28
- initializeTrayInteractionEventsBackend,
29
- initializeTrayLifecycleBackend,
30
- initializeTrayMenuBackend,
31
- initializeTrayMenuSelectionEventsBackend,
32
- initializeTrayPopupMenuBackend,
33
- initializeTrayPressedImageBackend,
34
- initializeTrayTemplateImageBackend,
35
- initializeTrayTitleBackend,
36
- initializeTrayTooltipBackend,
37
- } from './electronTray';
52
+ } from './types/index.ts';
38
53
 
39
54
  interface FakeImage extends ElectronNativeImage {
40
55
  source: string;
@@ -71,7 +86,7 @@ function fakeElectron() {
71
86
  templates.push(template);
72
87
  return { popup() {} };
73
88
  },
74
- setApplicationMenu() {},
89
+ setAppMenu() {},
75
90
  },
76
91
  Tray: function (this: FakeTray, image: ElectronNativeImage) {
77
92
  this.destroyed = false;
@@ -118,19 +133,19 @@ function fakeElectron() {
118
133
  return { electron, templates, trays };
119
134
  }
120
135
 
121
- async function acquire<
122
- Host extends { tray: { lifecycle: NonNullable<ReturnType<typeof createElectronTrayCapabilities>['lifecycle']> } },
123
- >(host: Host): Promise<TrayIconForHost<Host>> {
124
- const result = await createTrayIcon(host, { icon: 'icon.png' });
136
+ async function acquire(
137
+ hostTrayLifecycle: NonNullable<ReturnType<typeof electronHostTray>['lifecycle']>,
138
+ ): Promise<TrayIcon> {
139
+ const result = await createTrayIcon(hostTrayLifecycle, { icon: 'icon.png' });
125
140
  if (result.outcome !== 'created') throw new Error(result.outcome);
126
141
  return result.tray;
127
142
  }
128
143
 
129
- describe('createElectronTrayCapabilities', () => {
130
- it('exposes only the slots supported by the injected OS profile', () => {
144
+ describe('electronHostTray', () => {
145
+ it('exposes the slots supported by the injected OS profile and none exclusive to another', () => {
131
146
  const { electron } = fakeElectron();
132
- expect(Object.keys(createElectronTrayCapabilities(electron, 'linux')).sort()).toEqual(
133
- [
147
+ const supported = {
148
+ linux: [
134
149
  'bounds',
135
150
  'image',
136
151
  'interactionEvents',
@@ -139,10 +154,8 @@ describe('createElectronTrayCapabilities', () => {
139
154
  'menuSelectionEvents',
140
155
  'popupMenu',
141
156
  'tooltip',
142
- ].sort(),
143
- );
144
- expect(Object.keys(createElectronTrayCapabilities(electron, 'macos')).sort()).toEqual(
145
- [
157
+ ],
158
+ macos: [
146
159
  'bounds',
147
160
  'doubleClickPolicy',
148
161
  'dropEvents',
@@ -156,10 +169,8 @@ describe('createElectronTrayCapabilities', () => {
156
169
  'templateImage',
157
170
  'title',
158
171
  'tooltip',
159
- ].sort(),
160
- );
161
- expect(Object.keys(createElectronTrayCapabilities(electron, 'windows')).sort()).toEqual(
162
- [
172
+ ],
173
+ windows: [
163
174
  'balloon',
164
175
  'balloonEvents',
165
176
  'bounds',
@@ -170,14 +181,26 @@ describe('createElectronTrayCapabilities', () => {
170
181
  'menuSelectionEvents',
171
182
  'popupMenu',
172
183
  'tooltip',
173
- ].sort(),
174
- );
184
+ ],
185
+ } as const;
186
+ for (const profile of ['linux', 'macos', 'windows'] as const) {
187
+ const slots = Object.keys(electronHostTray(electron, profile));
188
+ const exclusiveElsewhere: readonly string[] = Object.entries(supported)
189
+ .filter(([other]) => other !== profile)
190
+ .flatMap(([, others]) => others)
191
+ .filter((slot) => !(supported[profile] as readonly string[]).includes(slot));
192
+ expect(slots, profile).toEqual(expect.arrayContaining([...supported[profile]]));
193
+ expect(
194
+ slots.filter((slot) => exclusiveElsewhere.includes(slot)),
195
+ profile,
196
+ ).toEqual([]);
197
+ }
175
198
  });
176
199
 
177
- it('constructs the native resource before publishing the Entity', async () => {
200
+ it('constructs the native resource before publishing', async () => {
178
201
  const { electron, trays } = fakeElectron();
179
- const host = { tray: createElectronTrayCapabilities(electron, 'macos') };
180
- const result = await createTrayIcon(host, {
202
+ const host = { tray: electronHostTray(electron, 'macos') };
203
+ const result = await createTrayIcon(host.tray.lifecycle, {
181
204
  icon: 'icon.png',
182
205
  iconTemplate: true,
183
206
  title: 'Flight',
@@ -191,12 +214,12 @@ describe('createElectronTrayCapabilities', () => {
191
214
 
192
215
  it('keeps one native listener while delivering full pointer payload to multiple subscribers', async () => {
193
216
  const { electron, trays } = fakeElectron();
194
- const host = { tray: createElectronTrayCapabilities(electron, 'linux') };
195
- const tray = await acquire(host);
217
+ const host = { tray: electronHostTray(electron, 'linux') };
218
+ const tray = await acquire(host.tray.lifecycle);
196
219
  const first = vi.fn();
197
220
  const second = vi.fn();
198
- onTrayInteraction(tray, first);
199
- onTrayInteraction(tray, second);
221
+ onTrayInteraction(host.tray.interactionEvents, tray, first);
222
+ onTrayInteraction(host.tray.interactionEvents, tray, second);
200
223
  expect(trays[0].handlers.click).toHaveLength(1);
201
224
  trays[0].handlers.click[0]!({ altKey: true, ctrlKey: true, metaKey: true, shiftKey: true }, { x: 7, y: 9 });
202
225
  expect(first).toHaveBeenCalledWith(
@@ -207,14 +230,14 @@ describe('createElectronTrayCapabilities', () => {
207
230
 
208
231
  it('routes a menu selection only through that Tray signal', async () => {
209
232
  const { electron, templates } = fakeElectron();
210
- const host = { tray: createElectronTrayCapabilities(electron, 'linux') };
211
- const first = await acquire(host);
212
- const second = await acquire(host);
233
+ const host = { tray: electronHostTray(electron, 'linux') };
234
+ const first = await acquire(host.tray.lifecycle);
235
+ const second = await acquire(host.tray.lifecycle);
213
236
  const firstIds: string[] = [];
214
237
  const secondIds: string[] = [];
215
- onTrayMenuSelection(first, ({ id }) => firstIds.push(id));
216
- onTrayMenuSelection(second, ({ id }) => secondIds.push(id));
217
- await setTrayIconContextMenu(first, [{ id: 'open', label: 'Open' }]);
238
+ onTrayMenuSelection(host.tray.menuSelectionEvents, first, ({ id }) => firstIds.push(id));
239
+ onTrayMenuSelection(host.tray.menuSelectionEvents, second, ({ id }) => secondIds.push(id));
240
+ await setTrayIconContextMenu(host.tray.menu, first, [{ id: 'open', label: 'Open' }]);
218
241
  templates[0][0].click?.();
219
242
  expect(firstIds).toEqual(['open']);
220
243
  expect(secondIds).toEqual([]);
@@ -222,16 +245,16 @@ describe('createElectronTrayCapabilities', () => {
222
245
 
223
246
  it('realizes later template changes through the current native image', async () => {
224
247
  const { electron, trays } = fakeElectron();
225
- const host = { tray: createElectronTrayCapabilities(electron, 'macos') };
226
- const tray = await acquire(host);
227
- expect((await setTrayIconTemplate(tray, true)).outcome).toBe('updated');
248
+ const host = { tray: electronHostTray(electron, 'macos') };
249
+ const tray = await acquire(host.tray.lifecycle);
250
+ expect((await setTrayIconTemplate(host.tray.templateImage, tray, true)).outcome).toBe('updated');
228
251
  expect((trays[0].image as FakeImage).template).toBe(true);
229
252
  });
230
253
 
231
254
  it('returns invalid-icon without publishing a ghost record', async () => {
232
255
  const { electron, trays } = fakeElectron();
233
- const host = { tray: createElectronTrayCapabilities(electron, 'linux') };
234
- const result = await createTrayIcon(host, { icon: 'invalid' });
256
+ const host = { tray: electronHostTray(electron, 'linux') };
257
+ const result = await createTrayIcon(host.tray.lifecycle, { icon: 'invalid' });
235
258
  expect(result.outcome).toBe('invalid-icon');
236
259
  expect(trays).toHaveLength(0);
237
260
  expect(host.tray.lifecycle.list()).toEqual([]);
@@ -239,8 +262,8 @@ describe('createElectronTrayCapabilities', () => {
239
262
 
240
263
  it('attempts listener and native teardown, then retries only failed steps', async () => {
241
264
  const { electron, trays } = fakeElectron();
242
- const host = { tray: createElectronTrayCapabilities(electron, 'linux') };
243
- const tray = await acquire(host);
265
+ const host = { tray: electronHostTray(electron, 'linux') };
266
+ const tray = await acquire(host.tray.lifecycle);
244
267
  trays[0].removeFailures = 1;
245
268
  trays[0].destroyFailures = 1;
246
269
  expect((await destroyTrayIcon(tray)).outcome).toBe('tray-destroy-failed');
@@ -250,97 +273,190 @@ describe('createElectronTrayCapabilities', () => {
250
273
 
251
274
  it('owns balloon commands only on the Windows shape', async () => {
252
275
  const { electron } = fakeElectron();
253
- const host = { tray: createElectronTrayCapabilities(electron, 'windows') };
254
- const tray = await acquire(host);
255
- expect((await displayTrayBalloon(tray, { text: 'Done', title: 'Flight' })).outcome).toBe('displayed');
276
+ const host = { tray: electronHostTray(electron, 'windows') };
277
+ const tray = await acquire(host.tray.lifecycle);
278
+ expect((await displayTrayBalloon(host.tray.balloon, tray, { text: 'Done', title: 'Flight' })).outcome).toBe(
279
+ 'displayed',
280
+ );
281
+ });
282
+ });
283
+
284
+ describe('electronHostTrayBalloon', () => {
285
+ it('constructs a tray balloon provider', () => {
286
+ expect(electronHostTrayBalloon(fakeElectron().electron)).toBeDefined();
287
+ });
288
+ });
289
+
290
+ describe('electronHostTrayBalloonEvents', () => {
291
+ it('constructs a tray balloon events provider', () => {
292
+ expect(electronHostTrayBalloonEvents(fakeElectron().electron)).toBeDefined();
293
+ });
294
+ });
295
+
296
+ describe('electronHostTrayBounds', () => {
297
+ it('constructs a tray bounds provider', () => {
298
+ expect(electronHostTrayBounds(fakeElectron().electron, 'linux')).toBeDefined();
299
+ });
300
+ });
301
+
302
+ describe('electronHostTrayDoubleClickPolicy', () => {
303
+ it('constructs a tray double click policy provider', () => {
304
+ expect(electronHostTrayDoubleClickPolicy(fakeElectron().electron)).toBeDefined();
305
+ });
306
+ });
307
+
308
+ describe('electronHostTrayDropEvents', () => {
309
+ it('constructs a tray drop events provider', () => {
310
+ expect(electronHostTrayDropEvents(fakeElectron().electron)).toBeDefined();
311
+ });
312
+ });
313
+
314
+ describe('electronHostTrayImage', () => {
315
+ it('constructs a tray image provider', () => {
316
+ expect(electronHostTrayImage(fakeElectron().electron, 'linux')).toBeDefined();
256
317
  });
257
318
  });
258
- describe('initializeTrayBalloonBackend', () => {
259
- it('is the construction initializer of createTrayBalloonBackend', () => {
260
- expect(typeof initializeTrayBalloonBackend).toBe('function');
319
+
320
+ describe('electronHostTrayInteractionEvents', () => {
321
+ it('constructs a tray interaction events provider', () => {
322
+ expect(electronHostTrayInteractionEvents(fakeElectron().electron, 'linux')).toBeDefined();
323
+ });
324
+ });
325
+
326
+ describe('electronHostTrayLifecycle', () => {
327
+ it('constructs a tray lifecycle provider', () => {
328
+ expect(electronHostTrayLifecycle(fakeElectron().electron, 'linux')).toBeDefined();
329
+ });
330
+ });
331
+
332
+ describe('electronHostTrayMenu', () => {
333
+ it('constructs a tray menu provider', () => {
334
+ expect(electronHostTrayMenu(fakeElectron().electron, 'linux')).toBeDefined();
335
+ });
336
+ });
337
+
338
+ describe('electronHostTrayMenuSelectionEvents', () => {
339
+ it('constructs a tray menu selection events provider', () => {
340
+ expect(electronHostTrayMenuSelectionEvents(fakeElectron().electron, 'linux')).toBeDefined();
341
+ });
342
+ });
343
+
344
+ describe('electronHostTrayPopupMenu', () => {
345
+ it('constructs a tray popup menu provider', () => {
346
+ expect(electronHostTrayPopupMenu(fakeElectron().electron, 'linux')).toBeDefined();
347
+ });
348
+ });
349
+
350
+ describe('electronHostTrayPressedImage', () => {
351
+ it('constructs a tray pressed image provider', () => {
352
+ expect(electronHostTrayPressedImage(fakeElectron().electron)).toBeDefined();
353
+ });
354
+ });
355
+
356
+ describe('electronHostTrayTemplateImage', () => {
357
+ it('constructs a tray template image provider', () => {
358
+ expect(electronHostTrayTemplateImage(fakeElectron().electron)).toBeDefined();
359
+ });
360
+ });
361
+
362
+ describe('electronHostTrayTitle', () => {
363
+ it('constructs a tray title provider', () => {
364
+ expect(electronHostTrayTitle(fakeElectron().electron)).toBeDefined();
365
+ });
366
+ });
367
+
368
+ describe('electronHostTrayTooltip', () => {
369
+ it('constructs a tray tooltip provider', () => {
370
+ expect(electronHostTrayTooltip(fakeElectron().electron, 'linux')).toBeDefined();
371
+ });
372
+ });
373
+
374
+ describe('populateElectronHostTrayBalloon', () => {
375
+ it('is the construction initializer of electronHostTrayBalloon', () => {
376
+ expect(typeof populateElectronHostTrayBalloon).toBe('function');
261
377
  });
262
378
  });
263
379
 
264
- describe('initializeTrayBalloonEventsBackend', () => {
265
- it('is the construction initializer of createTrayBalloonEventsBackend', () => {
266
- expect(typeof initializeTrayBalloonEventsBackend).toBe('function');
380
+ describe('populateElectronHostTrayBalloonEvents', () => {
381
+ it('is the construction initializer of electronHostTrayBalloonEvents', () => {
382
+ expect(typeof populateElectronHostTrayBalloonEvents).toBe('function');
267
383
  });
268
384
  });
269
385
 
270
- describe('initializeTrayBoundsBackend', () => {
271
- it('is the construction initializer of createTrayBoundsBackend', () => {
272
- expect(typeof initializeTrayBoundsBackend).toBe('function');
386
+ describe('populateElectronHostTrayBounds', () => {
387
+ it('is the construction initializer of electronHostTrayBounds', () => {
388
+ expect(typeof populateElectronHostTrayBounds).toBe('function');
273
389
  });
274
390
  });
275
391
 
276
- describe('initializeTrayDoubleClickPolicyBackend', () => {
277
- it('is the construction initializer of createTrayDoubleClickPolicyBackend', () => {
278
- expect(typeof initializeTrayDoubleClickPolicyBackend).toBe('function');
392
+ describe('populateElectronHostTrayDoubleClickPolicy', () => {
393
+ it('is the construction initializer of electronHostTrayDoubleClickPolicy', () => {
394
+ expect(typeof populateElectronHostTrayDoubleClickPolicy).toBe('function');
279
395
  });
280
396
  });
281
397
 
282
- describe('initializeTrayDropEventsBackend', () => {
283
- it('is the construction initializer of createTrayDropEventsBackend', () => {
284
- expect(typeof initializeTrayDropEventsBackend).toBe('function');
398
+ describe('populateElectronHostTrayDropEvents', () => {
399
+ it('is the construction initializer of electronHostTrayDropEvents', () => {
400
+ expect(typeof populateElectronHostTrayDropEvents).toBe('function');
285
401
  });
286
402
  });
287
403
 
288
- describe('initializeTrayImageBackend', () => {
289
- it('is the construction initializer of createTrayImageBackend', () => {
290
- expect(typeof initializeTrayImageBackend).toBe('function');
404
+ describe('populateElectronHostTrayImage', () => {
405
+ it('is the construction initializer of electronHostTrayImage', () => {
406
+ expect(typeof populateElectronHostTrayImage).toBe('function');
291
407
  });
292
408
  });
293
409
 
294
- describe('initializeTrayInteractionEventsBackend', () => {
295
- it('is the construction initializer of createTrayInteractionEventsBackend', () => {
296
- expect(typeof initializeTrayInteractionEventsBackend).toBe('function');
410
+ describe('populateElectronHostTrayInteractionEvents', () => {
411
+ it('is the construction initializer of electronHostTrayInteractionEvents', () => {
412
+ expect(typeof populateElectronHostTrayInteractionEvents).toBe('function');
297
413
  });
298
414
  });
299
415
 
300
- describe('initializeTrayLifecycleBackend', () => {
301
- it('is the construction initializer of createTrayLifecycleBackend', () => {
302
- expect(typeof initializeTrayLifecycleBackend).toBe('function');
416
+ describe('populateElectronHostTrayLifecycle', () => {
417
+ it('is the construction initializer of electronHostTrayLifecycle', () => {
418
+ expect(typeof populateElectronHostTrayLifecycle).toBe('function');
303
419
  });
304
420
  });
305
421
 
306
- describe('initializeTrayMenuBackend', () => {
307
- it('is the construction initializer of createTrayMenuBackend', () => {
308
- expect(typeof initializeTrayMenuBackend).toBe('function');
422
+ describe('populateElectronHostTrayMenu', () => {
423
+ it('is the construction initializer of electronHostTrayMenu', () => {
424
+ expect(typeof populateElectronHostTrayMenu).toBe('function');
309
425
  });
310
426
  });
311
427
 
312
- describe('initializeTrayMenuSelectionEventsBackend', () => {
313
- it('is the construction initializer of createTrayMenuSelectionEventsBackend', () => {
314
- expect(typeof initializeTrayMenuSelectionEventsBackend).toBe('function');
428
+ describe('populateElectronHostTrayMenuSelectionEvents', () => {
429
+ it('is the construction initializer of electronHostTrayMenuSelectionEvents', () => {
430
+ expect(typeof populateElectronHostTrayMenuSelectionEvents).toBe('function');
315
431
  });
316
432
  });
317
433
 
318
- describe('initializeTrayPopupMenuBackend', () => {
319
- it('is the construction initializer of createTrayPopupMenuBackend', () => {
320
- expect(typeof initializeTrayPopupMenuBackend).toBe('function');
434
+ describe('populateElectronHostTrayPopupMenu', () => {
435
+ it('is the construction initializer of electronHostTrayPopupMenu', () => {
436
+ expect(typeof populateElectronHostTrayPopupMenu).toBe('function');
321
437
  });
322
438
  });
323
439
 
324
- describe('initializeTrayPressedImageBackend', () => {
325
- it('is the construction initializer of createTrayPressedImageBackend', () => {
326
- expect(typeof initializeTrayPressedImageBackend).toBe('function');
440
+ describe('populateElectronHostTrayPressedImage', () => {
441
+ it('is the construction initializer of electronHostTrayPressedImage', () => {
442
+ expect(typeof populateElectronHostTrayPressedImage).toBe('function');
327
443
  });
328
444
  });
329
445
 
330
- describe('initializeTrayTemplateImageBackend', () => {
331
- it('is the construction initializer of createTrayTemplateImageBackend', () => {
332
- expect(typeof initializeTrayTemplateImageBackend).toBe('function');
446
+ describe('populateElectronHostTrayTemplateImage', () => {
447
+ it('is the construction initializer of electronHostTrayTemplateImage', () => {
448
+ expect(typeof populateElectronHostTrayTemplateImage).toBe('function');
333
449
  });
334
450
  });
335
451
 
336
- describe('initializeTrayTitleBackend', () => {
337
- it('is the construction initializer of createTrayTitleBackend', () => {
338
- expect(typeof initializeTrayTitleBackend).toBe('function');
452
+ describe('populateElectronHostTrayTitle', () => {
453
+ it('is the construction initializer of electronHostTrayTitle', () => {
454
+ expect(typeof populateElectronHostTrayTitle).toBe('function');
339
455
  });
340
456
  });
341
457
 
342
- describe('initializeTrayTooltipBackend', () => {
343
- it('is the construction initializer of createTrayTooltipBackend', () => {
344
- expect(typeof initializeTrayTooltipBackend).toBe('function');
458
+ describe('populateElectronHostTrayTooltip', () => {
459
+ it('is the construction initializer of electronHostTrayTooltip', () => {
460
+ expect(typeof populateElectronHostTrayTooltip).toBe('function');
345
461
  });
346
462
  });
@@ -1,7 +1,9 @@
1
- import type { ElectronApi } from '@flighthq/types/contract';
2
- import { EntityRuntimeKey } from '@flighthq/types/contract';
3
-
4
- import { createElectronUpdaterBackend, initializeElectronUpdaterBackend } from './electronUpdater';
1
+ import {
2
+ electronHostUpdater,
3
+ electronHostUpdaterCommand,
4
+ populateElectronHostUpdaterCommand,
5
+ } from './electronUpdater.ts';
6
+ import type { ElectronApi } from './types/index.ts';
5
7
 
6
8
  type NativeListener = (...args: unknown[]) => void;
7
9
 
@@ -58,12 +60,18 @@ function emit(listeners: Map<string, Set<NativeListener>>, event: string, ...arg
58
60
  for (const listener of [...(listeners.get(event) ?? [])]) listener(...args);
59
61
  }
60
62
 
61
- describe('createElectronUpdaterBackend', () => {
63
+ describe('electronHostUpdater', () => {
64
+ it('constructs the Entity-backed updater command slot', () => {
65
+ const updater = electronHostUpdater(fakeElectron().electron);
66
+ expect(Object.keys(updater)).toEqual(['command']);
67
+ });
68
+ });
69
+
70
+ describe('electronHostUpdaterCommand', () => {
62
71
  it('returns an Entity and applies its immutable feed policy at construction', () => {
63
72
  const { electron, calls } = fakeElectron();
64
- const backend = createElectronUpdaterBackend(electron, 'https://updates.test/feed');
73
+ const backend = electronHostUpdaterCommand(electron, 'https://updates.test/feed');
65
74
 
66
- expect(EntityRuntimeKey in backend).toBe(true);
67
75
  expect(calls.feedUrls).toEqual(['https://updates.test/feed']);
68
76
 
69
77
  backend.destroy();
@@ -72,7 +80,7 @@ describe('createElectronUpdaterBackend', () => {
72
80
 
73
81
  it('runs one awaited Squirrel check through the private native event transaction', async () => {
74
82
  const { electron, listeners, calls } = fakeElectron();
75
- const backend = createElectronUpdaterBackend(electron);
83
+ const backend = electronHostUpdaterCommand(electron);
76
84
 
77
85
  const pending = backend.check();
78
86
  expect(calls.checks).toBe(1);
@@ -83,7 +91,6 @@ describe('createElectronUpdaterBackend', () => {
83
91
  const outcome = await pending;
84
92
  expect(outcome.reason).toBe('downloaded');
85
93
  if (outcome.reason !== 'downloaded') throw new Error('expected downloaded update');
86
- expect(EntityRuntimeKey in outcome.update).toBe(true);
87
94
  expect(outcome.update.info).toEqual({
88
95
  downloadSizeBytes: null,
89
96
  isMandatory: null,
@@ -100,7 +107,7 @@ describe('createElectronUpdaterBackend', () => {
100
107
 
101
108
  it('copies and freezes downloaded metadata and uses null for every unknown field', async () => {
102
109
  const { electron, listeners } = fakeElectron();
103
- const backend = createElectronUpdaterBackend(electron);
110
+ const backend = electronHostUpdaterCommand(electron);
104
111
  const nativeArgs: unknown[] = [{}, '', undefined, ''];
105
112
 
106
113
  const pending = backend.check();
@@ -125,19 +132,19 @@ describe('createElectronUpdaterBackend', () => {
125
132
 
126
133
  it('settles not-available and native error with method-tight portable outcomes', async () => {
127
134
  const first = fakeElectron();
128
- const notAvailable = createElectronUpdaterBackend(first.electron).check();
135
+ const notAvailable = electronHostUpdaterCommand(first.electron).check();
129
136
  emit(first.listeners, 'update-not-available');
130
137
  await expect(notAvailable).resolves.toEqual({ reason: 'not-available' });
131
138
 
132
139
  const second = fakeElectron();
133
- const failed = createElectronUpdaterBackend(second.electron).check();
140
+ const failed = electronHostUpdaterCommand(second.electron).check();
134
141
  emit(second.listeners, 'error', new Error('native detail'));
135
142
  await expect(failed).resolves.toEqual({ reason: 'operation-failed' });
136
143
  });
137
144
 
138
145
  it('classifies a concurrent check without dispatching a second native operation', async () => {
139
146
  const { electron, listeners, calls } = fakeElectron();
140
- const backend = createElectronUpdaterBackend(electron);
147
+ const backend = electronHostUpdaterCommand(electron);
141
148
 
142
149
  const first = backend.check();
143
150
  await expect(backend.check()).resolves.toEqual({ reason: 'check-in-progress' });
@@ -148,7 +155,7 @@ describe('createElectronUpdaterBackend', () => {
148
155
 
149
156
  it('rolls back every listener acquired before a partial attach failure', async () => {
150
157
  const { electron, listeners, calls } = fakeElectron({ failAttachFor: 'update-not-available' });
151
- const backend = createElectronUpdaterBackend(electron);
158
+ const backend = electronHostUpdaterCommand(electron);
152
159
 
153
160
  await expect(backend.check()).resolves.toEqual({ reason: 'operation-failed' });
154
161
  expect(calls.checks).toBe(0);
@@ -160,7 +167,7 @@ describe('createElectronUpdaterBackend', () => {
160
167
  const { electron, listeners, calls } = fakeElectron({
161
168
  removeFailures: { 'update-available': 1 },
162
169
  });
163
- const backend = createElectronUpdaterBackend(electron);
170
+ const backend = electronHostUpdaterCommand(electron);
164
171
 
165
172
  const pending = backend.check();
166
173
  emit(listeners, 'update-not-available');
@@ -186,7 +193,7 @@ describe('createElectronUpdaterBackend', () => {
186
193
 
187
194
  it('settles an in-flight transaction and deduplicates repeated provider destroy aliases', async () => {
188
195
  const { electron, calls } = fakeElectron();
189
- const backend = createElectronUpdaterBackend(electron);
196
+ const backend = electronHostUpdaterCommand(electron);
190
197
  const pending = backend.check();
191
198
 
192
199
  backend.destroy();
@@ -203,8 +210,8 @@ describe('createElectronUpdaterBackend', () => {
203
210
  expect(calls.feedUrls).toEqual([]);
204
211
  });
205
212
  });
206
- describe('initializeElectronUpdaterBackend', () => {
207
- it('is the construction initializer of createElectronUpdaterBackend', () => {
208
- expect(typeof initializeElectronUpdaterBackend).toBe('function');
213
+ describe('populateElectronHostUpdaterCommand', () => {
214
+ it('is the construction initializer of electronHostUpdaterCommand', () => {
215
+ expect(typeof populateElectronHostUpdaterCommand).toBe('function');
209
216
  });
210
217
  });