@smileid/usesmileid_vision_document 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.
Files changed (34) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +33 -1
  3. package/dist/index.d.ts +4 -4
  4. package/dist/index.js +1 -34
  5. package/ios/UseSmileIDVisionDocumentExpo.podspec +2 -5
  6. package/ios/UseSmileIDVisionDocumentModule/ResizingFrameStorage.swift +1 -1
  7. package/ios/UseSmileIDVisionDocumentModule/UseSmileIDVisionDocumentKameraAnalysisTick.swift +80 -0
  8. package/ios/UseSmileIDVisionDocumentModule/UseSmileIDVisionDocumentModule.swift +9 -14
  9. package/package.json +13 -14
  10. package/plugin/build/index.d.ts +10 -1
  11. package/plugin/build/index.js +1 -124
  12. package/plugin/build/lib/deployment_target.js +1 -39
  13. package/plugin/build/lib/podfile.d.ts +15 -0
  14. package/plugin/build/lib/podfile.js +159 -130
  15. package/plugin/build/lib/signature_dedup.d.ts +14 -0
  16. package/plugin/build/lib/signature_dedup.js +2 -0
  17. package/plugin/build/lib/spm.d.ts +21 -0
  18. package/plugin/build/lib/spm.js +1 -196
  19. package/dist/index.d.ts.map +0 -1
  20. package/dist/index.js.map +0 -1
  21. package/ios/UseSmileIDVisionDocumentModule/UseSmileIDVisionDocumentFrameProcessorPlugin.swift +0 -149
  22. package/plugin/build/index.js.map +0 -1
  23. package/plugin/build/lib/deployment_target.js.map +0 -1
  24. package/plugin/build/lib/podfile.js.map +0 -1
  25. package/plugin/build/lib/spm.js.map +0 -1
  26. package/plugin/src/__tests__/deployment_target.test.ts +0 -41
  27. package/plugin/src/__tests__/podfile.test.ts +0 -138
  28. package/plugin/src/index.ts +0 -108
  29. package/plugin/src/lib/deployment_target.ts +0 -46
  30. package/plugin/src/lib/podfile.ts +0 -254
  31. package/plugin/src/lib/spm.ts +0 -314
  32. package/plugin/tsconfig.json +0 -24
  33. package/src/__tests__/use_smile_id_vision_document.test.ts +0 -79
  34. package/src/index.ts +0 -42
@@ -1,254 +0,0 @@
1
- // Injects an idempotent Ruby block into the Expo-generated Podfile's
2
- // `post_install` hook. The block runs at `pod install` time and wires
3
- // the Smile ID Swift Package into the autogenerated Pods.xcodeproj
4
- // for a specific bridge pod target — Pods.xcodeproj only exists at
5
- // pod-install time, so this is the only hook that can mutate it.
6
-
7
- import type { SpmPackage, SpmRequirement } from "./spm";
8
-
9
- const BEGIN_PREFIX = "# === BEGIN smileid-spm:";
10
- const END_PREFIX = "# === END smileid-spm:";
11
-
12
- export interface PodfileLinkOptions {
13
- /** Marker key — distinct per bridge so each plugin owns its own block. */
14
- marker: string;
15
- package: SpmPackage;
16
- /** Pod target name (e.g. `UseSmileIDVisionFaceExpo`). */
17
- podTarget: string;
18
- /** SPM library product names to link to the pod target. */
19
- products: string[];
20
- /** Fail `pod install` when the target is absent — a warning there reads as success. */
21
- required?: boolean;
22
- }
23
-
24
- /**
25
- * Idempotently injects an SPM-linking Ruby block into the Podfile's
26
- * top-level `post_install` block. Re-running on an already-injected
27
- * Podfile rewrites the same marker block in place (so version /
28
- * product changes flow through cleanly on the next prebuild).
29
- */
30
- export function injectPodfileSpmBlock(
31
- podfile: string,
32
- options: PodfileLinkOptions,
33
- ): string {
34
- validateRubySafe(options);
35
-
36
- const block = renderBlock(options);
37
- const beginMarker = `${BEGIN_PREFIX} ${options.marker} ===`;
38
- const endMarker = `${END_PREFIX} ${options.marker} ===`;
39
-
40
- // The indentation is captured so a rewrite can restore it; dropping it would
41
- // make every prebuild rewrite the Podfile.
42
- const blockRegex = new RegExp(
43
- `([ \\t]*)${escapeRegExp(beginMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`,
44
- "m",
45
- );
46
- const existing = podfile.match(blockRegex);
47
- if (existing) {
48
- // A replacer function, so `$` in the Ruby block is never a replacement pattern.
49
- return podfile.replace(blockRegex, () =>
50
- indentBlock(block, existing[1] ?? ""),
51
- );
52
- }
53
-
54
- // Inject at the *start* of the post_install body — right after
55
- // `post_install do |installer|`. We tried matching the closing
56
- // `end` pair instead, but a second plugin running on a Podfile
57
- // already mutated by the first sees a non-flat body and the
58
- // non-greedy `end…end` match latches onto inner block ends,
59
- // nesting the second injection inside the first. Anchoring on
60
- // the opening line removes that failure mode entirely. Order
61
- // relative to `react_native_post_install` doesn't matter because
62
- // CocoaPods persists the Pods project at the end of pod install
63
- // regardless of what we explicitly save mid-block.
64
- const headerRegex = /(post_install\s+do\s*\|\s*installer\s*\|)\r?\n/;
65
- const headerMatch = podfile.match(headerRegex);
66
- if (!headerMatch || headerMatch.index === undefined) {
67
- throw new Error(
68
- "[smileid-spm] Could not locate `post_install do |installer|` in Podfile. " +
69
- "Refusing to append a top-level post_install hook because CocoaPods only honors one — adding a second " +
70
- "would silently override the React Native post-install plumbing. Restore the Expo Podfile template " +
71
- "or wire the SPM block in manually.",
72
- );
73
- }
74
- const insertAt = headerMatch.index + headerMatch[0].length;
75
- const indented = `${indentBlock(block, " ")}\n`;
76
- return podfile.slice(0, insertAt) + indented + podfile.slice(insertAt);
77
- }
78
-
79
- function indentBlock(block: string, prefix: string): string {
80
- return block
81
- .split("\n")
82
- .map((line) => (line.length > 0 ? `${prefix}${line}` : line))
83
- .join("\n");
84
- }
85
-
86
- // Injected strings land in Ruby literals, so a typo here could otherwise become
87
- // code that runs during `pod install`. `#` and `"` are rejected alongside `'`,
88
- // `\` and control chars because the diagnostics are double-quoted, where Ruby
89
- // evaluates `#{...}`.
90
- function validateRubySafe(options: PodfileLinkOptions): void {
91
- const fields: Array<[string, string]> = [
92
- ["marker", options.marker],
93
- ["package.url", options.package.url],
94
- ["podTarget", options.podTarget],
95
- ];
96
- for (const product of options.products) {
97
- fields.push(["products[*]", product]);
98
- }
99
- switch (options.package.requirement.kind) {
100
- case "upToNextMajorVersion":
101
- case "upToNextMinorVersion":
102
- fields.push([
103
- "requirement.minimumVersion",
104
- options.package.requirement.minimumVersion,
105
- ]);
106
- break;
107
- case "exactVersion":
108
- fields.push(["requirement.version", options.package.requirement.version]);
109
- break;
110
- case "branch":
111
- fields.push(["requirement.branch", options.package.requirement.branch]);
112
- break;
113
- }
114
- for (const [name, value] of fields) {
115
- if (/['"#\\\n\r\t]/.test(value)) {
116
- throw new Error(
117
- `[smileid-spm] Refusing to inject Podfile block: '${name}' contains an unsafe character (got: ${JSON.stringify(value)}).`,
118
- );
119
- }
120
- }
121
- }
122
-
123
- function renderBlock(options: PodfileLinkOptions): string {
124
- const beginMarker = `${BEGIN_PREFIX} ${options.marker} ===`;
125
- const endMarker = `${END_PREFIX} ${options.marker} ===`;
126
- const requirement = renderRequirement(options.package.requirement);
127
- const productList = options.products.map((p) => `'${p}'`).join(", ");
128
- const missingTarget = options.required
129
- ? `raise "[smileid-spm] Pod target #{target_name} is missing from Pods.xcodeproj, so #{product_names.join(', ')} cannot be linked and the Smile ID bridge will not compile. Check that '@smileid/usesmileid_bridge' is installed and that its npm package ships its 'ios' directory."`
130
- : `Pod::UI.warn "[smileid-spm] Pod target #{target_name} not found; skipping SPM link."`;
131
-
132
- return `${beginMarker}
133
- # Wires ${options.package.url} into Pods.xcodeproj and links its
134
- # products to the '${options.podTarget}' pod target so the Swift
135
- # bridge code can \`import\` them. Idempotent across pod installs.
136
- #
137
- # UUIDs are minted via SecureRandom rather than \`pods_project.new\`
138
- # because \`prepare_react_native_project!\` sets
139
- # \`:deterministic_uuids => false\`. With that flag off, CocoaPods
140
- # skips its predictabilize step and \`stabilize_target_uuids\` resets
141
- # \`@generated_uuids\` to a tiny leftover pool — so any post_install
142
- # call to \`pods_project.new\` restarts the sequential index near 0
143
- # and re-mints UUIDs already in use. The collision then runs through
144
- # \`add_referrer\`, which clobbers \`objects_by_uuid[uuid]\` and
145
- # leaves the rootObject (\`46EB2E00000000\`) unreachable, crashing
146
- # Xcode 26 with \`XCSwiftPackageProductDependency
147
- # _setSavedArchiveVersion:\` unrecognized selector. Random 24-char
148
- # hex IDs can't collide with the 14-char cocoapods scheme.
149
- begin
150
- pods_project = installer.pods_project
151
- spm_url = '${options.package.url}'
152
- spm_requirement = ${requirement}
153
- product_names = [${productList}]
154
- target_name = '${options.podTarget}'
155
-
156
- smileid_spm_safe_uuid = lambda do |project|
157
- loop do
158
- candidate = SecureRandom.hex(12).upcase
159
- return candidate unless project.objects_by_uuid.key?(candidate)
160
- end
161
- end
162
-
163
- pkg = pods_project.root_object.package_references.find do |r|
164
- r.respond_to?(:repositoryURL) && r.repositoryURL == spm_url
165
- end
166
- unless pkg
167
- pkg_uuid = smileid_spm_safe_uuid.call(pods_project)
168
- pkg = Xcodeproj::Project::Object::XCRemoteSwiftPackageReference.new(pods_project, pkg_uuid)
169
- pkg.initialize_defaults
170
- pkg.repositoryURL = spm_url
171
- pkg.requirement = spm_requirement
172
- pods_project.root_object.package_references << pkg
173
- end
174
-
175
- target = pods_project.targets.find { |t| t.name == target_name }
176
- if target.nil?
177
- ${missingTarget}
178
- else
179
- product_names.each do |product_name|
180
- already = target.package_product_dependencies.any? do |d|
181
- d.package == pkg && d.product_name == product_name
182
- end
183
- next if already
184
-
185
- dep_uuid = smileid_spm_safe_uuid.call(pods_project)
186
- dep = Xcodeproj::Project::Object::XCSwiftPackageProductDependency.new(pods_project, dep_uuid)
187
- dep.initialize_defaults
188
- dep.package = pkg
189
- dep.product_name = product_name
190
- target.package_product_dependencies << dep
191
-
192
- bf_uuid = smileid_spm_safe_uuid.call(pods_project)
193
- bf = Xcodeproj::Project::Object::PBXBuildFile.new(pods_project, bf_uuid)
194
- bf.initialize_defaults
195
- bf.product_ref = dep
196
- target.frameworks_build_phase.files << bf
197
- end
198
-
199
- # Every linking static pod absorbs ios-spm's source-target objects and the
200
- # app's -ObjC link then sees duplicates — the app keeps the single copy.
201
- strip_name = '[smileid-spm] Strip absorbed SPM source objects'
202
- unless target.shell_script_build_phases.any? { |p| p.name == strip_name }
203
- phase = target.new_shell_script_build_phase(strip_name)
204
- phase.shell_script = <<~'STRIPSH'
205
- set -u
206
- A="\${TARGET_BUILD_DIR}/\${EXECUTABLE_PATH}"
207
- [ -f "$A" ] || exit 0
208
- strip_obj() {
209
- ar -t "$1" 2>/dev/null | grep -q "^$2$" || return 0
210
- ar -d "$1" "$2" && ranlib "$1" 2>/dev/null || true
211
- }
212
- ARCHS_IN=$(lipo -archs "$A" 2>/dev/null || true)
213
- for OBJ in UseSmileIDSentrySupport.o UseSmileIDLottieSupport.o; do
214
- if [ "$(echo "$ARCHS_IN" | wc -w)" -gt 1 ]; then
215
- THIN=""
216
- for ARCH in $ARCHS_IN; do
217
- lipo -thin "$ARCH" "$A" -output "$A.$ARCH"
218
- strip_obj "$A.$ARCH" "$OBJ"
219
- THIN="$THIN $A.$ARCH"
220
- done
221
- lipo -create $THIN -output "$A"
222
- rm -f $THIN
223
- else
224
- strip_obj "$A" "$OBJ"
225
- fi
226
- done
227
- STRIPSH
228
- end
229
- end
230
-
231
- pods_project.save
232
- rescue => e
233
- Pod::UI.warn "[smileid-spm] Failed to link SPM products for ${options.podTarget}: #{e.message}"
234
- raise
235
- end
236
- ${endMarker}`;
237
- }
238
-
239
- function renderRequirement(req: SpmRequirement): string {
240
- switch (req.kind) {
241
- case "upToNextMajorVersion":
242
- return `{ kind: 'upToNextMajorVersion', minimumVersion: '${req.minimumVersion}' }`;
243
- case "upToNextMinorVersion":
244
- return `{ kind: 'upToNextMinorVersion', minimumVersion: '${req.minimumVersion}' }`;
245
- case "exactVersion":
246
- return `{ kind: 'exactVersion', version: '${req.version}' }`;
247
- case "branch":
248
- return `{ kind: 'branch', branch: '${req.branch}' }`;
249
- }
250
- }
251
-
252
- function escapeRegExp(s: string): string {
253
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
254
- }
@@ -1,314 +0,0 @@
1
- // Shared plumbing for wiring a remote Swift Package into both the
2
- // consuming Expo app's Xcode project and the autogenerated CocoaPods
3
- // project for a specific bridge pod target.
4
- //
5
- // Why this exists: `expo-modules-autolinking@55.0.x`'s
6
- // `RawModuleConfigApple` schema does not surface a `dependencies`
7
- // field, so listing SPM products in `expo-module.config.json` is a
8
- // silent no-op. This module fills that gap.
9
-
10
- import { XcodeProject } from "expo/config-plugins";
11
-
12
- export interface SpmPackage {
13
- /** Remote git URL of the Swift Package, e.g. `https://github.com/smileidentity/ios-spm`. */
14
- url: string;
15
- /** Version requirement; mirrors Xcode's package resolution UI. */
16
- requirement: SpmRequirement;
17
- }
18
-
19
- export type SpmRequirement =
20
- | { kind: "upToNextMajorVersion"; minimumVersion: string }
21
- | { kind: "upToNextMinorVersion"; minimumVersion: string }
22
- | { kind: "exactVersion"; version: string }
23
- | { kind: "branch"; branch: string };
24
-
25
- export interface SpmTargetLink {
26
- /** Native target name in the project (app target or pod target). */
27
- targetName: string;
28
- /** SPM library product names to attach to the target. */
29
- products: string[];
30
- }
31
-
32
- /**
33
- * Adds (or reuses) a remote Swift Package reference on the given
34
- * Xcode project and links the requested products to the target.
35
- * Idempotent: existing package refs and product deps are reused so
36
- * multiple plugins can compose without conflict.
37
- */
38
- export function linkSpmPackage(
39
- project: XcodeProject,
40
- pkg: SpmPackage,
41
- link: SpmTargetLink,
42
- ): void {
43
- const pkgRef = upsertPackageReference(project, pkg);
44
- const target = findNativeTarget(project, link.targetName);
45
- if (!target) {
46
- throw new Error(
47
- `[smileid-spm] Native target '${link.targetName}' not found in Xcode project.`,
48
- );
49
- }
50
- for (const product of link.products) {
51
- upsertProductDependency(project, target.uuid, pkgRef, product);
52
- }
53
- }
54
-
55
- // Internals — pbxproj surgery. xcode.js doesn't expose SPM helpers,
56
- // so we manipulate the underlying object graph directly.
57
-
58
- interface PackageRef {
59
- uuid: string;
60
- }
61
-
62
- interface NativeTarget {
63
- uuid: string;
64
- obj: PbxNativeTarget;
65
- }
66
-
67
- interface PbxNativeTarget {
68
- isa: "PBXNativeTarget";
69
- name: string;
70
- packageProductDependencies?: Array<{ value: string; comment?: string }>;
71
- buildPhases: Array<{ value: string; comment?: string }>;
72
- }
73
-
74
- interface PbxProject {
75
- isa: "PBXProject";
76
- packageReferences?: Array<{ value: string; comment?: string }>;
77
- }
78
-
79
- function objects(project: XcodeProject): Record<string, unknown> {
80
- const hash = (
81
- project as unknown as {
82
- hash: { project: { objects: Record<string, unknown> } };
83
- }
84
- ).hash.project.objects;
85
- return hash;
86
- }
87
-
88
- function section<T>(project: XcodeProject, isa: string): Record<string, T> {
89
- const objs = objects(project);
90
- if (!objs[isa]) {
91
- objs[isa] = {};
92
- }
93
- return objs[isa] as Record<string, T>;
94
- }
95
-
96
- function generateUuid(project: XcodeProject): string {
97
- return (project as unknown as { generateUuid: () => string }).generateUuid();
98
- }
99
-
100
- function upsertPackageReference(
101
- project: XcodeProject,
102
- pkg: SpmPackage,
103
- ): PackageRef {
104
- const refs = section<{
105
- isa: string;
106
- repositoryURL?: string;
107
- requirement?: object;
108
- }>(project, "XCRemoteSwiftPackageReference");
109
-
110
- for (const [uuid, ref] of Object.entries(refs)) {
111
- if (uuid.endsWith("_comment")) continue;
112
- if (typeof ref !== "object" || ref === null) continue;
113
- if (ref.repositoryURL?.replace(/^"|"$/g, "") === pkg.url) {
114
- return { uuid };
115
- }
116
- }
117
-
118
- const uuid = generateUuid(project);
119
- refs[uuid] = {
120
- isa: "XCRemoteSwiftPackageReference",
121
- repositoryURL: `"${pkg.url}"`,
122
- requirement: serializeRequirement(pkg.requirement),
123
- };
124
- refs[`${uuid}_comment`] =
125
- `XCRemoteSwiftPackageReference "${repoName(pkg.url)}"` as never;
126
-
127
- // Attach to the PBXProject's packageReferences list.
128
- const projectSection = section<PbxProject>(project, "PBXProject");
129
- for (const [projUuid, proj] of Object.entries(projectSection)) {
130
- if (projUuid.endsWith("_comment")) continue;
131
- if (typeof proj !== "object" || proj === null) continue;
132
- if (proj.isa !== "PBXProject") continue;
133
- proj.packageReferences ??= [];
134
- if (!proj.packageReferences.some((r) => r.value === uuid)) {
135
- proj.packageReferences.push({
136
- value: uuid,
137
- comment: `XCRemoteSwiftPackageReference "${repoName(pkg.url)}"`,
138
- });
139
- }
140
- }
141
-
142
- return { uuid };
143
- }
144
-
145
- function upsertProductDependency(
146
- project: XcodeProject,
147
- targetUuid: string,
148
- pkgRef: PackageRef,
149
- productName: string,
150
- ): void {
151
- const targetSection = section<PbxNativeTarget>(project, "PBXNativeTarget");
152
- const target = targetSection[targetUuid];
153
- if (!target || typeof target !== "object") {
154
- throw new Error(
155
- `[smileid-spm] Target ${targetUuid} disappeared between lookups.`,
156
- );
157
- }
158
-
159
- const productDeps = section<{
160
- isa: string;
161
- package?: string;
162
- productName?: string;
163
- }>(project, "XCSwiftPackageProductDependency");
164
-
165
- // Each target owns its own XCSwiftPackageProductDependency entry —
166
- // sharing one across targets is not how Xcode writes pbxproj and
167
- // would cause downstream tools (and re-runs of this plugin) to
168
- // silently drop the second target's binding. Look up the dep
169
- // *within this target's* packageProductDependencies, never globally.
170
- target.packageProductDependencies ??= [];
171
- let depUuid = target.packageProductDependencies.find((d) => {
172
- const entry = productDeps[d.value];
173
- return (
174
- entry !== undefined &&
175
- typeof entry === "object" &&
176
- entry !== null &&
177
- entry.package === pkgRef.uuid &&
178
- entry.productName === productName
179
- );
180
- })?.value;
181
-
182
- if (!depUuid) {
183
- depUuid = generateUuid(project);
184
- productDeps[depUuid] = {
185
- isa: "XCSwiftPackageProductDependency",
186
- package: pkgRef.uuid,
187
- productName,
188
- };
189
- productDeps[`${depUuid}_comment`] = productName as never;
190
- target.packageProductDependencies.push({
191
- value: depUuid,
192
- comment: productName,
193
- });
194
- }
195
-
196
- ensureFrameworkLink(project, target, depUuid, productName);
197
- }
198
-
199
- function ensureFrameworkLink(
200
- project: XcodeProject,
201
- target: PbxNativeTarget,
202
- productDepUuid: string,
203
- productName: string,
204
- ): void {
205
- const frameworksPhase = findFrameworksBuildPhase(project, target);
206
- if (!frameworksPhase) {
207
- throw new Error(
208
- `[smileid-spm] Target '${target.name}' has no PBXFrameworksBuildPhase; cannot link ${productName}.`,
209
- );
210
- }
211
-
212
- const buildFiles = section<{ isa: string; productRef?: string }>(
213
- project,
214
- "PBXBuildFile",
215
- );
216
-
217
- // Scope the existence check to *this target's* frameworks phase.
218
- // A globally-scoped check would early-return when a sibling target
219
- // already linked the same product, leaving this target unlinked.
220
- frameworksPhase.obj.files ??= [];
221
- for (const fileRef of frameworksPhase.obj.files) {
222
- const bf = buildFiles[fileRef.value];
223
- if (
224
- bf !== undefined &&
225
- typeof bf === "object" &&
226
- bf !== null &&
227
- bf.productRef === productDepUuid
228
- ) {
229
- return;
230
- }
231
- }
232
-
233
- const buildFileUuid = generateUuid(project);
234
- buildFiles[buildFileUuid] = {
235
- isa: "PBXBuildFile",
236
- productRef: productDepUuid,
237
- };
238
- buildFiles[`${buildFileUuid}_comment`] =
239
- `${productName} in Frameworks` as never;
240
-
241
- frameworksPhase.obj.files.push({
242
- value: buildFileUuid,
243
- comment: `${productName} in Frameworks`,
244
- });
245
- }
246
-
247
- interface FrameworksPhase {
248
- uuid: string;
249
- obj: {
250
- isa: "PBXFrameworksBuildPhase";
251
- files?: Array<{ value: string; comment?: string }>;
252
- };
253
- }
254
-
255
- function findFrameworksBuildPhase(
256
- project: XcodeProject,
257
- target: PbxNativeTarget,
258
- ): FrameworksPhase | undefined {
259
- const phaseSection = section<{
260
- isa: string;
261
- files?: Array<{ value: string; comment?: string }>;
262
- }>(project, "PBXFrameworksBuildPhase");
263
- for (const phaseRef of target.buildPhases) {
264
- const phase = phaseSection[phaseRef.value];
265
- if (
266
- phase &&
267
- typeof phase === "object" &&
268
- phase.isa === "PBXFrameworksBuildPhase"
269
- ) {
270
- return { uuid: phaseRef.value, obj: phase as FrameworksPhase["obj"] };
271
- }
272
- }
273
- return undefined;
274
- }
275
-
276
- function findNativeTarget(
277
- project: XcodeProject,
278
- name: string,
279
- ): NativeTarget | undefined {
280
- const targets = section<PbxNativeTarget>(project, "PBXNativeTarget");
281
- for (const [uuid, t] of Object.entries(targets)) {
282
- if (uuid.endsWith("_comment")) continue;
283
- if (typeof t !== "object" || t === null) continue;
284
- if (t.isa !== "PBXNativeTarget") continue;
285
- if (t.name === name || t.name === `"${name}"`) {
286
- return { uuid, obj: t };
287
- }
288
- }
289
- return undefined;
290
- }
291
-
292
- function serializeRequirement(req: SpmRequirement): object {
293
- switch (req.kind) {
294
- case "upToNextMajorVersion":
295
- return {
296
- kind: "upToNextMajorVersion",
297
- minimumVersion: req.minimumVersion,
298
- };
299
- case "upToNextMinorVersion":
300
- return {
301
- kind: "upToNextMinorVersion",
302
- minimumVersion: req.minimumVersion,
303
- };
304
- case "exactVersion":
305
- return { kind: "exactVersion", version: req.version };
306
- case "branch":
307
- return { kind: "branch", branch: req.branch };
308
- }
309
- }
310
-
311
- function repoName(url: string): string {
312
- const match = url.replace(/\.git$/, "").match(/\/([^/]+)$/);
313
- return match?.[1] ?? url;
314
- }
@@ -1,24 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "./build",
5
- "rootDir": "./src",
6
- "module": "commonjs",
7
- "moduleResolution": "node",
8
- "ignoreDeprecations": "6.0",
9
- "target": "ES2021",
10
- "lib": ["ES2022"],
11
- "types": ["node"],
12
- "declaration": true,
13
- "declarationMap": false,
14
- "sourceMap": true,
15
- "composite": false
16
- },
17
- "include": ["src/**/*"],
18
- "exclude": [
19
- "src/**/*.test.ts",
20
- "src/**/__tests__/**",
21
- "build",
22
- "node_modules"
23
- ]
24
- }
@@ -1,79 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach, type Mock } from "vitest";
2
-
3
- const native = vi.hoisted(() => ({
4
- configure: vi.fn(),
5
- reset: vi.fn(),
6
- close: vi.fn(),
7
- }));
8
-
9
- vi.mock("expo-modules-core", () => ({
10
- requireNativeModule: vi.fn(() => native),
11
- }));
12
-
13
- import { requireNativeModule } from "expo-modules-core";
14
- import {
15
- useSmileIDVisionDocument,
16
- UseSmileIDVisionDocumentIdentifiers,
17
- } from "../index";
18
-
19
- describe("useSmileIDVisionDocument — TS wrapper", () => {
20
- beforeEach(() => {
21
- Object.values(native).forEach((m) => (m as Mock).mockReset());
22
- });
23
-
24
- it("looks up the native module under the contract-stable name", () => {
25
- expect(requireNativeModule).toHaveBeenCalledWith(
26
- "UseSmileIDVisionDocument",
27
- );
28
- });
29
-
30
- it("exposes the lifecycle surface — no per-frame analyze method", () => {
31
- expect(typeof useSmileIDVisionDocument.configure).toBe("function");
32
- expect(typeof useSmileIDVisionDocument.reset).toBe("function");
33
- expect(typeof useSmileIDVisionDocument.close).toBe("function");
34
- // Per-frame analysis lives in the native VisionCamera frame
35
- // processor plugin — raw pixels never cross the JS bridge.
36
- expect("analyze" in useSmileIDVisionDocument).toBe(false);
37
- });
38
-
39
- it("exposes the kind discriminator and frame processor plugin name", () => {
40
- expect(useSmileIDVisionDocument.kind).toBe("document");
41
- expect(useSmileIDVisionDocument.frameProcessorPluginName).toBe(
42
- UseSmileIDVisionDocumentIdentifiers.frameProcessorPluginName,
43
- );
44
- });
45
-
46
- describe("configure", () => {
47
- it("passes the validated config through to native", async () => {
48
- native.configure.mockResolvedValueOnce(undefined);
49
- await useSmileIDVisionDocument.configure({ timeout: 8_000 });
50
- expect(native.configure).toHaveBeenCalledTimes(1);
51
- expect(native.configure).toHaveBeenCalledWith({ timeout: 8_000 });
52
- });
53
-
54
- it("rejects malformed config at the JS boundary before crossing the bridge", async () => {
55
- await expect(
56
- useSmileIDVisionDocument.configure({
57
- // @ts-expect-error — int field with float value
58
- timeout: 8_000.5,
59
- }),
60
- ).rejects.toThrow();
61
- expect(native.configure).not.toHaveBeenCalled();
62
- });
63
- });
64
-
65
- describe("reset / close", () => {
66
- it("routes reset through to native", async () => {
67
- native.reset.mockResolvedValueOnce(undefined);
68
- await useSmileIDVisionDocument.reset();
69
- expect(native.reset).toHaveBeenCalledTimes(1);
70
- });
71
-
72
- it("routes close through to native and is idempotent", async () => {
73
- native.close.mockResolvedValue(undefined);
74
- await useSmileIDVisionDocument.close();
75
- await useSmileIDVisionDocument.close();
76
- expect(native.close).toHaveBeenCalledTimes(2);
77
- });
78
- });
79
- });