@flighthq/app 0.1.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/dist/app.d.ts +44 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +411 -0
- package/dist/app.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/src/app.test.ts +757 -0
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { App, AppActivationPolicy, AppBackend, AppLoginItem, AppLoginItemLike, AppPathKind, MenuItemTemplate } from '@flighthq/types';
|
|
2
|
+
export declare function addAppRecentDocument(path: string): void;
|
|
3
|
+
export declare function attachApp(app: App): void;
|
|
4
|
+
export declare function bounceAppDock(): number;
|
|
5
|
+
export declare function cancelAppAttention(id: number): void;
|
|
6
|
+
export declare function cancelAppDockBounce(id: number): void;
|
|
7
|
+
export declare function clearAppRecentDocuments(): void;
|
|
8
|
+
export declare function createApp(): App;
|
|
9
|
+
export declare function createAppLoginItem(): AppLoginItem;
|
|
10
|
+
export declare function createWebAppBackend(): AppBackend;
|
|
11
|
+
export declare function detachApp(app: App): void;
|
|
12
|
+
export declare function disposeApp(app: App): void;
|
|
13
|
+
export declare function focusApp(): void;
|
|
14
|
+
export declare function getAppBackend(): AppBackend;
|
|
15
|
+
export declare function getAppCommandLine(): readonly string[];
|
|
16
|
+
export declare function getAppCommandLineSwitch(name: string): string | null;
|
|
17
|
+
export declare function getAppDirectoryPath(kind: AppPathKind): string;
|
|
18
|
+
export declare function getAppExecutablePath(): string;
|
|
19
|
+
export declare function getAppLocale(): string;
|
|
20
|
+
export declare function getAppLoginItem(): AppLoginItem;
|
|
21
|
+
export declare function getAppName(): string;
|
|
22
|
+
export declare function getAppPath(): string;
|
|
23
|
+
export declare function getAppPreferredSystemLanguages(): readonly string[];
|
|
24
|
+
export declare function getAppSystemLocale(): string;
|
|
25
|
+
export declare function getAppVersion(): string;
|
|
26
|
+
export declare function hasAppCommandLineSwitch(name: string): boolean;
|
|
27
|
+
export declare function hasAppSingleInstanceLock(): boolean;
|
|
28
|
+
export declare function hideApp(): boolean;
|
|
29
|
+
export declare function isAppHidden(): boolean;
|
|
30
|
+
export declare function quitApp(): void;
|
|
31
|
+
export declare function relaunchApp(): void;
|
|
32
|
+
export declare function releaseAppSingleInstanceLock(): void;
|
|
33
|
+
export declare function requestAppAttention(critical: boolean): number;
|
|
34
|
+
export declare function requestAppSingleInstanceLock(): boolean;
|
|
35
|
+
export declare function setAppActivationPolicy(policy: AppActivationPolicy): void;
|
|
36
|
+
export declare function setAppBackend(backend: AppBackend | null): void;
|
|
37
|
+
export declare function setAppBadgeCount(count: number): boolean;
|
|
38
|
+
export declare function setAppDockBadge(text: string): void;
|
|
39
|
+
export declare function setAppDockMenu(items: readonly MenuItemTemplate[]): void;
|
|
40
|
+
export declare function setAppLoginItem(settings: Readonly<AppLoginItemLike>): boolean;
|
|
41
|
+
export declare function setAppName(name: string): boolean;
|
|
42
|
+
export declare function setAppUserModelId(id: string): boolean;
|
|
43
|
+
export declare function showApp(): boolean;
|
|
44
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,GAAG,EACH,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAIzB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAOD,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA0BxC;AAGD,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEnD;AAGD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEpD;AAGD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAGD,wBAAgB,SAAS,IAAI,GAAG,CAS/B;AAGD,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAID,wBAAgB,mBAAmB,IAAI,UAAU,CA4KhD;AAGD,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAMxC;AAID,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAEzC;AAGD,wBAAgB,QAAQ,IAAI,IAAI,CAE/B;AAGD,wBAAgB,aAAa,IAAI,UAAU,CAG1C;AAGD,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD;AAGD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnE;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAE7D;AAGD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAGD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAGD,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAGD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAGD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAID,wBAAgB,8BAA8B,IAAI,SAAS,MAAM,EAAE,CAElE;AAID,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAGD,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAGD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAGD,wBAAgB,OAAO,IAAI,OAAO,CAEjC;AAGD,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAGD,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAGD,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAGD,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD;AAID,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAE7D;AAID,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD;AAID,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAExE;AAGD,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE9D;AAID,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD;AAGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;AAGD,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,CAEvE;AAID,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAE7E;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAID,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD;AAGD,wBAAgB,OAAO,IAAI,OAAO,CAEjC"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { createSignal, emitSignal } from '@flighthq/signals';
|
|
2
|
+
// Adds a path to the system's recent-documents list (Jump List on Windows; macOS recents). No-op on
|
|
3
|
+
// web and platforms without a recents list.
|
|
4
|
+
export function addAppRecentDocument(path) {
|
|
5
|
+
getAppBackend().addRecentDocument(path);
|
|
6
|
+
}
|
|
7
|
+
// Begins delivering app events to `app`'s signals by subscribing to the active backend. Wires
|
|
8
|
+
// subscribeActivate→onActivate, subscribeAllWindowsClosed→onAllWindowsClosed,
|
|
9
|
+
// subscribeOpenFile→onOpenFile, subscribeQuitRequest→onQuitRequest,
|
|
10
|
+
// subscribeReady→onReady, subscribeSecondInstance→onSecondInstance.
|
|
11
|
+
// Idempotent: a prior subscription is torn down first. Pair with detachApp/disposeApp.
|
|
12
|
+
export function attachApp(app) {
|
|
13
|
+
detachApp(app);
|
|
14
|
+
const backend = getAppBackend();
|
|
15
|
+
const unsubscribeActivate = backend.subscribeActivate(() => emitSignal(app.onActivate));
|
|
16
|
+
const unsubscribeAllWindowsClosed = backend.subscribeAllWindowsClosed(() => emitSignal(app.onAllWindowsClosed));
|
|
17
|
+
const unsubscribeOpenFile = backend.subscribeOpenFile((path) => emitSignal(app.onOpenFile, path));
|
|
18
|
+
const unsubscribeQuitRequest = backend.subscribeQuitRequest((cancelHost) => {
|
|
19
|
+
emitSignal(app.onQuitRequest);
|
|
20
|
+
if (app.onQuitRequest.data?.cancelled === true) {
|
|
21
|
+
// A Flight listener vetoed the quit — cancel at the host level too so that Electron (and other
|
|
22
|
+
// native hosts) can call event.preventDefault() and prevent the OS from forcing a quit.
|
|
23
|
+
cancelHost();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
backend.quit();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const unsubscribeReady = backend.subscribeReady(() => emitSignal(app.onReady));
|
|
30
|
+
const unsubscribeSecondInstance = backend.subscribeSecondInstance((argv) => emitSignal(app.onSecondInstance, argv));
|
|
31
|
+
_subscriptions.set(app, () => {
|
|
32
|
+
unsubscribeActivate();
|
|
33
|
+
unsubscribeAllWindowsClosed();
|
|
34
|
+
unsubscribeOpenFile();
|
|
35
|
+
unsubscribeQuitRequest();
|
|
36
|
+
unsubscribeReady();
|
|
37
|
+
unsubscribeSecondInstance();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Starts a dock bounce; returns a request id usable with cancelAppDockBounce, or -1 when unsupported.
|
|
41
|
+
export function bounceAppDock() {
|
|
42
|
+
return getAppBackend().bounceDock();
|
|
43
|
+
}
|
|
44
|
+
// Cancels an app-level attention request previously started by requestAppAttention. No-op on web.
|
|
45
|
+
export function cancelAppAttention(id) {
|
|
46
|
+
getAppBackend().cancelAttention(id);
|
|
47
|
+
}
|
|
48
|
+
// Cancels a dock bounce previously started by bounceAppDock.
|
|
49
|
+
export function cancelAppDockBounce(id) {
|
|
50
|
+
getAppBackend().cancelDockBounce(id);
|
|
51
|
+
}
|
|
52
|
+
// Clears the system's recent-documents list (Jump List / macOS recents). No-op on web.
|
|
53
|
+
export function clearAppRecentDocuments() {
|
|
54
|
+
getAppBackend().clearRecentDocuments();
|
|
55
|
+
}
|
|
56
|
+
// Allocates an App event entity with inert signals; call attachApp to start delivery.
|
|
57
|
+
export function createApp() {
|
|
58
|
+
return {
|
|
59
|
+
onActivate: createSignal(),
|
|
60
|
+
onAllWindowsClosed: createSignal(),
|
|
61
|
+
onOpenFile: createSignal(),
|
|
62
|
+
onQuitRequest: createSignal(),
|
|
63
|
+
onReady: createSignal(),
|
|
64
|
+
onSecondInstance: createSignal(),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Allocates an AppLoginItem with default values.
|
|
68
|
+
export function createAppLoginItem() {
|
|
69
|
+
return { args: [], openAsHidden: false, openAtLogin: false, path: '' };
|
|
70
|
+
}
|
|
71
|
+
// Builds the default web backend over document/window/navigator. Degrades to empty strings and no-ops
|
|
72
|
+
// where the APIs are absent. A web tab is inherently single-instance, so the lock is always held.
|
|
73
|
+
export function createWebAppBackend() {
|
|
74
|
+
return {
|
|
75
|
+
addRecentDocument() {
|
|
76
|
+
// No web recent-documents list; no-op.
|
|
77
|
+
},
|
|
78
|
+
bounceDock() {
|
|
79
|
+
return -1;
|
|
80
|
+
},
|
|
81
|
+
cancelAttention() {
|
|
82
|
+
// No web attention API; no-op.
|
|
83
|
+
},
|
|
84
|
+
cancelDockBounce() {
|
|
85
|
+
// No web dock; no-op.
|
|
86
|
+
},
|
|
87
|
+
clearRecentDocuments() {
|
|
88
|
+
// No web recent-documents list; no-op.
|
|
89
|
+
},
|
|
90
|
+
focus() {
|
|
91
|
+
if (typeof window !== 'undefined') {
|
|
92
|
+
try {
|
|
93
|
+
window.focus();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Focus may be blocked by the host; ignore.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
getAppDirectoryPath() {
|
|
101
|
+
// Web sentinel '': a web tab has no app-identity-relative directory. Native: userData/logs/
|
|
102
|
+
// crashDumps under the per-app data root.
|
|
103
|
+
return '';
|
|
104
|
+
},
|
|
105
|
+
getAppPath() {
|
|
106
|
+
// Web sentinel '': no bundle/exe directory in a tab. Native: the application directory.
|
|
107
|
+
return '';
|
|
108
|
+
},
|
|
109
|
+
getCommandLine() {
|
|
110
|
+
// Web sentinel []: a tab has no process argv. Native: this process's command-line arguments.
|
|
111
|
+
return [];
|
|
112
|
+
},
|
|
113
|
+
getExecutablePath() {
|
|
114
|
+
// Web sentinel '': no executable in a tab. Native: the running executable's path.
|
|
115
|
+
return '';
|
|
116
|
+
},
|
|
117
|
+
getLocale() {
|
|
118
|
+
return typeof navigator !== 'undefined' ? (navigator.language ?? '') : '';
|
|
119
|
+
},
|
|
120
|
+
getPreferredSystemLanguages() {
|
|
121
|
+
if (typeof navigator !== 'undefined' && Array.isArray(navigator.languages)) {
|
|
122
|
+
return navigator.languages;
|
|
123
|
+
}
|
|
124
|
+
return [];
|
|
125
|
+
},
|
|
126
|
+
getSystemLocale() {
|
|
127
|
+
try {
|
|
128
|
+
return typeof Intl !== 'undefined' ? new Intl.DateTimeFormat().resolvedOptions().locale : '';
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return '';
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
getLoginItem() {
|
|
135
|
+
// Web sentinel: a default with openAtLogin false — a tab has no launch-at-login concept.
|
|
136
|
+
// Native: the OS launch-at-login registration for this app.
|
|
137
|
+
return { args: [], openAsHidden: false, openAtLogin: false, path: '' };
|
|
138
|
+
},
|
|
139
|
+
getName() {
|
|
140
|
+
// Web: document.title stands in for the app name ('' when no document). Native: the app's
|
|
141
|
+
// display name.
|
|
142
|
+
return typeof document !== 'undefined' ? document.title : '';
|
|
143
|
+
},
|
|
144
|
+
getVersion() {
|
|
145
|
+
// Web sentinel '': a tab carries no app version. Native: the packaged app version string.
|
|
146
|
+
return '';
|
|
147
|
+
},
|
|
148
|
+
hasSingleInstanceLock() {
|
|
149
|
+
return true;
|
|
150
|
+
},
|
|
151
|
+
hideApp() {
|
|
152
|
+
// No web application-hide; no-op.
|
|
153
|
+
return false;
|
|
154
|
+
},
|
|
155
|
+
isAppHidden() {
|
|
156
|
+
return false;
|
|
157
|
+
},
|
|
158
|
+
quit() {
|
|
159
|
+
if (typeof window !== 'undefined') {
|
|
160
|
+
try {
|
|
161
|
+
window.close();
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// window.close() is restricted for non-script-opened tabs; ignore.
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
relaunch() {
|
|
169
|
+
if (typeof location !== 'undefined') {
|
|
170
|
+
try {
|
|
171
|
+
location.reload();
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Reload may be blocked in some embedding contexts; ignore.
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
releaseSingleInstanceLock() {
|
|
179
|
+
// A web tab cannot relinquish a process-level lock; no-op.
|
|
180
|
+
},
|
|
181
|
+
requestAttention() {
|
|
182
|
+
return -1;
|
|
183
|
+
},
|
|
184
|
+
requestSingleInstanceLock() {
|
|
185
|
+
return true;
|
|
186
|
+
},
|
|
187
|
+
setActivationPolicy() {
|
|
188
|
+
// No macOS activation policy on web; no-op.
|
|
189
|
+
},
|
|
190
|
+
setBadgeCount(count) {
|
|
191
|
+
if (typeof navigator === 'undefined' || !('setAppBadge' in navigator))
|
|
192
|
+
return false;
|
|
193
|
+
try {
|
|
194
|
+
navigator.setAppBadge(count);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
setDockBadge() {
|
|
202
|
+
// No web dock; no-op.
|
|
203
|
+
},
|
|
204
|
+
setDockMenu() {
|
|
205
|
+
// No web dock menu; a native host (Electron app.dock) is required.
|
|
206
|
+
},
|
|
207
|
+
setLoginItem() {
|
|
208
|
+
// Web tabs have no login-item concept; no-op.
|
|
209
|
+
return false;
|
|
210
|
+
},
|
|
211
|
+
setName() {
|
|
212
|
+
// Cannot rename the application from web context; no-op.
|
|
213
|
+
return false;
|
|
214
|
+
},
|
|
215
|
+
setUserModelId() {
|
|
216
|
+
// AppUserModelID is Windows-only; no-op on web.
|
|
217
|
+
return false;
|
|
218
|
+
},
|
|
219
|
+
showApp() {
|
|
220
|
+
// No web application-show; no-op.
|
|
221
|
+
return false;
|
|
222
|
+
},
|
|
223
|
+
subscribeActivate() {
|
|
224
|
+
// No web app-activate event; the listener is never called. Native: dock/taskbar re-activation.
|
|
225
|
+
return () => { };
|
|
226
|
+
},
|
|
227
|
+
subscribeAllWindowsClosed() {
|
|
228
|
+
// No web all-windows-closed event; the listener is never called. Native: last window closed.
|
|
229
|
+
return () => { };
|
|
230
|
+
},
|
|
231
|
+
subscribeOpenFile() {
|
|
232
|
+
// No web open-file event; the listener is never called. Native: OS file-open / "Open With".
|
|
233
|
+
return () => { };
|
|
234
|
+
},
|
|
235
|
+
subscribeQuitRequest(_listener) {
|
|
236
|
+
// A web tab cannot intercept the browser's quit path; the listener is never called.
|
|
237
|
+
return () => { };
|
|
238
|
+
},
|
|
239
|
+
subscribeReady(listener) {
|
|
240
|
+
// On the web the DOM is already ready by the time script runs; fire on the next microtask.
|
|
241
|
+
const id = Promise.resolve().then(() => listener());
|
|
242
|
+
void id;
|
|
243
|
+
return () => { };
|
|
244
|
+
},
|
|
245
|
+
subscribeSecondInstance() {
|
|
246
|
+
// No web second-instance event; the listener is never called. Native: another launch hands its
|
|
247
|
+
// argv to the lock holder.
|
|
248
|
+
return () => { };
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
// Stops delivery to `app` and forgets its subscription. Safe to call when not attached.
|
|
253
|
+
export function detachApp(app) {
|
|
254
|
+
const unsubscribe = _subscriptions.get(app);
|
|
255
|
+
if (unsubscribe !== undefined) {
|
|
256
|
+
unsubscribe();
|
|
257
|
+
_subscriptions.delete(app);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Releases `app` for garbage collection by detaching its backend subscription. The signals remain
|
|
261
|
+
// plain GC-managed memory afterward.
|
|
262
|
+
export function disposeApp(app) {
|
|
263
|
+
detachApp(app);
|
|
264
|
+
}
|
|
265
|
+
// Brings the application to the foreground.
|
|
266
|
+
export function focusApp() {
|
|
267
|
+
getAppBackend().focus();
|
|
268
|
+
}
|
|
269
|
+
// The active app backend, or a lazily-created web default. There is always a backend.
|
|
270
|
+
export function getAppBackend() {
|
|
271
|
+
if (_backend === null)
|
|
272
|
+
_backend = createWebAppBackend();
|
|
273
|
+
return _backend;
|
|
274
|
+
}
|
|
275
|
+
// The command-line arguments for this process, or [] on web.
|
|
276
|
+
export function getAppCommandLine() {
|
|
277
|
+
return getAppBackend().getCommandLine();
|
|
278
|
+
}
|
|
279
|
+
// The value of a named command-line switch, or null when the switch is absent.
|
|
280
|
+
export function getAppCommandLineSwitch(name) {
|
|
281
|
+
const prefix = `--${name}=`;
|
|
282
|
+
const args = getAppBackend().getCommandLine();
|
|
283
|
+
for (const arg of args) {
|
|
284
|
+
if (arg === `--${name}`)
|
|
285
|
+
return '';
|
|
286
|
+
if (arg.startsWith(prefix))
|
|
287
|
+
return arg.slice(prefix.length);
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
// The app-identity-relative directory path for the given kind (userData/logs/crashDumps); '' on web.
|
|
292
|
+
// Note: bare OS directories (home, documents, downloads, appData, etc.) live in @flighthq/filesystem.
|
|
293
|
+
export function getAppDirectoryPath(kind) {
|
|
294
|
+
return getAppBackend().getAppDirectoryPath(kind);
|
|
295
|
+
}
|
|
296
|
+
// The application executable path, or '' on web.
|
|
297
|
+
export function getAppExecutablePath() {
|
|
298
|
+
return getAppBackend().getExecutablePath();
|
|
299
|
+
}
|
|
300
|
+
// The host UI locale (for example 'en-US'), or '' when unknown.
|
|
301
|
+
export function getAppLocale() {
|
|
302
|
+
return getAppBackend().getLocale();
|
|
303
|
+
}
|
|
304
|
+
// The application login-item settings. Returns a default with openAtLogin: false on web.
|
|
305
|
+
export function getAppLoginItem() {
|
|
306
|
+
return getAppBackend().getLoginItem();
|
|
307
|
+
}
|
|
308
|
+
// The application name, or '' when unknown.
|
|
309
|
+
export function getAppName() {
|
|
310
|
+
return getAppBackend().getName();
|
|
311
|
+
}
|
|
312
|
+
// The application bundle/exe directory path, or '' on web.
|
|
313
|
+
export function getAppPath() {
|
|
314
|
+
return getAppBackend().getAppPath();
|
|
315
|
+
}
|
|
316
|
+
// The ranked list of preferred system languages (for example ['en-US', 'fr-FR']), in preference
|
|
317
|
+
// order; [] when unavailable (on web: navigator.languages).
|
|
318
|
+
export function getAppPreferredSystemLanguages() {
|
|
319
|
+
return getAppBackend().getPreferredSystemLanguages();
|
|
320
|
+
}
|
|
321
|
+
// The OS-level system locale (for example 'en_US'), which may differ from the UI locale returned
|
|
322
|
+
// by getAppLocale; '' when unavailable.
|
|
323
|
+
export function getAppSystemLocale() {
|
|
324
|
+
return getAppBackend().getSystemLocale();
|
|
325
|
+
}
|
|
326
|
+
// The application version string, or '' when unknown.
|
|
327
|
+
export function getAppVersion() {
|
|
328
|
+
return getAppBackend().getVersion();
|
|
329
|
+
}
|
|
330
|
+
// True when the switch is present in the command line; false otherwise.
|
|
331
|
+
export function hasAppCommandLineSwitch(name) {
|
|
332
|
+
return getAppCommandLineSwitch(name) !== null;
|
|
333
|
+
}
|
|
334
|
+
// True when this process currently holds the single-instance lock.
|
|
335
|
+
export function hasAppSingleInstanceLock() {
|
|
336
|
+
return getAppBackend().hasSingleInstanceLock();
|
|
337
|
+
}
|
|
338
|
+
// Hides the application (macOS hide-all-windows). Returns true when supported. No-op on web.
|
|
339
|
+
export function hideApp() {
|
|
340
|
+
return getAppBackend().hideApp();
|
|
341
|
+
}
|
|
342
|
+
// True when the application is hidden (macOS only). Always false on web.
|
|
343
|
+
export function isAppHidden() {
|
|
344
|
+
return getAppBackend().isAppHidden();
|
|
345
|
+
}
|
|
346
|
+
// Quits the application.
|
|
347
|
+
export function quitApp() {
|
|
348
|
+
getAppBackend().quit();
|
|
349
|
+
}
|
|
350
|
+
// Relaunches the application.
|
|
351
|
+
export function relaunchApp() {
|
|
352
|
+
getAppBackend().relaunch();
|
|
353
|
+
}
|
|
354
|
+
// Releases a previously acquired single-instance lock.
|
|
355
|
+
export function releaseAppSingleInstanceLock() {
|
|
356
|
+
getAppBackend().releaseSingleInstanceLock();
|
|
357
|
+
}
|
|
358
|
+
// Draws attention to the application at the OS level (taskbar flash / dock bounce). Returns a
|
|
359
|
+
// request id for cancelAppAttention, or -1 when unsupported.
|
|
360
|
+
export function requestAppAttention(critical) {
|
|
361
|
+
return getAppBackend().requestAttention(critical);
|
|
362
|
+
}
|
|
363
|
+
// Attempts to acquire the single-instance lock. Returns true when this process owns it; false when
|
|
364
|
+
// another instance already holds it.
|
|
365
|
+
export function requestAppSingleInstanceLock() {
|
|
366
|
+
return getAppBackend().requestSingleInstanceLock();
|
|
367
|
+
}
|
|
368
|
+
// Sets the macOS activation policy, controlling dock presence and Command-Tab visibility. No-op on
|
|
369
|
+
// non-macOS and web.
|
|
370
|
+
export function setAppActivationPolicy(policy) {
|
|
371
|
+
getAppBackend().setActivationPolicy(policy);
|
|
372
|
+
}
|
|
373
|
+
// Installs a native host app backend; pass null to fall back to the web default.
|
|
374
|
+
export function setAppBackend(backend) {
|
|
375
|
+
_backend = backend;
|
|
376
|
+
}
|
|
377
|
+
// Sets the numeric application badge (taskbar overlay / dock / PWA badge). Returns false when
|
|
378
|
+
// unsupported. Canonical home for the app badge — the tray package no longer carries it.
|
|
379
|
+
export function setAppBadgeCount(count) {
|
|
380
|
+
return getAppBackend().setBadgeCount(count);
|
|
381
|
+
}
|
|
382
|
+
// Sets the dock/taskbar badge text. Pass '' to clear it.
|
|
383
|
+
export function setAppDockBadge(text) {
|
|
384
|
+
getAppBackend().setDockBadge(text);
|
|
385
|
+
}
|
|
386
|
+
// Sets the macOs dock menu (shown when right-clicking the dock icon). No-op where there is no dock.
|
|
387
|
+
export function setAppDockMenu(items) {
|
|
388
|
+
getAppBackend().setDockMenu(items);
|
|
389
|
+
}
|
|
390
|
+
// Updates login-item (launch-at-startup) settings. Returns false when unsupported (web, some Linux
|
|
391
|
+
// environments). Settings fields not provided keep their current values.
|
|
392
|
+
export function setAppLoginItem(settings) {
|
|
393
|
+
return getAppBackend().setLoginItem(settings);
|
|
394
|
+
}
|
|
395
|
+
// Sets the application name. Returns false when unsupported (web). On macOS/Windows this updates
|
|
396
|
+
// the display name shown in the dock/taskbar.
|
|
397
|
+
export function setAppName(name) {
|
|
398
|
+
return getAppBackend().setName(name);
|
|
399
|
+
}
|
|
400
|
+
// Sets the Windows AppUserModelID used for taskbar grouping, badging, and Jump Lists. Returns false
|
|
401
|
+
// when unsupported. Should be set at startup before creating any windows.
|
|
402
|
+
export function setAppUserModelId(id) {
|
|
403
|
+
return getAppBackend().setUserModelId(id);
|
|
404
|
+
}
|
|
405
|
+
// Shows the application after hideApp (macOS). Returns true when supported. No-op on web.
|
|
406
|
+
export function showApp() {
|
|
407
|
+
return getAppBackend().showApp();
|
|
408
|
+
}
|
|
409
|
+
let _backend = null;
|
|
410
|
+
const _subscriptions = new WeakMap();
|
|
411
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flighthq/app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src/**/*.test.ts",
|
|
16
|
+
"!dist/**/*.test.js",
|
|
17
|
+
"!dist/**/*.test.d.ts",
|
|
18
|
+
"!dist/**/*.test.js.map",
|
|
19
|
+
"!dist/**/*.test.d.ts.map"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -b",
|
|
23
|
+
"clean": "tsc -b --clean",
|
|
24
|
+
"test": "vitest run --config vitest.config.ts",
|
|
25
|
+
"test:watch": "vitest --watch --config vitest.config.ts",
|
|
26
|
+
"prepack": "npm run clean && npm run clean:dist && npm run build",
|
|
27
|
+
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@flighthq/signals": "0.1.0",
|
|
31
|
+
"@flighthq/types": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.3.0"
|
|
35
|
+
},
|
|
36
|
+
"description": "Application identity, lifecycle control, single-instance locking, dock control, and app event signals over a swappable web/native backend",
|
|
37
|
+
"sideEffects": false
|
|
38
|
+
}
|
package/src/app.test.ts
ADDED
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
import { cancelSignal, connectSignal } from '@flighthq/signals';
|
|
2
|
+
import type { AppBackend, AppLoginItem, AppLoginItemLike, MenuItemTemplate } from '@flighthq/types';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
addAppRecentDocument,
|
|
6
|
+
attachApp,
|
|
7
|
+
bounceAppDock,
|
|
8
|
+
cancelAppAttention,
|
|
9
|
+
cancelAppDockBounce,
|
|
10
|
+
clearAppRecentDocuments,
|
|
11
|
+
createApp,
|
|
12
|
+
createAppLoginItem,
|
|
13
|
+
createWebAppBackend,
|
|
14
|
+
detachApp,
|
|
15
|
+
disposeApp,
|
|
16
|
+
focusApp,
|
|
17
|
+
getAppBackend,
|
|
18
|
+
getAppCommandLine,
|
|
19
|
+
getAppCommandLineSwitch,
|
|
20
|
+
getAppDirectoryPath,
|
|
21
|
+
getAppExecutablePath,
|
|
22
|
+
getAppLocale,
|
|
23
|
+
getAppLoginItem,
|
|
24
|
+
getAppName,
|
|
25
|
+
getAppPath,
|
|
26
|
+
getAppPreferredSystemLanguages,
|
|
27
|
+
getAppSystemLocale,
|
|
28
|
+
getAppVersion,
|
|
29
|
+
hasAppCommandLineSwitch,
|
|
30
|
+
hasAppSingleInstanceLock,
|
|
31
|
+
hideApp,
|
|
32
|
+
isAppHidden,
|
|
33
|
+
quitApp,
|
|
34
|
+
relaunchApp,
|
|
35
|
+
releaseAppSingleInstanceLock,
|
|
36
|
+
requestAppAttention,
|
|
37
|
+
requestAppSingleInstanceLock,
|
|
38
|
+
setAppActivationPolicy,
|
|
39
|
+
setAppBackend,
|
|
40
|
+
setAppBadgeCount,
|
|
41
|
+
setAppDockBadge,
|
|
42
|
+
setAppDockMenu,
|
|
43
|
+
setAppLoginItem,
|
|
44
|
+
setAppName,
|
|
45
|
+
setAppUserModelId,
|
|
46
|
+
showApp,
|
|
47
|
+
} from './app';
|
|
48
|
+
|
|
49
|
+
function fakeBackend(): AppBackend & {
|
|
50
|
+
activationPolicy: string;
|
|
51
|
+
badge: string;
|
|
52
|
+
badgeCount: number;
|
|
53
|
+
bounceId: number;
|
|
54
|
+
cancelledAttention: number;
|
|
55
|
+
cancelledBounce: number;
|
|
56
|
+
commandLine: string[];
|
|
57
|
+
dockMenuItems: number;
|
|
58
|
+
focused: boolean;
|
|
59
|
+
hidden: boolean;
|
|
60
|
+
lastRecentDocument: string;
|
|
61
|
+
loginItem: AppLoginItem;
|
|
62
|
+
lock: boolean;
|
|
63
|
+
name: string;
|
|
64
|
+
preferredLanguages: string[];
|
|
65
|
+
recentDocumentsCleared: boolean;
|
|
66
|
+
systemLocale: string;
|
|
67
|
+
userModelId: string;
|
|
68
|
+
fireActivate: () => void;
|
|
69
|
+
fireAllWindowsClosed: () => void;
|
|
70
|
+
fireOpenFile: (path: string) => void;
|
|
71
|
+
fireQuitRequest: (cancel?: () => void) => void;
|
|
72
|
+
fireReady: () => void;
|
|
73
|
+
fireSecondInstance: (argv: readonly string[]) => void;
|
|
74
|
+
} {
|
|
75
|
+
let activate: (() => void) | null = null;
|
|
76
|
+
let allWindowsClosed: (() => void) | null = null;
|
|
77
|
+
let openFile: ((path: string) => void) | null = null;
|
|
78
|
+
let quitRequest: ((cancel: () => void) => void) | null = null;
|
|
79
|
+
let ready: (() => void) | null = null;
|
|
80
|
+
let secondInstance: ((argv: readonly string[]) => void) | null = null;
|
|
81
|
+
return {
|
|
82
|
+
activationPolicy: '',
|
|
83
|
+
badge: '',
|
|
84
|
+
badgeCount: -1,
|
|
85
|
+
bounceId: -1,
|
|
86
|
+
cancelledAttention: -1,
|
|
87
|
+
cancelledBounce: -1,
|
|
88
|
+
commandLine: [],
|
|
89
|
+
dockMenuItems: -1,
|
|
90
|
+
focused: false,
|
|
91
|
+
hidden: false,
|
|
92
|
+
lastRecentDocument: '',
|
|
93
|
+
loginItem: { args: [], openAsHidden: false, openAtLogin: false, path: '' },
|
|
94
|
+
lock: false,
|
|
95
|
+
name: 'TestApp',
|
|
96
|
+
preferredLanguages: ['en-US', 'fr-FR'],
|
|
97
|
+
recentDocumentsCleared: false,
|
|
98
|
+
systemLocale: 'en_US',
|
|
99
|
+
userModelId: '',
|
|
100
|
+
addRecentDocument(path) {
|
|
101
|
+
this.lastRecentDocument = path;
|
|
102
|
+
},
|
|
103
|
+
bounceDock() {
|
|
104
|
+
this.bounceId = 7;
|
|
105
|
+
return 7;
|
|
106
|
+
},
|
|
107
|
+
cancelAttention(id) {
|
|
108
|
+
this.cancelledAttention = id;
|
|
109
|
+
},
|
|
110
|
+
cancelDockBounce(id) {
|
|
111
|
+
this.cancelledBounce = id;
|
|
112
|
+
},
|
|
113
|
+
clearRecentDocuments() {
|
|
114
|
+
this.recentDocumentsCleared = true;
|
|
115
|
+
},
|
|
116
|
+
focus() {
|
|
117
|
+
this.focused = true;
|
|
118
|
+
},
|
|
119
|
+
getAppDirectoryPath() {
|
|
120
|
+
return '/test/app/userData';
|
|
121
|
+
},
|
|
122
|
+
getAppPath() {
|
|
123
|
+
return '/test/app';
|
|
124
|
+
},
|
|
125
|
+
getCommandLine() {
|
|
126
|
+
return this.commandLine;
|
|
127
|
+
},
|
|
128
|
+
getExecutablePath() {
|
|
129
|
+
return '/test/app/bin';
|
|
130
|
+
},
|
|
131
|
+
getLocale() {
|
|
132
|
+
return 'en-US';
|
|
133
|
+
},
|
|
134
|
+
getPreferredSystemLanguages() {
|
|
135
|
+
return this.preferredLanguages;
|
|
136
|
+
},
|
|
137
|
+
getSystemLocale() {
|
|
138
|
+
return this.systemLocale;
|
|
139
|
+
},
|
|
140
|
+
getLoginItem() {
|
|
141
|
+
return this.loginItem;
|
|
142
|
+
},
|
|
143
|
+
getName() {
|
|
144
|
+
return this.name;
|
|
145
|
+
},
|
|
146
|
+
getVersion() {
|
|
147
|
+
return '1.2.3';
|
|
148
|
+
},
|
|
149
|
+
hasSingleInstanceLock() {
|
|
150
|
+
return this.lock;
|
|
151
|
+
},
|
|
152
|
+
hideApp() {
|
|
153
|
+
this.hidden = true;
|
|
154
|
+
return true;
|
|
155
|
+
},
|
|
156
|
+
isAppHidden() {
|
|
157
|
+
return this.hidden;
|
|
158
|
+
},
|
|
159
|
+
quit() {},
|
|
160
|
+
relaunch() {},
|
|
161
|
+
releaseSingleInstanceLock() {
|
|
162
|
+
this.lock = false;
|
|
163
|
+
},
|
|
164
|
+
requestAttention() {
|
|
165
|
+
return 42;
|
|
166
|
+
},
|
|
167
|
+
requestSingleInstanceLock() {
|
|
168
|
+
this.lock = true;
|
|
169
|
+
return true;
|
|
170
|
+
},
|
|
171
|
+
setActivationPolicy(policy) {
|
|
172
|
+
this.activationPolicy = policy;
|
|
173
|
+
},
|
|
174
|
+
setBadgeCount(count) {
|
|
175
|
+
this.badgeCount = count;
|
|
176
|
+
return true;
|
|
177
|
+
},
|
|
178
|
+
setDockBadge(text) {
|
|
179
|
+
this.badge = text;
|
|
180
|
+
},
|
|
181
|
+
setDockMenu(items) {
|
|
182
|
+
this.dockMenuItems = items.length;
|
|
183
|
+
},
|
|
184
|
+
setLoginItem(settings) {
|
|
185
|
+
this.loginItem = { ...this.loginItem, ...settings };
|
|
186
|
+
return true;
|
|
187
|
+
},
|
|
188
|
+
setName(n) {
|
|
189
|
+
this.name = n;
|
|
190
|
+
return true;
|
|
191
|
+
},
|
|
192
|
+
setUserModelId(id) {
|
|
193
|
+
this.userModelId = id;
|
|
194
|
+
return true;
|
|
195
|
+
},
|
|
196
|
+
showApp() {
|
|
197
|
+
this.hidden = false;
|
|
198
|
+
return true;
|
|
199
|
+
},
|
|
200
|
+
subscribeActivate(l) {
|
|
201
|
+
activate = l;
|
|
202
|
+
return () => {
|
|
203
|
+
activate = null;
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
subscribeAllWindowsClosed(l) {
|
|
207
|
+
allWindowsClosed = l;
|
|
208
|
+
return () => {
|
|
209
|
+
allWindowsClosed = null;
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
subscribeOpenFile(l) {
|
|
213
|
+
openFile = l;
|
|
214
|
+
return () => {
|
|
215
|
+
openFile = null;
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
subscribeQuitRequest(l) {
|
|
219
|
+
quitRequest = l;
|
|
220
|
+
return () => {
|
|
221
|
+
quitRequest = null;
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
subscribeReady(l) {
|
|
225
|
+
ready = l;
|
|
226
|
+
return () => {
|
|
227
|
+
ready = null;
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
subscribeSecondInstance(l) {
|
|
231
|
+
secondInstance = l;
|
|
232
|
+
return () => {
|
|
233
|
+
secondInstance = null;
|
|
234
|
+
};
|
|
235
|
+
},
|
|
236
|
+
fireActivate() {
|
|
237
|
+
activate?.();
|
|
238
|
+
},
|
|
239
|
+
fireAllWindowsClosed() {
|
|
240
|
+
allWindowsClosed?.();
|
|
241
|
+
},
|
|
242
|
+
fireOpenFile(path) {
|
|
243
|
+
openFile?.(path);
|
|
244
|
+
},
|
|
245
|
+
fireQuitRequest(cancel?: () => void) {
|
|
246
|
+
quitRequest?.(cancel ?? (() => {}));
|
|
247
|
+
},
|
|
248
|
+
fireReady() {
|
|
249
|
+
ready?.();
|
|
250
|
+
},
|
|
251
|
+
fireSecondInstance(argv) {
|
|
252
|
+
secondInstance?.(argv);
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
afterEach(() => setAppBackend(null));
|
|
258
|
+
|
|
259
|
+
describe('addAppRecentDocument', () => {
|
|
260
|
+
it('forwards the path to the backend', () => {
|
|
261
|
+
const backend = fakeBackend();
|
|
262
|
+
setAppBackend(backend);
|
|
263
|
+
addAppRecentDocument('/home/user/file.txt');
|
|
264
|
+
expect(backend.lastRecentDocument).toBe('/home/user/file.txt');
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe('attachApp', () => {
|
|
269
|
+
it('wires activate, all-windows-closed, open-file, quit-request, ready, and second-instance subscriptions', () => {
|
|
270
|
+
const backend = fakeBackend();
|
|
271
|
+
setAppBackend(backend);
|
|
272
|
+
const app = createApp();
|
|
273
|
+
let activations = 0;
|
|
274
|
+
let allWindowsClosedCount = 0;
|
|
275
|
+
let openedPath = '';
|
|
276
|
+
let readyCount = 0;
|
|
277
|
+
let argv: readonly string[] = [];
|
|
278
|
+
connectSignal(app.onActivate, () => activations++);
|
|
279
|
+
connectSignal(app.onAllWindowsClosed, () => allWindowsClosedCount++);
|
|
280
|
+
connectSignal(app.onOpenFile, (path) => (openedPath = path));
|
|
281
|
+
connectSignal(app.onReady, () => readyCount++);
|
|
282
|
+
connectSignal(app.onSecondInstance, (a) => (argv = a));
|
|
283
|
+
attachApp(app);
|
|
284
|
+
backend.fireActivate();
|
|
285
|
+
backend.fireAllWindowsClosed();
|
|
286
|
+
backend.fireOpenFile('/tmp/file.txt');
|
|
287
|
+
backend.fireReady();
|
|
288
|
+
backend.fireSecondInstance(['--flag']);
|
|
289
|
+
expect(activations).toBe(1);
|
|
290
|
+
expect(allWindowsClosedCount).toBe(1);
|
|
291
|
+
expect(openedPath).toBe('/tmp/file.txt');
|
|
292
|
+
expect(readyCount).toBe(1);
|
|
293
|
+
expect(argv).toEqual(['--flag']);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('is idempotent — tears down the prior subscription before re-attaching', () => {
|
|
297
|
+
const backend = fakeBackend();
|
|
298
|
+
setAppBackend(backend);
|
|
299
|
+
const app = createApp();
|
|
300
|
+
let activations = 0;
|
|
301
|
+
connectSignal(app.onActivate, () => activations++);
|
|
302
|
+
attachApp(app);
|
|
303
|
+
attachApp(app);
|
|
304
|
+
backend.fireActivate();
|
|
305
|
+
expect(activations).toBe(1);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('quits when onQuitRequest is not cancelled', () => {
|
|
309
|
+
let quits = 0;
|
|
310
|
+
const backend = fakeBackend();
|
|
311
|
+
backend.quit = () => {
|
|
312
|
+
quits++;
|
|
313
|
+
};
|
|
314
|
+
setAppBackend(backend);
|
|
315
|
+
const app = createApp();
|
|
316
|
+
attachApp(app);
|
|
317
|
+
backend.fireQuitRequest();
|
|
318
|
+
expect(quits).toBe(1);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('does not quit when onQuitRequest is cancelled', () => {
|
|
322
|
+
let quits = 0;
|
|
323
|
+
const backend = fakeBackend();
|
|
324
|
+
backend.quit = () => {
|
|
325
|
+
quits++;
|
|
326
|
+
};
|
|
327
|
+
setAppBackend(backend);
|
|
328
|
+
const app = createApp();
|
|
329
|
+
connectSignal(app.onQuitRequest, () => cancelSignal(app.onQuitRequest));
|
|
330
|
+
attachApp(app);
|
|
331
|
+
backend.fireQuitRequest();
|
|
332
|
+
expect(quits).toBe(0);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('calls the host cancel callback when onQuitRequest is vetoed', () => {
|
|
336
|
+
let hostCancelled = false;
|
|
337
|
+
const backend = fakeBackend();
|
|
338
|
+
setAppBackend(backend);
|
|
339
|
+
const app = createApp();
|
|
340
|
+
connectSignal(app.onQuitRequest, () => cancelSignal(app.onQuitRequest));
|
|
341
|
+
attachApp(app);
|
|
342
|
+
backend.fireQuitRequest(() => {
|
|
343
|
+
hostCancelled = true;
|
|
344
|
+
});
|
|
345
|
+
expect(hostCancelled).toBe(true);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
describe('bounceAppDock', () => {
|
|
350
|
+
it('returns the backend bounce id', () => {
|
|
351
|
+
setAppBackend(fakeBackend());
|
|
352
|
+
expect(bounceAppDock()).toBe(7);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe('cancelAppAttention', () => {
|
|
357
|
+
it('forwards the id to the backend', () => {
|
|
358
|
+
const backend = fakeBackend();
|
|
359
|
+
setAppBackend(backend);
|
|
360
|
+
cancelAppAttention(42);
|
|
361
|
+
expect(backend.cancelledAttention).toBe(42);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
describe('cancelAppDockBounce', () => {
|
|
366
|
+
it('forwards the id to the backend', () => {
|
|
367
|
+
const backend = fakeBackend();
|
|
368
|
+
setAppBackend(backend);
|
|
369
|
+
cancelAppDockBounce(7);
|
|
370
|
+
expect(backend.cancelledBounce).toBe(7);
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
describe('clearAppRecentDocuments', () => {
|
|
375
|
+
it('clears via the backend', () => {
|
|
376
|
+
const backend = fakeBackend();
|
|
377
|
+
setAppBackend(backend);
|
|
378
|
+
clearAppRecentDocuments();
|
|
379
|
+
expect(backend.recentDocumentsCleared).toBe(true);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe('createApp', () => {
|
|
384
|
+
it('creates an entity with six signals', () => {
|
|
385
|
+
const app = createApp();
|
|
386
|
+
expect(app.onActivate).toBeDefined();
|
|
387
|
+
expect(app.onAllWindowsClosed).toBeDefined();
|
|
388
|
+
expect(app.onOpenFile).toBeDefined();
|
|
389
|
+
expect(app.onQuitRequest).toBeDefined();
|
|
390
|
+
expect(app.onReady).toBeDefined();
|
|
391
|
+
expect(app.onSecondInstance).toBeDefined();
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
describe('createAppLoginItem', () => {
|
|
396
|
+
it('returns a default login item', () => {
|
|
397
|
+
const item = createAppLoginItem();
|
|
398
|
+
expect(item.openAtLogin).toBe(false);
|
|
399
|
+
expect(item.openAsHidden).toBe(false);
|
|
400
|
+
expect(item.args).toEqual([]);
|
|
401
|
+
expect(item.path).toBe('');
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe('createWebAppBackend', () => {
|
|
406
|
+
it('reads identity values without throwing', () => {
|
|
407
|
+
const backend = createWebAppBackend();
|
|
408
|
+
expect(typeof backend.getName()).toBe('string');
|
|
409
|
+
expect(typeof backend.getVersion()).toBe('string');
|
|
410
|
+
expect(typeof backend.getLocale()).toBe('string');
|
|
411
|
+
expect(backend.requestSingleInstanceLock()).toBe(true);
|
|
412
|
+
expect(backend.hasSingleInstanceLock()).toBe(true);
|
|
413
|
+
expect(backend.bounceDock()).toBe(-1);
|
|
414
|
+
expect(backend.subscribeActivate(() => {})).toBeInstanceOf(Function);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('returns sentinel values for unavailable APIs', () => {
|
|
418
|
+
const backend = createWebAppBackend();
|
|
419
|
+
expect(backend.getAppPath()).toBe('');
|
|
420
|
+
expect(backend.getExecutablePath()).toBe('');
|
|
421
|
+
expect(backend.getCommandLine()).toEqual([]);
|
|
422
|
+
expect(backend.getLoginItem().openAtLogin).toBe(false);
|
|
423
|
+
expect(backend.hideApp()).toBe(false);
|
|
424
|
+
expect(backend.isAppHidden()).toBe(false);
|
|
425
|
+
expect(backend.requestAttention(false)).toBe(-1);
|
|
426
|
+
expect(backend.setLoginItem({})).toBe(false);
|
|
427
|
+
expect(backend.setName('X')).toBe(false);
|
|
428
|
+
expect(backend.setUserModelId('X')).toBe(false);
|
|
429
|
+
expect(backend.showApp()).toBe(false);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('returns preferred system languages and system locale', () => {
|
|
433
|
+
const backend = createWebAppBackend();
|
|
434
|
+
expect(Array.isArray(backend.getPreferredSystemLanguages())).toBe(true);
|
|
435
|
+
expect(typeof backend.getSystemLocale()).toBe('string');
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
describe('detachApp', () => {
|
|
440
|
+
it('stops further delivery', () => {
|
|
441
|
+
const backend = fakeBackend();
|
|
442
|
+
setAppBackend(backend);
|
|
443
|
+
const app = createApp();
|
|
444
|
+
let activations = 0;
|
|
445
|
+
connectSignal(app.onActivate, () => activations++);
|
|
446
|
+
attachApp(app);
|
|
447
|
+
detachApp(app);
|
|
448
|
+
backend.fireActivate();
|
|
449
|
+
expect(activations).toBe(0);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it('is safe to call when not attached', () => {
|
|
453
|
+
expect(() => detachApp(createApp())).not.toThrow();
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
describe('disposeApp', () => {
|
|
458
|
+
it('detaches the subscription', () => {
|
|
459
|
+
const backend = fakeBackend();
|
|
460
|
+
setAppBackend(backend);
|
|
461
|
+
const app = createApp();
|
|
462
|
+
attachApp(app);
|
|
463
|
+
expect(() => disposeApp(app)).not.toThrow();
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe('focusApp', () => {
|
|
468
|
+
it('focuses through the backend', () => {
|
|
469
|
+
const backend = fakeBackend();
|
|
470
|
+
setAppBackend(backend);
|
|
471
|
+
focusApp();
|
|
472
|
+
expect(backend.focused).toBe(true);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
describe('getAppBackend', () => {
|
|
477
|
+
it('falls back to a web backend', () => {
|
|
478
|
+
expect(getAppBackend()).not.toBeNull();
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
describe('getAppCommandLine', () => {
|
|
483
|
+
it('returns the command line from the backend', () => {
|
|
484
|
+
const backend = fakeBackend();
|
|
485
|
+
backend.commandLine = ['--flag', '--key=val'];
|
|
486
|
+
setAppBackend(backend);
|
|
487
|
+
expect(getAppCommandLine()).toEqual(['--flag', '--key=val']);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe('getAppCommandLineSwitch', () => {
|
|
492
|
+
it('returns empty string for a bare flag', () => {
|
|
493
|
+
const backend = fakeBackend();
|
|
494
|
+
backend.commandLine = ['--debug'];
|
|
495
|
+
setAppBackend(backend);
|
|
496
|
+
expect(getAppCommandLineSwitch('debug')).toBe('');
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('returns the value for a key=value switch', () => {
|
|
500
|
+
const backend = fakeBackend();
|
|
501
|
+
backend.commandLine = ['--port=3000'];
|
|
502
|
+
setAppBackend(backend);
|
|
503
|
+
expect(getAppCommandLineSwitch('port')).toBe('3000');
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('returns null when the switch is absent', () => {
|
|
507
|
+
setAppBackend(fakeBackend());
|
|
508
|
+
expect(getAppCommandLineSwitch('missing')).toBeNull();
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
describe('getAppDirectoryPath', () => {
|
|
513
|
+
it('returns the path from the backend', () => {
|
|
514
|
+
setAppBackend(fakeBackend());
|
|
515
|
+
expect(getAppDirectoryPath('userData')).toBe('/test/app/userData');
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe('getAppExecutablePath', () => {
|
|
520
|
+
it('returns the executable path from the backend', () => {
|
|
521
|
+
setAppBackend(fakeBackend());
|
|
522
|
+
expect(getAppExecutablePath()).toBe('/test/app/bin');
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
describe('getAppLocale', () => {
|
|
527
|
+
it('reads the backend locale', () => {
|
|
528
|
+
setAppBackend(fakeBackend());
|
|
529
|
+
expect(getAppLocale()).toBe('en-US');
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
describe('getAppLoginItem', () => {
|
|
534
|
+
it('returns the login item from the backend', () => {
|
|
535
|
+
const backend = fakeBackend();
|
|
536
|
+
backend.loginItem = { args: ['--hidden'], openAsHidden: true, openAtLogin: true, path: '/app' };
|
|
537
|
+
setAppBackend(backend);
|
|
538
|
+
const item = getAppLoginItem();
|
|
539
|
+
expect(item.openAtLogin).toBe(true);
|
|
540
|
+
expect(item.openAsHidden).toBe(true);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
describe('getAppName', () => {
|
|
545
|
+
it('reads the backend name', () => {
|
|
546
|
+
setAppBackend(fakeBackend());
|
|
547
|
+
expect(getAppName()).toBe('TestApp');
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
describe('getAppPath', () => {
|
|
552
|
+
it('returns the app path from the backend', () => {
|
|
553
|
+
setAppBackend(fakeBackend());
|
|
554
|
+
expect(getAppPath()).toBe('/test/app');
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
describe('getAppPreferredSystemLanguages', () => {
|
|
559
|
+
it('returns the preferred system languages from the backend', () => {
|
|
560
|
+
setAppBackend(fakeBackend());
|
|
561
|
+
expect(getAppPreferredSystemLanguages()).toEqual(['en-US', 'fr-FR']);
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
describe('getAppSystemLocale', () => {
|
|
566
|
+
it('returns the system locale from the backend', () => {
|
|
567
|
+
setAppBackend(fakeBackend());
|
|
568
|
+
expect(getAppSystemLocale()).toBe('en_US');
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
describe('getAppVersion', () => {
|
|
573
|
+
it('reads the backend version', () => {
|
|
574
|
+
setAppBackend(fakeBackend());
|
|
575
|
+
expect(getAppVersion()).toBe('1.2.3');
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
describe('hasAppCommandLineSwitch', () => {
|
|
580
|
+
it('returns true when the switch is present', () => {
|
|
581
|
+
const backend = fakeBackend();
|
|
582
|
+
backend.commandLine = ['--debug'];
|
|
583
|
+
setAppBackend(backend);
|
|
584
|
+
expect(hasAppCommandLineSwitch('debug')).toBe(true);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('returns false when the switch is absent', () => {
|
|
588
|
+
setAppBackend(fakeBackend());
|
|
589
|
+
expect(hasAppCommandLineSwitch('missing')).toBe(false);
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
describe('hasAppSingleInstanceLock', () => {
|
|
594
|
+
it('reflects the backend lock state', () => {
|
|
595
|
+
const backend = fakeBackend();
|
|
596
|
+
setAppBackend(backend);
|
|
597
|
+
expect(hasAppSingleInstanceLock()).toBe(false);
|
|
598
|
+
requestAppSingleInstanceLock();
|
|
599
|
+
expect(hasAppSingleInstanceLock()).toBe(true);
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
describe('hideApp', () => {
|
|
604
|
+
it('hides the app and returns true from the backend', () => {
|
|
605
|
+
const backend = fakeBackend();
|
|
606
|
+
setAppBackend(backend);
|
|
607
|
+
expect(hideApp()).toBe(true);
|
|
608
|
+
expect(backend.hidden).toBe(true);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
describe('isAppHidden', () => {
|
|
613
|
+
it('reflects the backend hidden state', () => {
|
|
614
|
+
const backend = fakeBackend();
|
|
615
|
+
setAppBackend(backend);
|
|
616
|
+
expect(isAppHidden()).toBe(false);
|
|
617
|
+
hideApp();
|
|
618
|
+
expect(isAppHidden()).toBe(true);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
describe('quitApp', () => {
|
|
623
|
+
it('quits without throwing', () => {
|
|
624
|
+
setAppBackend(fakeBackend());
|
|
625
|
+
expect(() => quitApp()).not.toThrow();
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe('relaunchApp', () => {
|
|
630
|
+
it('relaunches without throwing', () => {
|
|
631
|
+
setAppBackend(fakeBackend());
|
|
632
|
+
expect(() => relaunchApp()).not.toThrow();
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
describe('releaseAppSingleInstanceLock', () => {
|
|
637
|
+
it('releases the lock', () => {
|
|
638
|
+
const backend = fakeBackend();
|
|
639
|
+
setAppBackend(backend);
|
|
640
|
+
requestAppSingleInstanceLock();
|
|
641
|
+
releaseAppSingleInstanceLock();
|
|
642
|
+
expect(backend.lock).toBe(false);
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
describe('requestAppAttention', () => {
|
|
647
|
+
it('returns the attention id from the backend', () => {
|
|
648
|
+
setAppBackend(fakeBackend());
|
|
649
|
+
expect(requestAppAttention(true)).toBe(42);
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
describe('requestAppSingleInstanceLock', () => {
|
|
654
|
+
it('acquires the lock', () => {
|
|
655
|
+
setAppBackend(fakeBackend());
|
|
656
|
+
expect(requestAppSingleInstanceLock()).toBe(true);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
describe('setAppActivationPolicy', () => {
|
|
661
|
+
it('forwards the policy to the backend', () => {
|
|
662
|
+
const backend = fakeBackend();
|
|
663
|
+
setAppBackend(backend);
|
|
664
|
+
setAppActivationPolicy('accessory');
|
|
665
|
+
expect(backend.activationPolicy).toBe('accessory');
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
describe('setAppBackend', () => {
|
|
670
|
+
it('clears back to the web fallback when passed null', () => {
|
|
671
|
+
setAppBackend(fakeBackend());
|
|
672
|
+
setAppBackend(null);
|
|
673
|
+
expect(getAppBackend()).not.toBeNull();
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
describe('setAppBadgeCount', () => {
|
|
678
|
+
it('forwards the count to the backend', () => {
|
|
679
|
+
const backend = fakeBackend();
|
|
680
|
+
setAppBackend(backend);
|
|
681
|
+
expect(setAppBadgeCount(5)).toBe(true);
|
|
682
|
+
expect(backend.badgeCount).toBe(5);
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
it('returns a boolean from the web backend without throwing', () => {
|
|
686
|
+
expect(typeof setAppBadgeCount(2)).toBe('boolean');
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
describe('setAppDockBadge', () => {
|
|
691
|
+
it('forwards the badge text to the backend', () => {
|
|
692
|
+
const backend = fakeBackend();
|
|
693
|
+
setAppBackend(backend);
|
|
694
|
+
setAppDockBadge('3');
|
|
695
|
+
expect(backend.badge).toBe('3');
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
describe('setAppDockMenu', () => {
|
|
700
|
+
it('forwards the menu items to the backend', () => {
|
|
701
|
+
const backend = fakeBackend();
|
|
702
|
+
setAppBackend(backend);
|
|
703
|
+
const items: readonly MenuItemTemplate[] = [{ id: 'new', label: 'New' }];
|
|
704
|
+
setAppDockMenu(items);
|
|
705
|
+
expect(backend.dockMenuItems).toBe(1);
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
describe('setAppLoginItem', () => {
|
|
710
|
+
it('updates the login item and returns true when supported', () => {
|
|
711
|
+
const backend = fakeBackend();
|
|
712
|
+
setAppBackend(backend);
|
|
713
|
+
const settings: Readonly<AppLoginItemLike> = { openAtLogin: true, openAsHidden: false };
|
|
714
|
+
expect(setAppLoginItem(settings)).toBe(true);
|
|
715
|
+
expect(backend.loginItem.openAtLogin).toBe(true);
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
it('returns false on the web backend', () => {
|
|
719
|
+
expect(setAppLoginItem({ openAtLogin: true })).toBe(false);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
describe('setAppName', () => {
|
|
724
|
+
it('updates the name via the backend and returns true', () => {
|
|
725
|
+
const backend = fakeBackend();
|
|
726
|
+
setAppBackend(backend);
|
|
727
|
+
expect(setAppName('MyApp')).toBe(true);
|
|
728
|
+
expect(backend.name).toBe('MyApp');
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('returns false on the web backend', () => {
|
|
732
|
+
expect(setAppName('X')).toBe(false);
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
describe('setAppUserModelId', () => {
|
|
737
|
+
it('forwards the ID to the backend and returns true', () => {
|
|
738
|
+
const backend = fakeBackend();
|
|
739
|
+
setAppBackend(backend);
|
|
740
|
+
expect(setAppUserModelId('com.example.app')).toBe(true);
|
|
741
|
+
expect(backend.userModelId).toBe('com.example.app');
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it('returns false on the web backend', () => {
|
|
745
|
+
expect(setAppUserModelId('X')).toBe(false);
|
|
746
|
+
});
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
describe('showApp', () => {
|
|
750
|
+
it('shows the app and returns true from the backend', () => {
|
|
751
|
+
const backend = fakeBackend();
|
|
752
|
+
setAppBackend(backend);
|
|
753
|
+
hideApp();
|
|
754
|
+
expect(showApp()).toBe(true);
|
|
755
|
+
expect(backend.hidden).toBe(false);
|
|
756
|
+
});
|
|
757
|
+
});
|