@jupitermetalabs/face-zk-sdk 0.1.0

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.
Files changed (83) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +181 -0
  3. package/assets/README.md +22 -0
  4. package/assets/face-guidance/face-logic.js.txt +77 -0
  5. package/assets/face-guidance/index.html +173 -0
  6. package/assets/face-guidance/pose-guidance.js.txt +403 -0
  7. package/assets/liveness/antispoof.js.txt +143 -0
  8. package/assets/liveness/index.html +451 -0
  9. package/assets/liveness/liveness.js.txt +1003 -0
  10. package/assets/mediapipe/face_mesh.js.txt +131 -0
  11. package/assets/mediapipe/face_mesh_solution_packed_assets.data +0 -0
  12. package/assets/mediapipe/face_mesh_solution_simd_wasm_bin.wasm +0 -0
  13. package/assets/mediapipe/face_mesh_solution_wasm_bin.wasm +0 -0
  14. package/assets/onnx/ort-wasm-simd.wasm +0 -0
  15. package/assets/onnx/ort-wasm.wasm +0 -0
  16. package/assets/onnx/ort.min.js.txt +7 -0
  17. package/assets/wasm/zk_face_wasm_bg.wasm +0 -0
  18. package/assets/zk-worker.html +472 -0
  19. package/cli/copy-ort-assets.js +65 -0
  20. package/cli/setup.js +266 -0
  21. package/dist/FaceZkSdk.d.ts +69 -0
  22. package/dist/FaceZkSdk.js +132 -0
  23. package/dist/assets/onnx/ort-min.d.ts +1 -0
  24. package/dist/assets/onnx/ort-min.js +8 -0
  25. package/dist/config/defaults.d.ts +49 -0
  26. package/dist/config/defaults.js +55 -0
  27. package/dist/config/types.d.ts +123 -0
  28. package/dist/config/types.js +16 -0
  29. package/dist/core/enrollment-core.d.ts +68 -0
  30. package/dist/core/enrollment-core.js +202 -0
  31. package/dist/core/matching.d.ts +69 -0
  32. package/dist/core/matching.js +96 -0
  33. package/dist/core/types.d.ts +365 -0
  34. package/dist/core/types.js +34 -0
  35. package/dist/core/verification-core.d.ts +120 -0
  36. package/dist/core/verification-core.js +434 -0
  37. package/dist/core/zk-core.d.ts +69 -0
  38. package/dist/core/zk-core.js +240 -0
  39. package/dist/index.d.ts +29 -0
  40. package/dist/index.js +39 -0
  41. package/dist/react-native/adapters/faceEmbeddingProvider.d.ts +38 -0
  42. package/dist/react-native/adapters/faceEmbeddingProvider.js +41 -0
  43. package/dist/react-native/adapters/imageDataProvider.d.ts +53 -0
  44. package/dist/react-native/adapters/imageDataProvider.js +97 -0
  45. package/dist/react-native/adapters/livenessProvider.d.ts +133 -0
  46. package/dist/react-native/adapters/livenessProvider.js +144 -0
  47. package/dist/react-native/adapters/zkProofEngine-webview.d.ts +73 -0
  48. package/dist/react-native/adapters/zkProofEngine-webview.js +129 -0
  49. package/dist/react-native/components/FacePoseGuidanceWebView.d.ts +30 -0
  50. package/dist/react-native/components/FacePoseGuidanceWebView.js +474 -0
  51. package/dist/react-native/components/LivenessWebView.d.ts +39 -0
  52. package/dist/react-native/components/LivenessWebView.js +348 -0
  53. package/dist/react-native/components/OnnxRuntimeWebView.d.ts +54 -0
  54. package/dist/react-native/components/OnnxRuntimeWebView.js +394 -0
  55. package/dist/react-native/components/ZkProofWebView.d.ts +59 -0
  56. package/dist/react-native/components/ZkProofWebView.js +259 -0
  57. package/dist/react-native/dependencies.d.ts +144 -0
  58. package/dist/react-native/dependencies.js +123 -0
  59. package/dist/react-native/hooks/useOnnxLoader.d.ts +38 -0
  60. package/dist/react-native/hooks/useOnnxLoader.js +81 -0
  61. package/dist/react-native/hooks/useWasmLoader.d.ts +30 -0
  62. package/dist/react-native/hooks/useWasmLoader.js +122 -0
  63. package/dist/react-native/index.d.ts +59 -0
  64. package/dist/react-native/index.js +96 -0
  65. package/dist/react-native/services/FaceRecognition.d.ts +70 -0
  66. package/dist/react-native/services/FaceRecognition.js +517 -0
  67. package/dist/react-native/ui/FaceZkVerificationFlow.d.ts +97 -0
  68. package/dist/react-native/ui/FaceZkVerificationFlow.js +433 -0
  69. package/dist/react-native/ui/ReferenceEnrollmentFlow.d.ts +72 -0
  70. package/dist/react-native/ui/ReferenceEnrollmentFlow.js +321 -0
  71. package/dist/react-native/utils/faceAlignment.d.ts +37 -0
  72. package/dist/react-native/utils/faceAlignment.js +182 -0
  73. package/dist/react-native/utils/modelInitialisationChecks.d.ts +36 -0
  74. package/dist/react-native/utils/modelInitialisationChecks.js +92 -0
  75. package/dist/react-native/utils/resolveModelUri.d.ts +55 -0
  76. package/dist/react-native/utils/resolveModelUri.js +172 -0
  77. package/dist/react-native/utils/resolveUiConfig.d.ts +41 -0
  78. package/dist/react-native/utils/resolveUiConfig.js +76 -0
  79. package/dist/storage/defaultStorageAdapter.d.ts +44 -0
  80. package/dist/storage/defaultStorageAdapter.js +299 -0
  81. package/dist/tsconfig.tsbuildinfo +1 -0
  82. package/face-zk.config.example.js +88 -0
  83. package/package.json +76 -0
@@ -0,0 +1,348 @@
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
+ import { Asset } from "expo-asset";
17
+ import { useCameraPermissions } from "expo-camera";
18
+ import * as FileSystem from "expo-file-system/legacy";
19
+ import React, { useEffect, useRef, useState } from "react";
20
+ import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
21
+ import { WebView } from "react-native-webview";
22
+ export const ZkFaceAuth = ({ onSuccess, onError, manualTargetPose, referenceImageUri, renderOverlay, headless = true, }) => {
23
+ const webViewRef = useRef(null);
24
+ const [htmlContent, setHtmlContent] = useState(null);
25
+ const [permission, requestPermission] = useCameraPermissions();
26
+ const [isLoading, setIsLoading] = useState(true);
27
+ const [loadError, setLoadError] = useState(null);
28
+ // Realtime engine state
29
+ const [engineState, setEngineState] = useState(null);
30
+ useEffect(() => {
31
+ loadResources();
32
+ }, [headless]);
33
+ const loadResources = async () => {
34
+ try {
35
+ console.log("[ZkFaceAuth] Loading resources...");
36
+ setLoadError(null);
37
+ // 1. Load HTML and JS files
38
+ console.log("[ZkFaceAuth] Resolving assets...");
39
+ const htmlAsset = Asset.fromModule(require("../../assets/liveness/index.html"));
40
+ const antispoofJsAsset = Asset.fromModule(require("../../assets/liveness/antispoof.js.txt"));
41
+ const livenessJsAsset = Asset.fromModule(require("../../assets/liveness/liveness.js.txt"));
42
+ // Load MediaPipe Local Assets
43
+ const mpFaceMeshJsAsset = Asset.fromModule(require("../../assets/mediapipe/face_mesh.js.txt"));
44
+ console.log("[ZkFaceAuth] Assets resolved, beginning download...");
45
+ await Promise.all([
46
+ htmlAsset.downloadAsync(),
47
+ antispoofJsAsset.downloadAsync(),
48
+ livenessJsAsset.downloadAsync(),
49
+ mpFaceMeshJsAsset.downloadAsync(),
50
+ ]);
51
+ console.log("[ZkFaceAuth] Initial assets downloaded. Reading strings...");
52
+ const html = await FileSystem.readAsStringAsync(htmlAsset.localUri || htmlAsset.uri);
53
+ const antispoofJs = await FileSystem.readAsStringAsync(antispoofJsAsset.localUri || antispoofJsAsset.uri);
54
+ const livenessJs = await FileSystem.readAsStringAsync(livenessJsAsset.localUri || livenessJsAsset.uri);
55
+ const mpFaceMeshJs = await FileSystem.readAsStringAsync(mpFaceMeshJsAsset.localUri || mpFaceMeshJsAsset.uri);
56
+ console.log("[ZkFaceAuth] JS read successfully. Injecting...");
57
+ // 2. Inject JS into HTML
58
+ let finalHtml = html
59
+ .replace('<script src="/static/js/onnx_antispoof.js"></script>', `<script>${antispoofJs}</script>`)
60
+ .replace('<script src="/static/js/real_liveness.js"></script>', `<script>${livenessJs}</script>`)
61
+ .replace("<!-- MEDIAPIPE_LOCAL_INJECT -->", `<script>${mpFaceMeshJs}</script>`);
62
+ // Also check for relative paths if any were changed
63
+ finalHtml = finalHtml
64
+ .replace('<script src="./antispoof.js"></script>', `<script>${antispoofJs}</script>`)
65
+ .replace('<script src="./liveness.js"></script>', `<script>${livenessJs}</script>`);
66
+ // Inject headless mode variable
67
+ if (headless) {
68
+ finalHtml = finalHtml.replace(/<\s*head\s*>/i, "<head><script>window.HEADLESS_MODE = true;</script>");
69
+ }
70
+ console.log("[ZkFaceAuth] HTML prepared");
71
+ setHtmlContent(finalHtml);
72
+ setIsLoading(false);
73
+ }
74
+ catch (error) {
75
+ console.error("[ZkFaceAuth] Error loading resources:", error);
76
+ setLoadError(error.message);
77
+ setIsLoading(false);
78
+ onError("Failed to load liveness resources: " + error.message);
79
+ }
80
+ };
81
+ const injectModel = async () => {
82
+ try {
83
+ console.log("[ZkFaceAuth] Injecting model...");
84
+ // ... (model injection logic remains same)
85
+ const modelAsset = Asset.fromModule(require("../../assets/models/antispoof.onnx"));
86
+ await modelAsset.downloadAsync();
87
+ const modelBase64 = await FileSystem.readAsStringAsync(modelAsset.localUri || modelAsset.uri, {
88
+ encoding: FileSystem.EncodingType.Base64,
89
+ });
90
+ // Read reference image if available (Base64 on Native)
91
+ let referenceBase64 = "";
92
+ if (referenceImageUri) {
93
+ try {
94
+ referenceBase64 = await FileSystem.readAsStringAsync(referenceImageUri, { encoding: FileSystem.EncodingType.Base64 });
95
+ referenceBase64 = `data:image/jpeg;base64,${referenceBase64}`;
96
+ }
97
+ catch (e) {
98
+ console.warn("Failed to read reference image for injection", e);
99
+ }
100
+ }
101
+ // Read MediaPipe WASM bindings (Base64)
102
+ console.log("[ZkFaceAuth] Reading MediaPipe binaries...");
103
+ const mpWasmSimdAsset = Asset.fromModule(require("../../assets/mediapipe/face_mesh_solution_simd_wasm_bin.wasm"));
104
+ const mpWasmAsset = Asset.fromModule(require("../../assets/mediapipe/face_mesh_solution_wasm_bin.wasm"));
105
+ const mpDataAsset = Asset.fromModule(require("../../assets/mediapipe/face_mesh_solution_packed_assets.data"));
106
+ await Promise.all([
107
+ mpWasmSimdAsset.downloadAsync(),
108
+ mpWasmAsset.downloadAsync(),
109
+ mpDataAsset.downloadAsync(),
110
+ ]);
111
+ const mpWasmSimdBase64 = await FileSystem.readAsStringAsync(mpWasmSimdAsset.localUri || mpWasmSimdAsset.uri, { encoding: FileSystem.EncodingType.Base64 });
112
+ const mpWasmBase64 = await FileSystem.readAsStringAsync(mpWasmAsset.localUri || mpWasmAsset.uri, { encoding: FileSystem.EncodingType.Base64 });
113
+ const mpDataBase64 = await FileSystem.readAsStringAsync(mpDataAsset.localUri || mpDataAsset.uri, { encoding: FileSystem.EncodingType.Base64 });
114
+ const injectScript = `
115
+ // Inject MediaPipe Files globally to intercept locateFile
116
+ window.MP_WASM_SIMD_BASE64 = ${JSON.stringify(mpWasmSimdBase64)};
117
+ window.MP_WASM_BASE64 = ${JSON.stringify(mpWasmBase64)};
118
+ window.MP_DATA_BASE64 = ${JSON.stringify(mpDataBase64)};
119
+ console.log("[ZkFaceAuth] MediaPipe injected");
120
+
121
+ if (window.loadAntispoofModel) {
122
+ window.loadAntispoofModel(${JSON.stringify(modelBase64)});
123
+ } else {
124
+ console.error('loadAntispoofModel not found');
125
+ }
126
+
127
+ // Set target pose if available
128
+ if (${JSON.stringify(manualTargetPose)}) {
129
+ window.TARGET_POSE = ${JSON.stringify(manualTargetPose)};
130
+ console.log('Target Pose Injected:', window.TARGET_POSE);
131
+ }
132
+
133
+ // Set Reference Image if available
134
+ if (${JSON.stringify(referenceBase64)}) {
135
+ window.REFERENCE_IMAGE_URI = ${JSON.stringify(referenceBase64)};
136
+ console.log('Reference Image Injected');
137
+ }
138
+
139
+ // Start execution ONLY after injecting Native variables
140
+ if (window.initializeLiveness) {
141
+ window.initializeLiveness();
142
+ } else {
143
+ console.error('initializeLiveness not found');
144
+ }
145
+
146
+ true;
147
+ `;
148
+ webViewRef.current?.injectJavaScript(injectScript);
149
+ console.log("[ZkFaceAuth] Model & Pose injection script sent");
150
+ }
151
+ catch (error) {
152
+ console.error("[ZkFaceAuth] Failed to inject model:", error);
153
+ }
154
+ };
155
+ // ... (rest of render logic remains same)
156
+ const [redirecting, setRedirecting] = useState(false);
157
+ const handleMessage = (event) => {
158
+ try {
159
+ const data = JSON.parse(event.nativeEvent.data);
160
+ if (data.type === "log") {
161
+ console.log("[ZkFaceAuth] Log:", data.message);
162
+ }
163
+ else if (data.type === "liveness_state") {
164
+ // High Frequency State Updates from the AI Engine
165
+ setEngineState(data.data);
166
+ }
167
+ else if (data.type === "success") {
168
+ setRedirecting(true); // Visual feedback that RN got the msg
169
+ onSuccess(data.image, data.metadata);
170
+ }
171
+ else if (data.type === "error") {
172
+ console.error("[ZkFaceAuth] WebView Error:", data.message);
173
+ onError(data.message);
174
+ }
175
+ else if (data.type === "modelLoaded") {
176
+ console.log("[ZkFaceAuth] Model loaded confirmed");
177
+ }
178
+ }
179
+ catch (e) {
180
+ console.error("[ZkFaceAuth] Error parsing message:", e);
181
+ }
182
+ };
183
+ // ... (rest of code) ...
184
+ // Inside return (after WebView, before closing View if wrapped?)
185
+ // Wait, LivenessWebView returns WebView directly. I need to wrap it if I want overlay.
186
+ // Actually, LivenessWebView is wrapped in ScanScreen.tsx.
187
+ // But I can't change LivenessWebView return type structure easily without breaking styles?
188
+ // Let's modify the return structure.
189
+ if (isLoading || !htmlContent) {
190
+ if (loadError) {
191
+ return (<View style={styles.center}>
192
+ <Text style={[styles.text, { color: "#ef4444" }]}>
193
+ Failed to load resources: {loadError}
194
+ </Text>
195
+ </View>);
196
+ }
197
+ return (<View style={styles.center}>
198
+ <ActivityIndicator size="large" color="#10b981"/>
199
+ <Text style={[styles.text, { marginTop: 20 }]}>
200
+ Loading capabilities...
201
+ </Text>
202
+ </View>);
203
+ }
204
+ // Handle Camera Permissions Explicitly
205
+ if (!permission?.granted) {
206
+ if (permission?.canAskAgain) {
207
+ requestPermission();
208
+ return (<View style={styles.center}>
209
+ <ActivityIndicator size="large" color="#10b981"/>
210
+ <Text style={[styles.text, { marginTop: 20 }]}>
211
+ Requesting camera access...
212
+ </Text>
213
+ </View>);
214
+ }
215
+ else {
216
+ // Temporarily render a view, but in a real flow it might just call onError
217
+ // Since this mount is often unmounted/remounted, it is safer to call onError here if we can't show UI
218
+ // But Since this is a component, let's just show a text that says "Camera permission denied"
219
+ // or we can call onError. Let's call onError on mount if denied.
220
+ setTimeout(() => onError("Camera permission denied. Please enable it in Settings."), 50);
221
+ return (<View style={styles.center}>
222
+ <Text style={[styles.text, { color: "#ef4444" }]}>
223
+ Camera access denied
224
+ </Text>
225
+ </View>);
226
+ }
227
+ }
228
+ if (redirecting) {
229
+ return (<View style={styles.center}>
230
+ <ActivityIndicator size="large" color="#10b981"/>
231
+ <Text style={[styles.text, { marginTop: 20 }]}>
232
+ Processing Capture...
233
+ </Text>
234
+ </View>);
235
+ }
236
+ return (<View style={styles.container}>
237
+ <WebView ref={webViewRef}
238
+ // CRITICAL: baseUrl must be https://localhost/ to provide a Secure Context for WebAssembly/ONNX.
239
+ // It does NOT make actual network requests, but prevents the WebView from throwing security errors.
240
+ source={{ html: htmlContent, baseUrl: "https://localhost/" }} style={styles.webview} javaScriptEnabled={true} domStorageEnabled={true} allowsInlineMediaPlayback={true} mediaPlaybackRequiresUserAction={false} scrollEnabled={false} bounces={false} overScrollMode="never" scalesPageToFit={true} onMessage={handleMessage}
241
+ // @ts-expect-error — onPermissionRequest is an Android WebView prop not in react-native-webview types
242
+ onPermissionRequest={(event) => {
243
+ const { resources } = event.nativeEvent;
244
+ if (resources.includes("camera")) {
245
+ event.grant(resources);
246
+ }
247
+ }} onLoadEnd={() => {
248
+ console.log("[ZkFaceAuth] Load End - Injecting model");
249
+ injectModel();
250
+ }} onError={(syntheticEvent) => {
251
+ const { nativeEvent } = syntheticEvent;
252
+ console.error("[ZkFaceAuth] WebView Error:", nativeEvent);
253
+ }} onHttpError={(syntheticEvent) => {
254
+ const { nativeEvent } = syntheticEvent;
255
+ console.error("[ZkFaceAuth] WebView HTTP Error:", nativeEvent);
256
+ }} originWhitelist={["*"]}/>
257
+
258
+ {/* Render Customer Overlay or Default Fallback Overlayer */}
259
+ {headless && renderOverlay && engineState && (<View style={StyleSheet.absoluteFillObject} pointerEvents="none">
260
+ {renderOverlay(engineState)}
261
+ </View>)}
262
+
263
+ {/* Render built in default overlay if they want headless but provided no overlay */}
264
+ {headless && !renderOverlay && engineState && (<DefaultLivenessOverlay state={engineState}/>)}
265
+ </View>);
266
+ };
267
+ // Extremely basic default overlay for consumers who don't want to build their own UI
268
+ // but still use the cleanly detached SDK.
269
+ const DefaultLivenessOverlay = ({ state, }) => {
270
+ let borderColor = "#e2e8f0";
271
+ if (state.phase === "success")
272
+ borderColor = "#22c55e";
273
+ else if (state.phase === "fail")
274
+ borderColor = "#ef4444";
275
+ else if (state.isFaceLocked)
276
+ borderColor = "#6366f1";
277
+ return (<View style={StyleSheet.absoluteFillObject} pointerEvents="none">
278
+ {/* Dark semi transparent background with a cutout for the face */}
279
+ <View style={[
280
+ StyleSheet.absoluteFillObject,
281
+ {
282
+ backgroundColor: "rgba(0,0,0,0.5)",
283
+ justifyContent: "center",
284
+ alignItems: "center",
285
+ },
286
+ ]}>
287
+ {state.promptText && (<Text style={{
288
+ color: "white",
289
+ fontSize: 24,
290
+ fontWeight: "bold",
291
+ position: "absolute",
292
+ top: 100,
293
+ }}>
294
+ {state.promptText}
295
+ </Text>)}
296
+
297
+ <View style={{
298
+ width: 320,
299
+ height: 320,
300
+ borderRadius: 160,
301
+ borderWidth: 4,
302
+ borderColor: borderColor,
303
+ backgroundColor: "transparent", // this would be a real cutout in a true complex UI
304
+ }}/>
305
+
306
+ {/* Progress bar mapping 0-100 */}
307
+ {state.progressPercent > 0 && state.progressPercent < 100 && (<View style={{
308
+ position: "absolute",
309
+ bottom: 150,
310
+ width: 200,
311
+ height: 8,
312
+ backgroundColor: "#333",
313
+ borderRadius: 4,
314
+ }}>
315
+ <View style={{
316
+ width: `${state.progressPercent}%`,
317
+ height: "100%",
318
+ backgroundColor: "#6366f1",
319
+ borderRadius: 4,
320
+ }}/>
321
+ </View>)}
322
+
323
+ {state.icon && (<Text style={{ fontSize: 48, position: "absolute", bottom: 50 }}>
324
+ {state.icon}
325
+ </Text>)}
326
+ </View>
327
+ </View>);
328
+ };
329
+ const styles = StyleSheet.create({
330
+ container: {
331
+ flex: 1,
332
+ backgroundColor: "#000",
333
+ },
334
+ webview: {
335
+ flex: 1,
336
+ backgroundColor: "transparent",
337
+ },
338
+ center: {
339
+ flex: 1,
340
+ justifyContent: "center",
341
+ alignItems: "center",
342
+ backgroundColor: "#fff",
343
+ },
344
+ text: {
345
+ fontSize: 16,
346
+ color: "#333",
347
+ },
348
+ });
@@ -0,0 +1,54 @@
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
+ import React from 'react';
17
+ import { WebView } from 'react-native-webview';
18
+ interface OnnxRuntimeBridgeProps {
19
+ onReady: (bridge: OnnxRuntimeBridge) => void;
20
+ onError: (error: string) => void;
21
+ }
22
+ export declare class OnnxRuntimeBridge {
23
+ private webViewRef;
24
+ private messageCallbacks;
25
+ private ready;
26
+ constructor(webViewRef: React.RefObject<WebView | null>);
27
+ loadModels(detModelData: string, recModelData: string, wasmData?: string): Promise<void>;
28
+ runDetection(imageData: Float32Array, width: number, height: number): Promise<{
29
+ outputs: Record<string, {
30
+ data: number[];
31
+ dims: number[];
32
+ }>;
33
+ }>;
34
+ runRecognition(imageData: Float32Array, width: number, height: number): Promise<{
35
+ data: number[];
36
+ dims: number[];
37
+ }>;
38
+ handleMessage(event: any): void;
39
+ /**
40
+ * Send a message to the WebView via postMessage.
41
+ * postMessage has no practical size limit (unlike injectJavaScript which fails
42
+ * on Android above ~4 MB). This is critical for large model and tensor payloads.
43
+ */
44
+ sendMessage(type: string, params?: any): void;
45
+ /**
46
+ * Encodes a Float32Array as base64 binary using chunked String.fromCharCode
47
+ * to avoid call-stack overflow on large arrays (e.g. 640×640×3 = 4.9 MB).
48
+ * Result is ~4/3× the byte size, far smaller than JSON (which costs ~6–8×).
49
+ */
50
+ private float32ToBase64;
51
+ isReady(): boolean;
52
+ }
53
+ export declare const OnnxRuntimeWebView: React.FC<OnnxRuntimeBridgeProps>;
54
+ export {};