@jupitermetalabs/face-zk-sdk 0.3.4 → 0.3.7
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/README.md +46 -1
- package/assets/face-guidance/pose-guidance.js.txt +4 -2
- package/assets/liveness/liveness.js.txt +3 -0
- package/dist/FaceZkSdk.d.ts +69 -0
- package/dist/FaceZkSdk.js +136 -0
- package/dist/assets/face-guidance/pose-guidance.js.txt +4 -2
- package/dist/assets/liveness/liveness.js.txt +3 -0
- package/dist/assets/onnx/ort-min.d.ts +1 -0
- package/dist/assets/onnx/ort-min.js +11 -0
- package/dist/config/defaults.d.ts +51 -0
- package/dist/config/defaults.js +61 -0
- package/dist/config/types.d.ts +169 -0
- package/dist/config/types.js +17 -0
- package/dist/core/enrollment-core.d.ts +70 -0
- package/dist/core/enrollment-core.js +206 -0
- package/dist/core/idGenerator.d.ts +11 -0
- package/dist/core/idGenerator.js +32 -0
- package/dist/core/matching.d.ts +69 -0
- package/dist/core/matching.js +101 -0
- package/dist/core/types.d.ts +379 -0
- package/dist/core/types.js +37 -0
- package/dist/core/verification-core.d.ts +120 -0
- package/dist/core/verification-core.js +442 -0
- package/dist/core/zk-core.d.ts +69 -0
- package/dist/core/zk-core.js +244 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +51 -0
- package/dist/react-native/adapters/faceEmbeddingProvider.d.ts +38 -0
- package/dist/react-native/adapters/faceEmbeddingProvider.js +45 -0
- package/dist/react-native/adapters/imageDataProvider.d.ts +53 -0
- package/dist/react-native/adapters/imageDataProvider.js +134 -0
- package/dist/react-native/adapters/livenessProvider.d.ts +133 -0
- package/dist/react-native/adapters/livenessProvider.js +150 -0
- package/dist/react-native/adapters/zkProofEngine-webview.d.ts +73 -0
- package/dist/react-native/adapters/zkProofEngine-webview.js +135 -0
- package/dist/react-native/bundledRuntimeAssets.d.ts +39 -0
- package/dist/react-native/bundledRuntimeAssets.js +44 -0
- package/dist/react-native/components/FacePoseGuidanceWebView.d.ts +30 -0
- package/dist/react-native/components/FacePoseGuidanceWebView.js +530 -0
- package/dist/react-native/components/LivenessWebView.d.ts +39 -0
- package/dist/react-native/components/LivenessWebView.js +386 -0
- package/dist/react-native/components/OnnxRuntimeWebView.d.ts +58 -0
- package/dist/react-native/components/OnnxRuntimeWebView.js +518 -0
- package/dist/react-native/components/ZkProofWebView.d.ts +59 -0
- package/dist/react-native/components/ZkProofWebView.js +297 -0
- package/dist/react-native/dependencies.d.ts +144 -0
- package/dist/react-native/dependencies.js +130 -0
- package/dist/react-native/hooks/useOnnxLoader.d.ts +37 -0
- package/dist/react-native/hooks/useOnnxLoader.js +74 -0
- package/dist/react-native/hooks/useWasmLoader.d.ts +30 -0
- package/dist/react-native/hooks/useWasmLoader.js +158 -0
- package/dist/react-native/index.d.ts +61 -0
- package/dist/react-native/index.js +144 -0
- package/dist/react-native/services/FaceRecognition.d.ts +92 -0
- package/dist/react-native/services/FaceRecognition.js +674 -0
- package/dist/react-native/ui/FaceZkVerificationFlow.d.ts +97 -0
- package/dist/react-native/ui/FaceZkVerificationFlow.js +477 -0
- package/dist/react-native/ui/ReferenceEnrollmentFlow.d.ts +72 -0
- package/dist/react-native/ui/ReferenceEnrollmentFlow.js +369 -0
- package/dist/react-native/utils/faceAlignment.d.ts +37 -0
- package/dist/react-native/utils/faceAlignment.js +186 -0
- package/dist/react-native/utils/modelInitialisationChecks.d.ts +36 -0
- package/dist/react-native/utils/modelInitialisationChecks.js +128 -0
- package/dist/react-native/utils/resolveModelUri.d.ts +55 -0
- package/dist/react-native/utils/resolveModelUri.js +211 -0
- package/dist/react-native/utils/resolveRuntimeAsset.d.ts +25 -0
- package/dist/react-native/utils/resolveRuntimeAsset.js +94 -0
- package/dist/react-native/utils/resolveUiConfig.d.ts +41 -0
- package/dist/react-native/utils/resolveUiConfig.js +81 -0
- package/dist/storage/defaultStorageAdapter.d.ts +44 -0
- package/dist/storage/defaultStorageAdapter.js +344 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/face-zk.config.example.js +10 -3
- package/package.json +2 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 JupiterMeta Labs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Face+ZK SDK – Default Config Values
|
|
18
|
+
*
|
|
19
|
+
* Default CDN base URL and model filenames used by `npx face-zk setup`
|
|
20
|
+
* and as fallback URLs when a model source only provides a relative path.
|
|
21
|
+
*/
|
|
22
|
+
import type { FaceZkSetupConfig } from "./types";
|
|
23
|
+
/** Canonical model filenames matching what's tracked in the SDK repo. */
|
|
24
|
+
export declare const DEFAULT_MODEL_FILES: {
|
|
25
|
+
readonly detection: "det_500m.onnx";
|
|
26
|
+
readonly recognition: "w600k_mbf.onnx";
|
|
27
|
+
readonly antispoof: "antispoof.onnx";
|
|
28
|
+
readonly ageGender: "genderage.onnx";
|
|
29
|
+
readonly wasm: "zk_face_wasm_bg.wasm";
|
|
30
|
+
readonly zkWorkerHtml: "zk-worker.html";
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Default setup config used when no face-zk.config.js is found in the project.
|
|
34
|
+
* The source URL is a placeholder — replace it with your own CDN before use.
|
|
35
|
+
*/
|
|
36
|
+
export declare const DEFAULT_SETUP_CONFIG: FaceZkSetupConfig;
|
|
37
|
+
/**
|
|
38
|
+
* Build full absolute CDN URLs for all required models.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} base - The base CDN URL (e.g. from sdkConfig or environment).
|
|
41
|
+
* @param {FaceZkSetupConfig["models"]["files"]} [files] - Optional static file name overrides.
|
|
42
|
+
* @returns {Record<string, string>} A dictionary of fully qualified URIs ready for pre-fetching.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildModelUrls(base: string, files?: FaceZkSetupConfig["models"]["files"]): {
|
|
45
|
+
detection: string;
|
|
46
|
+
recognition: string;
|
|
47
|
+
antispoof: string;
|
|
48
|
+
ageGender: string;
|
|
49
|
+
wasm: string;
|
|
50
|
+
zkWorkerHtml: string;
|
|
51
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 JupiterMeta Labs
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.DEFAULT_SETUP_CONFIG = exports.DEFAULT_MODEL_FILES = void 0;
|
|
19
|
+
exports.buildModelUrls = buildModelUrls;
|
|
20
|
+
/** Canonical model filenames matching what's tracked in the SDK repo. */
|
|
21
|
+
exports.DEFAULT_MODEL_FILES = {
|
|
22
|
+
detection: "det_500m.onnx",
|
|
23
|
+
recognition: "w600k_mbf.onnx",
|
|
24
|
+
antispoof: "antispoof.onnx",
|
|
25
|
+
ageGender: "genderage.onnx",
|
|
26
|
+
wasm: "zk_face_wasm_bg.wasm",
|
|
27
|
+
zkWorkerHtml: "zk-worker.html",
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Default setup config used when no face-zk.config.js is found in the project.
|
|
31
|
+
* The source URL is a placeholder — replace it with your own CDN before use.
|
|
32
|
+
*/
|
|
33
|
+
exports.DEFAULT_SETUP_CONFIG = {
|
|
34
|
+
models: {
|
|
35
|
+
source: "https://cdn.your-company.com/face-zk/v1",
|
|
36
|
+
dest: "./assets/face-zk/",
|
|
37
|
+
},
|
|
38
|
+
features: {
|
|
39
|
+
liveness: true,
|
|
40
|
+
zk: true,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Build full absolute CDN URLs for all required models.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} base - The base CDN URL (e.g. from sdkConfig or environment).
|
|
47
|
+
* @param {FaceZkSetupConfig["models"]["files"]} [files] - Optional static file name overrides.
|
|
48
|
+
* @returns {Record<string, string>} A dictionary of fully qualified URIs ready for pre-fetching.
|
|
49
|
+
*/
|
|
50
|
+
function buildModelUrls(base, files) {
|
|
51
|
+
const f = { ...exports.DEFAULT_MODEL_FILES, ...files };
|
|
52
|
+
const b = base.replace(/\/$/, ""); // strip trailing slash
|
|
53
|
+
return {
|
|
54
|
+
detection: `${b}/${f.detection}`,
|
|
55
|
+
recognition: `${b}/${f.recognition}`,
|
|
56
|
+
antispoof: `${b}/${f.antispoof}`,
|
|
57
|
+
ageGender: `${b}/${f.ageGender}`,
|
|
58
|
+
wasm: `${b}/${f.wasm}`,
|
|
59
|
+
zkWorkerHtml: `${b}/${f.zkWorkerHtml}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 JupiterMeta Labs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Face+ZK SDK – Config Types
|
|
18
|
+
*
|
|
19
|
+
* Defines the configuration interfaces for SDK initialization and CLI setup.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Describes where to find a model binary. Provide exactly one of:
|
|
23
|
+
* - `module` – result of require('./path/to/model.onnx'); bundled by Metro at build time (fastest)
|
|
24
|
+
* - `url` – remote CDN/HTTP URL; downloaded and cached on first use
|
|
25
|
+
* - `localUri` – pre-resolved local file:// URI (e.g., already on device)
|
|
26
|
+
*/
|
|
27
|
+
export interface ModelSource {
|
|
28
|
+
/** Result of require('./assets/model.onnx') – bundled asset, resolved by Metro. */
|
|
29
|
+
module?: any;
|
|
30
|
+
/** Remote URL to download from at runtime (stored persistently in FileSystem.documentDirectory). */
|
|
31
|
+
url?: string;
|
|
32
|
+
/** Already-resolved local file URI (e.g., file:///data/user/0/.../model.onnx). */
|
|
33
|
+
localUri?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface FaceZkModelsConfig {
|
|
36
|
+
/** Face detection model – det_500m.onnx */
|
|
37
|
+
detection: ModelSource;
|
|
38
|
+
/** Face recognition / embedding model – w600k_mbf.onnx */
|
|
39
|
+
recognition: ModelSource;
|
|
40
|
+
/** Anti-spoof model – antispoof.onnx (optional; falls back to bundled) */
|
|
41
|
+
antispoof?: ModelSource;
|
|
42
|
+
/** Age/Gender model – genderage.onnx (optional) */
|
|
43
|
+
ageGender?: ModelSource;
|
|
44
|
+
/** ZK proof WASM binary – zk_face_wasm_bg.wasm (optional; falls back to bundled) */
|
|
45
|
+
wasm?: ModelSource;
|
|
46
|
+
/** ZK proof worker HTML – zk-worker.html (optional; falls back to bundled) */
|
|
47
|
+
zkWorkerHtml?: ModelSource;
|
|
48
|
+
}
|
|
49
|
+
export interface FaceZkFeaturesConfig {
|
|
50
|
+
/** Enable liveness / anti-spoof checks. Default: true */
|
|
51
|
+
liveness?: boolean;
|
|
52
|
+
/** Enable ZK proof generation. Default: true */
|
|
53
|
+
zk?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Optional overrides for runtime WebView assets (HTML, JS bundles, WASM binaries).
|
|
57
|
+
* Every field defaults to the SDK's bundled copy when omitted.
|
|
58
|
+
*
|
|
59
|
+
* Use this to supply CDN-hosted or pre-downloaded versions of any asset so that
|
|
60
|
+
* the SDK ships without forcing Metro to bundle large files into the consumer app.
|
|
61
|
+
*
|
|
62
|
+
* Each field accepts the same `ModelSource` union as the model fields:
|
|
63
|
+
* - `{ module: require('./myAsset.html') }` – Metro-bundled asset
|
|
64
|
+
* - `{ url: 'https://cdn.example.com/v1/liveness.html' }` – downloaded & cached
|
|
65
|
+
* - `{ localUri: 'file:///...' }` – pre-resolved on-device URI
|
|
66
|
+
*/
|
|
67
|
+
export interface FaceZkRuntimeAssetsConfig {
|
|
68
|
+
/** ort.min.js text content — inlined into the ONNX Runtime WebView */
|
|
69
|
+
ortJs?: ModelSource;
|
|
70
|
+
/** ort-wasm-simd.wasm binary — sent to the ONNX Runtime WebView as base64 */
|
|
71
|
+
ortWasm?: ModelSource;
|
|
72
|
+
/** liveness/index.html — the liveness WebView page */
|
|
73
|
+
livenessHtml?: ModelSource;
|
|
74
|
+
/** liveness/antispoof.js — anti-spoof inference script */
|
|
75
|
+
antispoofJs?: ModelSource;
|
|
76
|
+
/** liveness/liveness.js — liveness challenge script */
|
|
77
|
+
livenessJs?: ModelSource;
|
|
78
|
+
/** mediapipe/face_mesh.js — MediaPipe Face Mesh JS bundle */
|
|
79
|
+
mediapipeFaceMeshJs?: ModelSource;
|
|
80
|
+
/** mediapipe/face_mesh_solution_simd_wasm_bin.wasm — SIMD WASM binary */
|
|
81
|
+
mediapipeSimdWasm?: ModelSource;
|
|
82
|
+
/** mediapipe/face_mesh_solution_wasm_bin.wasm — non-SIMD WASM binary */
|
|
83
|
+
mediapipeWasm?: ModelSource;
|
|
84
|
+
/** mediapipe/face_mesh_solution_packed_assets.data — packed assets blob */
|
|
85
|
+
mediapipeData?: ModelSource;
|
|
86
|
+
/** face-guidance/index.html — the face pose guidance WebView page */
|
|
87
|
+
faceGuidanceHtml?: ModelSource;
|
|
88
|
+
/** face-guidance/pose-guidance.js — pose guidance script */
|
|
89
|
+
faceGuidancePoseJs?: ModelSource;
|
|
90
|
+
/** face-guidance/face-logic.js — face detection logic script */
|
|
91
|
+
faceGuidanceLogicJs?: ModelSource;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Config passed to `FaceZkSdk.init()` at app startup.
|
|
95
|
+
*
|
|
96
|
+
* @example – bundled assets (user copies models into their app)
|
|
97
|
+
* ```ts
|
|
98
|
+
* FaceZkSdk.init({
|
|
99
|
+
* models: {
|
|
100
|
+
* detection: { module: require('./assets/face-zk/det_500m.onnx') },
|
|
101
|
+
* recognition: { module: require('./assets/face-zk/w600k_mbf.onnx') },
|
|
102
|
+
* },
|
|
103
|
+
* })
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example – CDN download (models fetched on first use)
|
|
107
|
+
* ```ts
|
|
108
|
+
* FaceZkSdk.init({
|
|
109
|
+
* models: {
|
|
110
|
+
* detection: { url: 'https://cdn.example.com/face-zk/det_500m.onnx' },
|
|
111
|
+
* recognition: { url: 'https://cdn.example.com/face-zk/w600k_mbf.onnx' },
|
|
112
|
+
* },
|
|
113
|
+
* })
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export interface FaceZkConfig {
|
|
117
|
+
models: FaceZkModelsConfig;
|
|
118
|
+
/**
|
|
119
|
+
* Optional overrides for runtime WebView assets. Every field falls back to the
|
|
120
|
+
* SDK's bundled copy when omitted. See `FaceZkRuntimeAssetsConfig` for details.
|
|
121
|
+
*/
|
|
122
|
+
runtimeAssets?: FaceZkRuntimeAssetsConfig;
|
|
123
|
+
features?: FaceZkFeaturesConfig;
|
|
124
|
+
/**
|
|
125
|
+
* Allowlist of hostnames that the SDK is permitted to download models from.
|
|
126
|
+
* Only applies to `ModelSource.url` entries — module and localUri sources
|
|
127
|
+
* are unaffected.
|
|
128
|
+
*
|
|
129
|
+
* When provided, any URL whose hostname is not in this list is rejected
|
|
130
|
+
* before a network request is made. Omitting this field disables the check
|
|
131
|
+
* (permissive — suitable for development; not recommended for production).
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* allowedDomains: ["cdn.yourcompany.com"]
|
|
135
|
+
*/
|
|
136
|
+
allowedDomains?: string[];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Shape of `face-zk.config.js` read by `npx face-zk setup`.
|
|
140
|
+
* This file is for developer tooling only – NOT read at runtime by the app.
|
|
141
|
+
*
|
|
142
|
+
* @example face-zk.config.js
|
|
143
|
+
* ```js
|
|
144
|
+
* module.exports = {
|
|
145
|
+
* models: {
|
|
146
|
+
* source: 'https://cdn.jmdt.io/face-zk/v1',
|
|
147
|
+
* dest: './assets/face-zk/',
|
|
148
|
+
* },
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export interface FaceZkSetupConfig {
|
|
153
|
+
models: {
|
|
154
|
+
/** Base URL of the model CDN (no trailing slash). */
|
|
155
|
+
source: string;
|
|
156
|
+
/** Local directory to download models into (relative to project root). */
|
|
157
|
+
dest: string;
|
|
158
|
+
/** Override individual file names if your CDN uses different names. */
|
|
159
|
+
files?: {
|
|
160
|
+
detection?: string;
|
|
161
|
+
recognition?: string;
|
|
162
|
+
antispoof?: string;
|
|
163
|
+
ageGender?: string;
|
|
164
|
+
wasm?: string;
|
|
165
|
+
zkWorkerHtml?: string;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
features?: FaceZkFeaturesConfig;
|
|
169
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 JupiterMeta Labs
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 JupiterMeta Labs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Face+ZK SDK – Enrollment Core
|
|
18
|
+
*
|
|
19
|
+
* Headless enrollment functions for creating reference templates from images.
|
|
20
|
+
* This module orchestrates the face embedding extraction and reference template creation.
|
|
21
|
+
*/
|
|
22
|
+
import type { ReferenceTemplate, EnrollmentOptions, FaceZkRuntimeConfig } from "./types";
|
|
23
|
+
/**
|
|
24
|
+
* Interface for face embedding provider.
|
|
25
|
+
* This will be implemented by platform-specific adapters (e.g., wrapping faceRecognitionService).
|
|
26
|
+
*/
|
|
27
|
+
export interface FaceEmbeddingProvider {
|
|
28
|
+
/**
|
|
29
|
+
* Process an image and extract face embedding + pose.
|
|
30
|
+
*
|
|
31
|
+
* @param imageUri URI of the image to process
|
|
32
|
+
* @returns Result containing embedding, pose, and status
|
|
33
|
+
*/
|
|
34
|
+
processImageForEmbedding(imageUri: string): Promise<{
|
|
35
|
+
status: "ok" | "no_face" | "multiple_faces" | "error";
|
|
36
|
+
embedding?: number[];
|
|
37
|
+
pose?: {
|
|
38
|
+
yaw: number;
|
|
39
|
+
pitch: number;
|
|
40
|
+
roll: number;
|
|
41
|
+
};
|
|
42
|
+
message?: string;
|
|
43
|
+
gender?: "Male" | "Female" | "Unknown";
|
|
44
|
+
age?: number;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a reference template from an image URI to be used in future verification attempts.
|
|
49
|
+
*
|
|
50
|
+
* This is the primary enrollment function. It orchestrates:
|
|
51
|
+
* 1. Image processing to extract the facial embedding and head pose via the injected `FaceEmbeddingProvider`.
|
|
52
|
+
* 2. Creation of a `ReferenceTemplate` paired with a cryptographically safe `ReferenceId`.
|
|
53
|
+
* 3. Optional persistence of the template via the configured `StorageAdapter`.
|
|
54
|
+
*
|
|
55
|
+
* **Crypto/ZK Context:** The embedding generated here acts as the ground truth. When a user authenticates later, the ZK WASM circuit will prove that their live facial embedding matches this enrolled blueprint without storing the face image itself.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} imageUri - URI of the reference image (e.g. `file://` or `content://`).
|
|
58
|
+
* @param {FaceZkRuntimeConfig} sdkConfig - Global SDK configuration requiring at least a working logger and optional storage adapter.
|
|
59
|
+
* @param {FaceEmbeddingProvider} embeddingProvider - The platform-specific adapter capable of running ONNX inference.
|
|
60
|
+
* @param {EnrollmentOptions} [options={}] - Options dictating metadata injection and whether to persist the result.
|
|
61
|
+
* @returns {Promise<ReferenceTemplate>} The enrolled identity containing the ID, embedding, and baseline pose.
|
|
62
|
+
* @throws {SdkError} Throws if no face is found, multiple faces are found, or pose estimation fails.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const template = await createReferenceFromImage(
|
|
66
|
+
* 'file:///tmp/face.jpg', config, provider, { persist: true }
|
|
67
|
+
* );
|
|
68
|
+
* console.log(`Enrolled ID: ${template.referenceId}`);
|
|
69
|
+
*/
|
|
70
|
+
export declare function createReferenceFromImage(imageUri: string, sdkConfig: FaceZkRuntimeConfig, embeddingProvider: FaceEmbeddingProvider, options?: EnrollmentOptions): Promise<ReferenceTemplate>;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 JupiterMeta Labs
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.createReferenceFromImage = createReferenceFromImage;
|
|
19
|
+
const types_1 = require("./types");
|
|
20
|
+
const idGenerator_1 = require("./idGenerator");
|
|
21
|
+
/**
|
|
22
|
+
* Creates a reference template from an image URI to be used in future verification attempts.
|
|
23
|
+
*
|
|
24
|
+
* This is the primary enrollment function. It orchestrates:
|
|
25
|
+
* 1. Image processing to extract the facial embedding and head pose via the injected `FaceEmbeddingProvider`.
|
|
26
|
+
* 2. Creation of a `ReferenceTemplate` paired with a cryptographically safe `ReferenceId`.
|
|
27
|
+
* 3. Optional persistence of the template via the configured `StorageAdapter`.
|
|
28
|
+
*
|
|
29
|
+
* **Crypto/ZK Context:** The embedding generated here acts as the ground truth. When a user authenticates later, the ZK WASM circuit will prove that their live facial embedding matches this enrolled blueprint without storing the face image itself.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} imageUri - URI of the reference image (e.g. `file://` or `content://`).
|
|
32
|
+
* @param {FaceZkRuntimeConfig} sdkConfig - Global SDK configuration requiring at least a working logger and optional storage adapter.
|
|
33
|
+
* @param {FaceEmbeddingProvider} embeddingProvider - The platform-specific adapter capable of running ONNX inference.
|
|
34
|
+
* @param {EnrollmentOptions} [options={}] - Options dictating metadata injection and whether to persist the result.
|
|
35
|
+
* @returns {Promise<ReferenceTemplate>} The enrolled identity containing the ID, embedding, and baseline pose.
|
|
36
|
+
* @throws {SdkError} Throws if no face is found, multiple faces are found, or pose estimation fails.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const template = await createReferenceFromImage(
|
|
40
|
+
* 'file:///tmp/face.jpg', config, provider, { persist: true }
|
|
41
|
+
* );
|
|
42
|
+
* console.log(`Enrolled ID: ${template.referenceId}`);
|
|
43
|
+
*/
|
|
44
|
+
async function createReferenceFromImage(imageUri, sdkConfig, embeddingProvider, options = {}) {
|
|
45
|
+
const { metadata, persist = false } = options;
|
|
46
|
+
// Log enrollment start
|
|
47
|
+
sdkConfig.onLog?.({
|
|
48
|
+
level: "info",
|
|
49
|
+
message: "Starting reference enrollment",
|
|
50
|
+
context: { imageUri, persist },
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
// Step 1: Extract embedding + pose using the embedding provider
|
|
54
|
+
sdkConfig.onLog?.({
|
|
55
|
+
level: "debug",
|
|
56
|
+
message: "Extracting face embedding and pose",
|
|
57
|
+
context: { imageUri },
|
|
58
|
+
});
|
|
59
|
+
const result = await embeddingProvider.processImageForEmbedding(imageUri);
|
|
60
|
+
// Handle errors from embedding provider
|
|
61
|
+
if (result.status !== "ok") {
|
|
62
|
+
const errorCode = result.status === "no_face"
|
|
63
|
+
? "NO_FACE"
|
|
64
|
+
: result.status === "multiple_faces"
|
|
65
|
+
? "MULTIPLE_FACES"
|
|
66
|
+
: "SYSTEM_ERROR";
|
|
67
|
+
const error = {
|
|
68
|
+
code: errorCode,
|
|
69
|
+
message: result.message || `Face processing failed: ${result.status}`,
|
|
70
|
+
details: { stage: "embedding", status: result.status },
|
|
71
|
+
};
|
|
72
|
+
sdkConfig.onLog?.({
|
|
73
|
+
level: "error",
|
|
74
|
+
message: "Enrollment failed during face processing",
|
|
75
|
+
context: { ...error.details, code: error.code },
|
|
76
|
+
});
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
// Validate that we have embedding
|
|
80
|
+
if (!result.embedding || result.embedding.length === 0) {
|
|
81
|
+
const error = {
|
|
82
|
+
code: "SYSTEM_ERROR",
|
|
83
|
+
message: "Face processing succeeded but missing or empty embedding",
|
|
84
|
+
details: {
|
|
85
|
+
stage: "embedding",
|
|
86
|
+
hasEmbedding: !!result.embedding,
|
|
87
|
+
embeddingLength: result.embedding?.length || 0,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
sdkConfig.onLog?.({
|
|
91
|
+
level: "error",
|
|
92
|
+
message: "Enrollment failed: missing embedding",
|
|
93
|
+
context: { ...error.details, code: error.code },
|
|
94
|
+
});
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
// Validate that we have pose with all required fields
|
|
98
|
+
if (!result.pose ||
|
|
99
|
+
typeof result.pose.yaw !== "number" ||
|
|
100
|
+
typeof result.pose.pitch !== "number" ||
|
|
101
|
+
typeof result.pose.roll !== "number" ||
|
|
102
|
+
!isFinite(result.pose.yaw) ||
|
|
103
|
+
!isFinite(result.pose.pitch) ||
|
|
104
|
+
!isFinite(result.pose.roll)) {
|
|
105
|
+
const error = {
|
|
106
|
+
code: "SYSTEM_ERROR",
|
|
107
|
+
message: "Face processing succeeded but pose estimation failed or invalid",
|
|
108
|
+
details: {
|
|
109
|
+
stage: "pose_estimation",
|
|
110
|
+
hasPose: !!result.pose,
|
|
111
|
+
pose: result.pose,
|
|
112
|
+
reason: !result.pose
|
|
113
|
+
? "Pose object is null/undefined"
|
|
114
|
+
: typeof result.pose.yaw !== "number"
|
|
115
|
+
? "Yaw is not a number"
|
|
116
|
+
: typeof result.pose.pitch !== "number"
|
|
117
|
+
? "Pitch is not a number"
|
|
118
|
+
: typeof result.pose.roll !== "number"
|
|
119
|
+
? "Roll is not a number"
|
|
120
|
+
: !isFinite(result.pose.yaw) ||
|
|
121
|
+
!isFinite(result.pose.pitch) ||
|
|
122
|
+
!isFinite(result.pose.roll)
|
|
123
|
+
? "Pose contains NaN or Infinity"
|
|
124
|
+
: "Unknown error",
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
sdkConfig.onLog?.({
|
|
128
|
+
level: "error",
|
|
129
|
+
message: "Enrollment failed: invalid pose",
|
|
130
|
+
context: { ...error.details, code: error.code },
|
|
131
|
+
});
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
// Step 2: Build reference template
|
|
135
|
+
const referenceId = (0, idGenerator_1.generateReferenceId)();
|
|
136
|
+
const templateMetadata = {
|
|
137
|
+
...(metadata ?? {}),
|
|
138
|
+
sdkResponse: {
|
|
139
|
+
gender: result.gender ?? "Unknown",
|
|
140
|
+
age: result.age ?? null,
|
|
141
|
+
embeddingGenerated: true,
|
|
142
|
+
pose: result.pose,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
const template = {
|
|
146
|
+
referenceId,
|
|
147
|
+
embedding: result.embedding,
|
|
148
|
+
pose: result.pose,
|
|
149
|
+
metadata: templateMetadata,
|
|
150
|
+
};
|
|
151
|
+
sdkConfig.onLog?.({
|
|
152
|
+
level: "debug",
|
|
153
|
+
message: "Reference template created",
|
|
154
|
+
context: {
|
|
155
|
+
referenceId,
|
|
156
|
+
embeddingDim: result.embedding.length,
|
|
157
|
+
pose: result.pose,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
// Step 3: Optionally persist via storage adapter
|
|
161
|
+
if (persist && sdkConfig.storage) {
|
|
162
|
+
sdkConfig.onLog?.({
|
|
163
|
+
level: "debug",
|
|
164
|
+
message: "Persisting reference template",
|
|
165
|
+
context: { referenceId },
|
|
166
|
+
});
|
|
167
|
+
await sdkConfig.storage.saveReference(template);
|
|
168
|
+
sdkConfig.onLog?.({
|
|
169
|
+
level: "info",
|
|
170
|
+
message: "Reference template persisted successfully",
|
|
171
|
+
context: { referenceId },
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else if (persist && !sdkConfig.storage) {
|
|
175
|
+
sdkConfig.onLog?.({
|
|
176
|
+
level: "warn",
|
|
177
|
+
message: "Persist requested but no storage adapter configured, skipping persistence",
|
|
178
|
+
context: { referenceId },
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
sdkConfig.onLog?.({
|
|
182
|
+
level: "info",
|
|
183
|
+
message: "Reference enrollment completed successfully",
|
|
184
|
+
context: { referenceId },
|
|
185
|
+
});
|
|
186
|
+
return template;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// Re-throw SdkError as-is
|
|
190
|
+
if ((0, types_1.isSdkError)(error)) {
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
// Wrap unexpected errors
|
|
194
|
+
const sdkError = {
|
|
195
|
+
code: "SYSTEM_ERROR",
|
|
196
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
197
|
+
details: { stage: "enrollment", originalError: String(error) },
|
|
198
|
+
};
|
|
199
|
+
sdkConfig.onLog?.({
|
|
200
|
+
level: "error",
|
|
201
|
+
message: "Unexpected error during enrollment",
|
|
202
|
+
context: { ...sdkError.details, code: sdkError.code },
|
|
203
|
+
});
|
|
204
|
+
throw sdkError;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReferenceId } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Generates a unique reference ID using platform-native crypto.
|
|
4
|
+
* Format: ref_<12-char-ms-timestamp-hex>_<20-char-random-hex>
|
|
5
|
+
*
|
|
6
|
+
* Uses crypto.getRandomValues() — available natively in:
|
|
7
|
+
* - Node.js 15.7+ (Jest test environment)
|
|
8
|
+
* - All modern browsers
|
|
9
|
+
* - Hermes (React Native 0.71+) — no polyfill required
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateReferenceId(): ReferenceId;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateReferenceId = generateReferenceId;
|
|
4
|
+
/**
|
|
5
|
+
* Generates a unique reference ID using platform-native crypto.
|
|
6
|
+
* Format: ref_<12-char-ms-timestamp-hex>_<20-char-random-hex>
|
|
7
|
+
*
|
|
8
|
+
* Uses crypto.getRandomValues() — available natively in:
|
|
9
|
+
* - Node.js 15.7+ (Jest test environment)
|
|
10
|
+
* - All modern browsers
|
|
11
|
+
* - Hermes (React Native 0.71+) — no polyfill required
|
|
12
|
+
*/
|
|
13
|
+
function generateReferenceId() {
|
|
14
|
+
const tsHex = Date.now().toString(16).padStart(12, "0");
|
|
15
|
+
const randomBytes = new Uint8Array(10);
|
|
16
|
+
const cryptoApi = typeof globalThis !== "undefined" &&
|
|
17
|
+
globalThis.crypto &&
|
|
18
|
+
typeof globalThis.crypto.getRandomValues === "function"
|
|
19
|
+
? globalThis.crypto
|
|
20
|
+
: undefined;
|
|
21
|
+
if (cryptoApi) {
|
|
22
|
+
cryptoApi.getRandomValues(randomBytes);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Fallback for runtimes where Web Crypto is unavailable.
|
|
26
|
+
for (let i = 0; i < randomBytes.length; i += 1) {
|
|
27
|
+
randomBytes[i] = Math.floor(Math.random() * 256);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const randomHex = Array.from(randomBytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
31
|
+
return `ref_${tsHex}_${randomHex}`;
|
|
32
|
+
}
|