@chipmobilesdk/rn-camera 0.2.0 → 0.2.1
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/CHANGELOG.md +107 -93
- package/README.md +364 -364
- package/package.json +44 -47
- package/skills/sdk-rn-camera/SKILL.md +74 -75
- package/src/config/types.ts +143 -149
- package/src/core/capabilities.ts +41 -44
- package/src/core/captureController.ts +120 -120
- package/src/core/controller.ts +516 -518
- package/src/core/sessionMachine.ts +104 -111
- package/src/diagnostics/errors.ts +92 -92
- package/src/diagnostics/logger.ts +26 -31
- package/src/geometry/coordinateMapping.ts +129 -129
- package/src/index.ts +78 -78
- package/src/react/CameraPreview.tsx +126 -125
- package/src/react/VisionCameraFeed.tsx +177 -178
- package/src/react/hooks.ts +56 -58
- package/src/storage/artifactStore.ts +141 -141
- package/src/testing/testCameraAdapter.ts +256 -256
package/package.json
CHANGED
|
@@ -1,47 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@chipmobilesdk/rn-camera",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"private": false,
|
|
5
|
-
"license": "UNLICENSED",
|
|
6
|
-
"main": "src/index.ts",
|
|
7
|
-
"types": "src/index.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./src/index.ts",
|
|
11
|
-
"react-native": "./src/index.ts",
|
|
12
|
-
"default": "./src/index.ts"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"src/index.ts",
|
|
17
|
-
"src/config",
|
|
18
|
-
"src/core",
|
|
19
|
-
"src/diagnostics",
|
|
20
|
-
"src/geometry",
|
|
21
|
-
"src/native",
|
|
22
|
-
"src/permissions",
|
|
23
|
-
"src/react",
|
|
24
|
-
"src/storage",
|
|
25
|
-
"src/testing",
|
|
26
|
-
"skills",
|
|
27
|
-
"README.md",
|
|
28
|
-
"CHANGELOG.md"
|
|
29
|
-
],
|
|
30
|
-
"sideEffects": false,
|
|
31
|
-
"scripts": {
|
|
32
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
-
"pack:
|
|
34
|
-
},
|
|
35
|
-
"peerDependencies": {
|
|
36
|
-
"react": ">=19",
|
|
37
|
-
"react-native": ">=0.85",
|
|
38
|
-
"react-native-vision-camera": ">=5.1.1"
|
|
39
|
-
},
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"registry": "https://registry.npmjs.org/"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@chipmobilesdk/rn-camera",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.ts",
|
|
11
|
+
"react-native": "./src/index.ts",
|
|
12
|
+
"default": "./src/index.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src/index.ts",
|
|
17
|
+
"src/config",
|
|
18
|
+
"src/core",
|
|
19
|
+
"src/diagnostics",
|
|
20
|
+
"src/geometry",
|
|
21
|
+
"src/native",
|
|
22
|
+
"src/permissions",
|
|
23
|
+
"src/react",
|
|
24
|
+
"src/storage",
|
|
25
|
+
"src/testing",
|
|
26
|
+
"skills",
|
|
27
|
+
"README.md",
|
|
28
|
+
"CHANGELOG.md"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"scripts": {
|
|
32
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"pack:check": "npm pack --dry-run"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": ">=19",
|
|
37
|
+
"react-native": ">=0.85",
|
|
38
|
+
"react-native-vision-camera": ">=5.1.1"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"registry": "https://registry.npmjs.org/"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,75 +1,74 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sdk-rn-camera
|
|
3
|
-
description: "Camera capture via @chipmobilesdk/rn-camera: controller, VisionCamera engine, permissions, artifact storage, hardware-free testing. Use when adding capture/preview, handling camera permissions, storing captures, or writing camera tests."
|
|
4
|
-
metadata:
|
|
5
|
-
package: "@chipmobilesdk/rn-camera"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- `
|
|
51
|
-
- `
|
|
52
|
-
- `
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
55
|
-
- `
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
| Native config | `## Native capability`, `## Compatibility` |
|
|
1
|
+
---
|
|
2
|
+
name: sdk-rn-camera
|
|
3
|
+
description: "Camera capture via @chipmobilesdk/rn-camera: controller, VisionCamera engine, permissions, artifact storage, hardware-free testing. Use when adding capture/preview, handling camera permissions, storing captures, or writing camera tests."
|
|
4
|
+
metadata:
|
|
5
|
+
package: "@chipmobilesdk/rn-camera"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
disable-model-invocation: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# @chipmobilesdk/rn-camera
|
|
11
|
+
|
|
12
|
+
Camera capture built on VisionCamera, with an injectable engine, a permission port,
|
|
13
|
+
artifact storage for captures, and a test double that needs no hardware.
|
|
14
|
+
|
|
15
|
+
## Use this when
|
|
16
|
+
|
|
17
|
+
- Adding a capture or preview screen
|
|
18
|
+
- Requesting/handling camera permissions
|
|
19
|
+
- Persisting captured images and managing their lifetime
|
|
20
|
+
- Writing tests for a camera flow
|
|
21
|
+
- Answering a privacy/data-safety question about captures
|
|
22
|
+
|
|
23
|
+
## Release the camera on unmount
|
|
24
|
+
|
|
25
|
+
The camera is a hardware resource. It MUST be released when the screen loses focus or
|
|
26
|
+
unmounts — a retained camera drains battery and blocks other screens from acquiring it.
|
|
27
|
+
Verify teardown explicitly; this is the most common defect in camera code. Prefer
|
|
28
|
+
`useCameraController`: it disposes on unmount and survives StrictMode remounts. A
|
|
29
|
+
disposed controller rejects `start`/`capture` with `notReady`.
|
|
30
|
+
|
|
31
|
+
## Captures expire
|
|
32
|
+
|
|
33
|
+
`DEFAULT_TEMPORARY_TTL_MS` exists because cache-stored captures are temporary. If a
|
|
34
|
+
capture must survive, pass a `destination` (app-owned) or move it out deliberately —
|
|
35
|
+
do not assume persistence. Give the controller a `store` whose `FileSystemBridge`
|
|
36
|
+
implements `move()`, or VisionCamera captures stay outside it and `cleanup()` cannot
|
|
37
|
+
delete them. See `## Data behaviour` for what this means for App Privacy disclosures.
|
|
38
|
+
|
|
39
|
+
## Test without hardware
|
|
40
|
+
|
|
41
|
+
`createTestCamera`, `createMemoryFileSystem` and `DEFAULT_TEST_CAPABILITIES` let camera
|
|
42
|
+
flows be unit-tested with no device. Use these rather than mocking VisionCamera by hand —
|
|
43
|
+
see `## Testing without hardware`.
|
|
44
|
+
|
|
45
|
+
## Public API
|
|
46
|
+
|
|
47
|
+
Runtime:
|
|
48
|
+
|
|
49
|
+
- `createCameraController(...)`, `useCameraController`, `useCameraState`
|
|
50
|
+
- `createVisionCameraEngine(...)` — the default `CameraEngine`; injectable
|
|
51
|
+
- `createVisionCameraPermissions(...)` — implements `PermissionPort`
|
|
52
|
+
- `createArtifactStore(...)`, `createCacheArtifactStore(...)`
|
|
53
|
+
- `CameraPreview` (+ `CameraPreviewProps`)
|
|
54
|
+
- `CameraError`, `isCameraError`, `redact` — `redact` strips sensitive paths before logging
|
|
55
|
+
- Testing: `createTestCamera`, `createMemoryFileSystem`, `DEFAULT_TEST_CAPABILITIES`
|
|
56
|
+
|
|
57
|
+
Types: `CameraEngine`, `EngineOptions`, `PermissionPort`, `ArtifactStore`,
|
|
58
|
+
`FileSystemBridge`, `StoreOptions`, `CameraErrorCode`, `CameraLogEvent`,
|
|
59
|
+
`CameraLogEventType`, `CameraLogger`
|
|
60
|
+
|
|
61
|
+
Always pass camera log payloads through `redact` before logging.
|
|
62
|
+
|
|
63
|
+
## Where the detail lives
|
|
64
|
+
|
|
65
|
+
Read one section of `node_modules/@chipmobilesdk/rn-camera/README.md` (~340 lines):
|
|
66
|
+
|
|
67
|
+
| Need | Section |
|
|
68
|
+
|---|---|
|
|
69
|
+
| First integration | `## Install (consuming app)`, `## Quick start` |
|
|
70
|
+
| Engine / port / store model | `## Core concepts` |
|
|
71
|
+
| Tests | `## Testing without hardware` |
|
|
72
|
+
| Failure handling | `## Errors`, `## Diagnostics` |
|
|
73
|
+
| Privacy disclosures | `## Data behaviour (for App Privacy and Data Safety)` |
|
|
74
|
+
| Native config | `## Native capability`, `## Compatibility` |
|
package/src/config/types.ts
CHANGED
|
@@ -1,149 +1,143 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public type contract for @chipmobilesdk/rn-camera.
|
|
3
|
-
*
|
|
4
|
-
* Every type here is re-exported from `src/index.ts` (LIB-002/LIB-003). See
|
|
5
|
-
* `specs/006-rn-camera-package/contracts/public-api.md` for the authoritative
|
|
6
|
-
* contract and `data-model.md` for the rules behind each field.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/** Camera authorization status. Seven distinguishable outcomes (FR-004). */
|
|
10
|
-
export type CameraPermissionState =
|
|
11
|
-
| 'undetermined'
|
|
12
|
-
| 'requesting'
|
|
13
|
-
| 'granted'
|
|
14
|
-
| 'denied'
|
|
15
|
-
| 'deniedPermanently'
|
|
16
|
-
| 'unavailable'
|
|
17
|
-
| 'unsupported';
|
|
18
|
-
|
|
19
|
-
export type CameraPosition = 'front' | 'back';
|
|
20
|
-
export type FlashMode = 'auto' | 'on' | 'off';
|
|
21
|
-
export type ResizeMode = 'cover' | 'contain';
|
|
22
|
-
export type ArtifactOwnership = 'packageTemporary' | 'appOwned';
|
|
23
|
-
|
|
24
|
-
export type SessionStatus =
|
|
25
|
-
| '
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
readonly
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
readonly
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
readonly
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
readonly
|
|
85
|
-
readonly
|
|
86
|
-
readonly
|
|
87
|
-
readonly
|
|
88
|
-
readonly
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
readonly
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
readonly
|
|
108
|
-
readonly
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
readonly
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
readonly
|
|
119
|
-
readonly
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
readonly
|
|
126
|
-
readonly
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
readonly
|
|
132
|
-
readonly
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
*/
|
|
145
|
-
export interface CameraErrorLike {
|
|
146
|
-
readonly code: string;
|
|
147
|
-
readonly recoverable: boolean;
|
|
148
|
-
readonly message: string;
|
|
149
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Public type contract for @chipmobilesdk/rn-camera.
|
|
3
|
+
*
|
|
4
|
+
* Every type here is re-exported from `src/index.ts` (LIB-002/LIB-003). See
|
|
5
|
+
* `specs/006-rn-camera-package/contracts/public-api.md` for the authoritative
|
|
6
|
+
* contract and `data-model.md` for the rules behind each field.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Camera authorization status. Seven distinguishable outcomes (FR-004). */
|
|
10
|
+
export type CameraPermissionState =
|
|
11
|
+
| 'undetermined'
|
|
12
|
+
| 'requesting'
|
|
13
|
+
| 'granted'
|
|
14
|
+
| 'denied'
|
|
15
|
+
| 'deniedPermanently'
|
|
16
|
+
| 'unavailable'
|
|
17
|
+
| 'unsupported';
|
|
18
|
+
|
|
19
|
+
export type CameraPosition = 'front' | 'back';
|
|
20
|
+
export type FlashMode = 'auto' | 'on' | 'off';
|
|
21
|
+
export type ResizeMode = 'cover' | 'contain';
|
|
22
|
+
export type ArtifactOwnership = 'packageTemporary' | 'appOwned';
|
|
23
|
+
|
|
24
|
+
export type SessionStatus =
|
|
25
|
+
'idle' | 'starting' | 'active' | 'paused' | 'stopping' | 'stopped' | 'error';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A metadata field the platform could not determine (FR-022). Distinct from an
|
|
29
|
+
* absent property so consumers can tell "not reported" from "not asked for".
|
|
30
|
+
*/
|
|
31
|
+
export interface Unavailable {
|
|
32
|
+
readonly available: false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Known<T> {
|
|
36
|
+
readonly available: true;
|
|
37
|
+
readonly value: T;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type Maybe<T> = Known<T> | Unavailable;
|
|
41
|
+
|
|
42
|
+
export function known<T>(value: T): Known<T> {
|
|
43
|
+
return { available: true, value };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function unavailable(): Unavailable {
|
|
47
|
+
return { available: false };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** What this device and platform actually support (FR-033). */
|
|
51
|
+
export interface CapabilityProfile {
|
|
52
|
+
readonly availablePositions: readonly CameraPosition[];
|
|
53
|
+
readonly hasFlash: boolean;
|
|
54
|
+
readonly hasTorch: boolean;
|
|
55
|
+
readonly supportsOrientationChange: boolean;
|
|
56
|
+
readonly hasCameraHardware: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Instruction to take one still photo. Carries no business context (FR-002). */
|
|
60
|
+
export interface CaptureRequest {
|
|
61
|
+
/** 0..1, clamped to what the device supports. */
|
|
62
|
+
readonly quality?: number;
|
|
63
|
+
/** Longest edge in pixels, applied within device limits. */
|
|
64
|
+
readonly maxDimension?: number;
|
|
65
|
+
readonly cameraPosition?: CameraPosition;
|
|
66
|
+
readonly flashMode?: FlashMode;
|
|
67
|
+
/**
|
|
68
|
+
* Supplying a destination makes the result `appOwned` and the package writes
|
|
69
|
+
* directly there. Omitting it makes the result `packageTemporary` (FR-026a).
|
|
70
|
+
* This is the only way ownership is decided.
|
|
71
|
+
*/
|
|
72
|
+
readonly destination?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Result of one successful capture. Always a file reference (FR-021/FR-021a). */
|
|
76
|
+
export interface CapturedImage {
|
|
77
|
+
/** File URI or handle. Never a base64 string, never an in-memory buffer. */
|
|
78
|
+
readonly uri: string;
|
|
79
|
+
readonly mimeType: string;
|
|
80
|
+
readonly width: number;
|
|
81
|
+
readonly height: number;
|
|
82
|
+
readonly timestamp: number;
|
|
83
|
+
readonly cameraPosition: CameraPosition;
|
|
84
|
+
readonly ownership: ArtifactOwnership;
|
|
85
|
+
readonly effectiveQuality: number;
|
|
86
|
+
readonly effectiveMaxDimension: Maybe<number>;
|
|
87
|
+
readonly fileSize: Maybe<number>;
|
|
88
|
+
readonly orientation: Maybe<number>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Options accepted when starting a session. */
|
|
92
|
+
export interface StartOptions {
|
|
93
|
+
readonly cameraPosition?: CameraPosition;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Relationship between captured-image space and on-screen preview space.
|
|
98
|
+
* Consumed by the pure mapping functions in `geometry/coordinateMapping`.
|
|
99
|
+
*/
|
|
100
|
+
export interface PreviewGeometry {
|
|
101
|
+
readonly imageWidth: number;
|
|
102
|
+
readonly imageHeight: number;
|
|
103
|
+
readonly previewWidth: number;
|
|
104
|
+
readonly previewHeight: number;
|
|
105
|
+
readonly resizeMode: ResizeMode;
|
|
106
|
+
/** Clockwise degrees: 0, 90, 180, or 270. */
|
|
107
|
+
readonly orientation: number;
|
|
108
|
+
readonly isMirrored: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface Point {
|
|
112
|
+
readonly x: number;
|
|
113
|
+
readonly y: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface Rect {
|
|
117
|
+
readonly x: number;
|
|
118
|
+
readonly y: number;
|
|
119
|
+
readonly width: number;
|
|
120
|
+
readonly height: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Aggregate observable state exposed by the controller. */
|
|
124
|
+
export interface CameraState {
|
|
125
|
+
readonly session: SessionStatus;
|
|
126
|
+
readonly permission: CameraPermissionState;
|
|
127
|
+
readonly capabilities: CapabilityProfile | null;
|
|
128
|
+
readonly cameraPosition: CameraPosition;
|
|
129
|
+
readonly flashMode: FlashMode;
|
|
130
|
+
readonly torchEnabled: boolean;
|
|
131
|
+
readonly capturing: boolean;
|
|
132
|
+
readonly error: CameraErrorLike | null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Structural view of a CameraError, kept here so `CameraState` does not create
|
|
137
|
+
* a circular import with the diagnostics module.
|
|
138
|
+
*/
|
|
139
|
+
export interface CameraErrorLike {
|
|
140
|
+
readonly code: string;
|
|
141
|
+
readonly recoverable: boolean;
|
|
142
|
+
readonly message: string;
|
|
143
|
+
}
|
package/src/core/capabilities.ts
CHANGED
|
@@ -1,44 +1,41 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capability gating (FR-033, FR-034).
|
|
3
|
-
*
|
|
4
|
-
* An unsupported capability must produce an `unsupportedCapability` result, not
|
|
5
|
-
* an unexpected failure — that is what lets an app hide a control instead of
|
|
6
|
-
* discovering at tap time that the device has no flash.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { CameraPosition, CapabilityProfile, FlashMode } from '../config/types';
|
|
10
|
-
import { CameraError } from '../diagnostics/errors';
|
|
11
|
-
|
|
12
|
-
export const EMPTY_CAPABILITIES: CapabilityProfile = {
|
|
13
|
-
availablePositions: [],
|
|
14
|
-
hasFlash: false,
|
|
15
|
-
hasTorch: false,
|
|
16
|
-
supportsOrientationChange: false,
|
|
17
|
-
hasCameraHardware: false,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export function supportsPosition(
|
|
21
|
-
profile: CapabilityProfile | null,
|
|
22
|
-
position: CameraPosition,
|
|
23
|
-
): boolean {
|
|
24
|
-
return profile?.availablePositions.includes(position) ?? false;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** `off` is always legal — it is the absence of flash, not a use of it. */
|
|
28
|
-
export function supportsFlashMode(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
throw new CameraError('unsupportedCapability', `Not supported on this device: ${what}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Capability gating (FR-033, FR-034).
|
|
3
|
+
*
|
|
4
|
+
* An unsupported capability must produce an `unsupportedCapability` result, not
|
|
5
|
+
* an unexpected failure — that is what lets an app hide a control instead of
|
|
6
|
+
* discovering at tap time that the device has no flash.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CameraPosition, CapabilityProfile, FlashMode } from '../config/types';
|
|
10
|
+
import { CameraError } from '../diagnostics/errors';
|
|
11
|
+
|
|
12
|
+
export const EMPTY_CAPABILITIES: CapabilityProfile = {
|
|
13
|
+
availablePositions: [],
|
|
14
|
+
hasFlash: false,
|
|
15
|
+
hasTorch: false,
|
|
16
|
+
supportsOrientationChange: false,
|
|
17
|
+
hasCameraHardware: false,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function supportsPosition(
|
|
21
|
+
profile: CapabilityProfile | null,
|
|
22
|
+
position: CameraPosition,
|
|
23
|
+
): boolean {
|
|
24
|
+
return profile?.availablePositions.includes(position) ?? false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** `off` is always legal — it is the absence of flash, not a use of it. */
|
|
28
|
+
export function supportsFlashMode(profile: CapabilityProfile | null, mode: FlashMode): boolean {
|
|
29
|
+
return mode === 'off' ? true : profile?.hasFlash === true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function supportsTorch(profile: CapabilityProfile | null): boolean {
|
|
33
|
+
return profile?.hasTorch === true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Throws the uniform unsupported error so every gate reads the same way. */
|
|
37
|
+
export function assertSupported(supported: boolean, what: string): void {
|
|
38
|
+
if (!supported) {
|
|
39
|
+
throw new CameraError('unsupportedCapability', `Not supported on this device: ${what}`);
|
|
40
|
+
}
|
|
41
|
+
}
|