@flighthq/webcam 0.4.0-next.1898.266773a → 0.4.0-next.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/webcam.d.ts +5 -0
- package/dist/webcam.d.ts.map +1 -1
- package/dist/webcam.js +75 -15
- package/dist/webcam.js.map +1 -1
- package/package.json +3 -3
- package/src/webcam.test.ts +81 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createWebcamStreamEntity, recordWebcamVideo, requestWebcamPermission, selectWebcamImage, takeWebcamPhoto, } from './contract';
|
|
1
|
+
export { explainWebcamBackend, createWebcamStreamEntity, recordWebcamVideo, requestWebcamPermission, selectWebcamImage, takeWebcamPhoto, } 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,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createWebcamStreamEntity, recordWebcamVideo, requestWebcamPermission, selectWebcamImage, takeWebcamPhoto, } from './contract';
|
|
1
|
+
export { explainWebcamBackend, createWebcamStreamEntity, recordWebcamVideo, requestWebcamPermission, selectWebcamImage, takeWebcamPhoto, } 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,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/webcam.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import type { BackendExplanation } from '@flighthq/types/contract';
|
|
1
2
|
import type { WebcamBackend, WebcamCaptureOptions, WebcamPhoto, WebcamVideo } from '@flighthq/types/contract';
|
|
2
3
|
export declare function createWebWebcamBackend(): WebcamBackend;
|
|
4
|
+
export declare function explainWebcamBackend(): BackendExplanation;
|
|
3
5
|
export declare function getWebcamBackend(): WebcamBackend;
|
|
6
|
+
export declare function installWebcamHostBackend(backend: WebcamBackend): void;
|
|
7
|
+
export declare function observeWebcamHostResult(operation: string, succeeded: boolean): void;
|
|
4
8
|
export declare function recordWebcamVideo(options?: Readonly<WebcamCaptureOptions>): Promise<WebcamVideo | null>;
|
|
5
9
|
export declare function requestWebcamPermission(): Promise<boolean>;
|
|
10
|
+
export declare function resetWebcamBackendForTest(): void;
|
|
6
11
|
export declare function selectWebcamImage(options?: Readonly<WebcamCaptureOptions>): Promise<WebcamPhoto | null>;
|
|
7
12
|
export declare function setWebcamBackend(backend: WebcamBackend | null): void;
|
|
8
13
|
export declare function takeWebcamPhoto(options?: Readonly<WebcamCaptureOptions>): Promise<WebcamPhoto | null>;
|
package/dist/webcam.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webcam.d.ts","sourceRoot":"","sources":["../src/webcam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAK9G,wBAAgB,sBAAsB,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"webcam.d.ts","sourceRoot":"","sources":["../src/webcam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAK9G,wBAAgB,sBAAsB,IAAI,aAAa,CAwGtD;AAED,wBAAgB,oBAAoB,IAAI,kBAAkB,CAazD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAMrE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAKnF;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAEvG;AAGD,wBAAgB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE1D;AAED,wBAAgB,yBAAyB,IAAI,IAAI,CAKhD;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAEvG;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAEpE;AAGD,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAErG"}
|
package/dist/webcam.js
CHANGED
|
@@ -6,6 +6,7 @@ export function createWebWebcamBackend() {
|
|
|
6
6
|
capture(options) {
|
|
7
7
|
return new Promise((resolve) => {
|
|
8
8
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
9
|
+
observeWebcamHostResult('capture', false);
|
|
9
10
|
resolve(null);
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
@@ -23,6 +24,7 @@ export function createWebWebcamBackend() {
|
|
|
23
24
|
}
|
|
24
25
|
const reader = new FileReader();
|
|
25
26
|
reader.onload = () => {
|
|
27
|
+
observeWebcamHostResult('capture', true);
|
|
26
28
|
resolve({
|
|
27
29
|
dataUrl: typeof reader.result === 'string' ? reader.result : '',
|
|
28
30
|
width: 0,
|
|
@@ -30,12 +32,16 @@ export function createWebWebcamBackend() {
|
|
|
30
32
|
format: file.type,
|
|
31
33
|
});
|
|
32
34
|
};
|
|
33
|
-
reader.onerror = () =>
|
|
35
|
+
reader.onerror = () => {
|
|
36
|
+
observeWebcamHostResult('capture', false);
|
|
37
|
+
resolve(null);
|
|
38
|
+
};
|
|
34
39
|
reader.readAsDataURL(file);
|
|
35
40
|
};
|
|
36
41
|
input.click();
|
|
37
42
|
}
|
|
38
43
|
catch {
|
|
44
|
+
observeWebcamHostResult('capture', false);
|
|
39
45
|
resolve(null);
|
|
40
46
|
}
|
|
41
47
|
});
|
|
@@ -43,6 +49,7 @@ export function createWebWebcamBackend() {
|
|
|
43
49
|
captureVideo(options) {
|
|
44
50
|
return new Promise((resolve) => {
|
|
45
51
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
52
|
+
observeWebcamHostResult('captureVideo', false);
|
|
46
53
|
resolve(null);
|
|
47
54
|
return;
|
|
48
55
|
}
|
|
@@ -60,46 +67,80 @@ export function createWebWebcamBackend() {
|
|
|
60
67
|
}
|
|
61
68
|
const reader = new FileReader();
|
|
62
69
|
reader.onload = () => {
|
|
70
|
+
observeWebcamHostResult('captureVideo', true);
|
|
63
71
|
resolve({
|
|
64
72
|
dataUrl: typeof reader.result === 'string' ? reader.result : '',
|
|
65
|
-
// The web file input cannot decode the clip; native hosts report a real duration.
|
|
66
73
|
duration: 0,
|
|
67
74
|
format: file.type,
|
|
68
75
|
});
|
|
69
76
|
};
|
|
70
|
-
reader.onerror = () =>
|
|
77
|
+
reader.onerror = () => {
|
|
78
|
+
observeWebcamHostResult('captureVideo', false);
|
|
79
|
+
resolve(null);
|
|
80
|
+
};
|
|
71
81
|
reader.readAsDataURL(file);
|
|
72
82
|
};
|
|
73
83
|
input.click();
|
|
74
84
|
}
|
|
75
85
|
catch {
|
|
86
|
+
observeWebcamHostResult('captureVideo', false);
|
|
76
87
|
resolve(null);
|
|
77
88
|
}
|
|
78
89
|
});
|
|
79
90
|
},
|
|
80
91
|
async requestPermission() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (typeof navigator === 'undefined')
|
|
92
|
+
if (typeof navigator === 'undefined') {
|
|
93
|
+
observeWebcamHostResult('requestPermission', false);
|
|
84
94
|
return false;
|
|
95
|
+
}
|
|
85
96
|
try {
|
|
86
97
|
const permissions = navigator.permissions;
|
|
87
|
-
if (permissions === undefined || typeof permissions.query !== 'function')
|
|
98
|
+
if (permissions === undefined || typeof permissions.query !== 'function') {
|
|
99
|
+
observeWebcamHostResult('requestPermission', false);
|
|
88
100
|
return false;
|
|
101
|
+
}
|
|
89
102
|
const status = await permissions.query({ name: 'camera' });
|
|
90
|
-
|
|
103
|
+
const granted = status.state === 'granted';
|
|
104
|
+
observeWebcamHostResult('requestPermission', granted);
|
|
105
|
+
return granted;
|
|
91
106
|
}
|
|
92
107
|
catch {
|
|
108
|
+
observeWebcamHostResult('requestPermission', false);
|
|
93
109
|
return false;
|
|
94
110
|
}
|
|
95
111
|
},
|
|
96
112
|
};
|
|
97
113
|
}
|
|
98
|
-
|
|
114
|
+
export function explainWebcamBackend() {
|
|
115
|
+
if (_custom !== null) {
|
|
116
|
+
return { conflict: _hostConflict, layer: 'custom', operation: null, viability: 'unobserved' };
|
|
117
|
+
}
|
|
118
|
+
if (_host !== null) {
|
|
119
|
+
return {
|
|
120
|
+
conflict: _hostConflict,
|
|
121
|
+
layer: 'host',
|
|
122
|
+
operation: _hostObservation !== null ? _hostObservation.operation : null,
|
|
123
|
+
viability: _hostObservation !== null ? _hostObservation.viability : 'unobserved',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return { conflict: false, layer: 'host-not-enabled', operation: null, viability: 'unobserved' };
|
|
127
|
+
}
|
|
99
128
|
export function getWebcamBackend() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
129
|
+
return _custom ?? _host ?? _sentinel;
|
|
130
|
+
}
|
|
131
|
+
export function installWebcamHostBackend(backend) {
|
|
132
|
+
if (_host !== null) {
|
|
133
|
+
if (_host !== backend)
|
|
134
|
+
_hostConflict = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
_host = backend;
|
|
138
|
+
}
|
|
139
|
+
export function observeWebcamHostResult(operation, succeeded) {
|
|
140
|
+
_hostObservation = {
|
|
141
|
+
operation,
|
|
142
|
+
viability: succeeded ? 'available' : 'runtime-api-unavailable',
|
|
143
|
+
};
|
|
103
144
|
}
|
|
104
145
|
// Records a video from the device camera. Resolves null when cancelled, denied, or unavailable.
|
|
105
146
|
export function recordWebcamVideo(options) {
|
|
@@ -109,17 +150,36 @@ export function recordWebcamVideo(options) {
|
|
|
109
150
|
export function requestWebcamPermission() {
|
|
110
151
|
return getWebcamBackend().requestPermission();
|
|
111
152
|
}
|
|
153
|
+
export function resetWebcamBackendForTest() {
|
|
154
|
+
_custom = null;
|
|
155
|
+
_host = null;
|
|
156
|
+
_hostConflict = false;
|
|
157
|
+
_hostObservation = null;
|
|
158
|
+
}
|
|
112
159
|
// Picks an existing image from the photo library. Resolves null when cancelled or unavailable.
|
|
113
160
|
export function selectWebcamImage(options) {
|
|
114
161
|
return getWebcamBackend().capture({ ...options, source: 'photos' });
|
|
115
162
|
}
|
|
116
|
-
// Installs a native host camera backend; pass null to fall back to the web default.
|
|
117
163
|
export function setWebcamBackend(backend) {
|
|
118
|
-
|
|
164
|
+
_custom = backend;
|
|
119
165
|
}
|
|
120
166
|
// Captures a photo from the device camera. Resolves null when cancelled, denied, or unavailable.
|
|
121
167
|
export function takeWebcamPhoto(options) {
|
|
122
168
|
return getWebcamBackend().capture({ ...options, source: 'camera' });
|
|
123
169
|
}
|
|
124
|
-
let
|
|
170
|
+
let _custom = null;
|
|
171
|
+
let _host = null;
|
|
172
|
+
let _hostConflict = false;
|
|
173
|
+
let _hostObservation = null;
|
|
174
|
+
const _sentinel = {
|
|
175
|
+
async capture() {
|
|
176
|
+
return null;
|
|
177
|
+
},
|
|
178
|
+
async captureVideo() {
|
|
179
|
+
return null;
|
|
180
|
+
},
|
|
181
|
+
async requestPermission() {
|
|
182
|
+
return false;
|
|
183
|
+
},
|
|
184
|
+
};
|
|
125
185
|
//# sourceMappingURL=webcam.js.map
|
package/dist/webcam.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webcam.js","sourceRoot":"","sources":["../src/webcam.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webcam.js","sourceRoot":"","sources":["../src/webcam.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/webcam",
|
|
3
|
-
"version": "0.4.0-next.
|
|
3
|
+
"version": "0.4.0-next.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/entity": "0.4.0-next.
|
|
42
|
-
"@flighthq/types": "0.4.0-next.
|
|
41
|
+
"@flighthq/entity": "0.4.0-next.1908.751021c",
|
|
42
|
+
"@flighthq/types": "0.4.0-next.1908.751021c"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.3.0"
|
package/src/webcam.test.ts
CHANGED
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
selectWebcamImage,
|
|
9
9
|
setWebcamBackend,
|
|
10
10
|
takeWebcamPhoto,
|
|
11
|
+
explainWebcamBackend,
|
|
12
|
+
installWebcamHostBackend,
|
|
13
|
+
observeWebcamHostResult,
|
|
14
|
+
resetWebcamBackendForTest,
|
|
11
15
|
} from './webcam';
|
|
12
16
|
|
|
13
17
|
function fakeBackend(): WebcamBackend & { lastOptions: WebcamCaptureOptions | null } {
|
|
@@ -36,6 +40,34 @@ describe('createWebWebcamBackend', () => {
|
|
|
36
40
|
});
|
|
37
41
|
});
|
|
38
42
|
|
|
43
|
+
describe('explainWebcamBackend', () => {
|
|
44
|
+
afterEach(() => resetWebcamBackendForTest());
|
|
45
|
+
|
|
46
|
+
it('reports host-not-enabled when no backend is installed', () => {
|
|
47
|
+
resetWebcamBackendForTest();
|
|
48
|
+
const explanation = explainWebcamBackend();
|
|
49
|
+
expect(explanation.layer).toBe('host-not-enabled');
|
|
50
|
+
expect(explanation.conflict).toBe(false);
|
|
51
|
+
expect(explanation.viability).toBe('unobserved');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('reports custom layer when a custom backend is set', () => {
|
|
55
|
+
setWebcamBackend(fakeBackend());
|
|
56
|
+
expect(explainWebcamBackend().layer).toBe('custom');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('reports host layer when a host backend is installed', () => {
|
|
60
|
+
installWebcamHostBackend(fakeBackend());
|
|
61
|
+
expect(explainWebcamBackend().layer).toBe('host');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('reports conflict when two different host backends are installed', () => {
|
|
65
|
+
installWebcamHostBackend(fakeBackend());
|
|
66
|
+
installWebcamHostBackend(fakeBackend());
|
|
67
|
+
expect(explainWebcamBackend().conflict).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
39
71
|
describe('getWebcamBackend', () => {
|
|
40
72
|
it('falls back to a web backend', () => {
|
|
41
73
|
expect(getWebcamBackend()).not.toBeNull();
|
|
@@ -48,6 +80,43 @@ describe('getWebcamBackend', () => {
|
|
|
48
80
|
});
|
|
49
81
|
});
|
|
50
82
|
|
|
83
|
+
describe('installWebcamHostBackend', () => {
|
|
84
|
+
afterEach(() => resetWebcamBackendForTest());
|
|
85
|
+
|
|
86
|
+
it('installs a host backend that getWebcamBackend returns', () => {
|
|
87
|
+
const backend = fakeBackend();
|
|
88
|
+
installWebcamHostBackend(backend);
|
|
89
|
+
expect(getWebcamBackend()).toBe(backend);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('is first-host-wins: a second different backend sets conflict', () => {
|
|
93
|
+
const first = fakeBackend();
|
|
94
|
+
const second = fakeBackend();
|
|
95
|
+
installWebcamHostBackend(first);
|
|
96
|
+
installWebcamHostBackend(second);
|
|
97
|
+
expect(getWebcamBackend()).toBe(first);
|
|
98
|
+
expect(explainWebcamBackend().conflict).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('observeWebcamHostResult', () => {
|
|
103
|
+
afterEach(() => resetWebcamBackendForTest());
|
|
104
|
+
|
|
105
|
+
it('records a successful observation', () => {
|
|
106
|
+
installWebcamHostBackend(fakeBackend());
|
|
107
|
+
observeWebcamHostResult('capture', true);
|
|
108
|
+
const explanation = explainWebcamBackend();
|
|
109
|
+
expect(explanation.operation).toBe('capture');
|
|
110
|
+
expect(explanation.viability).toBe('available');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('records a failed observation', () => {
|
|
114
|
+
installWebcamHostBackend(fakeBackend());
|
|
115
|
+
observeWebcamHostResult('capture', false);
|
|
116
|
+
expect(explainWebcamBackend().viability).toBe('runtime-api-unavailable');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
51
120
|
describe('recordWebcamVideo', () => {
|
|
52
121
|
it('captures video with the camera source', async () => {
|
|
53
122
|
const backend = fakeBackend();
|
|
@@ -74,6 +143,18 @@ describe('requestWebcamPermission', () => {
|
|
|
74
143
|
});
|
|
75
144
|
});
|
|
76
145
|
|
|
146
|
+
describe('resetWebcamBackendForTest', () => {
|
|
147
|
+
it('clears all backend slots', () => {
|
|
148
|
+
setWebcamBackend(fakeBackend());
|
|
149
|
+
installWebcamHostBackend(fakeBackend());
|
|
150
|
+
observeWebcamHostResult('capture', true);
|
|
151
|
+
resetWebcamBackendForTest();
|
|
152
|
+
expect(explainWebcamBackend().layer).toBe('host-not-enabled');
|
|
153
|
+
expect(explainWebcamBackend().conflict).toBe(false);
|
|
154
|
+
expect(explainWebcamBackend().viability).toBe('unobserved');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
77
158
|
describe('selectWebcamImage', () => {
|
|
78
159
|
it('captures with the photos source', async () => {
|
|
79
160
|
const backend = fakeBackend();
|