@flighthq/permissions 0.3.1-next.975.01aea94 → 0.4.0-edge.1908.751021c
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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/permission.d.ts +5 -1
- package/dist/permission.d.ts.map +1 -1
- package/dist/permission.js +87 -51
- package/dist/permission.js.map +1 -1
- package/package.json +3 -3
- package/src/enablePermissionGuards.test.ts +11 -2
- package/src/permission.test.ts +83 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { disablePermissionGuards, enablePermissionGuards, explainPermissionState, getPermissionState, getPermissionStates, requestPermission, } from './contract';
|
|
1
|
+
export { explainPermissionBackend, disablePermissionGuards, enablePermissionGuards, explainPermissionState, getPermissionState, getPermissionStates, requestPermission, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { disablePermissionGuards, enablePermissionGuards, explainPermissionState, getPermissionState, getPermissionStates, requestPermission, } from './contract';
|
|
1
|
+
export { explainPermissionBackend, disablePermissionGuards, enablePermissionGuards, explainPermissionState, getPermissionState, getPermissionStates, requestPermission, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
package/dist/permission.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type { PermissionBackend, PermissionName, PermissionRequestFallbackGuard, PermissionState, PermissionStateExplanation } from '@flighthq/types/contract';
|
|
1
|
+
import type { BackendExplanation, PermissionBackend, PermissionName, PermissionRequestFallbackGuard, PermissionState, PermissionStateExplanation } from '@flighthq/types/contract';
|
|
2
2
|
export declare function createWebPermissionBackend(): PermissionBackend;
|
|
3
|
+
export declare function explainPermissionBackend(): BackendExplanation;
|
|
3
4
|
export declare function explainPermissionState(name: PermissionName): Promise<PermissionStateExplanation>;
|
|
4
5
|
export declare function getPermissionBackend(): PermissionBackend;
|
|
5
6
|
export declare function getPermissionState(name: PermissionName): Promise<PermissionState>;
|
|
6
7
|
export declare function getPermissionStates(names: readonly PermissionName[]): Promise<PermissionState[]>;
|
|
8
|
+
export declare function installPermissionHostBackend(backend: PermissionBackend): void;
|
|
9
|
+
export declare function observePermissionHostResult(operation: string, succeeded: boolean): void;
|
|
7
10
|
export declare function requestPermission(name: PermissionName): Promise<PermissionState>;
|
|
11
|
+
export declare function resetPermissionBackendForTest(): void;
|
|
8
12
|
export declare function setPermissionBackend(backend: PermissionBackend | null): void;
|
|
9
13
|
export declare function setPermissionRequestFallbackGuard(guard: PermissionRequestFallbackGuard | null): void;
|
|
10
14
|
//# sourceMappingURL=permission.d.ts.map
|
package/dist/permission.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,8BAA8B,EAC9B,eAAe,EACf,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAOlC,wBAAgB,0BAA0B,IAAI,iBAAiB,CAS9D;AAUD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAiBtG;
|
|
1
|
+
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,8BAA8B,EAC9B,eAAe,EACf,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAOlC,wBAAgB,0BAA0B,IAAI,iBAAiB,CAS9D;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAa7D;AAUD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAiBtG;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAEjF;AAMD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAEhG;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAM7E;AAED,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAKvF;AAKD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAEhF;AAED,wBAAgB,6BAA6B,IAAI,IAAI,CAKpD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAE5E;AAKD,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,8BAA8B,GAAG,IAAI,GAAG,IAAI,CAEpG"}
|
package/dist/permission.js
CHANGED
|
@@ -13,6 +13,20 @@ export function createWebPermissionBackend() {
|
|
|
13
13
|
},
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
export function explainPermissionBackend() {
|
|
17
|
+
if (_custom !== null) {
|
|
18
|
+
return { conflict: _hostConflict, layer: 'custom', operation: null, viability: 'unobserved' };
|
|
19
|
+
}
|
|
20
|
+
if (_host !== null) {
|
|
21
|
+
return {
|
|
22
|
+
conflict: _hostConflict,
|
|
23
|
+
layer: 'host',
|
|
24
|
+
operation: _hostObservation !== null ? _hostObservation.operation : null,
|
|
25
|
+
viability: _hostObservation !== null ? _hostObservation.viability : 'unobserved',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return { conflict: false, layer: 'host-not-enabled', operation: null, viability: 'unobserved' };
|
|
29
|
+
}
|
|
16
30
|
// Reports WHY a state read came out the way it did, for the caller who got 'prompt' and cannot act on it.
|
|
17
31
|
// That one value means three different things — undecided, unqueryable name, or no Permissions API at all —
|
|
18
32
|
// and they have opposite remedies. Runs the same read as getPermissionState and reports which branch the
|
|
@@ -23,7 +37,7 @@ export function createWebPermissionBackend() {
|
|
|
23
37
|
// 'unqueryable' from 'unsupported', because only it knows whether navigator.permissions exists.
|
|
24
38
|
export async function explainPermissionState(name) {
|
|
25
39
|
const backend = getPermissionBackend();
|
|
26
|
-
if (
|
|
40
|
+
if (_custom !== null) {
|
|
27
41
|
const state = await backend.getState(name);
|
|
28
42
|
return { name, source: state === 'prompt' ? 'undecided' : 'decided', state };
|
|
29
43
|
}
|
|
@@ -40,13 +54,8 @@ export async function explainPermissionState(name) {
|
|
|
40
54
|
return { name, source: 'unqueryable', state: readWebFallbackPermissionState(name) };
|
|
41
55
|
}
|
|
42
56
|
}
|
|
43
|
-
// The active permission backend, lazily defaulting to the web backend. There is always a backend.
|
|
44
57
|
export function getPermissionBackend() {
|
|
45
|
-
|
|
46
|
-
_backend = createWebPermissionBackend();
|
|
47
|
-
_webBackend = _backend;
|
|
48
|
-
}
|
|
49
|
-
return _backend;
|
|
58
|
+
return _custom ?? _host ?? _sentinel;
|
|
50
59
|
}
|
|
51
60
|
// Resolves the current state of a named permission without prompting. Returns 'granted', 'denied',
|
|
52
61
|
// or 'prompt' (not yet decided); 'prompt' is also the sentinel for an unqueryable name.
|
|
@@ -60,15 +69,34 @@ export function getPermissionState(name) {
|
|
|
60
69
|
export function getPermissionStates(names) {
|
|
61
70
|
return Promise.all(names.map((name) => getPermissionState(name)));
|
|
62
71
|
}
|
|
72
|
+
export function installPermissionHostBackend(backend) {
|
|
73
|
+
if (_host !== null) {
|
|
74
|
+
if (_host !== backend)
|
|
75
|
+
_hostConflict = true;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
_host = backend;
|
|
79
|
+
}
|
|
80
|
+
export function observePermissionHostResult(operation, succeeded) {
|
|
81
|
+
_hostObservation = {
|
|
82
|
+
operation,
|
|
83
|
+
viability: succeeded ? 'available' : 'runtime-api-unavailable',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
63
86
|
// Requests a named permission, triggering the OS prompt where the platform supports it. Resolves to
|
|
64
87
|
// the resulting state; a name with no request path falls back to a plain state query, and a missing
|
|
65
88
|
// API resolves to a sentinel rather than throwing.
|
|
66
89
|
export function requestPermission(name) {
|
|
67
90
|
return getPermissionBackend().request(name);
|
|
68
91
|
}
|
|
69
|
-
|
|
92
|
+
export function resetPermissionBackendForTest() {
|
|
93
|
+
_custom = null;
|
|
94
|
+
_host = null;
|
|
95
|
+
_hostConflict = false;
|
|
96
|
+
_hostObservation = null;
|
|
97
|
+
}
|
|
70
98
|
export function setPermissionBackend(backend) {
|
|
71
|
-
|
|
99
|
+
_custom = backend;
|
|
72
100
|
}
|
|
73
101
|
// Diagnostics seam for the silent degradation in requestPermission: a name with no concrete request path
|
|
74
102
|
// resolves to a plain state query, so no prompt ever appears and the caller cannot tell. Core stays
|
|
@@ -76,11 +104,6 @@ export function setPermissionBackend(backend) {
|
|
|
76
104
|
export function setPermissionRequestFallbackGuard(guard) {
|
|
77
105
|
_requestFallbackGuard = guard;
|
|
78
106
|
}
|
|
79
|
-
let _backend = null;
|
|
80
|
-
let _requestFallbackGuard = null;
|
|
81
|
-
// Identity of the lazily-created default, so explainPermissionState can tell whether the active backend is
|
|
82
|
-
// the web one whose branches it knows how to describe.
|
|
83
|
-
let _webBackend = null;
|
|
84
107
|
// The per-name fallback state when the Permissions API is absent or the name is unqueryable.
|
|
85
108
|
// notifications is still readable synchronously via Notification.permission ('default' → 'prompt');
|
|
86
109
|
// every other name resolves to the 'prompt' sentinel.
|
|
@@ -92,6 +115,36 @@ function readWebFallbackPermissionState(name) {
|
|
|
92
115
|
}
|
|
93
116
|
return 'prompt';
|
|
94
117
|
}
|
|
118
|
+
function getWebNotification() {
|
|
119
|
+
return typeof Notification !== 'undefined' ? Notification : null;
|
|
120
|
+
}
|
|
121
|
+
function getWebNotificationPermission() {
|
|
122
|
+
const notification = getWebNotification();
|
|
123
|
+
if (notification === null)
|
|
124
|
+
return null;
|
|
125
|
+
return notification.permission ?? null;
|
|
126
|
+
}
|
|
127
|
+
function getWebPermissions() {
|
|
128
|
+
if (typeof navigator === 'undefined')
|
|
129
|
+
return null;
|
|
130
|
+
const permissions = navigator.permissions ?? null;
|
|
131
|
+
if (permissions === null || typeof permissions.query !== 'function')
|
|
132
|
+
return null;
|
|
133
|
+
return permissions;
|
|
134
|
+
}
|
|
135
|
+
let _custom = null;
|
|
136
|
+
let _host = null;
|
|
137
|
+
let _hostConflict = false;
|
|
138
|
+
let _hostObservation = null;
|
|
139
|
+
let _requestFallbackGuard = null;
|
|
140
|
+
const _sentinel = {
|
|
141
|
+
getState() {
|
|
142
|
+
return Promise.resolve('prompt');
|
|
143
|
+
},
|
|
144
|
+
request() {
|
|
145
|
+
return Promise.resolve('prompt');
|
|
146
|
+
},
|
|
147
|
+
};
|
|
95
148
|
async function readWebPermissionState(name) {
|
|
96
149
|
const permissions = getWebPermissions();
|
|
97
150
|
if (permissions !== null) {
|
|
@@ -136,18 +189,6 @@ async function requestWebMediaPermission(kind) {
|
|
|
136
189
|
return 'denied';
|
|
137
190
|
}
|
|
138
191
|
}
|
|
139
|
-
async function requestWebNotificationPermission() {
|
|
140
|
-
const notification = getWebNotification();
|
|
141
|
-
if (notification === null || typeof notification.requestPermission !== 'function')
|
|
142
|
-
return 'prompt';
|
|
143
|
-
try {
|
|
144
|
-
const result = await notification.requestPermission();
|
|
145
|
-
return result === 'default' ? 'prompt' : result;
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return 'prompt';
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
192
|
// Observes a MIDI access grant purely for the prompt; the access object is discarded, mirroring the
|
|
152
193
|
// discarded geolocation position. sysex is not requested — that is a strictly larger prompt than the
|
|
153
194
|
// 'midi' permission this name denotes.
|
|
@@ -165,6 +206,26 @@ async function requestWebMidiPermission() {
|
|
|
165
206
|
return 'denied';
|
|
166
207
|
}
|
|
167
208
|
}
|
|
209
|
+
async function requestWebNotificationPermission() {
|
|
210
|
+
const notification = getWebNotification();
|
|
211
|
+
if (notification === null || typeof notification.requestPermission !== 'function')
|
|
212
|
+
return 'prompt';
|
|
213
|
+
try {
|
|
214
|
+
const result = await notification.requestPermission();
|
|
215
|
+
return result === 'default' ? 'prompt' : result;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return 'prompt';
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function requestWebPermission(name) {
|
|
222
|
+
const router = _permissionRequestRouters[name];
|
|
223
|
+
if (router !== undefined)
|
|
224
|
+
return await router();
|
|
225
|
+
const state = await readWebPermissionState(name);
|
|
226
|
+
_requestFallbackGuard?.(name, state);
|
|
227
|
+
return state;
|
|
228
|
+
}
|
|
168
229
|
async function requestWebPersistentStoragePermission() {
|
|
169
230
|
const storage = getWebStorageManager();
|
|
170
231
|
if (storage === null || typeof storage.persist !== 'function')
|
|
@@ -196,14 +257,6 @@ async function requestWebScreenWakeLockPermission() {
|
|
|
196
257
|
return 'denied';
|
|
197
258
|
}
|
|
198
259
|
}
|
|
199
|
-
async function requestWebPermission(name) {
|
|
200
|
-
const router = _permissionRequestRouters[name];
|
|
201
|
-
if (router !== undefined)
|
|
202
|
-
return await router();
|
|
203
|
-
const state = await readWebPermissionState(name);
|
|
204
|
-
_requestFallbackGuard?.(name, state);
|
|
205
|
-
return state;
|
|
206
|
-
}
|
|
207
260
|
// Stops every track of a granted media stream, releasing the device. Guards a missing getTracks so a
|
|
208
261
|
// stubbed or partial stream never throws.
|
|
209
262
|
function stopMediaStreamTracks(stream) {
|
|
@@ -224,23 +277,6 @@ function getWebMediaDevices() {
|
|
|
224
277
|
return null;
|
|
225
278
|
return navigator.mediaDevices ?? null;
|
|
226
279
|
}
|
|
227
|
-
function getWebNotification() {
|
|
228
|
-
return typeof Notification !== 'undefined' ? Notification : null;
|
|
229
|
-
}
|
|
230
|
-
function getWebNotificationPermission() {
|
|
231
|
-
const notification = getWebNotification();
|
|
232
|
-
if (notification === null)
|
|
233
|
-
return null;
|
|
234
|
-
return notification.permission ?? null;
|
|
235
|
-
}
|
|
236
|
-
function getWebPermissions() {
|
|
237
|
-
if (typeof navigator === 'undefined')
|
|
238
|
-
return null;
|
|
239
|
-
const permissions = navigator.permissions ?? null;
|
|
240
|
-
if (permissions === null || typeof permissions.query !== 'function')
|
|
241
|
-
return null;
|
|
242
|
-
return permissions;
|
|
243
|
-
}
|
|
244
280
|
function getWebStorageManager() {
|
|
245
281
|
if (typeof navigator === 'undefined')
|
|
246
282
|
return null;
|
package/dist/permission.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission.js","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"permission.js","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/permissions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-edge.1908.751021c",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/log": "0.
|
|
42
|
-
"@flighthq/types": "0.
|
|
41
|
+
"@flighthq/log": "0.4.0-edge.1908.751021c",
|
|
42
|
+
"@flighthq/types": "0.4.0-edge.1908.751021c"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.3.0"
|
|
@@ -3,7 +3,13 @@ import type { LogEntry } from '@flighthq/types/contract';
|
|
|
3
3
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
|
|
5
5
|
import { arePermissionGuardsEnabled, disablePermissionGuards, enablePermissionGuards } from './enablePermissionGuards';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
createWebPermissionBackend,
|
|
8
|
+
installPermissionHostBackend,
|
|
9
|
+
requestPermission,
|
|
10
|
+
resetPermissionBackendForTest,
|
|
11
|
+
setPermissionBackend,
|
|
12
|
+
} from './permission';
|
|
7
13
|
|
|
8
14
|
function captureLog(run: () => Promise<void>): Promise<readonly LogEntry[]> {
|
|
9
15
|
const sink = createMemoryLogSink(8);
|
|
@@ -20,7 +26,7 @@ function messageOf(entry: Readonly<LogEntry>): string {
|
|
|
20
26
|
|
|
21
27
|
afterEach(() => {
|
|
22
28
|
disablePermissionGuards();
|
|
23
|
-
|
|
29
|
+
resetPermissionBackendForTest();
|
|
24
30
|
vi.unstubAllGlobals();
|
|
25
31
|
});
|
|
26
32
|
|
|
@@ -37,6 +43,7 @@ describe('arePermissionGuardsEnabled', () => {
|
|
|
37
43
|
describe('disablePermissionGuards', () => {
|
|
38
44
|
it('returns the silent degradation to silence', async () => {
|
|
39
45
|
vi.stubGlobal('navigator', { permissions: { query: async () => ({ state: 'prompt' }) } });
|
|
46
|
+
installPermissionHostBackend(createWebPermissionBackend());
|
|
40
47
|
enablePermissionGuards();
|
|
41
48
|
disablePermissionGuards();
|
|
42
49
|
|
|
@@ -53,6 +60,7 @@ describe('enablePermissionGuards', () => {
|
|
|
53
60
|
// ONE test in order, and every test in this file uses a distinct permission name.
|
|
54
61
|
it('WARNS that a request showed no prompt, then suppresses the repeat', async () => {
|
|
55
62
|
vi.stubGlobal('navigator', { permissions: { query: async () => ({ state: 'prompt' }) } });
|
|
63
|
+
installPermissionHostBackend(createWebPermissionBackend());
|
|
56
64
|
enablePermissionGuards();
|
|
57
65
|
|
|
58
66
|
const entries = await captureLog(async () => {
|
|
@@ -72,6 +80,7 @@ describe('enablePermissionGuards', () => {
|
|
|
72
80
|
it('stays SILENT for a name that has a real request path', async () => {
|
|
73
81
|
vi.stubGlobal('navigator', { permissions: { query: async () => ({ state: 'prompt' }) } });
|
|
74
82
|
vi.stubGlobal('Notification', { permission: 'default', requestPermission: async () => 'granted' });
|
|
83
|
+
installPermissionHostBackend(createWebPermissionBackend());
|
|
75
84
|
enablePermissionGuards();
|
|
76
85
|
|
|
77
86
|
const entries = await captureLog(async () => {
|
package/src/permission.test.ts
CHANGED
|
@@ -7,9 +7,13 @@ import {
|
|
|
7
7
|
getPermissionBackend,
|
|
8
8
|
getPermissionState,
|
|
9
9
|
getPermissionStates,
|
|
10
|
+
installPermissionHostBackend,
|
|
10
11
|
requestPermission,
|
|
12
|
+
resetPermissionBackendForTest,
|
|
11
13
|
setPermissionBackend,
|
|
12
14
|
setPermissionRequestFallbackGuard,
|
|
15
|
+
explainPermissionBackend,
|
|
16
|
+
observePermissionHostResult,
|
|
13
17
|
} from './permission';
|
|
14
18
|
|
|
15
19
|
// A recording mock backend: relays a fixed state and captures the last name each method saw.
|
|
@@ -200,6 +204,34 @@ describe('createWebPermissionBackend', () => {
|
|
|
200
204
|
});
|
|
201
205
|
});
|
|
202
206
|
|
|
207
|
+
describe('explainPermissionBackend', () => {
|
|
208
|
+
afterEach(() => resetPermissionBackendForTest());
|
|
209
|
+
|
|
210
|
+
it('reports host-not-enabled when no backend is installed', () => {
|
|
211
|
+
resetPermissionBackendForTest();
|
|
212
|
+
const explanation = explainPermissionBackend();
|
|
213
|
+
expect(explanation.layer).toBe('host-not-enabled');
|
|
214
|
+
expect(explanation.conflict).toBe(false);
|
|
215
|
+
expect(explanation.viability).toBe('unobserved');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('reports custom layer when a custom backend is set', () => {
|
|
219
|
+
setPermissionBackend(fakeBackend('granted'));
|
|
220
|
+
expect(explainPermissionBackend().layer).toBe('custom');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('reports host layer when a host backend is installed', () => {
|
|
224
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
225
|
+
expect(explainPermissionBackend().layer).toBe('host');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('reports conflict when two different host backends are installed', () => {
|
|
229
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
230
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
231
|
+
expect(explainPermissionBackend().conflict).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
203
235
|
describe('explainPermissionState', () => {
|
|
204
236
|
afterEach(() => {
|
|
205
237
|
setPermissionBackend(null);
|
|
@@ -287,6 +319,43 @@ describe('getPermissionStates', () => {
|
|
|
287
319
|
});
|
|
288
320
|
});
|
|
289
321
|
|
|
322
|
+
describe('installPermissionHostBackend', () => {
|
|
323
|
+
afterEach(() => resetPermissionBackendForTest());
|
|
324
|
+
|
|
325
|
+
it('installs a host backend that getPermissionBackend returns', () => {
|
|
326
|
+
const backend = fakeBackend('granted');
|
|
327
|
+
installPermissionHostBackend(backend);
|
|
328
|
+
expect(getPermissionBackend()).toBe(backend);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('is first-host-wins: a second different backend sets conflict', () => {
|
|
332
|
+
const first = fakeBackend('granted');
|
|
333
|
+
const second = fakeBackend('granted');
|
|
334
|
+
installPermissionHostBackend(first);
|
|
335
|
+
installPermissionHostBackend(second);
|
|
336
|
+
expect(getPermissionBackend()).toBe(first);
|
|
337
|
+
expect(explainPermissionBackend().conflict).toBe(true);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
describe('observePermissionHostResult', () => {
|
|
342
|
+
afterEach(() => resetPermissionBackendForTest());
|
|
343
|
+
|
|
344
|
+
it('records a successful observation', () => {
|
|
345
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
346
|
+
observePermissionHostResult('getState', true);
|
|
347
|
+
const explanation = explainPermissionBackend();
|
|
348
|
+
expect(explanation.operation).toBe('getState');
|
|
349
|
+
expect(explanation.viability).toBe('available');
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('records a failed observation', () => {
|
|
353
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
354
|
+
observePermissionHostResult('getState', false);
|
|
355
|
+
expect(explainPermissionBackend().viability).toBe('runtime-api-unavailable');
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
290
359
|
describe('requestPermission', () => {
|
|
291
360
|
it('dispatches to the active backend and relays the resolved state', async () => {
|
|
292
361
|
const backend = fakeBackend('granted');
|
|
@@ -296,6 +365,18 @@ describe('requestPermission', () => {
|
|
|
296
365
|
});
|
|
297
366
|
});
|
|
298
367
|
|
|
368
|
+
describe('resetPermissionBackendForTest', () => {
|
|
369
|
+
it('clears all backend slots', () => {
|
|
370
|
+
setPermissionBackend(fakeBackend('granted'));
|
|
371
|
+
installPermissionHostBackend(fakeBackend('granted'));
|
|
372
|
+
observePermissionHostResult('getState', true);
|
|
373
|
+
resetPermissionBackendForTest();
|
|
374
|
+
expect(explainPermissionBackend().layer).toBe('host-not-enabled');
|
|
375
|
+
expect(explainPermissionBackend().conflict).toBe(false);
|
|
376
|
+
expect(explainPermissionBackend().viability).toBe('unobserved');
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
299
380
|
describe('setPermissionBackend', () => {
|
|
300
381
|
it('installs a backend and restores a fresh distinct web default on null', () => {
|
|
301
382
|
const backend = fakeBackend('prompt');
|
|
@@ -311,7 +392,7 @@ describe('setPermissionBackend', () => {
|
|
|
311
392
|
describe('setPermissionRequestFallbackGuard', () => {
|
|
312
393
|
afterEach(() => {
|
|
313
394
|
setPermissionRequestFallbackGuard(null);
|
|
314
|
-
|
|
395
|
+
resetPermissionBackendForTest();
|
|
315
396
|
vi.unstubAllGlobals();
|
|
316
397
|
});
|
|
317
398
|
|
|
@@ -323,6 +404,7 @@ describe('setPermissionRequestFallbackGuard', () => {
|
|
|
323
404
|
permission: 'default',
|
|
324
405
|
requestPermission: () => Promise.resolve('granted'),
|
|
325
406
|
});
|
|
407
|
+
installPermissionHostBackend(createWebPermissionBackend());
|
|
326
408
|
setPermissionRequestFallbackGuard((name) => seen.push(name));
|
|
327
409
|
|
|
328
410
|
expect(await requestPermission('push')).toBe('prompt');
|