@chipmobilesdk/rn-camera 0.1.1 → 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 -34
- package/README.md +250 -227
- package/package.json +44 -47
- package/skills/sdk-rn-camera/SKILL.md +8 -5
- package/src/config/types.ts +143 -149
- package/src/core/capabilities.ts +41 -44
- package/src/core/captureController.ts +120 -118
- package/src/core/controller.ts +516 -385
- 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 -120
- package/src/react/VisionCameraFeed.tsx +40 -18
- package/src/react/hooks.ts +56 -44
- package/src/storage/artifactStore.ts +141 -108
- package/src/testing/testCameraAdapter.ts +256 -249
|
@@ -1,108 +1,141 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ArtifactStore port + default cache-directory adapter (FR-026..FR-029).
|
|
3
|
-
*
|
|
4
|
-
* Package-owned artifacts live in a dedicated `rn-camera` subdirectory of the
|
|
5
|
-
* platform cache directory (research R6). That dedicated prefix is what makes
|
|
6
|
-
* ownership checkable rather than advisory: `owns()` is a path-prefix test, so
|
|
7
|
-
* the package can refuse to delete anything it did not create (FR-028).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export interface ArtifactStore {
|
|
11
|
-
/** Absolute path of the package-owned temporary directory. */
|
|
12
|
-
temporaryDirectory(): string;
|
|
13
|
-
/** True only for paths the package created (FR-028). */
|
|
14
|
-
owns(uri: string): boolean;
|
|
15
|
-
/** Deletes an artifact. Resolves even if already gone (FR-027). */
|
|
16
|
-
remove(uri: string): Promise<void>;
|
|
17
|
-
/** Deletes owned artifacts older than `olderThanMs`; returns the count. */
|
|
18
|
-
sweep(olderThanMs: number): Promise<number>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
readonly
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ArtifactStore port + default cache-directory adapter (FR-026..FR-029).
|
|
3
|
+
*
|
|
4
|
+
* Package-owned artifacts live in a dedicated `rn-camera` subdirectory of the
|
|
5
|
+
* platform cache directory (research R6). That dedicated prefix is what makes
|
|
6
|
+
* ownership checkable rather than advisory: `owns()` is a path-prefix test, so
|
|
7
|
+
* the package can refuse to delete anything it did not create (FR-028).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface ArtifactStore {
|
|
11
|
+
/** Absolute path of the package-owned temporary directory. */
|
|
12
|
+
temporaryDirectory(): string;
|
|
13
|
+
/** True only for paths the package created (FR-028). */
|
|
14
|
+
owns(uri: string): boolean;
|
|
15
|
+
/** Deletes an artifact. Resolves even if already gone (FR-027). */
|
|
16
|
+
remove(uri: string): Promise<void>;
|
|
17
|
+
/** Deletes owned artifacts older than `olderThanMs`; returns the count. */
|
|
18
|
+
sweep(olderThanMs: number): Promise<number>;
|
|
19
|
+
/**
|
|
20
|
+
* Brings a fresh capture under the store and returns its managed URI: a file
|
|
21
|
+
* already inside the store is recorded as created by this process, a file
|
|
22
|
+
* anywhere else is moved in. Without this, a capture the engine wrote to its
|
|
23
|
+
* own temporary directory is never owned, so `cleanup()` refuses it and the
|
|
24
|
+
* sweep never sees it. Optional so app-written stores keep compiling.
|
|
25
|
+
*/
|
|
26
|
+
adopt?(uri: string): Promise<string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Minimal filesystem surface the adapter needs. Injectable for tests. */
|
|
30
|
+
export interface FileSystemBridge {
|
|
31
|
+
cacheDirectory(): string;
|
|
32
|
+
exists(path: string): Promise<boolean>;
|
|
33
|
+
unlink(path: string): Promise<void>;
|
|
34
|
+
list(directory: string): Promise<readonly string[]>;
|
|
35
|
+
createdAt(path: string): Promise<number>;
|
|
36
|
+
ensureDirectory(directory: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Moves a file. Needed by `adopt()` to pull a capture out of the engine's own
|
|
39
|
+
* temporary directory; a bridge without it can only adopt files already
|
|
40
|
+
* inside the store.
|
|
41
|
+
*/
|
|
42
|
+
move?(from: string, to: string): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface StoreOptions {
|
|
46
|
+
readonly fs?: FileSystemBridge;
|
|
47
|
+
/** Directory name under the cache directory. Defaults to `rn-camera`. */
|
|
48
|
+
readonly directoryName?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Normalizes separators so prefix comparison works on both platforms. */
|
|
52
|
+
function normalize(path: string): string {
|
|
53
|
+
return path.replace(/\\/g, '/').replace(/^file:\/\//, '');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createArtifactStore(
|
|
57
|
+
fs: FileSystemBridge,
|
|
58
|
+
directoryName = 'rn-camera',
|
|
59
|
+
): ArtifactStore {
|
|
60
|
+
const root = `${fs.cacheDirectory().replace(/\/$/, '')}/${directoryName}`;
|
|
61
|
+
const normalizedRoot = normalize(root);
|
|
62
|
+
// Artifacts created by this process are never swept, no matter their age.
|
|
63
|
+
const createdThisProcess = new Set<string>();
|
|
64
|
+
|
|
65
|
+
function owns(uri: string): boolean {
|
|
66
|
+
return normalize(uri).startsWith(`${normalizedRoot}/`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
temporaryDirectory() {
|
|
71
|
+
return root;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
owns,
|
|
75
|
+
|
|
76
|
+
async remove(uri) {
|
|
77
|
+
if (!owns(uri)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const path = normalize(uri);
|
|
81
|
+
// Idempotent: a missing artifact is a successful cleanup (FR-027).
|
|
82
|
+
if (await fs.exists(path)) {
|
|
83
|
+
await fs.unlink(path);
|
|
84
|
+
}
|
|
85
|
+
createdThisProcess.delete(path);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async sweep(olderThanMs) {
|
|
89
|
+
await fs.ensureDirectory(root);
|
|
90
|
+
const entries = await fs.list(root);
|
|
91
|
+
const cutoff = Date.now() - olderThanMs;
|
|
92
|
+
let removed = 0;
|
|
93
|
+
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
const path = normalize(entry);
|
|
96
|
+
if (createdThisProcess.has(path)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const created = await fs.createdAt(path);
|
|
100
|
+
if (created < cutoff) {
|
|
101
|
+
await fs.unlink(path);
|
|
102
|
+
removed += 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return removed;
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
async adopt(uri) {
|
|
109
|
+
const path = normalize(uri);
|
|
110
|
+
if (owns(uri)) {
|
|
111
|
+
createdThisProcess.add(path);
|
|
112
|
+
return uri;
|
|
113
|
+
}
|
|
114
|
+
if (!fs.move) {
|
|
115
|
+
throw new Error('This FileSystemBridge has no move(), so it cannot adopt a capture');
|
|
116
|
+
}
|
|
117
|
+
await fs.ensureDirectory(root);
|
|
118
|
+
const name = path.slice(path.lastIndexOf('/') + 1) || `capture-${Date.now()}.jpg`;
|
|
119
|
+
const target = `${root}/${name}`;
|
|
120
|
+
await fs.move(path, target);
|
|
121
|
+
createdThisProcess.add(normalize(target));
|
|
122
|
+
return uri.startsWith('file://') ? `file://${normalize(target)}` : target;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Default adapter. The concrete filesystem bridge is supplied by the native
|
|
129
|
+
* layer at runtime; it is a parameter rather than a hard import so the package
|
|
130
|
+
* takes no filesystem dependency of its own.
|
|
131
|
+
*/
|
|
132
|
+
export function createCacheArtifactStore(options: StoreOptions = {}): ArtifactStore {
|
|
133
|
+
const fs = options.fs;
|
|
134
|
+
if (!fs) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
'createCacheArtifactStore requires a FileSystemBridge. Pass `fs`, or use ' +
|
|
137
|
+
'createTestCamera() in tests.',
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return createArtifactStore(fs, options.directoryName);
|
|
141
|
+
}
|