@smileid/usesmileid_mlkit_face 12.0.2 → 12.1.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 +12 -0
- package/README.md +7 -3
- package/android/build.gradle +21 -21
- package/android/src/main/java/com/usesmileid/mlkit/face/UseSmileIDMlkitFaceKameraAnalysisTick.kt +42 -0
- package/android/src/main/java/com/usesmileid/mlkit/face/UseSmileIDMlkitFaceModule.kt +6 -28
- package/android/src/main/java/com/usesmileid/mlkit/face/UseSmileIDMlkitFaceSessionHolder.kt +2 -3
- package/android/src/main/java/com/usesmileid/rn/analyzer/mlkitface/UseSmileIDAnalyzerExecutor.kt +28 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -38
- package/package.json +12 -13
- package/plugin/build/index.js +1 -27
- package/plugin/build/lib/mlkit_manifest.js +1 -54
- package/plugin/build/lib/root_project.d.ts +11 -3
- package/plugin/build/lib/root_project.js +4 -109
- package/android/src/main/java/com/usesmileid/mlkit/face/UseSmileIDMlkitFaceFrameProcessorPlugin.kt +0 -79
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/plugin/build/index.js.map +0 -1
- package/plugin/build/lib/mlkit_manifest.js.map +0 -1
- package/plugin/build/lib/root_project.js.map +0 -1
- package/plugin/src/__tests__/mirrored_sources.test.ts +0 -57
- package/plugin/src/__tests__/mlkit_manifest.test.ts +0 -117
- package/plugin/src/__tests__/root_project.test.ts +0 -195
- package/plugin/src/index.ts +0 -47
- package/plugin/src/lib/mlkit_manifest.ts +0 -88
- package/plugin/src/lib/root_project.ts +0 -160
- package/plugin/tsconfig.json +0 -24
- package/src/__tests__/use_smile_id_mlkit_face.test.ts +0 -101
- package/src/index.ts +0 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
Full release notes: [Smile ID docs](https://docs.usesmileid.com/developer-resources/sdks/mobile/release-notes/react-native-expo).
|
|
2
|
+
|
|
3
|
+
## 12.1.1
|
|
4
|
+
|
|
5
|
+
See the repository CHANGELOG for the 12.1.1 release notes.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## 12.1.0
|
|
9
|
+
|
|
10
|
+
See the repository CHANGELOG for the 12.1.0 release notes.
|
|
11
|
+
|
|
12
|
+
|
|
1
13
|
## 12.0.2
|
|
2
14
|
|
|
3
15
|
See the repository CHANGELOG for the 12.0.2 release notes.
|
package/README.md
CHANGED
|
@@ -30,15 +30,15 @@ package to `expo.plugins` in `app.json` and run `npx expo prebuild --clean`:
|
|
|
30
30
|
"plugins": [
|
|
31
31
|
[
|
|
32
32
|
"@smileid/usesmileid_mlkit_face",
|
|
33
|
-
{ "additionalModelDependencies": ["barcode_ui"] }
|
|
33
|
+
{ "kspVersion": "2.3.6", "additionalModelDependencies": ["barcode_ui"] }
|
|
34
34
|
]
|
|
35
35
|
]
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
The plugin pins
|
|
41
|
-
|
|
40
|
+
The plugin pins the Kotlin the AAR was compiled with (2.3.20) and the
|
|
41
|
+
`androidx.core` version that resolves under Expo's Android Gradle Plugin.
|
|
42
42
|
It also claims the `com.google.mlkit.vision.DEPENDENCIES` meta-data on your
|
|
43
43
|
`<application>` with `tools:replace`: this AAR declares that key as `face`, so
|
|
44
44
|
without the override a second ML Kit consumer declaring its own value (for
|
|
@@ -47,6 +47,10 @@ Android manifest merger. `additionalModelDependencies` is optional — name the
|
|
|
47
47
|
hints your other consumers declare so their models are prefetched at install
|
|
48
48
|
time rather than downloaded on first use.
|
|
49
49
|
|
|
50
|
+
Expo's own KSP lookup carries no entry for that Kotlin and falls back to a KSP
|
|
51
|
+
the compiler cannot load, so pass `kspVersion` as shown — the samples use
|
|
52
|
+
`2.3.6`. `kotlinVersion` overrides the Kotlin pin.
|
|
53
|
+
|
|
50
54
|
## Usage
|
|
51
55
|
|
|
52
56
|
```ts
|
package/android/build.gradle
CHANGED
|
@@ -17,7 +17,7 @@ plugins {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
group = 'com.usesmileid.mlkit.face'
|
|
20
|
-
version = '12.
|
|
20
|
+
version = '12.1.1'
|
|
21
21
|
|
|
22
22
|
android {
|
|
23
23
|
namespace 'com.usesmileid.mlkit.face'
|
|
@@ -29,7 +29,7 @@ android {
|
|
|
29
29
|
// android/build.gradle and the rest of the @expo/* modules.
|
|
30
30
|
defaultConfig {
|
|
31
31
|
versionCode 1
|
|
32
|
-
versionName '12.
|
|
32
|
+
versionName '12.1.1'
|
|
33
33
|
// R8 keep-rules to bundle into partner apps that depend on this
|
|
34
34
|
// module. Without these, R8 may rename the Expo module entry
|
|
35
35
|
// point and the JS-bridged member functions, breaking autolinking.
|
|
@@ -38,26 +38,26 @@ android {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
dependencies {
|
|
41
|
+
// kamera native core: the analyzer executor takes analysis frames from
|
|
42
|
+
// kamera's KameraFrameHub so pixels never cross the JS bridge. Resolves from
|
|
43
|
+
// Maven Central; a local publishToMavenLocal build wins (see kamera.md).
|
|
44
|
+
implementation 'com.usesmileid:kamera:1.0.6'
|
|
45
|
+
|
|
41
46
|
// Existing Smile ID native AAR — the entire ML pipeline lives here.
|
|
42
47
|
// This Expo Module is a thin Kotlin shim that constructs the
|
|
43
48
|
// session and bridges its four methods to JS via Expo Modules.
|
|
44
|
-
implementation 'com.usesmileid:mlkit-face:12.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// `FaceDetectorAnalyzer()` takes a defaulted `FaceDetector` argument, so the compiler
|
|
60
|
-
// needs that type to emit the call. The AAR above declares ML Kit at runtime
|
|
61
|
-
// scope only — enough to execute, not to compile against.
|
|
62
|
-
compileOnly 'com.google.android.gms:play-services-mlkit-face-detection:17.1.0'
|
|
49
|
+
implementation 'com.usesmileid:mlkit-face:12.1.1'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// kamera resolves from Maven Central. mavenLocal stays injected — content-filtered to
|
|
55
|
+
// com.usesmileid — the same way kamera's own glue does it, so a locally published kamera
|
|
56
|
+
// build takes precedence during the kamera dev loop without host apps editing repos.
|
|
57
|
+
rootProject.allprojects {
|
|
58
|
+
repositories {
|
|
59
|
+
mavenLocal {
|
|
60
|
+
content { includeGroup 'com.usesmileid' }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
}
|
package/android/src/main/java/com/usesmileid/mlkit/face/UseSmileIDMlkitFaceKameraAnalysisTick.kt
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package com.usesmileid.mlkit.face
|
|
2
|
+
|
|
3
|
+
import com.usesmileid.bridge.model.YuvFrame as NativeYuvFrame
|
|
4
|
+
import com.usesmileid.kamera.integration.KameraFrameHub
|
|
5
|
+
import com.usesmileid.rn.analyzer.mlkitface.toNativeYuvFrame
|
|
6
|
+
import kotlin.coroutines.cancellation.CancellationException
|
|
7
|
+
import kotlinx.coroutines.runBlocking
|
|
8
|
+
import kotlinx.coroutines.withContext
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Scans the latest [KameraFrameHub] frame natively; no pending frame returns the `no_frame` wire error.
|
|
12
|
+
* The frame's rotationDegrees already uprights the buffer to the locked interface axis.
|
|
13
|
+
*/
|
|
14
|
+
internal fun analyzeKameraFrameTick(arguments: Map<String, Any?>?): Any {
|
|
15
|
+
val frame = KameraFrameHub.take() ?: return mapOf("error" to "no_frame")
|
|
16
|
+
val yuvFrame = try {
|
|
17
|
+
frame.toNativeYuvFrame()
|
|
18
|
+
} finally {
|
|
19
|
+
// Closing releases the frame to the pipeline; the converted copy owns its own bytes.
|
|
20
|
+
frame.close()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Device-tilt context (0 = upright portrait) for the validators.
|
|
24
|
+
val jsRotation = (arguments?.get("rotation") as? Number)?.toInt() ?: 0
|
|
25
|
+
|
|
26
|
+
return runBlocking {
|
|
27
|
+
withContext(UseSmileIDMlkitFaceSessionHolder.sessionDispatcher) {
|
|
28
|
+
val activeSession = UseSmileIDMlkitFaceSessionHolder.session
|
|
29
|
+
?: return@withContext mapOf("error" to "session_not_configured")
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
val scanResult = activeSession.scan(yuvFrame, jsRotation)
|
|
33
|
+
val events = activeSession.drainCaptureReadyEvents()
|
|
34
|
+
UseSmileIDMlkitFaceModule.buildWireResult(scanResult, events)
|
|
35
|
+
} catch (cancellation: CancellationException) {
|
|
36
|
+
throw cancellation
|
|
37
|
+
} catch (e: Exception) {
|
|
38
|
+
mapOf("error" to ("scan_failed: " + (e.message ?: e.javaClass.simpleName)))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -14,7 +14,6 @@ import com.usesmileid.bridge.session.UseSmileIDFaceSession
|
|
|
14
14
|
import com.usesmileid.bridge.session.UseSmileIDScanState
|
|
15
15
|
import com.usesmileid.bridge.session.UseSmileIDScanStateType
|
|
16
16
|
import com.usesmileid.bridge.storage.FrameStorage
|
|
17
|
-
import com.mrousavy.camera.frameprocessors.FrameProcessorPluginRegistry
|
|
18
17
|
import com.usesmileid.rn.analyzer.mlkitface.UseSmileIDAnalyzerExecutor
|
|
19
18
|
import expo.modules.kotlin.Promise
|
|
20
19
|
import expo.modules.kotlin.modules.Module
|
|
@@ -31,10 +30,7 @@ import expo.modules.kotlin.modules.ModuleDefinition
|
|
|
31
30
|
* subclass hooks (session construction, wire conversion) and forwards
|
|
32
31
|
* the async functions through it.
|
|
33
32
|
*
|
|
34
|
-
*
|
|
35
|
-
* which is registered with VisionCamera's frame-processor runtime in
|
|
36
|
-
* [OnCreate]. Partners call `VisionCameraProxy.initFrameProcessorPlugin`
|
|
37
|
-
* from their JS worklet instead of the old `AsyncFunction("analyze")`.
|
|
33
|
+
* Frames reach `analyzeKameraFrame` through kamera's native hub; pixels never cross the JS bridge.
|
|
38
34
|
*
|
|
39
35
|
* Lifecycle: Expo instantiates exactly one `Module` per app process;
|
|
40
36
|
* the executor is owned for the module's lifetime.
|
|
@@ -118,20 +114,17 @@ class UseSmileIDMlkitFaceModule : Module() {
|
|
|
118
114
|
?: throw IllegalStateException("Module not attached to a React context")
|
|
119
115
|
executor.onAttach(ctx)
|
|
120
116
|
|
|
121
|
-
// Guard against duplicate registration on dev-client hot reloads
|
|
122
|
-
// where OnCreate can fire more than once in the same process.
|
|
123
|
-
if (!pluginRegistered) {
|
|
124
|
-
pluginRegistered = true
|
|
125
|
-
FrameProcessorPluginRegistry.addFrameProcessorPlugin(
|
|
126
|
-
FRAME_PROCESSOR_PLUGIN_NAME,
|
|
127
|
-
) { _, _ -> UseSmileIDMlkitFaceFrameProcessorPlugin() }
|
|
128
|
-
}
|
|
129
117
|
}
|
|
130
118
|
|
|
131
119
|
AsyncFunction("configure") { config: Map<String, Any?> ->
|
|
132
120
|
executor.handleConfigure(config)
|
|
133
121
|
}
|
|
134
122
|
|
|
123
|
+
AsyncFunction("analyzeKameraFrame") { arguments: Map<String, Any?>? ->
|
|
124
|
+
// Blocks this module's async queue so only one scan is in flight at a time.
|
|
125
|
+
analyzeKameraFrameTick(arguments)
|
|
126
|
+
}
|
|
127
|
+
|
|
135
128
|
AsyncFunction("reset") {
|
|
136
129
|
executor.handleReset()
|
|
137
130
|
}
|
|
@@ -158,21 +151,6 @@ class UseSmileIDMlkitFaceModule : Module() {
|
|
|
158
151
|
/** Wire-format key partners pass via `FaceConfig.analyzerFactoryKey`. */
|
|
159
152
|
const val KEY: String = "mlkit-face"
|
|
160
153
|
|
|
161
|
-
/**
|
|
162
|
-
* Must match the JS worklet's `VisionCameraProxy.initFrameProcessorPlugin(...)`
|
|
163
|
-
* call exactly — drift is a runtime "plugin not found" error.
|
|
164
|
-
*/
|
|
165
|
-
const val FRAME_PROCESSOR_PLUGIN_NAME: String = "UseSmileIDMlkitFaceFrameProcessor"
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* [FrameProcessorPluginRegistry.addFrameProcessorPlugin] asserts uniqueness
|
|
169
|
-
* and crashes on duplicate registration; this guard prevents that on dev-client
|
|
170
|
-
* hot reloads where [OnCreate] fires more than once per process.
|
|
171
|
-
*/
|
|
172
|
-
@Volatile
|
|
173
|
-
private var pluginRegistered: Boolean = false
|
|
174
|
-
|
|
175
|
-
/** Wire-result builder shared with [UseSmileIDMlkitFaceFrameProcessorPlugin]. */
|
|
176
154
|
internal fun buildWireResult(
|
|
177
155
|
scanResult: UseSmileIDFaceScanResult,
|
|
178
156
|
events: List<NativeCaptureReadyEvent>,
|
|
@@ -10,9 +10,8 @@ import kotlinx.coroutines.asCoroutineDispatcher
|
|
|
10
10
|
*
|
|
11
11
|
* The session's state machine is not thread-safe; all operations —
|
|
12
12
|
* scan+drain as one atomic unit, flush, reset, close — are serialized
|
|
13
|
-
* through [sessionDispatcher] (a single-thread executor). The
|
|
14
|
-
*
|
|
15
|
-
* arrive while a scan is in flight rather than queuing them.
|
|
13
|
+
* through [sessionDispatcher] (a single-thread executor). The analysis tick blocks its
|
|
14
|
+
* caller via [runBlocking]; kamera's hub keeps only the latest frame, so frames never queue.
|
|
16
15
|
*/
|
|
17
16
|
internal object UseSmileIDMlkitFaceSessionHolder {
|
|
18
17
|
|
package/android/src/main/java/com/usesmileid/rn/analyzer/mlkitface/UseSmileIDAnalyzerExecutor.kt
CHANGED
|
@@ -12,6 +12,8 @@ import com.usesmileid.bridge.model.CaptureType
|
|
|
12
12
|
import com.usesmileid.bridge.model.YuvFrame as NativeYuvFrame
|
|
13
13
|
import com.usesmileid.bridge.storage.DocumentSide
|
|
14
14
|
import com.usesmileid.bridge.storage.FrameStorage
|
|
15
|
+
import com.usesmileid.kamera.frame.KameraFrame
|
|
16
|
+
import com.usesmileid.kamera.integration.KameraFrameHub
|
|
15
17
|
import java.io.File
|
|
16
18
|
import kotlinx.coroutines.CoroutineDispatcher
|
|
17
19
|
import kotlinx.coroutines.CoroutineScope
|
|
@@ -171,6 +173,7 @@ abstract class UseSmileIDAnalyzerExecutor<
|
|
|
171
173
|
|
|
172
174
|
// Shared implementation behind the Expo Module's async functions -----
|
|
173
175
|
|
|
176
|
+
|
|
174
177
|
/**
|
|
175
178
|
* Implementation behind `configure`. Closes any prior session,
|
|
176
179
|
* allocates a fresh on-disk session directory, and delegates session
|
|
@@ -281,3 +284,28 @@ abstract class UseSmileIDAnalyzerExecutor<
|
|
|
281
284
|
return dir
|
|
282
285
|
}
|
|
283
286
|
}
|
|
287
|
+
|
|
288
|
+
/** Copies the YUV planes so the frame can close at once; rotation stays metadata for the detector. */
|
|
289
|
+
internal fun KameraFrame.toNativeYuvFrame(): NativeYuvFrame {
|
|
290
|
+
val yPlane = planes[0]
|
|
291
|
+
val uPlane = planes[1]
|
|
292
|
+
val vPlane = planes[2]
|
|
293
|
+
fun copyBytes(buffer: java.nio.ByteBuffer): ByteArray {
|
|
294
|
+
val source = buffer.duplicate()
|
|
295
|
+
source.rewind()
|
|
296
|
+
return ByteArray(source.remaining()).also { source.get(it) }
|
|
297
|
+
}
|
|
298
|
+
return NativeYuvFrame(
|
|
299
|
+
planeY = copyBytes(yPlane.buffer),
|
|
300
|
+
planeU = copyBytes(uPlane.buffer),
|
|
301
|
+
planeV = copyBytes(vPlane.buffer),
|
|
302
|
+
yRowStride = yPlane.rowStride,
|
|
303
|
+
uRowStride = uPlane.rowStride,
|
|
304
|
+
vRowStride = vPlane.rowStride,
|
|
305
|
+
uPixelStride = uPlane.pixelStride,
|
|
306
|
+
vPixelStride = vPlane.pixelStride,
|
|
307
|
+
width = width,
|
|
308
|
+
height = height,
|
|
309
|
+
rotation = rotationDegrees,
|
|
310
|
+
)
|
|
311
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,9 +20,10 @@ import type { FaceConfig, FaceScanResult } from "@smileid/usesmileid_bridge";
|
|
|
20
20
|
* `FaceAnalyzer` for the canonical contract.
|
|
21
21
|
*/
|
|
22
22
|
/**
|
|
23
|
-
* Must match the Kotlin Expo Module's `Name("UseSmileIDMlkitFace")`
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Must match the Kotlin Expo Module's `Name("UseSmileIDMlkitFace")` — drift is a runtime
|
|
24
|
+
* "module not found" error, not a compile error.
|
|
25
|
+
*
|
|
26
|
+
* `frameProcessorPluginName` is inert; kept only for API compatibility.
|
|
26
27
|
*/
|
|
27
28
|
export declare const UseSmileIDMlkitFaceIdentifiers: {
|
|
28
29
|
readonly nativeModuleName: "UseSmileIDMlkitFace";
|
|
@@ -30,4 +31,3 @@ export declare const UseSmileIDMlkitFaceIdentifiers: {
|
|
|
30
31
|
};
|
|
31
32
|
export declare const useSmileIDMlkitFace: import("@smileid/usesmileid_platform_interface").FaceAnalyzer;
|
|
32
33
|
export type { FaceConfig, FaceScanResult };
|
|
33
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,38 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useSmileIDAnalyzerExecutor } from "@smileid/usesmileid_platform_interface";
|
|
3
|
-
/**
|
|
4
|
-
* Google ML Kit face analyzer (Android-only).
|
|
5
|
-
*
|
|
6
|
-
* Thin shim around the existing native session
|
|
7
|
-
* `com.usesmileid.bridge.session.UseSmileIDFaceSession(FaceDetectorAnalyzer())`
|
|
8
|
-
* shipped in the `com.smileidentity:mlkit-face` AAR. The native side
|
|
9
|
-
* runs the entire pipeline (analyzer + validator + transitioner +
|
|
10
|
-
* state machine); this TS layer only routes calls and validates wire
|
|
11
|
-
* payloads at the channel boundary.
|
|
12
|
-
*
|
|
13
|
-
* The canonical wiring lives in [useSmileIDAnalyzerExecutor] in
|
|
14
|
-
* `usesmileid_platform_interface`. This file only supplies the
|
|
15
|
-
* provider-specific identity so all six provider modules share one set
|
|
16
|
-
* of correctness properties by construction.
|
|
17
|
-
*
|
|
18
|
-
* Lifecycle: `configure()` → per-frame analysis via the native frame
|
|
19
|
-
* processor plugin → `reset()`? → `close()`. Calling
|
|
20
|
-
* `close()` twice is idempotent. See `usesmileid_platform_interface`
|
|
21
|
-
* `FaceAnalyzer` for the canonical contract.
|
|
22
|
-
*/
|
|
23
|
-
/**
|
|
24
|
-
* Must match the Kotlin Expo Module's `Name("UseSmileIDMlkitFace")` and its
|
|
25
|
-
* VisionCamera frame-processor-plugin registration — drift is a runtime
|
|
26
|
-
* "module/plugin not found" error, not a compile error.
|
|
27
|
-
*/
|
|
28
|
-
export const UseSmileIDMlkitFaceIdentifiers = {
|
|
29
|
-
nativeModuleName: "UseSmileIDMlkitFace",
|
|
30
|
-
frameProcessorPluginName: "UseSmileIDMlkitFaceFrameProcessor",
|
|
31
|
-
};
|
|
32
|
-
export const useSmileIDMlkitFace = useSmileIDAnalyzerExecutor({
|
|
33
|
-
nativeModuleName: UseSmileIDMlkitFaceIdentifiers.nativeModuleName,
|
|
34
|
-
frameProcessorPluginName: UseSmileIDMlkitFaceIdentifiers.frameProcessorPluginName,
|
|
35
|
-
kind: "face",
|
|
36
|
-
key: AnalyzerFactoryKey.MLKitFace,
|
|
37
|
-
});
|
|
38
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";import{AnalyzerFactoryKey as e}from"@smileid/usesmileid_bridge";import{useSmileIDAnalyzerExecutor as r}from"@smileid/usesmileid_platform_interface";export const UseSmileIDMlkitFaceIdentifiers={nativeModuleName:"UseSmileIDMlkitFace",frameProcessorPluginName:"UseSmileIDMlkitFaceFrameProcessor"},useSmileIDMlkitFace=r({nativeModuleName:UseSmileIDMlkitFaceIdentifiers.nativeModuleName,frameProcessorPluginName:UseSmileIDMlkitFaceIdentifiers.frameProcessorPluginName,kind:"face",key:e.MLKitFace});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smileid/usesmileid_mlkit_face",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.1.1",
|
|
4
4
|
"description": "Android MLKit face detection implementation for the UseSmileID React Native (Expo) SDK.",
|
|
5
5
|
"homepage": "https://usesmileid.com",
|
|
6
6
|
"repository": {
|
|
@@ -36,11 +36,10 @@
|
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
|
-
"
|
|
40
|
-
"android",
|
|
39
|
+
"android/build.gradle",
|
|
40
|
+
"android/consumer-rules.pro",
|
|
41
|
+
"android/src/main",
|
|
41
42
|
"plugin/build",
|
|
42
|
-
"plugin/src",
|
|
43
|
-
"plugin/tsconfig.json",
|
|
44
43
|
"app.plugin.js",
|
|
45
44
|
"expo-module.config.json",
|
|
46
45
|
"README.md",
|
|
@@ -48,8 +47,8 @@
|
|
|
48
47
|
"CHANGELOG.md"
|
|
49
48
|
],
|
|
50
49
|
"dependencies": {
|
|
51
|
-
"@smileid/usesmileid_bridge": "12.
|
|
52
|
-
"@smileid/usesmileid_platform_interface": "12.
|
|
50
|
+
"@smileid/usesmileid_bridge": "12.1.1",
|
|
51
|
+
"@smileid/usesmileid_platform_interface": "12.1.1"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
54
|
"expo": ">=56.0.0",
|
|
@@ -57,22 +56,22 @@
|
|
|
57
56
|
"react-native": ">=0.83.0"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
|
-
"@types/node": "^
|
|
61
|
-
"expo": "
|
|
62
|
-
"expo-modules-core": "^
|
|
63
|
-
"react-native": "^0.
|
|
59
|
+
"@types/node": "^26.4.1",
|
|
60
|
+
"expo": "~57.0.20",
|
|
61
|
+
"expo-modules-core": "^57.0.16",
|
|
62
|
+
"react-native": "^0.86.3",
|
|
64
63
|
"typescript": "^6.0.3"
|
|
65
64
|
},
|
|
66
65
|
"publishConfig": {
|
|
67
66
|
"access": "public"
|
|
68
67
|
},
|
|
69
68
|
"scripts": {
|
|
70
|
-
"build": "pnpm run build:lib && pnpm run build:plugin",
|
|
69
|
+
"build": "pnpm run build:lib && pnpm run build:plugin && node ../Scripts/copy-assets.mjs",
|
|
71
70
|
"build:lib": "tsc -p tsconfig.json",
|
|
72
71
|
"build:plugin": "tsc -p plugin/tsconfig.json",
|
|
73
72
|
"typecheck": "tsc -b && tsc -p plugin/tsconfig.json --noEmit",
|
|
74
73
|
"test": "vitest run",
|
|
75
74
|
"test:watch": "vitest",
|
|
76
|
-
"clean": "rm -rf dist plugin/build .turbo coverage"
|
|
75
|
+
"clean": "rm -rf dist plugin/build .turbo coverage tsconfig.tsbuildinfo"
|
|
77
76
|
}
|
|
78
77
|
}
|
package/plugin/build/index.js
CHANGED
|
@@ -1,27 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// The module is autolinked as a Gradle subproject, so it inherits the host's
|
|
3
|
-
// Kotlin compiler and `compileSdk`; Expo's defaults for both are lower than the
|
|
4
|
-
// AARs accept and a library cannot raise a setting the root project owns.
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const root_project_1 = require("./lib/root_project");
|
|
7
|
-
const mlkit_manifest_1 = require("./lib/mlkit_manifest");
|
|
8
|
-
// Lowest Kotlin that reads the AARs' 2.4.x metadata AND has Expo
|
|
9
|
-
// compiler-plugin (pika) artifacts; higher pins break expo-modules-core.
|
|
10
|
-
// KSP is left to Expo's own kotlin→ksp lookup table.
|
|
11
|
-
const DEFAULT_KOTLIN_VERSION = "2.3.20";
|
|
12
|
-
const COMPILE_SDK_VERSION = 37;
|
|
13
|
-
const FORCED_DEPENDENCIES = [
|
|
14
|
-
"androidx.core:core:1.18.0",
|
|
15
|
-
"androidx.core:core-ktx:1.18.0",
|
|
16
|
-
];
|
|
17
|
-
const withMlkitFace = (config, options) => {
|
|
18
|
-
const { kotlinVersion, kspVersion, ...manifestOptions } = options ?? {};
|
|
19
|
-
return (0, mlkit_manifest_1.withMlkitManifestMerge)((0, root_project_1.withAndroidRootProjectPins)(config, {
|
|
20
|
-
kotlinVersion: kotlinVersion ?? DEFAULT_KOTLIN_VERSION,
|
|
21
|
-
...(kspVersion !== undefined ? { kspVersion } : {}),
|
|
22
|
-
compileSdkVersion: COMPILE_SDK_VERSION,
|
|
23
|
-
forcedDependencies: FORCED_DEPENDENCIES,
|
|
24
|
-
}), manifestOptions);
|
|
25
|
-
};
|
|
26
|
-
exports.default = withMlkitFace;
|
|
27
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const root_project_1=require("./lib/root_project"),mlkit_manifest_1=require("./lib/mlkit_manifest"),DEFAULT_KOTLIN_VERSION="2.3.20",FORCED_DEPENDENCIES=["androidx.core:core:1.18.0","androidx.core:core-ktx:1.18.0"],withMlkitFace=(t,o)=>{const{kotlinVersion:i,kspVersion:e,...r}=o??{};return(0,mlkit_manifest_1.withMlkitManifestMerge)((0,root_project_1.withAndroidRootProjectPins)(t,{kotlinVersion:i??DEFAULT_KOTLIN_VERSION,...e!==void 0?{kspVersion:e}:{},forcedDependencies:FORCED_DEPENDENCIES}),r)};exports.default=withMlkitFace;
|
|
@@ -1,54 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// The AAR declares this meta-data without `tools:replace`, so only the host `<application>` can claim it for every ML Kit consumer at once.
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.withMlkitManifestMerge = void 0;
|
|
5
|
-
exports.mergedModelDependencies = mergedModelDependencies;
|
|
6
|
-
exports.applyMlkitManifestMerge = applyMlkitManifestMerge;
|
|
7
|
-
const config_plugins_1 = require("expo/config-plugins");
|
|
8
|
-
const META_DATA_NAME = "com.google.mlkit.vision.DEPENDENCIES";
|
|
9
|
-
const TOOLS_NAMESPACE = "http://schemas.android.com/tools";
|
|
10
|
-
/** The hint this package's AAR declares; always part of the merged value. */
|
|
11
|
-
const PROVIDER_MODEL_DEPENDENCY = "face";
|
|
12
|
-
// ML Kit's own hint vocabulary — lowercase words and underscores.
|
|
13
|
-
const MODEL_DEPENDENCY = /^[a-z0-9_]+$/;
|
|
14
|
-
/** Provider hint first, then the caller's, deduplicated and order-stable. */
|
|
15
|
-
function mergedModelDependencies(additional) {
|
|
16
|
-
for (const dependency of additional) {
|
|
17
|
-
if (!MODEL_DEPENDENCY.test(dependency)) {
|
|
18
|
-
throw new Error(`[smileid-android] '${dependency}' is not a valid ML Kit model dependency. ` +
|
|
19
|
-
"Expected a lowercase hint such as 'barcode_ui', as printed in the manifest-merger error.");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return [...new Set([PROVIDER_MODEL_DEPENDENCY, ...additional])].join(",");
|
|
23
|
-
}
|
|
24
|
-
/** Declares the merged `com.google.mlkit.vision.DEPENDENCIES` on the host `<application>` with `tools:replace`. */
|
|
25
|
-
const withMlkitManifestMerge = (config, options) => (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
26
|
-
config.modResults = applyMlkitManifestMerge(config.modResults, mergedModelDependencies(options?.additionalModelDependencies ?? []));
|
|
27
|
-
return config;
|
|
28
|
-
});
|
|
29
|
-
exports.withMlkitManifestMerge = withMlkitManifestMerge;
|
|
30
|
-
/** Pure form of the edit. Idempotent; a re-run replaces a stale value. */
|
|
31
|
-
function applyMlkitManifestMerge(manifest, value) {
|
|
32
|
-
const application = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(manifest);
|
|
33
|
-
application["meta-data"] ??= [];
|
|
34
|
-
const entries = application["meta-data"];
|
|
35
|
-
const existing = entries.find((entry) => entry?.$?.["android:name"] === META_DATA_NAME);
|
|
36
|
-
if (existing) {
|
|
37
|
-
existing.$["android:value"] = value;
|
|
38
|
-
existing.$["tools:replace"] = "android:value";
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
entries.push({
|
|
42
|
-
$: {
|
|
43
|
-
"android:name": META_DATA_NAME,
|
|
44
|
-
"android:value": value,
|
|
45
|
-
"tools:replace": "android:value",
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
// Without the namespace on <manifest>, `tools:replace` merges as an unknown attribute.
|
|
50
|
-
manifest.manifest.$ ??= {};
|
|
51
|
-
manifest.manifest.$["xmlns:tools"] ??= TOOLS_NAMESPACE;
|
|
52
|
-
return manifest;
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=mlkit_manifest.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.withMlkitManifestMerge=void 0,exports.mergedModelDependencies=mergedModelDependencies,exports.applyMlkitManifestMerge=applyMlkitManifestMerge;const config_plugins_1=require("expo/config-plugins"),META_DATA_NAME="com.google.mlkit.vision.DEPENDENCIES",TOOLS_NAMESPACE="http://schemas.android.com/tools",PROVIDER_MODEL_DEPENDENCY="face",MODEL_DEPENDENCY=/^[a-z0-9_]+$/;function mergedModelDependencies(e){for(const t of e)if(!MODEL_DEPENDENCY.test(t))throw new Error(`[smileid-android] '${t}' is not a valid ML Kit model dependency. Expected a lowercase hint such as 'barcode_ui', as printed in the manifest-merger error.`);return[...new Set([PROVIDER_MODEL_DEPENDENCY,...e])].join(",")}const withMlkitManifestMerge=(e,t)=>(0,config_plugins_1.withAndroidManifest)(e,n=>(n.modResults=applyMlkitManifestMerge(n.modResults,mergedModelDependencies(t?.additionalModelDependencies??[])),n));exports.withMlkitManifestMerge=withMlkitManifestMerge;function applyMlkitManifestMerge(e,t){const n=config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(e);n["meta-data"]??=[];const i=n["meta-data"],o=i.find(s=>s?.$?.["android:name"]===META_DATA_NAME);return o?(o.$["android:value"]=t,o.$["tools:replace"]="android:value"):i.push({$:{"android:name":META_DATA_NAME,"android:value":t,"tools:replace":"android:value"}}),e.manifest.$??={},e.manifest.$["xmlns:tools"]??=TOOLS_NAMESPACE,e}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type ConfigPlugin } from "expo/config-plugins";
|
|
1
|
+
import { type AndroidConfig, type ConfigPlugin } from "expo/config-plugins";
|
|
2
|
+
type PropertiesItem = AndroidConfig.Properties.PropertiesItem;
|
|
2
3
|
export interface AndroidRootProjectPins {
|
|
3
4
|
/**
|
|
4
5
|
* Opt-in: only for hosts whose Kotlin predates the AARs' compiler. Current
|
|
@@ -8,12 +9,19 @@ export interface AndroidRootProjectPins {
|
|
|
8
9
|
kotlinVersion?: string;
|
|
9
10
|
/** Only alongside `kotlinVersion` — Expo's own lookup table may carry no entry for it. */
|
|
10
11
|
kspVersion?: string;
|
|
11
|
-
/**
|
|
12
|
-
compileSdkVersion
|
|
12
|
+
/** Opt-in: only for a host that must compile above React Native's default. The AARs declare their own consumer floor. */
|
|
13
|
+
compileSdkVersion?: number;
|
|
13
14
|
/** `group:name:version` coordinates forced everywhere, for deps whose newest release the host toolchain cannot consume. */
|
|
14
15
|
forcedDependencies: readonly string[];
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* AGP matches this against the resolved platform, which may or may not carry a minor
|
|
19
|
+
* (`android-37` vs `android-37.0`), so both forms are listed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function suppressUnsupportedCompileSdkValue(compileSdkVersion: number): string;
|
|
22
|
+
export declare function suppressAdvisoryProperties(items: PropertiesItem[], compileSdkVersion: number | undefined): PropertiesItem[];
|
|
16
23
|
/** Declares the pins ahead of `apply plugin: "expo-root-project"`. */
|
|
17
24
|
export declare const withAndroidRootProjectPins: ConfigPlugin<AndroidRootProjectPins>;
|
|
18
25
|
/** Pure form of the edit. Idempotent; a re-run replaces stale values rather than appending. */
|
|
19
26
|
export declare function applyAndroidRootProjectPins(contents: string, pins: AndroidRootProjectPins): string;
|
|
27
|
+
export {};
|
|
@@ -1,109 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// `expo-root-project`
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.withAndroidRootProjectPins = void 0;
|
|
6
|
-
exports.applyAndroidRootProjectPins = applyAndroidRootProjectPins;
|
|
7
|
-
const config_plugins_1 = require("expo/config-plugins");
|
|
8
|
-
const BEGIN_MARKER = "// === BEGIN smileid root-project pins ===";
|
|
9
|
-
const END_MARKER = "// === END smileid root-project pins ===";
|
|
10
|
-
const APPLY_ROOT_PROJECT = /^apply\s+plugin:\s*["']expo-root-project["']/m;
|
|
11
|
-
// Bumping `ext.kotlinVersion` moves the dependency catalog but not the compiler, so
|
|
12
|
-
// the classpath line needs pinning too. Version and parentheses are optional so an
|
|
13
|
-
// already-pinned line and Groovy's space-call form still match.
|
|
14
|
-
const KGP_CLASSPATH = /classpath\s*(?:\(\s*)?['"]org\.jetbrains\.kotlin:kotlin-gradle-plugin(?::[^'"]*)?['"](?:\s*\))?/;
|
|
15
|
-
/** Declares the pins ahead of `apply plugin: "expo-root-project"`. */
|
|
16
|
-
const withAndroidRootProjectPins = (config, pins) => (0, config_plugins_1.withProjectBuildGradle)(config, (config) => {
|
|
17
|
-
if (config.modResults.language !== "groovy") {
|
|
18
|
-
throw new Error("[smileid-android] Expected android/build.gradle to be Groovy DSL; refusing to edit " +
|
|
19
|
-
`a ${config.modResults.language} build script.`);
|
|
20
|
-
}
|
|
21
|
-
config.modResults.contents = applyAndroidRootProjectPins(config.modResults.contents, pins);
|
|
22
|
-
return config;
|
|
23
|
-
});
|
|
24
|
-
exports.withAndroidRootProjectPins = withAndroidRootProjectPins;
|
|
25
|
-
/** Pure form of the edit. Idempotent; a re-run replaces stale values rather than appending. */
|
|
26
|
-
function applyAndroidRootProjectPins(contents, pins) {
|
|
27
|
-
if (pins.kspVersion !== undefined && pins.kotlinVersion === undefined) {
|
|
28
|
-
throw new Error("[smileid-android] `kspVersion` only makes sense alongside `kotlinVersion`.");
|
|
29
|
-
}
|
|
30
|
-
validateGroovySafe(pins);
|
|
31
|
-
const pinned = pins.kotlinVersion === undefined
|
|
32
|
-
? contents
|
|
33
|
-
: pinKotlinGradlePlugin(contents, pins.kotlinVersion);
|
|
34
|
-
return upsertPinBlock(pinned, renderPinBlock(pins));
|
|
35
|
-
}
|
|
36
|
-
// Every value lands in a single-quoted Groovy literal; reject anything that could close one.
|
|
37
|
-
function validateGroovySafe(pins) {
|
|
38
|
-
const values = [
|
|
39
|
-
pins.kotlinVersion,
|
|
40
|
-
pins.kspVersion,
|
|
41
|
-
...pins.forcedDependencies,
|
|
42
|
-
].filter((value) => value !== undefined);
|
|
43
|
-
for (const value of values) {
|
|
44
|
-
if (/['\\\n\r\t$]/.test(value)) {
|
|
45
|
-
throw new Error(`[smileid-android] Refusing to edit android/build.gradle: '${value}' contains an unsafe character.`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function pinKotlinGradlePlugin(contents, kotlinVersion) {
|
|
50
|
-
const pinned = `classpath('org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}')`;
|
|
51
|
-
if (!KGP_CLASSPATH.test(contents)) {
|
|
52
|
-
throw new Error("[smileid-android] Could not locate the kotlin-gradle-plugin classpath line in " +
|
|
53
|
-
"android/build.gradle. Refusing to silently no-op — the Smile ID analyzer modules do not " +
|
|
54
|
-
`compile unless the Kotlin compiler is pinned to ${kotlinVersion}.`);
|
|
55
|
-
}
|
|
56
|
-
return contents.replace(KGP_CLASSPATH, pinned);
|
|
57
|
-
}
|
|
58
|
-
// Adding a further root-project pin means adding an entry here.
|
|
59
|
-
function renderPinBlock(pins) {
|
|
60
|
-
const extProperties = [];
|
|
61
|
-
if (pins.kotlinVersion !== undefined) {
|
|
62
|
-
extProperties.push(["kotlinVersion", `'${pins.kotlinVersion}'`]);
|
|
63
|
-
}
|
|
64
|
-
if (pins.kspVersion !== undefined) {
|
|
65
|
-
extProperties.push(["kspVersion", `'${pins.kspVersion}'`]);
|
|
66
|
-
}
|
|
67
|
-
extProperties.push(["compileSdkVersion", String(pins.compileSdkVersion)]);
|
|
68
|
-
const lines = extProperties.map(([name, value]) => `ext.${name} = ${value}`);
|
|
69
|
-
return [
|
|
70
|
-
BEGIN_MARKER,
|
|
71
|
-
...lines,
|
|
72
|
-
...renderForcedDependencies(pins.forcedDependencies),
|
|
73
|
-
END_MARKER,
|
|
74
|
-
].join("\n");
|
|
75
|
-
}
|
|
76
|
-
// Its own `allprojects` block, which Gradle merges — editing the template's would
|
|
77
|
-
// break the moment its shape changes.
|
|
78
|
-
function renderForcedDependencies(coordinates) {
|
|
79
|
-
if (coordinates.length === 0) {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
return [
|
|
83
|
-
"",
|
|
84
|
-
"// Forced to the newest release that resolves under the AGP Expo generates.",
|
|
85
|
-
"allprojects {",
|
|
86
|
-
" configurations.all {",
|
|
87
|
-
" resolutionStrategy {",
|
|
88
|
-
...coordinates.map((coordinate) => ` force '${coordinate}'`),
|
|
89
|
-
" }",
|
|
90
|
-
" }",
|
|
91
|
-
"}",
|
|
92
|
-
];
|
|
93
|
-
}
|
|
94
|
-
function upsertPinBlock(contents, block) {
|
|
95
|
-
const existing = new RegExp(`${escapeRegExp(BEGIN_MARKER)}[\\s\\S]*?${escapeRegExp(END_MARKER)}`, "m");
|
|
96
|
-
if (existing.test(contents)) {
|
|
97
|
-
return contents.replace(existing, block);
|
|
98
|
-
}
|
|
99
|
-
if (!APPLY_ROOT_PROJECT.test(contents)) {
|
|
100
|
-
throw new Error('[smileid-android] Could not locate `apply plugin: "expo-root-project"` in ' +
|
|
101
|
-
"android/build.gradle. Refusing to silently no-op — these pins only take effect when " +
|
|
102
|
-
"declared before that plugin applies.");
|
|
103
|
-
}
|
|
104
|
-
return contents.replace(APPLY_ROOT_PROJECT, (match) => `${block}\n\n${match}`);
|
|
105
|
-
}
|
|
106
|
-
function escapeRegExp(value) {
|
|
107
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108
|
-
}
|
|
109
|
-
//# sourceMappingURL=root_project.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.withAndroidRootProjectPins=void 0,exports.suppressUnsupportedCompileSdkValue=suppressUnsupportedCompileSdkValue,exports.suppressAdvisoryProperties=suppressAdvisoryProperties,exports.applyAndroidRootProjectPins=applyAndroidRootProjectPins;const config_plugins_1=require("expo/config-plugins"),SUPPRESS_KEY="android.suppressUnsupportedCompileSdk",BEGIN_MARKER="// === BEGIN smileid root-project pins ===",END_MARKER="// === END smileid root-project pins ===",APPLY_ROOT_PROJECT=/^apply\s+plugin:\s*["']expo-root-project["']/m,KGP_CLASSPATH=/classpath\s*(?:\(\s*)?['"]org\.jetbrains\.kotlin:kotlin-gradle-plugin(?::[^'"]*)?['"](?:\s*\))?/;function suppressUnsupportedCompileSdkValue(e){return`${e},${e}.0`}function suppressAdvisoryProperties(e,o){if(o===void 0)return e;const r={type:"property",key:SUPPRESS_KEY,value:suppressUnsupportedCompileSdkValue(o)},n=e.findIndex(t=>t.type==="property"&&t.key===SUPPRESS_KEY);return n===-1?[...e,r]:e.map((t,i)=>i===n?r:t)}const withSuppressedCompileSdkAdvisory=(e,o)=>(0,config_plugins_1.withGradleProperties)(e,r=>(r.modResults=suppressAdvisoryProperties(r.modResults,o),r)),withAndroidRootProjectPins=(e,o)=>withSuppressedCompileSdkAdvisory((0,config_plugins_1.withProjectBuildGradle)(e,r=>{if(r.modResults.language!=="groovy")throw new Error(`[smileid-android] Expected android/build.gradle to be Groovy DSL; refusing to edit a ${r.modResults.language} build script.`);return r.modResults.contents=applyAndroidRootProjectPins(r.modResults.contents,o),r}),o.compileSdkVersion);exports.withAndroidRootProjectPins=withAndroidRootProjectPins;function applyAndroidRootProjectPins(e,o){if(o.kspVersion!==void 0&&o.kotlinVersion===void 0)throw new Error("[smileid-android] `kspVersion` only makes sense alongside `kotlinVersion`.");validateGroovySafe(o);const r=o.kotlinVersion===void 0?e:pinKotlinGradlePlugin(e,o.kotlinVersion);return upsertPinBlock(r,renderPinBlock(o))}function validateGroovySafe(e){const o=[e.kotlinVersion,e.kspVersion,...e.forcedDependencies].filter(r=>r!==void 0);for(const r of o)if(/['\\\n\r\t$]/.test(r))throw new Error(`[smileid-android] Refusing to edit android/build.gradle: '${r}' contains an unsafe character.`)}function pinKotlinGradlePlugin(e,o){const r=`classpath('org.jetbrains.kotlin:kotlin-gradle-plugin:${o}')`;if(!KGP_CLASSPATH.test(e))throw new Error(`[smileid-android] Could not locate the kotlin-gradle-plugin classpath line in android/build.gradle. Refusing to silently no-op \u2014 the Smile ID analyzer modules do not compile unless the Kotlin compiler is pinned to ${o}.`);return e.replace(KGP_CLASSPATH,r)}function renderPinBlock(e){const o=[];e.kotlinVersion!==void 0&&o.push(["kotlinVersion",`'${e.kotlinVersion}'`]),e.kspVersion!==void 0&&o.push(["kspVersion",`'${e.kspVersion}'`]),e.compileSdkVersion!==void 0&&o.push(["compileSdkVersion",String(e.compileSdkVersion)]);const r=o.map(([n,t])=>`ext.${n} = ${t}`);return[BEGIN_MARKER,...r,...renderForcedDependencies(e.forcedDependencies),END_MARKER].join(`
|
|
2
|
+
`)}function renderForcedDependencies(e){return e.length===0?[]:["","// Forced to the newest release that resolves under the AGP Expo generates.","allprojects {"," configurations.all {"," resolutionStrategy {",...e.map(o=>` force '${o}'`)," }"," }","}"]}function upsertPinBlock(e,o){const r=new RegExp(`${escapeRegExp(BEGIN_MARKER)}[\\s\\S]*?${escapeRegExp(END_MARKER)}`,"m");if(r.test(e))return e.replace(r,o);if(!APPLY_ROOT_PROJECT.test(e))throw new Error('[smileid-android] Could not locate `apply plugin: "expo-root-project"` in android/build.gradle. Refusing to silently no-op \u2014 these pins only take effect when declared before that plugin applies.');return e.replace(APPLY_ROOT_PROJECT,n=>`${o}
|
|
3
|
+
|
|
4
|
+
${n}`)}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}
|