@smileid/usesmileid_vision_document 12.0.1 → 12.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ Full release notes: [Smile ID docs](https://docs.usesmileid.com/developer-resources/sdks/mobile/release-notes/react-native-expo).
2
+
3
+ ## 12.1.0
4
+
5
+ See the repository CHANGELOG for the 12.1.0 release notes.
6
+
7
+
8
+ ## 12.0.2
9
+
10
+ See the repository CHANGELOG for the 12.0.2 release notes.
11
+
1
12
  ## 12.0.1
2
13
 
3
14
  See the repository CHANGELOG for the 12.0.1 release notes.
package/README.md CHANGED
@@ -17,14 +17,46 @@ No ML logic is reimplemented in this package — it's a pure passthrough.
17
17
  ## Installation
18
18
 
19
19
  ```sh
20
- pnpm add @smileid/usesmileid_vision_document
20
+ pnpm add @smileid/usesmileid_vision_document react-native-vision-camera@^4
21
21
  ```
22
22
 
23
+ This package's pod depends on VisionCamera: without it `pod install` fails
24
+ with `Unable to find a specification for VisionCamera depended upon by
25
+ UseSmileIDVisionDocumentExpo`. Pin v4 — the SDK is built against the v4
26
+ API, and a bare `expo install react-native-vision-camera` resolves a v5.
27
+
23
28
  The Smile ID native SDK is declared as an SPM dependency in
24
29
  `expo-module.config.json`. Expo Modules autolinking surfaces it to
25
30
  the iOS target — partners do not need to add anything to their
26
31
  `Podfile` beyond the standard `use_expo_modules!` invocation.
27
32
 
33
+ ## Config plugin options
34
+
35
+ | Option | Values | Default |
36
+ | ------------------------- | ------------------------ | -------- |
37
+ | `iosSignatureAggregation` | `"keep"` \| `"disabled"` | `"keep"` |
38
+
39
+ Several targets have to reference the same signed Smile ID XCFramework, and an
40
+ iOS release archive collects framework signatures into one directory keyed by
41
+ filename — so `"keep"` adds a build phase that leaves exactly one staged copy of
42
+ each signature while the archive is assembled.
43
+
44
+ `"disabled"` instead turns off Xcode's signature aggregation for the app target.
45
+ Reach for it only if an Xcode version we have not seen still fails to archive:
46
+ it drops the recorded signatures of every framework in the archive, including
47
+ your own and other vendors'.
48
+
49
+ ```json
50
+ {
51
+ "plugins": [
52
+ [
53
+ "@smileid/usesmileid_vision_document",
54
+ { "iosSignatureAggregation": "disabled" }
55
+ ]
56
+ ]
57
+ }
58
+ ```
59
+
28
60
  ## Usage
29
61
 
30
62
  ```ts
package/dist/index.d.ts CHANGED
@@ -18,9 +18,10 @@ import type { DocumentConfig, DocumentScanResult } from "@smileid/usesmileid_bri
18
18
  * contract.
19
19
  */
20
20
  /**
21
- * Must match the Swift Expo Module's `Name("UseSmileIDVisionDocument")` and
22
- * its VisionCamera frame-processor-plugin registration — drift is a runtime
23
- * "module/plugin not found" error, not a compile error.
21
+ * Must match the Swift Expo Module's `Name("UseSmileIDVisionDocument")` — drift is a runtime
22
+ * "module not found" error, not a compile error.
23
+ *
24
+ * `frameProcessorPluginName` is inert; kept only for API compatibility.
24
25
  */
25
26
  export declare const UseSmileIDVisionDocumentIdentifiers: {
26
27
  readonly nativeModuleName: "UseSmileIDVisionDocument";
@@ -28,4 +29,3 @@ export declare const UseSmileIDVisionDocumentIdentifiers: {
28
29
  };
29
30
  export declare const useSmileIDVisionDocument: import("@smileid/usesmileid_platform_interface").DocumentAnalyzer;
30
31
  export type { DocumentConfig, DocumentScanResult };
31
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,34 +1 @@
1
- import { useSmileIDAnalyzerExecutor } from "@smileid/usesmileid_platform_interface";
2
- /**
3
- * Apple Vision document analyzer (iOS-only).
4
- *
5
- * Thin shim around the existing native session
6
- * `UseSmileID.UseSmileIDDocumentSession(DocumentDetectorAnalyzer())` shipped
7
- * in the `UseSmileIDVisionDocument` Swift Package. The native side runs the
8
- * entire pipeline (analyzer + validator + transitioner + state machine);
9
- * this TS layer routes calls and validates wire payloads at the channel
10
- * boundary.
11
- *
12
- * The canonical wiring lives in [useSmileIDAnalyzerExecutor] in
13
- * `usesmileid_platform_interface`.
14
- *
15
- * Lifecycle: `configure()` → per-frame analysis via the native frame
16
- * processor plugin → `reset()`? → `close()`. See
17
- * `usesmileid_platform_interface` `DocumentAnalyzer` for the canonical
18
- * contract.
19
- */
20
- /**
21
- * Must match the Swift Expo Module's `Name("UseSmileIDVisionDocument")` and
22
- * its VisionCamera frame-processor-plugin registration — drift is a runtime
23
- * "module/plugin not found" error, not a compile error.
24
- */
25
- export const UseSmileIDVisionDocumentIdentifiers = {
26
- nativeModuleName: "UseSmileIDVisionDocument",
27
- frameProcessorPluginName: "UseSmileIDVisionDocumentFrameProcessor",
28
- };
29
- export const useSmileIDVisionDocument = useSmileIDAnalyzerExecutor({
30
- nativeModuleName: UseSmileIDVisionDocumentIdentifiers.nativeModuleName,
31
- frameProcessorPluginName: UseSmileIDVisionDocumentIdentifiers.frameProcessorPluginName,
32
- kind: "document",
33
- });
34
- //# sourceMappingURL=index.js.map
1
+ "use strict";import{useSmileIDAnalyzerExecutor as e}from"@smileid/usesmileid_platform_interface";export const UseSmileIDVisionDocumentIdentifiers={nativeModuleName:"UseSmileIDVisionDocument",frameProcessorPluginName:"UseSmileIDVisionDocumentFrameProcessor"},useSmileIDVisionDocument=e({nativeModuleName:UseSmileIDVisionDocumentIdentifiers.nativeModuleName,frameProcessorPluginName:UseSmileIDVisionDocumentIdentifiers.frameProcessorPluginName,kind:"document"});
@@ -20,11 +20,8 @@ Pod::Spec.new do |s|
20
20
  s.static_framework = true
21
21
 
22
22
  s.dependency 'ExpoModulesCore'
23
- # VisionCamera provides the FrameProcessorPlugin base class and
24
- # FrameProcessorPluginRegistry used by UseSmileIDVisionDocumentFrameProcessorPlugin.
25
- # Frame processors additionally require react-native-worklets-core in the
26
- # consuming app (already declared as an SDK peer dependency).
27
- s.dependency 'VisionCamera'
23
+ # kamera native core (pre-release pod); analyzeKameraFrame takes frames from its KameraFrameHub.
24
+ s.dependency 'kamera-rn'
28
25
 
29
26
  # The Smile ID native deps (`UseSmileIDVisionDocument` / `UseSmileIDBridge`)
30
27
  # are SPM-only — declared in `expo-module.config.json` under
@@ -34,7 +34,7 @@ final class ResizingFrameStorage: FrameStorage {
34
34
  private let livenessQuality: CGFloat
35
35
  private let documentQuality: CGFloat
36
36
  private let writer: Writer
37
- // The frame-processor plugin calls `setCropRegion` on the VisionCamera FP
37
+ // The analysis tick calls `setCropRegion` on the module's async-function
38
38
  // thread; `persist` reads the value on that same serialised scan path before
39
39
  // handing it (by value) to the background encode task. The Swift value is a
40
40
  // `Sendable` struct captured by value into `Writer.enqueue`, so no background
@@ -0,0 +1,80 @@
1
+ import CoreMedia
2
+ import Kamera
3
+ import CoreImage
4
+ import UIKit
5
+ import UseSmileIDBridge
6
+
7
+
8
+ private extension CGImagePropertyOrientation {
9
+ /// Kamera rotation + mirror metadata → the preview's view of the frame. The rotation already
10
+ /// follows the locked interface axis, so no further fold onto the viewport is needed.
11
+ init(rotationDegrees: Int, isMirrored: Bool) {
12
+ let normalised = ((rotationDegrees % 360) + 360) % 360
13
+ switch (normalised, isMirrored) {
14
+ case (90, false): self = .right
15
+ case (90, true): self = .leftMirrored
16
+ case (180, false): self = .down
17
+ case (180, true): self = .downMirrored
18
+ case (270, false): self = .left
19
+ case (270, true): self = .rightMirrored
20
+ case (_, true): self = .upMirrored
21
+ default: self = .up
22
+ }
23
+ }
24
+ }
25
+
26
+ /// Scans the latest `KameraFrameHub` frame; no pending frame returns the `no_frame` wire error.
27
+ enum UseSmileIDVisionDocumentKameraTick {
28
+ /// Reused across ticks — per-tick creation recompiles the GPU pipeline.
29
+ private static let ciContext = CIContext(options: [.useSoftwareRenderer: false])
30
+
31
+ static func analyze(arguments: [String: Any?]?) -> Any {
32
+ guard let frame = KameraFrameHub.take() else {
33
+ return ["error": "no_frame"]
34
+ }
35
+ guard let concrete = frame as? CVPixelBufferKameraFrame else {
36
+ frame.close()
37
+ return ["error": "frame_conversion_failed"]
38
+ }
39
+
40
+ let orientedImage = CIImage(cvPixelBuffer: concrete.pixelBuffer)
41
+ .oriented(CGImagePropertyOrientation(
42
+ rotationDegrees: frame.rotationDegrees,
43
+ isMirrored: frame.isMirrored
44
+ ))
45
+ let cgImage = ciContext.createCGImage(orientedImage, from: orientedImage.extent)
46
+ frame.close()
47
+ guard let cgImage else {
48
+ return ["error": "frame_conversion_failed"]
49
+ }
50
+
51
+ let rotation = (arguments?["rotation"] as? NSNumber)?.intValue ?? 0
52
+
53
+ // Crop the saved capture to the guide rectangle the user framed.
54
+ UseSmileIDVisionDocumentSessionHolder.shared.setCropRegion(kameraCropRegionFrom(arguments))
55
+
56
+ guard let result = UseSmileIDVisionDocumentSessionHolder.shared.scanAndDrain(
57
+ image: UIImage(cgImage: cgImage),
58
+ rotation: rotation
59
+ ) else {
60
+ return ["error": "session_not_configured"]
61
+ }
62
+ return result
63
+ }
64
+ }
65
+
66
+ /// Crop region from the flat crop args; nil when `cropWidth <= 0` means no region.
67
+ private func kameraCropRegionFrom(_ arguments: [String: Any?]?) -> ViewportCropRegion? {
68
+ guard let width = (arguments?["cropWidth"] as? NSNumber)?.floatValue, width > 0 else {
69
+ return nil
70
+ }
71
+ return ViewportCropRegion(
72
+ left: (arguments?["cropLeft"] as? NSNumber)?.floatValue ?? 0,
73
+ top: (arguments?["cropTop"] as? NSNumber)?.floatValue ?? 0,
74
+ width: width,
75
+ height: (arguments?["cropHeight"] as? NSNumber)?.floatValue ?? 0,
76
+ viewportWidthPx: (arguments?["cropViewportWidth"] as? NSNumber)?.intValue ?? 0,
77
+ viewportHeightPx: (arguments?["cropViewportHeight"] as? NSNumber)?.intValue ?? 0,
78
+ contentScale: .crop
79
+ )
80
+ }
@@ -1,8 +1,6 @@
1
1
  import ExpoModulesCore
2
- import UIKit
3
2
  import UseSmileIDBridge
4
3
  import UseSmileIDVisionDocument
5
- import VisionCamera
6
4
 
7
5
  /// Expo Module bridging the native `UseSmileIDDocumentSession` (from the
8
6
  /// `UseSmileIDVisionDocument` Swift Package) to JS. No ML logic here — it
@@ -12,10 +10,6 @@ import VisionCamera
12
10
  public class UseSmileIDVisionDocumentModule: Module {
13
11
  private lazy var analyzer: DocumentDetectorAnalyzer = DocumentDetectorAnalyzer.Factory().newInstance()!
14
12
 
15
- /// Prevents double-registration of the frame processor plugin when
16
- /// Expo Go / dev-client fast-refreshes the JS bundle and `OnCreate`
17
- /// runs again in the same native process.
18
- private static var isFrameProcessorRegistered = false
19
13
 
20
14
  private var session: UseSmileIDDocumentSession?
21
15
 
@@ -23,13 +17,6 @@ public class UseSmileIDVisionDocumentModule: Module {
23
17
  Name("UseSmileIDVisionDocument")
24
18
 
25
19
  OnCreate {
26
- // Guard prevents double-registration on dev-client fast-refresh reloads.
27
- if !Self.isFrameProcessorRegistered {
28
- FrameProcessorPluginRegistry.addFrameProcessorPlugin("UseSmileIDVisionDocumentFrameProcessor") { proxy, options in
29
- UseSmileIDVisionDocumentFrameProcessorPlugin(proxy: proxy, options: options)
30
- }
31
- Self.isFrameProcessorRegistered = true
32
- }
33
20
  }
34
21
 
35
22
  AsyncFunction("configure") { (config: [String: Any?]) in
@@ -64,6 +51,11 @@ public class UseSmileIDVisionDocumentModule: Module {
64
51
  UseSmileIDVisionDocumentSessionHolder.shared.setStorage(storage)
65
52
  }
66
53
 
54
+ AsyncFunction("analyzeKameraFrame") { (arguments: [String: Any?]?) -> Any in
55
+ // Runs on this module's async queue, so only one scan is in flight at a time.
56
+ UseSmileIDVisionDocumentKameraTick.analyze(arguments: arguments)
57
+ }
58
+
67
59
  AsyncFunction("reset") {
68
60
  UseSmileIDVisionDocumentSessionHolder.shared.reset()
69
61
  }
@@ -121,7 +113,9 @@ private extension Dictionary where Key == String, Value == Any? {
121
113
  timeout: (self["timeout"] as? NSNumber)?.intValue ?? 15_000,
122
114
  iouThreshold: (self["iouThreshold"] as? NSNumber)?.floatValue ?? 0.85,
123
115
  timeRequired: (self["timeRequired"] as? NSNumber)?.intValue ?? 1_000,
124
- minCoverageThreshold: (self["minCoverageThreshold"] as? NSNumber)?.floatValue ?? 0.18,
116
+ // Coverage is measured against the full analysis frame, which is wider than the preview;
117
+ // a guide-filling document covers only ~0.2 of it, so the floor must sit below that.
118
+ minCoverageThreshold: (self["minCoverageThreshold"] as? NSNumber)?.floatValue ?? 0.12,
125
119
  maxCoverageThreshold: (self["maxCoverageThreshold"] as? NSNumber)?.floatValue ?? 0.78,
126
120
  centerToleranceX: (self["centerToleranceX"] as? NSNumber)?.floatValue ?? 0.05,
127
121
  centerToleranceY: (self["centerToleranceY"] as? NSNumber)?.floatValue ?? 0.05
@@ -214,3 +208,4 @@ extension UseSmileIDBridge.UseSmileIDScanState {
214
208
  return map
215
209
  }
216
210
  }
211
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smileid/usesmileid_vision_document",
3
- "version": "12.0.1",
3
+ "version": "12.1.0",
4
4
  "description": "Apple Vision document detection implementation for the UseSmileID React Native (Expo) SDK.",
5
5
  "homepage": "https://usesmileid.com",
6
6
  "repository": {
@@ -36,11 +36,9 @@
36
36
  },
37
37
  "files": [
38
38
  "dist",
39
- "src",
40
- "ios",
39
+ "ios/UseSmileIDVisionDocumentExpo.podspec",
40
+ "ios/UseSmileIDVisionDocumentModule",
41
41
  "plugin/build",
42
- "plugin/src",
43
- "plugin/tsconfig.json",
44
42
  "app.plugin.js",
45
43
  "expo-module.config.json",
46
44
  "README.md",
@@ -48,8 +46,8 @@
48
46
  "CHANGELOG.md"
49
47
  ],
50
48
  "dependencies": {
51
- "@smileid/usesmileid_bridge": "12.0.1",
52
- "@smileid/usesmileid_platform_interface": "12.0.1"
49
+ "@smileid/usesmileid_platform_interface": "12.1.0",
50
+ "@smileid/usesmileid_bridge": "12.1.0"
53
51
  },
54
52
  "peerDependencies": {
55
53
  "expo": ">=56.0.0",
@@ -57,22 +55,23 @@
57
55
  "react-native": ">=0.83.0"
58
56
  },
59
57
  "devDependencies": {
60
- "@expo/config-plugins": "^56.0.8",
61
- "@types/node": "^25.9.1",
62
- "expo-modules-core": "^56.0.15",
63
- "react-native": "^0.85.3",
64
- "typescript": "^6.0.3"
58
+ "@types/node": "^26.4.1",
59
+ "expo": "~57.0.20",
60
+ "expo-modules-core": "^57.0.16",
61
+ "react-native": "^0.86.3",
62
+ "typescript": "^6.0.3",
63
+ "xcode": "^3.0.1"
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
  }
@@ -1,3 +1,12 @@
1
- import { ConfigPlugin } from "@expo/config-plugins";
2
- declare const withVisionDocumentSpm: ConfigPlugin;
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
+ export interface VisionDocumentOptions {
3
+ /**
4
+ * `"disabled"` stops Xcode recording XCFramework signatures in iOS archives
5
+ * instead of keeping one staged copy per framework — an escape hatch that
6
+ * drops the records for every framework, Smile ID's and yours alike.
7
+ */
8
+ iosSignatureAggregation?: "keep" | "disabled";
9
+ }
10
+ export declare const SPM_PRODUCTS: readonly ["UseSmileIDVisionDocument"];
11
+ declare const withVisionDocumentSpm: ConfigPlugin<VisionDocumentOptions | void>;
3
12
  export default withVisionDocumentSpm;
@@ -1,107 +1 @@
1
- "use strict";
2
- // Expo config plugin that wires the Smile Identity Swift Package
3
- // (`https://github.com/smileidentity/ios-spm`) into both:
4
- // 1. The consuming app's Xcode project — so the .xcframeworks ship
5
- // and embed in the final .app bundle.
6
- // 2. The autogenerated Pods.xcodeproj at `pod install` time — so
7
- // the Expo Module bridge (`UseSmileIDVisionDocumentExpo`) compiles
8
- // with `import UseSmileIDVisionDocument` / `import UseSmileIDBridge`.
9
- //
10
- // Why a plugin: `expo-modules-autolinking@55.0.x`'s
11
- // `RawModuleConfigApple` schema has no `dependencies` field, so the
12
- // `apple.dependencies` block in `expo-module.config.json` is silently
13
- // ignored. Without this plugin, neither the bridge nor the host app
14
- // know about the SPM package.
15
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- var desc = Object.getOwnPropertyDescriptor(m, k);
18
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
- desc = { enumerable: true, get: function() { return m[k]; } };
20
- }
21
- Object.defineProperty(o, k2, desc);
22
- }) : (function(o, m, k, k2) {
23
- if (k2 === undefined) k2 = k;
24
- o[k2] = m[k];
25
- }));
26
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
- Object.defineProperty(o, "default", { enumerable: true, value: v });
28
- }) : function(o, v) {
29
- o["default"] = v;
30
- });
31
- var __importStar = (this && this.__importStar) || (function () {
32
- var ownKeys = function(o) {
33
- ownKeys = Object.getOwnPropertyNames || function (o) {
34
- var ar = [];
35
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
- return ar;
37
- };
38
- return ownKeys(o);
39
- };
40
- return function (mod) {
41
- if (mod && mod.__esModule) return mod;
42
- var result = {};
43
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
- __setModuleDefault(result, mod);
45
- return result;
46
- };
47
- })();
48
- Object.defineProperty(exports, "__esModule", { value: true });
49
- const config_plugins_1 = require("@expo/config-plugins");
50
- const fs = __importStar(require("fs"));
51
- const path = __importStar(require("path"));
52
- const podfile_1 = require("./lib/podfile");
53
- const spm_1 = require("./lib/spm");
54
- // Pinned to the exact `12.0.0` release tag — `from: 12.0.0`
55
- // would not resolve because `ios-spm` publishes pre-release tags (e.g.
56
- // `12.0.0`), and SPM excludes pre-release tags from open-ended
57
- // major-version requirements.
58
- const SMILE_ID_PACKAGE = {
59
- url: "https://github.com/smileidentity/ios-spm",
60
- requirement: {
61
- kind: "exactVersion",
62
- version: "12.0.1-SNAPSHOT.20260729180601.30478033861",
63
- },
64
- };
65
- const POD_TARGET = "UseSmileIDVisionDocumentExpo";
66
- const SPM_PRODUCTS = ["UseSmileIDVisionDocument", "UseSmileIDBridge"];
67
- const PODFILE_MARKER = "usesmileid_vision_document";
68
- const withVisionDocumentSpm = (config) => {
69
- // 1. Add the package + products to the host app's Xcode project so
70
- // Xcode resolves the binary xcframeworks and embeds them in the
71
- // .app at link time.
72
- config = (0, config_plugins_1.withXcodeProject)(config, (config) => {
73
- const appTarget = config.modRequest.projectName;
74
- if (!appTarget) {
75
- throw new Error("[usesmileid_vision_document] Unable to resolve host app native target name from Expo config.");
76
- }
77
- (0, spm_1.linkSpmPackage)(config.modResults, SMILE_ID_PACKAGE, {
78
- targetName: appTarget,
79
- products: [...SPM_PRODUCTS],
80
- });
81
- return config;
82
- });
83
- // 2. Inject a Ruby block into the Podfile's post_install hook that
84
- // re-applies the same wiring to Pods.xcodeproj when CocoaPods
85
- // materializes it. The bridge pod target needs the products
86
- // visible at compile time; the host-app step alone isn't enough.
87
- config = (0, config_plugins_1.withDangerousMod)(config, [
88
- "ios",
89
- (config) => {
90
- const podfilePath = path.join(config.modRequest.platformProjectRoot, "Podfile");
91
- const original = fs.readFileSync(podfilePath, "utf-8");
92
- const next = (0, podfile_1.injectPodfileSpmBlock)(original, {
93
- marker: PODFILE_MARKER,
94
- package: SMILE_ID_PACKAGE,
95
- podTarget: POD_TARGET,
96
- products: [...SPM_PRODUCTS],
97
- });
98
- if (next !== original) {
99
- fs.writeFileSync(podfilePath, next);
100
- }
101
- return config;
102
- },
103
- ]);
104
- return config;
105
- };
106
- exports.default = withVisionDocumentSpm;
107
- //# sourceMappingURL=index.js.map
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(i,r,t,e){e===void 0&&(e=t);var o=Object.getOwnPropertyDescriptor(r,t);(!o||("get"in o?!r.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(i,e,o)}):(function(i,r,t,e){e===void 0&&(e=t),i[e]=r[t]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(i,r){Object.defineProperty(i,"default",{enumerable:!0,value:r})}):function(i,r){i.default=r}),__importStar=this&&this.__importStar||(function(){var i=function(r){return i=Object.getOwnPropertyNames||function(t){var e=[];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[e.length]=o);return e},i(r)};return function(r){if(r&&r.__esModule)return r;var t={};if(r!=null)for(var e=i(r),o=0;o<e.length;o++)e[o]!=="default"&&__createBinding(t,r,e[o]);return __setModuleDefault(t,r),t}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.SPM_PRODUCTS=void 0;const config_plugins_1=require("expo/config-plugins"),fs=__importStar(require("fs")),path=__importStar(require("path")),deployment_target_1=require("./lib/deployment_target"),podfile_1=require("./lib/podfile"),signature_dedup_1=require("./lib/signature_dedup"),spm_1=require("./lib/spm"),IOS_DEPLOYMENT_TARGET="16.4",SMILE_ID_PACKAGE={url:"https://github.com/smileidentity/ios-spm",requirement:{kind:"exactVersion",version:"12.1.0"}},POD_TARGET="UseSmileIDVisionDocumentExpo";exports.SPM_PRODUCTS=["UseSmileIDVisionDocument"];const PODFILE_MARKER="usesmileid_vision_document",BRIDGE_POD_TARGET="UseSmileIDBridgeExpo",BRIDGE_SPM_PRODUCTS=["UseSmileIDBridge"],BRIDGE_PODFILE_MARKER="usesmileid_bridge",withVisionDocumentSpm=(i,r)=>(i=(0,deployment_target_1.withIosDeploymentTargetFloor)(i,IOS_DEPLOYMENT_TARGET),i=(0,config_plugins_1.withXcodeProject)(i,t=>{const e=t.modRequest.projectName;if(!e)throw new Error("[usesmileid_vision_document] Unable to resolve host app native target name from Expo config.");return(0,spm_1.linkSpmPackage)(t.modResults,SMILE_ID_PACKAGE,{targetName:e,products:[...exports.SPM_PRODUCTS]}),r?.iosSignatureAggregation==="disabled"?(0,signature_dedup_1.disableSignatureAggregation)(t.modResults,e):(0,signature_dedup_1.ensureSignatureDedupPhase)(t.modResults,e),t}),i=(0,config_plugins_1.withDangerousMod)(i,["ios",t=>{const e=path.join(t.modRequest.platformProjectRoot,"Podfile"),o=fs.readFileSync(e,"utf-8");let n=(0,podfile_1.injectPodfileSpmBlock)(o,{marker:PODFILE_MARKER,package:SMILE_ID_PACKAGE,podTarget:POD_TARGET,products:[...exports.SPM_PRODUCTS]});return n=(0,podfile_1.injectPodfileSpmBlock)(n,{marker:BRIDGE_PODFILE_MARKER,package:SMILE_ID_PACKAGE,podTarget:BRIDGE_POD_TARGET,products:[...BRIDGE_SPM_PRODUCTS],required:!0}),n=(0,podfile_1.injectPodfileKameraLinkBlock)(n),n=(0,podfile_1.injectPodfileSignatureDedupBlock)(n),n!==o&&fs.writeFileSync(e,n),t}]),i);exports.default=withVisionDocumentSpm;
@@ -0,0 +1,5 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ /** Sets `ios.deploymentTarget` to `minimum` unless the project already asks for a higher one. */
3
+ export declare const withIosDeploymentTargetFloor: ConfigPlugin<string>;
4
+ /** Pure form of the edit the plugin makes to the Podfile properties. */
5
+ export declare function raiseDeploymentTarget(properties: Readonly<Record<string, string>>, minimum: string): Record<string, string>;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.withIosDeploymentTargetFloor=void 0,exports.raiseDeploymentTarget=raiseDeploymentTarget;const config_plugins_1=require("expo/config-plugins"),withIosDeploymentTargetFloor=(e,t)=>(0,config_plugins_1.withPodfileProperties)(e,r=>(r.modResults=raiseDeploymentTarget(r.modResults,t),r));exports.withIosDeploymentTargetFloor=withIosDeploymentTargetFloor;function raiseDeploymentTarget(e,t){const r=e["ios.deploymentTarget"];return r!==void 0&&compareVersions(r,t)>=0?{...e}:{...e,"ios.deploymentTarget":t}}function compareVersions(e,t){const r=e.split("."),n=t.split(".");for(let o=0;o<Math.max(r.length,n.length);o++){const s=toNumber(r[o]??"0")-toNumber(n[o]??"0");if(s!==0)return s}return 0}function toNumber(e){const t=Number.parseInt(e,10);return Number.isNaN(t)?0:t}
@@ -7,6 +7,8 @@ export interface PodfileLinkOptions {
7
7
  podTarget: string;
8
8
  /** SPM library product names to link to the pod target. */
9
9
  products: string[];
10
+ /** Fail `pod install` when the target is absent — a warning there reads as success. */
11
+ required?: boolean;
10
12
  }
11
13
  /**
12
14
  * Idempotently injects an SPM-linking Ruby block into the Podfile's
@@ -15,3 +17,18 @@ export interface PodfileLinkOptions {
15
17
  * product changes flow through cleanly on the next prebuild).
16
18
  */
17
19
  export declare function injectPodfileSpmBlock(podfile: string, options: PodfileLinkOptions): string;
20
+ /**
21
+ * Links kamera-spm's products into the `kamera-rn` (and `kamera-testing`) pod
22
+ * targets with the helper `@smileid/kamera` ships. The SDK's own binaries link
23
+ * `Kamera.framework` dynamically and ios-spm declares kamera-spm for the app, so
24
+ * the kamera pod must take Kamera from that same package instead of vendoring a
25
+ * second copy; the helper pins kamera-spm at the installed `@smileid/kamera`
26
+ * version, so the pin can never drift from the JS side. Idempotent per marker.
27
+ */
28
+ export declare function injectPodfileKameraLinkBlock(podfile: string): string;
29
+ /**
30
+ * Adds the archive signature-dedup phase to the app target of the user's own
31
+ * project — the path for apps whose `ios/` is hand-maintained, where no config
32
+ * plugin runs. Guarded by phase name, so an app on both paths gets one.
33
+ */
34
+ export declare function injectPodfileSignatureDedupBlock(podfile: string): string;