facecog-liveness-showcase 0.0.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 (229) hide show
  1. package/.browserslistrc +15 -0
  2. package/.dockerignore +48 -0
  3. package/.editorconfig +16 -0
  4. package/.eslintrc.json +47 -0
  5. package/.vercelignore +7 -0
  6. package/.vscode/extensions.json +5 -0
  7. package/.vscode/settings.json +3 -0
  8. package/DOCKER.md +221 -0
  9. package/Dockerfile +33 -0
  10. package/README.md +268 -0
  11. package/angular.json +156 -0
  12. package/capacitor.config.ts +9 -0
  13. package/docker-compose.dev.yml +20 -0
  14. package/docker-compose.yml +18 -0
  15. package/ionic.config.json +7 -0
  16. package/jest.config.js +38 -0
  17. package/nginx.conf +50 -0
  18. package/package.json +131 -0
  19. package/patches/ng-packagr+20.3.2.patch +60 -0
  20. package/projects/facecog-liveness-verification/README.md +295 -0
  21. package/projects/facecog-liveness-verification/ng-package.json +7 -0
  22. package/projects/facecog-liveness-verification/package.json +48 -0
  23. package/projects/facecog-liveness-verification/scripts/build-with-wrapper-copy.js +38 -0
  24. package/projects/facecog-liveness-verification/scripts/copy-wrapper-after-ngc.js +35 -0
  25. package/projects/facecog-liveness-verification/sources/FaceLivenessReactWrapper.tsx +320 -0
  26. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.d.ts +28 -0
  27. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.js +247 -0
  28. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.generated.js.map +1 -0
  29. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.js.map +1 -0
  30. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/FaceLivenessReactWrapper.ts +5 -0
  31. package/projects/facecog-liveness-verification/src/lib/components/aws-face-liveness/aws-face-liveness.component.ts +500 -0
  32. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.html +41 -0
  33. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.scss +234 -0
  34. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.spec.ts +158 -0
  35. package/projects/facecog-liveness-verification/src/lib/components/camera-permission/camera-permission.component.ts +58 -0
  36. package/projects/facecog-liveness-verification/src/lib/components/camera-verification/camera-verification.component.html +34 -0
  37. package/projects/facecog-liveness-verification/src/lib/components/camera-verification/camera-verification.component.ts +210 -0
  38. package/projects/facecog-liveness-verification/src/lib/components/dialogs/save-custom-pose-dialog.component.ts +174 -0
  39. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.html +45 -0
  40. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.scss +87 -0
  41. package/projects/facecog-liveness-verification/src/lib/components/facetec-scan/facetec-scan.component.ts +182 -0
  42. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.html +394 -0
  43. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.scss +1567 -0
  44. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.spec.ts +699 -0
  45. package/projects/facecog-liveness-verification/src/lib/components/intro/intro.component.ts +721 -0
  46. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.html +120 -0
  47. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.scss +611 -0
  48. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.spec.ts +605 -0
  49. package/projects/facecog-liveness-verification/src/lib/components/live-preview/live-preview.component.ts +524 -0
  50. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.html +73 -0
  51. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.scss +19 -0
  52. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.spec.ts +673 -0
  53. package/projects/facecog-liveness-verification/src/lib/components/liveness-flow/liveness-flow.component.ts +963 -0
  54. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.html +38 -0
  55. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.scss +10 -0
  56. package/projects/facecog-liveness-verification/src/lib/components/liveness-verification/liveness-verification.component.ts +233 -0
  57. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.html +17 -0
  58. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.spec.ts +35 -0
  59. package/projects/facecog-liveness-verification/src/lib/components/pose-selection/pose-selection.component.ts +33 -0
  60. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.html +17 -0
  61. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.scss +156 -0
  62. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.spec.ts +46 -0
  63. package/projects/facecog-liveness-verification/src/lib/components/processing/processing.component.ts +18 -0
  64. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.html +190 -0
  65. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.scss +534 -0
  66. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.spec.ts +286 -0
  67. package/projects/facecog-liveness-verification/src/lib/components/verification-result/verification-result.component.ts +155 -0
  68. package/projects/facecog-liveness-verification/src/lib/interfaces/analyze-response.interface.ts +16 -0
  69. package/projects/facecog-liveness-verification/src/lib/interfaces/aws-face-liveness.interface.ts +46 -0
  70. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-adapter.interface.ts +21 -0
  71. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-http-client.interface.ts +93 -0
  72. package/projects/facecog-liveness-verification/src/lib/interfaces/backend-response.interface.ts +9 -0
  73. package/projects/facecog-liveness-verification/src/lib/interfaces/camera-provider.interface.ts +107 -0
  74. package/projects/facecog-liveness-verification/src/lib/interfaces/category-info.interface.ts +9 -0
  75. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-data.interface.ts +14 -0
  76. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-repository.interface.ts +48 -0
  77. package/projects/facecog-liveness-verification/src/lib/interfaces/custom-pose-response.interface.ts +14 -0
  78. package/projects/facecog-liveness-verification/src/lib/interfaces/index.ts +52 -0
  79. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-action-result.interface.ts +13 -0
  80. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-config.interface.ts +17 -0
  81. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-metadata.interface.ts +17 -0
  82. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-result.interface.ts +24 -0
  83. package/projects/facecog-liveness-verification/src/lib/interfaces/liveness-verification-config.interface.ts +41 -0
  84. package/projects/facecog-liveness-verification/src/lib/interfaces/multi-backend-analyze-response.interface.ts +21 -0
  85. package/projects/facecog-liveness-verification/src/lib/interfaces/multi-backend-liveness-result.interface.ts +14 -0
  86. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-definition.interface.ts +35 -0
  87. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-keypoint.interface.ts +12 -0
  88. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-match-result.interface.ts +9 -0
  89. package/projects/facecog-liveness-verification/src/lib/interfaces/pose-verify-response.interface.ts +8 -0
  90. package/projects/facecog-liveness-verification/src/lib/interfaces/scan-results.interface.ts +29 -0
  91. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-plan.interface.ts +42 -0
  92. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-progress-event.interface.ts +12 -0
  93. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-session.interface.ts +72 -0
  94. package/projects/facecog-liveness-verification/src/lib/interfaces/verification-step-change-event.interface.ts +11 -0
  95. package/projects/facecog-liveness-verification/src/lib/interfaces/video-recording.interface.ts +9 -0
  96. package/projects/facecog-liveness-verification/src/lib/liveness-verification.module.ts +123 -0
  97. package/projects/facecog-liveness-verification/src/lib/models/constants/aws-face-liveness-component.token.ts +23 -0
  98. package/projects/facecog-liveness-verification/src/lib/models/constants/category-info.constant.ts +14 -0
  99. package/projects/facecog-liveness-verification/src/lib/models/constants/default-liveness-config.constant.ts +18 -0
  100. package/projects/facecog-liveness-verification/src/lib/models/constants/index.ts +5 -0
  101. package/projects/facecog-liveness-verification/src/lib/models/constants/liveness-verification-config.token.ts +16 -0
  102. package/projects/facecog-liveness-verification/src/lib/models/constants/pose-definitions.constant.ts +377 -0
  103. package/projects/facecog-liveness-verification/src/lib/models/index.ts +5 -0
  104. package/projects/facecog-liveness-verification/src/lib/models/utils/index.ts +2 -0
  105. package/projects/facecog-liveness-verification/src/lib/models/utils/pose.utils.spec.ts +76 -0
  106. package/projects/facecog-liveness-verification/src/lib/models/utils/pose.utils.ts +59 -0
  107. package/projects/facecog-liveness-verification/src/lib/services/aws-face-liveness.service.ts +49 -0
  108. package/projects/facecog-liveness-verification/src/lib/services/backend-http.service.spec.ts +111 -0
  109. package/projects/facecog-liveness-verification/src/lib/services/backend-http.service.ts +130 -0
  110. package/projects/facecog-liveness-verification/src/lib/services/backends/azure-backend.service.spec.ts +69 -0
  111. package/projects/facecog-liveness-verification/src/lib/services/backends/azure-backend.service.ts +72 -0
  112. package/projects/facecog-liveness-verification/src/lib/services/backends/facetec-backend.service.spec.ts +24 -0
  113. package/projects/facecog-liveness-verification/src/lib/services/backends/facetec-backend.service.ts +35 -0
  114. package/projects/facecog-liveness-verification/src/lib/services/backends/mock-backend.service.spec.ts +36 -0
  115. package/projects/facecog-liveness-verification/src/lib/services/backends/mock-backend.service.ts +39 -0
  116. package/projects/facecog-liveness-verification/src/lib/services/backends/openpose-backend.service.spec.ts +81 -0
  117. package/projects/facecog-liveness-verification/src/lib/services/backends/openpose-backend.service.ts +72 -0
  118. package/projects/facecog-liveness-verification/src/lib/services/backends/rekognition-analysis-backend.service.spec.ts +69 -0
  119. package/projects/facecog-liveness-verification/src/lib/services/backends/rekognition-analysis-backend.service.ts +83 -0
  120. package/projects/facecog-liveness-verification/src/lib/services/camera.service.spec.ts +200 -0
  121. package/projects/facecog-liveness-verification/src/lib/services/camera.service.ts +155 -0
  122. package/projects/facecog-liveness-verification/src/lib/services/custom-poses-api.service.ts +117 -0
  123. package/projects/facecog-liveness-verification/src/lib/services/index.ts +18 -0
  124. package/projects/facecog-liveness-verification/src/lib/services/liveness-backend.service.spec.ts +103 -0
  125. package/projects/facecog-liveness-verification/src/lib/services/liveness-backend.service.ts +61 -0
  126. package/projects/facecog-liveness-verification/src/lib/services/liveness-config.service.spec.ts +109 -0
  127. package/projects/facecog-liveness-verification/src/lib/services/liveness-config.service.ts +70 -0
  128. package/projects/facecog-liveness-verification/src/lib/services/liveness-orchestrator.service.spec.ts +144 -0
  129. package/projects/facecog-liveness-verification/src/lib/services/liveness-orchestrator.service.ts +162 -0
  130. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/hand-gesture-detection.service.ts +315 -0
  131. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/index.ts +5 -0
  132. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/openpose.service.ts +287 -0
  133. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/pose-comparison.service.ts +353 -0
  134. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/pose-matching.service.ts +2370 -0
  135. package/projects/facecog-liveness-verification/src/lib/services/pose-detection/reference-pose.service.ts +271 -0
  136. package/projects/facecog-liveness-verification/src/lib/services/pose-selection.service.spec.ts +183 -0
  137. package/projects/facecog-liveness-verification/src/lib/services/pose-selection.service.ts +179 -0
  138. package/projects/facecog-liveness-verification/src/lib/services/verification-api.service.spec.ts +159 -0
  139. package/projects/facecog-liveness-verification/src/lib/services/verification-api.service.ts +151 -0
  140. package/projects/facecog-liveness-verification/src/lib/services/verification-plan.service.spec.ts +184 -0
  141. package/projects/facecog-liveness-verification/src/lib/services/verification-plan.service.ts +94 -0
  142. package/projects/facecog-liveness-verification/src/lib/services/video-recorder.service.spec.ts +52 -0
  143. package/projects/facecog-liveness-verification/src/lib/services/video-recorder.service.ts +117 -0
  144. package/projects/facecog-liveness-verification/src/lib/types/detection-strategy.type.ts +5 -0
  145. package/projects/facecog-liveness-verification/src/lib/types/index.ts +7 -0
  146. package/projects/facecog-liveness-verification/src/lib/types/liveness-action.type.ts +31 -0
  147. package/projects/facecog-liveness-verification/src/lib/types/liveness-backend.type.ts +5 -0
  148. package/projects/facecog-liveness-verification/src/lib/types/pose-category.type.ts +5 -0
  149. package/projects/facecog-liveness-verification/src/lib/types/pose-difficulty.type.ts +5 -0
  150. package/projects/facecog-liveness-verification/src/lib/types/verification-flow-step.type.ts +5 -0
  151. package/projects/facecog-liveness-verification/src/lib/types/verification-step-kind.type.ts +4 -0
  152. package/projects/facecog-liveness-verification/src/public-api.ts +150 -0
  153. package/projects/facecog-liveness-verification/tsconfig.lib.json +20 -0
  154. package/projects/facecog-liveness-verification/tsconfig.lib.prod.json +11 -0
  155. package/projects/facecog-liveness-verification/tsconfig.spec.json +13 -0
  156. package/projects/facecog-liveness-verification/tsconfig.wrapper.json +15 -0
  157. package/projects/facecog-liveness-verification-test/src/app/app-routing.module.ts +22 -0
  158. package/projects/facecog-liveness-verification-test/src/app/app.component.html +3 -0
  159. package/projects/facecog-liveness-verification-test/src/app/app.component.scss +0 -0
  160. package/projects/facecog-liveness-verification-test/src/app/app.component.ts +11 -0
  161. package/projects/facecog-liveness-verification-test/src/app/app.module.ts +27 -0
  162. package/projects/facecog-liveness-verification-test/src/app/home/home-routing.module.ts +16 -0
  163. package/projects/facecog-liveness-verification-test/src/app/home/home.module.ts +19 -0
  164. package/projects/facecog-liveness-verification-test/src/app/home/home.page.html +39 -0
  165. package/projects/facecog-liveness-verification-test/src/app/home/home.page.scss +97 -0
  166. package/projects/facecog-liveness-verification-test/src/app/home/home.page.spec.ts +24 -0
  167. package/projects/facecog-liveness-verification-test/src/app/home/home.page.ts +92 -0
  168. package/projects/facecog-liveness-verification-test/src/app/home/verification-modal.component.ts +106 -0
  169. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Bold_0.ttf +0 -0
  170. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Medium_0.ttf +0 -0
  171. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Regular_0.ttf +0 -0
  172. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-SemiBold_0.ttf +0 -0
  173. package/projects/facecog-liveness-verification-test/src/assets/fonts/gilroy/Gilroy-Thin_0.ttf +0 -0
  174. package/projects/facecog-liveness-verification-test/src/assets/icon/favicon.png +0 -0
  175. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Five_Fingers_Left.jpg +0 -0
  176. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Left_Palm.jpg +0 -0
  177. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Ok_Sign_Right.jpg +0 -0
  178. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Peace_Sign_Left.jpg +0 -0
  179. package/projects/facecog-liveness-verification-test/src/assets/images/poses/README.md +77 -0
  180. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Right_Palm.jpg +0 -0
  181. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Speak_Phrase.jpg +0 -0
  182. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Three_Fingers_Right.jpg +0 -0
  183. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Thumbs_Up_Left.jpg +0 -0
  184. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Thumbs_Up_Right.jpg +0 -0
  185. package/projects/facecog-liveness-verification-test/src/assets/images/poses/Wave_Right.jpg +0 -0
  186. package/projects/facecog-liveness-verification-test/src/assets/images/poses/blink.jpeg +0 -0
  187. package/projects/facecog-liveness-verification-test/src/assets/images/poses/blink_twice.jpeg +0 -0
  188. package/projects/facecog-liveness-verification-test/src/assets/images/poses/center_face.png +0 -0
  189. package/projects/facecog-liveness-verification-test/src/assets/images/poses/clap.jpeg +0 -0
  190. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cover_mouth.png +0 -0
  191. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cover_right_eye.png +0 -0
  192. package/projects/facecog-liveness-verification-test/src/assets/images/poses/cross_arms.png +0 -0
  193. package/projects/facecog-liveness-verification-test/src/assets/images/poses/face_straight.png +0 -0
  194. package/projects/facecog-liveness-verification-test/src/assets/images/poses/follow_dot.png +0 -0
  195. package/projects/facecog-liveness-verification-test/src/assets/images/poses/look_down.png +0 -0
  196. package/projects/facecog-liveness-verification-test/src/assets/images/poses/look_up.png +0 -0
  197. package/projects/facecog-liveness-verification-test/src/assets/images/poses/move_closer.png +0 -0
  198. package/projects/facecog-liveness-verification-test/src/assets/images/poses/nod.png +0 -0
  199. package/projects/facecog-liveness-verification-test/src/assets/images/poses/open_mouth.png +0 -0
  200. package/projects/facecog-liveness-verification-test/src/assets/images/poses/raise_eyebrow.png +0 -0
  201. package/projects/facecog-liveness-verification-test/src/assets/images/poses/rotate_face.jpeg +0 -0
  202. package/projects/facecog-liveness-verification-test/src/assets/images/poses/shake_head.jpeg +0 -0
  203. package/projects/facecog-liveness-verification-test/src/assets/images/poses/smile.png +0 -0
  204. package/projects/facecog-liveness-verification-test/src/assets/images/poses/tilt_left.png +0 -0
  205. package/projects/facecog-liveness-verification-test/src/assets/images/poses/tilt_right.png +0 -0
  206. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_chin_left.jpg +0 -0
  207. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_left_cheek.jpeg +0 -0
  208. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_nose_right.png +0 -0
  209. package/projects/facecog-liveness-verification-test/src/assets/images/poses/touch_right_cheek.jpeg +0 -0
  210. package/projects/facecog-liveness-verification-test/src/assets/images/poses/turn_left.png +0 -0
  211. package/projects/facecog-liveness-verification-test/src/assets/images/poses/turn_right.png +0 -0
  212. package/projects/facecog-liveness-verification-test/src/assets/images/poses/wink.jpeg +0 -0
  213. package/projects/facecog-liveness-verification-test/src/assets/images/reference-pose.jpg +0 -0
  214. package/projects/facecog-liveness-verification-test/src/assets/shapes.svg +1 -0
  215. package/projects/facecog-liveness-verification-test/src/environments/environment.prod.ts +4 -0
  216. package/projects/facecog-liveness-verification-test/src/environments/environment.ts +17 -0
  217. package/projects/facecog-liveness-verification-test/src/global.scss +288 -0
  218. package/projects/facecog-liveness-verification-test/src/index.html +31 -0
  219. package/projects/facecog-liveness-verification-test/src/main.ts +6 -0
  220. package/projects/facecog-liveness-verification-test/src/polyfills.ts +55 -0
  221. package/projects/facecog-liveness-verification-test/src/theme/nextsapien-theme.scss +174 -0
  222. package/projects/facecog-liveness-verification-test/src/theme/variables.scss +2 -0
  223. package/projects/facecog-liveness-verification-test/src/zone-flags.ts +6 -0
  224. package/projects/facecog-liveness-verification-test/tsconfig.app.json +15 -0
  225. package/projects/facecog-liveness-verification-test/tsconfig.spec.json +14 -0
  226. package/setup-jest.ts +118 -0
  227. package/tsconfig.json +41 -0
  228. package/tsconfig.spec.json +15 -0
  229. package/vercel.json +24 -0
@@ -0,0 +1,123 @@
1
+ import { NgModule, ModuleWithProviders } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonicModule } from '@ionic/angular';
4
+ import { HttpClientModule } from '@angular/common/http';
5
+
6
+ import { LivenessVerificationComponent } from './components/liveness-verification/liveness-verification.component';
7
+ import { PoseSelectionComponent } from './components/pose-selection/pose-selection.component';
8
+ import { CameraVerificationComponent } from './components/camera-verification/camera-verification.component';
9
+ import { VerificationResultComponent } from './components/verification-result/verification-result.component';
10
+ import { AwsFaceLivenessComponent } from './components/aws-face-liveness/aws-face-liveness.component';
11
+ import { LivenessVerificationConfig } from './interfaces/liveness-verification-config.interface';
12
+ import { DEFAULT_LIVENESS_CONFIG } from './models/constants/default-liveness-config.constant';
13
+ import { LIVENESS_VERIFICATION_CONFIG } from './models/constants/liveness-verification-config.token';
14
+ import { AWS_FACE_LIVENESS_COMPONENT } from './models/constants/aws-face-liveness-component.token';
15
+ import { CAMERA_PROVIDER } from './interfaces/camera-provider.interface';
16
+ import { BACKEND_HTTP_CLIENT } from './interfaces/backend-http-client.interface';
17
+ import { CUSTOM_POSE_REPOSITORY } from './interfaces/custom-pose-repository.interface';
18
+ import { LivenessConfigService } from './services/liveness-config.service';
19
+ import { PoseSelectionService } from './services/pose-selection.service';
20
+ import { CameraService } from './services/camera.service';
21
+ import { VideoRecorderService } from './services/video-recorder.service';
22
+ import { MockBackendService } from './services/backends/mock-backend.service';
23
+ import { BackendHttpService } from './services/backend-http.service';
24
+ import { CustomPosesApiService } from './services/custom-poses-api.service';
25
+
26
+ @NgModule({
27
+ imports: [
28
+ CommonModule,
29
+ IonicModule,
30
+ HttpClientModule,
31
+ LivenessVerificationComponent,
32
+ PoseSelectionComponent,
33
+ CameraVerificationComponent,
34
+ VerificationResultComponent
35
+ ],
36
+ exports: [
37
+ LivenessVerificationComponent,
38
+ PoseSelectionComponent,
39
+ CameraVerificationComponent,
40
+ VerificationResultComponent
41
+ ]
42
+ })
43
+ export class LivenessVerificationModule {
44
+ /**
45
+ * Configure the module with global settings
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * LivenessVerificationModule.forRoot({
50
+ * apiUrl: 'https://api.example.com',
51
+ * backends: ['amazon', 'facetec'],
52
+ * maxRetries: 3
53
+ * })
54
+ * ```
55
+ */
56
+ static forRoot(config?: Partial<LivenessVerificationConfig>): ModuleWithProviders<LivenessVerificationModule> {
57
+ return {
58
+ ngModule: LivenessVerificationModule,
59
+ providers: [
60
+ {
61
+ provide: LIVENESS_VERIFICATION_CONFIG,
62
+ useValue: { ...DEFAULT_LIVENESS_CONFIG, ...config }
63
+ },
64
+ LivenessConfigService,
65
+ PoseSelectionService,
66
+ CameraService,
67
+ VideoRecorderService,
68
+ MockBackendService
69
+ ]
70
+ };
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Provide liveness verification services for standalone components
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * bootstrapApplication(AppComponent, {
80
+ * providers: [
81
+ * provideLivenessVerification({
82
+ * apiUrl: 'https://api.example.com',
83
+ * backends: ['mock']
84
+ * })
85
+ * ]
86
+ * });
87
+ * ```
88
+ */
89
+ export function provideLivenessVerification(config?: Partial<LivenessVerificationConfig>) {
90
+ return [
91
+ {
92
+ provide: LIVENESS_VERIFICATION_CONFIG,
93
+ useValue: { ...DEFAULT_LIVENESS_CONFIG, ...config }
94
+ },
95
+ LivenessConfigService,
96
+ PoseSelectionService,
97
+ CameraService,
98
+ VideoRecorderService,
99
+ MockBackendService
100
+ ];
101
+ }
102
+
103
+ /**
104
+ * Provide the full liveness flow (showcase-style) with default AWS component and backend/camera providers.
105
+ * Use this when you want the same UI as the FaceCog showcase with <facecog-liveness-flow>.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * providers: [
110
+ * provideLivenessFlow({ apiUrl: environment.facecogApiUrl })
111
+ * ]
112
+ * ```
113
+ * Then in template: <facecog-liveness-flow></facecog-liveness-flow>
114
+ */
115
+ export function provideLivenessFlow(config?: Partial<LivenessVerificationConfig>) {
116
+ return [
117
+ ...provideLivenessVerification(config),
118
+ { provide: BACKEND_HTTP_CLIENT, useClass: BackendHttpService },
119
+ { provide: CUSTOM_POSE_REPOSITORY, useClass: CustomPosesApiService },
120
+ { provide: CAMERA_PROVIDER, useExisting: CameraService },
121
+ { provide: AWS_FACE_LIVENESS_COMPONENT, useValue: AwsFaceLivenessComponent }
122
+ ];
123
+ }
@@ -0,0 +1,23 @@
1
+ import { InjectionToken, Type } from '@angular/core';
2
+
3
+ /**
4
+ * Optional injection token for the AWS Face Liveness component.
5
+ * When provided, the LivenessFlowComponent will render it in the aws-liveness step
6
+ * when useAwsFaceLiveness is true. The component must have:
7
+ * - @Input() region: string
8
+ * - @Input() autoStart: boolean
9
+ * - @Input() showCancelButton?: boolean
10
+ * - @Output() scanComplete: EventEmitter<AwsFaceLivenessScanResult>
11
+ * - @Output() scanCancelled: EventEmitter<void>
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { AwsFaceLivenessComponent } from './aws-face-liveness.component';
16
+ * import { AWS_FACE_LIVENESS_COMPONENT } from '@naniteninja/liveness-verification';
17
+ *
18
+ * providers: [
19
+ * { provide: AWS_FACE_LIVENESS_COMPONENT, useValue: AwsFaceLivenessComponent }
20
+ * ]
21
+ * ```
22
+ */
23
+ export const AWS_FACE_LIVENESS_COMPONENT = new InjectionToken<Type<unknown>>('AWS_FACE_LIVENESS_COMPONENT');
@@ -0,0 +1,14 @@
1
+ import { PoseCategory } from '../../types/pose-category.type';
2
+ import { CategoryInfo } from '../../interfaces/category-info.interface';
3
+
4
+ /**
5
+ * Category display names and colors
6
+ */
7
+ export const CATEGORY_INFO: Record<PoseCategory, CategoryInfo> = {
8
+ face: { name: 'Face Expressions', icon: 'happy-outline', color: 'primary' },
9
+ head: { name: 'Head Movements', icon: 'sync-outline', color: 'secondary' },
10
+ hand: { name: 'Hand Gestures', icon: 'hand-left-outline', color: 'tertiary' },
11
+ gesture: { name: 'Gestures', icon: 'hand-right-outline', color: 'success' },
12
+ combined: { name: 'Combined', icon: 'body-outline', color: 'warning' }
13
+ };
14
+
@@ -0,0 +1,18 @@
1
+ import { LivenessVerificationConfig } from '../../interfaces/liveness-verification-config.interface';
2
+
3
+ /**
4
+ * Default configuration for the library
5
+ */
6
+ export const DEFAULT_LIVENESS_CONFIG: LivenessVerificationConfig = {
7
+ apiUrl: 'http://localhost:3002',
8
+ backends: ['mock'],
9
+ maxRetries: 3,
10
+ autoCapture: true,
11
+ enableVideoRecording: true,
12
+ similarityThreshold: 0.62,
13
+ videoMaxSizeMB: 10,
14
+ captureFrameCount: 5,
15
+ showIntroScreen: true,
16
+ showPoseSelector: true
17
+ };
18
+
@@ -0,0 +1,5 @@
1
+ export { DEFAULT_LIVENESS_CONFIG } from './default-liveness-config.constant';
2
+ export { LIVENESS_VERIFICATION_CONFIG } from './liveness-verification-config.token';
3
+ export { POSE_DEFINITIONS } from './pose-definitions.constant';
4
+ export { CATEGORY_INFO } from './category-info.constant';
5
+
@@ -0,0 +1,16 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { LivenessVerificationConfig } from '../../interfaces/liveness-verification-config.interface';
3
+ import { DEFAULT_LIVENESS_CONFIG } from './default-liveness-config.constant';
4
+
5
+ /**
6
+ * Injection token for library configuration.
7
+ * Provides DEFAULT_LIVENESS_CONFIG as factory fallback so services that inject
8
+ * this token with @Optional() never hit NG0203 in dynamic component contexts.
9
+ */
10
+ export const LIVENESS_VERIFICATION_CONFIG = new InjectionToken<LivenessVerificationConfig>(
11
+ 'LivenessVerificationConfig',
12
+ {
13
+ providedIn: 'root',
14
+ factory: () => DEFAULT_LIVENESS_CONFIG
15
+ }
16
+ );
@@ -0,0 +1,377 @@
1
+ import { PoseDefinition } from '../../interfaces/pose-definition.interface';
2
+
3
+ /**
4
+ * All predefined poses for liveness verification (40 poses)
5
+ */
6
+ export const POSE_DEFINITIONS: PoseDefinition[] = [
7
+ // Face Expressions & Movements (1-6)
8
+ {
9
+ id: 1,
10
+ name: 'Face Straight',
11
+ description: 'Face straight, hold still',
12
+ category: 'face',
13
+ imagePath: 'assets/images/poses/face_straight.png',
14
+ detectionStrategy: 'face-api',
15
+ difficulty: 'easy'
16
+ },
17
+ {
18
+ id: 2,
19
+ name: 'Blink Once',
20
+ description: 'Blink once, naturally',
21
+ category: 'face',
22
+ imagePath: 'assets/images/poses/blink.jpeg',
23
+ detectionStrategy: 'face-api',
24
+ difficulty: 'easy'
25
+ },
26
+ {
27
+ id: 3,
28
+ name: 'Blink Twice',
29
+ description: 'Blink twice, quickly',
30
+ category: 'face',
31
+ imagePath: 'assets/images/poses/blink_twice.jpeg',
32
+ detectionStrategy: 'face-api',
33
+ difficulty: 'medium'
34
+ },
35
+ {
36
+ id: 4,
37
+ name: 'Open Mouth',
38
+ description: 'Open mouth, then close',
39
+ category: 'face',
40
+ imagePath: 'assets/images/poses/open_mouth.png',
41
+ detectionStrategy: 'face-api',
42
+ difficulty: 'easy'
43
+ },
44
+ {
45
+ id: 5,
46
+ name: 'Smile',
47
+ description: 'Smile, then return to neutral',
48
+ category: 'face',
49
+ imagePath: 'assets/images/poses/smile.png',
50
+ detectionStrategy: 'face-api',
51
+ difficulty: 'easy'
52
+ },
53
+ {
54
+ id: 6,
55
+ name: 'Raise Eyebrows',
56
+ description: 'Raise eyebrows ("surprised" look)',
57
+ category: 'face',
58
+ imagePath: 'assets/images/poses/raise_eyebrow.png',
59
+ detectionStrategy: 'face-api',
60
+ difficulty: 'easy'
61
+ },
62
+
63
+ // Head Movements (7-14)
64
+ {
65
+ id: 7,
66
+ name: 'Turn Left',
67
+ description: 'Turn head slowly left (profile)',
68
+ category: 'head',
69
+ imagePath: 'assets/images/poses/turn_left.png',
70
+ detectionStrategy: 'face-api',
71
+ difficulty: 'easy'
72
+ },
73
+ {
74
+ id: 8,
75
+ name: 'Turn Right',
76
+ description: 'Turn head slowly right (profile)',
77
+ category: 'head',
78
+ imagePath: 'assets/images/poses/turn_right.png',
79
+ detectionStrategy: 'face-api',
80
+ difficulty: 'easy'
81
+ },
82
+ {
83
+ id: 9,
84
+ name: 'Look Up',
85
+ description: 'Look up with just your eyes',
86
+ category: 'face',
87
+ imagePath: 'assets/images/poses/look_up.png',
88
+ detectionStrategy: 'face-api',
89
+ difficulty: 'medium'
90
+ },
91
+ {
92
+ id: 10,
93
+ name: 'Look Down',
94
+ description: 'Look down with just your eyes',
95
+ category: 'face',
96
+ imagePath: 'assets/images/poses/look_down.png',
97
+ detectionStrategy: 'face-api',
98
+ difficulty: 'medium'
99
+ },
100
+ {
101
+ id: 11,
102
+ name: 'Tilt Left',
103
+ description: 'Tilt head slightly left (ear to shoulder)',
104
+ category: 'head',
105
+ imagePath: 'assets/images/poses/tilt_left.png',
106
+ detectionStrategy: 'face-api',
107
+ difficulty: 'easy'
108
+ },
109
+ {
110
+ id: 12,
111
+ name: 'Tilt Right',
112
+ description: 'Tilt head slightly right (ear to shoulder)',
113
+ category: 'head',
114
+ imagePath: 'assets/images/poses/tilt_right.png',
115
+ detectionStrategy: 'face-api',
116
+ difficulty: 'easy'
117
+ },
118
+ {
119
+ id: 13,
120
+ name: 'Nod',
121
+ description: 'Nod up and down once or twice',
122
+ category: 'head',
123
+ imagePath: 'assets/images/poses/nod.png',
124
+ detectionStrategy: 'face-api',
125
+ difficulty: 'easy'
126
+ },
127
+ {
128
+ id: 14,
129
+ name: 'Shake Head',
130
+ description: 'Shake head left to right once or twice',
131
+ category: 'head',
132
+ imagePath: 'assets/images/poses/shake_head.jpeg',
133
+ detectionStrategy: 'face-api',
134
+ difficulty: 'easy'
135
+ },
136
+
137
+ // Eye & Face Tracking (15-20)
138
+ {
139
+ id: 15,
140
+ name: 'Follow Dot',
141
+ description: 'Follow a moving dot/marker with your eyes',
142
+ category: 'face',
143
+ imagePath: 'assets/images/poses/follow_dot.png',
144
+ detectionStrategy: 'face-api',
145
+ difficulty: 'hard'
146
+ },
147
+ {
148
+ id: 16,
149
+ name: 'Wink',
150
+ description: 'Hold a wink (close one eye)',
151
+ category: 'face',
152
+ imagePath: 'assets/images/poses/wink.jpeg',
153
+ detectionStrategy: 'face-api',
154
+ difficulty: 'medium'
155
+ },
156
+ {
157
+ id: 17,
158
+ name: 'Move Closer',
159
+ description: 'Move your face closer, then back to center',
160
+ category: 'head',
161
+ imagePath: 'assets/images/poses/move_closer.png',
162
+ detectionStrategy: 'face-api',
163
+ difficulty: 'medium'
164
+ },
165
+ {
166
+ id: 18,
167
+ name: 'Speak Phrase',
168
+ description: 'Speak a short random phrase (audio+video)',
169
+ category: 'face',
170
+ imagePath: 'assets/images/poses/18-speak-phrase.png',
171
+ detectionStrategy: 'face-api',
172
+ difficulty: 'hard'
173
+ },
174
+ {
175
+ id: 19,
176
+ name: 'Rotate Face',
177
+ description: 'Slowly rotate face under normal light (passive liveness)',
178
+ category: 'head',
179
+ imagePath: 'assets/images/poses/rotate_face.jpeg',
180
+ detectionStrategy: 'face-api',
181
+ difficulty: 'medium'
182
+ },
183
+ {
184
+ id: 20,
185
+ name: 'Center Face',
186
+ description: 'Keep face centered while the phone moves slightly (parallax)',
187
+ category: 'head',
188
+ imagePath: 'assets/images/poses/20-center-face.png',
189
+ detectionStrategy: 'face-api',
190
+ difficulty: 'hard'
191
+ },
192
+
193
+ // Basic Hand Gestures (21-29)
194
+ {
195
+ id: 21,
196
+ name: 'Right Palm',
197
+ description: 'Show your RIGHT hand with palm facing camera (all fingers extended)',
198
+ category: 'hand',
199
+ imagePath: 'assets/images/poses/21-right-palm.png',
200
+ detectionStrategy: 'openpose',
201
+ difficulty: 'easy'
202
+ },
203
+ {
204
+ id: 22,
205
+ name: 'Left Palm',
206
+ description: 'Show your LEFT hand with palm facing camera (all fingers extended)',
207
+ category: 'hand',
208
+ imagePath: 'assets/images/poses/22-left-palm.png',
209
+ detectionStrategy: 'openpose',
210
+ difficulty: 'easy'
211
+ },
212
+ {
213
+ id: 23,
214
+ name: 'Wave Right',
215
+ description: 'Raise RIGHT hand and wave',
216
+ category: 'gesture',
217
+ imagePath: 'assets/images/poses/23-wave-right.png',
218
+ detectionStrategy: 'openpose',
219
+ difficulty: 'medium'
220
+ },
221
+ {
222
+ id: 24,
223
+ name: 'Thumbs Up Right',
224
+ description: 'Show your RIGHT hand with thumbs up gesture (only thumb extended)',
225
+ category: 'gesture',
226
+ imagePath: 'assets/images/poses/24-thumbs-up-right.png',
227
+ detectionStrategy: 'openpose',
228
+ difficulty: 'easy'
229
+ },
230
+ {
231
+ id: 25,
232
+ name: 'Thumbs Up Left',
233
+ description: 'Show your LEFT hand with thumbs up gesture (only thumb extended)',
234
+ category: 'gesture',
235
+ imagePath: 'assets/images/poses/25-thumbs-up-left.png',
236
+ detectionStrategy: 'openpose',
237
+ difficulty: 'easy'
238
+ },
239
+ {
240
+ id: 26,
241
+ name: 'OK Sign Right',
242
+ description: '"OK" sign with right hand',
243
+ category: 'gesture',
244
+ imagePath: 'assets/images/poses/26-ok-sign-right.png',
245
+ detectionStrategy: 'openpose',
246
+ difficulty: 'medium'
247
+ },
248
+ {
249
+ id: 27,
250
+ name: 'Peace Sign Left',
251
+ description: 'Show your LEFT hand with peace/V sign (index and middle fingers extended)',
252
+ category: 'gesture',
253
+ imagePath: 'assets/images/poses/27-peace-sign-left.png',
254
+ detectionStrategy: 'openpose',
255
+ difficulty: 'easy'
256
+ },
257
+ {
258
+ id: 28,
259
+ name: 'Three Fingers Right',
260
+ description: 'Hold up three fingers (right hand)',
261
+ category: 'gesture',
262
+ imagePath: 'assets/images/poses/28-three-fingers-right.png',
263
+ detectionStrategy: 'openpose',
264
+ difficulty: 'medium'
265
+ },
266
+ {
267
+ id: 29,
268
+ name: 'Five Fingers Left',
269
+ description: 'Hold up five fingers (left hand)',
270
+ category: 'gesture',
271
+ imagePath: 'assets/images/poses/29-five-fingers-left.png',
272
+ detectionStrategy: 'openpose',
273
+ difficulty: 'easy'
274
+ },
275
+
276
+ // Face + Hand Combined Poses (30-40)
277
+ {
278
+ id: 30,
279
+ name: 'Touch Nose Right',
280
+ description: 'Touch your nose with right index finger',
281
+ category: 'combined',
282
+ imagePath: 'assets/images/poses/touch_nose_right.png',
283
+ detectionStrategy: 'combined',
284
+ difficulty: 'medium'
285
+ },
286
+ {
287
+ id: 31,
288
+ name: 'Touch Chin Left',
289
+ description: 'Touch your chin with left index finger',
290
+ category: 'combined',
291
+ imagePath: 'assets/images/poses/touch_chin_left.png',
292
+ detectionStrategy: 'combined',
293
+ difficulty: 'medium'
294
+ },
295
+ {
296
+ id: 32,
297
+ name: 'Touch Right Cheek',
298
+ description: 'Touch your right cheek with right palm',
299
+ category: 'combined',
300
+ imagePath: 'assets/images/poses/touch_right_cheek.jpeg',
301
+ detectionStrategy: 'combined',
302
+ difficulty: 'medium'
303
+ },
304
+ {
305
+ id: 33,
306
+ name: 'Touch Left Cheek',
307
+ description: 'Touch your left cheek with left palm',
308
+ category: 'combined',
309
+ imagePath: 'assets/images/poses/touch_left_cheek.jpeg',
310
+ detectionStrategy: 'combined',
311
+ difficulty: 'medium'
312
+ },
313
+ {
314
+ id: 34,
315
+ name: 'Cover Right Eye',
316
+ description: 'Cover right eye with right hand, then uncover',
317
+ category: 'combined',
318
+ imagePath: 'assets/images/poses/cover_right_eye.png',
319
+ detectionStrategy: 'combined',
320
+ difficulty: 'medium'
321
+ },
322
+ {
323
+ id: 35,
324
+ name: 'Cover Mouth',
325
+ description: 'Cover your mouth with one hand, then uncover',
326
+ category: 'combined',
327
+ imagePath: 'assets/images/poses/cover_mouth.png',
328
+ detectionStrategy: 'combined',
329
+ difficulty: 'easy'
330
+ },
331
+ {
332
+ id: 36,
333
+ name: 'Frame Face',
334
+ description: 'Frame your face with both hands (sides of face)',
335
+ category: 'combined',
336
+ imagePath: 'assets/images/poses/36-frame-face.png',
337
+ detectionStrategy: 'combined',
338
+ difficulty: 'medium'
339
+ },
340
+ {
341
+ id: 37,
342
+ name: 'Hand Ear to Shoulder',
343
+ description: 'Move right hand from ear level to shoulder level',
344
+ category: 'gesture',
345
+ imagePath: 'assets/images/poses/37-hand-ear-shoulder.png',
346
+ detectionStrategy: 'openpose',
347
+ difficulty: 'medium'
348
+ },
349
+ {
350
+ id: 38,
351
+ name: 'Cross Arms',
352
+ description: 'Cross arms briefly, then return hands down',
353
+ category: 'gesture',
354
+ imagePath: 'assets/images/poses/cross_arms.png',
355
+ detectionStrategy: 'openpose',
356
+ difficulty: 'easy'
357
+ },
358
+ {
359
+ id: 39,
360
+ name: 'Clap Once',
361
+ description: 'Clap once softly in view',
362
+ category: 'gesture',
363
+ imagePath: 'assets/images/poses/clap.jpeg',
364
+ detectionStrategy: 'openpose',
365
+ difficulty: 'medium'
366
+ },
367
+ {
368
+ id: 40,
369
+ name: 'Point Left-Right',
370
+ description: 'Point to left edge, then right edge of screen with index finger',
371
+ category: 'gesture',
372
+ imagePath: 'assets/images/poses/40-point-left-right.png',
373
+ detectionStrategy: 'openpose',
374
+ difficulty: 'hard'
375
+ }
376
+ ];
377
+
@@ -0,0 +1,5 @@
1
+ // Constants
2
+ export * from './constants';
3
+
4
+ // Utils
5
+ export * from './utils';
@@ -0,0 +1,2 @@
1
+ export { getPosesByCategory, getPosesByDifficulty, getPoseById } from './pose.utils';
2
+
@@ -0,0 +1,76 @@
1
+ import {
2
+ getPosesByCategory,
3
+ getPosesByDifficulty,
4
+ getPoseById,
5
+ customPoseToPoseDefinition,
6
+ mergeCustomPoses,
7
+ getCustomPosesOnly,
8
+ } from './pose.utils';
9
+ import { POSE_DEFINITIONS } from '../constants/pose-definitions.constant';
10
+
11
+ describe('pose.utils', () => {
12
+ it('getPosesByCategory filters by category', () => {
13
+ const facePoses = getPosesByCategory('face');
14
+ expect(facePoses.length).toBeGreaterThan(0);
15
+ expect(facePoses.every(p => p.category === 'face')).toBe(true);
16
+ });
17
+
18
+ it('getPosesByDifficulty filters by difficulty', () => {
19
+ const easyPoses = getPosesByDifficulty('easy');
20
+ expect(easyPoses.length).toBeGreaterThan(0);
21
+ expect(easyPoses.every(p => p.difficulty === 'easy')).toBe(true);
22
+ });
23
+
24
+ it('getPoseById returns correct pose', () => {
25
+ const pose = getPoseById(1);
26
+ expect(pose).toBeDefined();
27
+ expect(pose!.id).toBe(1);
28
+ });
29
+
30
+ it('getPoseById returns undefined for non-existent id', () => {
31
+ expect(getPoseById(99999)).toBeUndefined();
32
+ });
33
+
34
+ it('customPoseToPoseDefinition converts correctly', () => {
35
+ const customPose = {
36
+ id: 5,
37
+ name: 'Custom Smile',
38
+ description: 'A custom smile pose',
39
+ category: 'face',
40
+ difficulty: 'easy',
41
+ detectionStrategy: 'face-api',
42
+ imageBlobUrl: 'https://example.com/img.png',
43
+ poseKeypoints: [{ x: 0, y: 0 }],
44
+ };
45
+
46
+ const result = customPoseToPoseDefinition(customPose as any);
47
+ expect(result.id).toBe(10005);
48
+ expect(result.name).toBe('Custom Smile');
49
+ expect(result.isCustom).toBe(true);
50
+ expect(result.imageBlobUrl).toBe('https://example.com/img.png');
51
+ expect(result.poseKeypoints).toEqual([{ x: 0, y: 0 }]);
52
+ });
53
+
54
+ it('mergeCustomPoses combines static and custom poses', () => {
55
+ const customPoses = [
56
+ { id: 1, name: 'Custom1', description: 'd', category: 'face', difficulty: 'easy' },
57
+ ];
58
+ const merged = mergeCustomPoses(customPoses as any);
59
+ expect(merged.length).toBe(POSE_DEFINITIONS.length + 1);
60
+ expect(merged[merged.length - 1].isCustom).toBe(true);
61
+ });
62
+
63
+ it('getCustomPosesOnly filters custom poses', () => {
64
+ const poses = [
65
+ ...POSE_DEFINITIONS,
66
+ { ...POSE_DEFINITIONS[0], id: 10001, isCustom: true },
67
+ ];
68
+ const custom = getCustomPosesOnly(poses);
69
+ expect(custom.length).toBe(1);
70
+ expect(custom[0].isCustom).toBe(true);
71
+ });
72
+
73
+ it('getCustomPosesOnly returns empty for no custom poses', () => {
74
+ expect(getCustomPosesOnly(POSE_DEFINITIONS).length).toBe(0);
75
+ });
76
+ });