package expo.modules.zkexpo import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import java.io.File class ZkExpoModule : Module() { companion object { init { System.loadLibrary("native_rust_lib") } } // addToCache now returns a String: empty = success, non-empty = error JSON external fun groth16ProveV2(a: String, b: String, c: String): String external fun groth16ProveV2Base64(a: String, b: String, c: String): String external fun addToCache(a: String, b: String, c: String): String external fun clearCache(): Unit override fun definition() = ModuleDefinition { Name("ZkExpo") AsyncFunction("groth16ProveV2") { a: String, b: String, c: String -> guardPath(a, "graph_path") guardPath(b, "zkey_path") val result = groth16ProveV2(a, b, c) throwIfError(result, "groth16ProveV2") result } AsyncFunction("groth16ProveV2Base64") { a: String, b: String, c: String -> val result = groth16ProveV2Base64(a, b, c) throwIfError(result, "groth16ProveV2Base64") result } AsyncFunction("addToCache") { a: String, b: String, c: String -> guardPath(b, "path1") guardPath(c, "path2") val error = addToCache(a, b, c) ?: "" if (error.isNotEmpty()) { throw Exception("[$a] $error") } } AsyncFunction("clearCache") { clearCache() } } private fun guardPath(path: String, label: String) { if (path.contains('%')) { throw Exception( "$label appears URL-encoded ('$path'). " + "Strip the 'file://' prefix and call Uri.decode() / decodeURIComponent() " + "before passing the path to zk-expo." ) } if (!File(path).exists()) { throw Exception("File not found at $label: $path") } } private fun throwIfError(result: String, fn: String) { if (result.startsWith("{\"error\"")) { throw Exception("[$fn] $result") } } }