scandoc-ai-components 0.0.99 → 0.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 (3) hide show
  1. package/README.md +4 -6
  2. package/dist/index.js +114 -36
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -42,8 +42,7 @@ An example HTML page integration:
42
42
 
43
43
  <script src="scandoc.js"></script>
44
44
  <script>
45
- const key = ''; // Use the key provided by our team
46
- createScanDocAIConfig(key, "test");
45
+ const token = ""
47
46
 
48
47
  setScanDocAIConfig({
49
48
  SHOULD_RETURN_DOCUMENT_IMAGE: true,
@@ -54,7 +53,7 @@ An example HTML page integration:
54
53
  MAX_UNSUPPORTED_ATTEMPTS: 5,
55
54
  });
56
55
 
57
- const extractionVideo = getExtractionVideo(function (result) {
56
+ const extractionVideo = getExtractionVideo(token, function (result) {
58
57
  console.log("Extraction Result:", result);
59
58
  if (result.success) {
60
59
  extractionVideo.reset();
@@ -82,8 +81,7 @@ An example React integration:
82
81
  import { useEffect, useMemo } from "react";
83
82
  import "scandoc-ai-components/dist/index"
84
83
 
85
- const key = ""; // Use the key provided by our team
86
- window.createScanDocAIConfig(key, "test");
84
+ const token = "";
87
85
  window.setScanDocAIConfig({
88
86
  SHOULD_RETURN_DOCUMENT_IMAGE: true,
89
87
  SHOULD_RETURN_FACE_IF_DETECTED: true,
@@ -93,7 +91,7 @@ window.setScanDocAIConfig({
93
91
  MAX_UNSUPPORTED_ATTEMPTS: 4,
94
92
  });
95
93
 
96
- const extractionVideo = window.getExtractionVideo(result => {
94
+ const extractionVideo = window.getExtractionVideo(token, result => {
97
95
  console.log("Extraction Result:", result);
98
96
  if (result.success) {
99
97
  extractionVideo.reset();
package/dist/index.js CHANGED
@@ -11180,8 +11180,7 @@ class ExtractorVideo {
11180
11180
  },
11181
11181
  height: {
11182
11182
  ideal: 1080
11183
- },
11184
- facingMode: "environment"
11183
+ }
11185
11184
  });
11186
11185
  constructor(onExtractedResults) {
11187
11186
  this.candidateImages = [];
@@ -11350,7 +11349,7 @@ class ExtractorVideo {
11350
11349
  async startVideo() {
11351
11350
  try {
11352
11351
  const serviceConfig = (0,_config__WEBPACK_IMPORTED_MODULE_1__.getScanDocAIConfig)();
11353
- await serviceConfig.getAccessToken(true);
11352
+ await serviceConfig.getAccessToken(false);
11354
11353
  const videoElem = document.getElementById("ScanDocAIVideoElement");
11355
11354
  if (!videoElem) {
11356
11355
  throw new Error("Video element not found.");
@@ -11358,22 +11357,47 @@ class ExtractorVideo {
11358
11357
  this.video = videoElem;
11359
11358
  this.isRunning = true;
11360
11359
  this.scanStartTime = Date.now();
11360
+ const cfgValues = (0,_config__WEBPACK_IMPORTED_MODULE_1__.getScanDocAIConfigValues)();
11361
+ const mode = cfgValues.VIDEO_FACING_MODE ?? "environment";
11361
11362
  const devices = await navigator.mediaDevices.enumerateDevices();
11362
11363
  const environmentCameras = devices.filter(device => device.kind === "videoinput" && device.label.toLowerCase().includes("back"));
11363
- const cameras = await checkAutofocusSupport(environmentCameras);
11364
11364
  let deviceId;
11365
- if (cameras.length > 0) {
11366
- deviceId = cameras[0].deviceId;
11365
+ if (mode === "environment") {
11366
+ const af = await checkAutofocusSupport(environmentCameras);
11367
+ deviceId = af[0]?.deviceId || environmentCameras[0]?.deviceId;
11367
11368
  }
11368
- const userMediaConstraints = {
11369
- ...ExtractorVideo.VIDEO_SETTINGS
11369
+ const buildConstraints = () => {
11370
+ const base = {
11371
+ ...ExtractorVideo.VIDEO_SETTINGS
11372
+ };
11373
+ if (typeof mode === "string") {
11374
+ base.facingMode = {
11375
+ ideal: mode
11376
+ }; // "environment" | "user"
11377
+ } else if (mode && typeof mode === "object") {
11378
+ base.facingMode = mode; // e.g. { exact: "user" }
11379
+ } else {
11380
+ base.facingMode = {
11381
+ ideal: "environment"
11382
+ };
11383
+ }
11384
+ if (mode === "environment" && deviceId) {
11385
+ base.deviceId = {
11386
+ exact: deviceId
11387
+ };
11388
+ }
11389
+ return {
11390
+ video: base
11391
+ };
11370
11392
  };
11371
- if (deviceId) {
11372
- userMediaConstraints.deviceId = deviceId;
11393
+ let stream;
11394
+ try {
11395
+ stream = await navigator.mediaDevices.getUserMedia(buildConstraints());
11396
+ } catch (e) {
11397
+ stream = await navigator.mediaDevices.getUserMedia({
11398
+ video: true
11399
+ });
11373
11400
  }
11374
- const stream = await navigator.mediaDevices.getUserMedia({
11375
- video: userMediaConstraints
11376
- });
11377
11401
  this.video.srcObject = stream;
11378
11402
  await this.video.play().catch(e => {
11379
11403
  console.warn(`Error on video play: ${e}`);
@@ -11394,7 +11418,7 @@ class ExtractorVideo {
11394
11418
  this.onExtractedResults({
11395
11419
  success: false,
11396
11420
  code: error.status === 401 || error.status === 403 ? "004" : "005",
11397
- info: error.status === 401 || error.status === 403 ? "Authentication failed: Invalid API key." : "Startup failed: " + (error.message || "Unknown error")
11421
+ info: error.status === 401 || error.status === 403 ? "Authentication failed: Invalid API key/token." : "Startup failed: " + (error.message || "Unknown error")
11398
11422
  });
11399
11423
  return false;
11400
11424
  }
@@ -11438,8 +11462,7 @@ class ExtractorVideo {
11438
11462
  const cfgValues = (0,_config__WEBPACK_IMPORTED_MODULE_1__.getScanDocAIConfigValues)();
11439
11463
  const borderColor = cfgValues.VIDEO_COLORS?.borderColor;
11440
11464
  const messageColor = cfgValues.VIDEO_COLORS?.messageColor;
11441
- const isMobile = window.innerWidth < 768 || window.innerHeight > window.innerWidth;
11442
- window.innerWidth < 768 || window.innerHeight > window.innerWidth && window.innerWidth < 1024;
11465
+ const isMobile = window.innerWidth < 768 || window.innerHeight > window.innerWidth && window.innerWidth < 1024;
11443
11466
  if (isMobile) {
11444
11467
  // Mobile version with overlay feedback
11445
11468
  return `
@@ -11508,7 +11531,7 @@ class ExtractorVideo {
11508
11531
  <div class="desktopFeedback" id="ScanDocAIMessage"></div>
11509
11532
  <div class="desktopVideoArea">
11510
11533
  <div class="desktopVideoHolder">
11511
- <video id="ScanDocAIVideoElement" class="desktopVideo" autoPlay muted playsInline></video>
11534
+ <video id="ScanDocAIVideoElement" class="desktopVideo" autoplay muted playsinline></video>
11512
11535
  <div class="backgroundOverlay"></div>
11513
11536
  <div class="centerGuideDot"></div>
11514
11537
  </div>
@@ -11587,11 +11610,29 @@ class ExtractorVideo {
11587
11610
  }
11588
11611
  }
11589
11612
  let EXTRACTION_VIDEO = undefined;
11590
- function getExtractionVideo(onSuccessfulExtraction) {
11591
- if (EXTRACTION_VIDEO === undefined) {
11592
- EXTRACTION_VIDEO = new ExtractorVideo(onSuccessfulExtraction);
11613
+ function getExtractionVideo(tokenOrCallback, maybeCallback) {
11614
+ let token;
11615
+ let cb;
11616
+ if (typeof tokenOrCallback === "function") {
11617
+ cb = tokenOrCallback;
11593
11618
  } else {
11594
- console.error("Extraction video already created. Returning existing object.");
11619
+ token = tokenOrCallback;
11620
+ cb = maybeCallback;
11621
+ }
11622
+ if (token !== undefined) {
11623
+ (0,_config__WEBPACK_IMPORTED_MODULE_1__.setScanDocAIAccessToken)(token);
11624
+ }
11625
+ if (EXTRACTION_VIDEO === undefined) {
11626
+ if (typeof cb !== "function") {
11627
+ throw new Error("getExtractionVideo requires a callback.");
11628
+ }
11629
+ EXTRACTION_VIDEO = new ExtractorVideo(cb);
11630
+ return EXTRACTION_VIDEO;
11631
+ }
11632
+
11633
+ // If called again, update callback too
11634
+ if (typeof cb === "function") {
11635
+ EXTRACTION_VIDEO.onExtractedResults = cb;
11595
11636
  }
11596
11637
  return EXTRACTION_VIDEO;
11597
11638
  }
@@ -11611,12 +11652,14 @@ async function checkAutofocusSupport(environmentCameras) {
11611
11652
  // Try to access camera stream with autofocus enabled
11612
11653
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
11613
11654
  const tracks = stream.getVideoTracks();
11614
-
11615
- // Check if autofocus is supported
11616
- const capabilities = tracks[0].getCapabilities();
11617
- // console.log(capabilities);
11618
- if (capabilities.focusMode && capabilities.focusMode.includes("continuous")) {
11619
- camerasWithAutofocus.push(camera);
11655
+ const track = tracks[0];
11656
+ if (track) {
11657
+ // Check if autofocus is supported
11658
+ const capabilities = track.getCapabilities();
11659
+ // console.log(capabilities);
11660
+ if (capabilities.focusMode && capabilities.focusMode.includes("continuous")) {
11661
+ camerasWithAutofocus.push(camera);
11662
+ }
11620
11663
  }
11621
11664
 
11622
11665
  // Cleanup
@@ -11680,6 +11723,7 @@ __webpack_require__.r(__webpack_exports__);
11680
11723
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
11681
11724
  /* harmony export */ getScanDocAIConfig: () => (/* binding */ getScanDocAIConfig),
11682
11725
  /* harmony export */ getScanDocAIConfigValues: () => (/* binding */ getScanDocAIConfigValues),
11726
+ /* harmony export */ setScanDocAIAccessToken: () => (/* binding */ setScanDocAIAccessToken),
11683
11727
  /* harmony export */ setScanDocAIConfig: () => (/* binding */ setScanDocAIConfig)
11684
11728
  /* harmony export */ });
11685
11729
  let internalConfig = {
@@ -11694,6 +11738,7 @@ let internalConfig = {
11694
11738
  MAX_REQUEST_TRY: 3,
11695
11739
  MAX_AUTH_TRY: 3,
11696
11740
  USE_KEY_SERVICE: true,
11741
+ VIDEO_FACING_MODE: "environment",
11697
11742
  // validation settings:
11698
11743
  VALIDATION_CONTRAST_BORDER_SIZE: null,
11699
11744
  VALIDATION_CONTRAST_THRESHOLD: null,
@@ -11732,9 +11777,9 @@ function setScanDocAIConfig(newConfig = {}) {
11732
11777
  internalConfig = {
11733
11778
  ...internalConfig,
11734
11779
  ...newConfig,
11735
- COLORS: {
11736
- ...internalConfig.COLORS,
11737
- ...newConfig.COLORS
11780
+ VIDEO_COLORS: {
11781
+ ...internalConfig.VIDEO_COLORS,
11782
+ ...newConfig.VIDEO_COLORS
11738
11783
  }
11739
11784
  };
11740
11785
  }
@@ -11831,6 +11876,34 @@ class InactiveServiceConfig {
11831
11876
  }
11832
11877
  async refreshTokens() {}
11833
11878
  }
11879
+ class TokenServiceConfig {
11880
+ static CONFIG = undefined;
11881
+ constructor() {
11882
+ this.accessToken = undefined;
11883
+ }
11884
+ setAccessToken(token) {
11885
+ this.accessToken = token || undefined;
11886
+ }
11887
+ async getAccessToken() {
11888
+ if (!this.accessToken) {
11889
+ const err = new Error("Missing access token");
11890
+ err.status = 401;
11891
+ throw err;
11892
+ }
11893
+ return this.accessToken;
11894
+ }
11895
+ async refreshTokens() {
11896
+ // client provides a new token
11897
+ }
11898
+ }
11899
+ function setScanDocAIAccessToken(token) {
11900
+ const config = getScanDocAIConfigValues();
11901
+ if (config.USE_KEY_SERVICE === false) return;
11902
+ if (TokenServiceConfig.CONFIG === undefined) {
11903
+ TokenServiceConfig.CONFIG = new TokenServiceConfig();
11904
+ }
11905
+ TokenServiceConfig.CONFIG.setAccessToken(token);
11906
+ }
11834
11907
  function createScanDocAIConfig(staticKey, subClient) {
11835
11908
  const config = getScanDocAIConfigValues();
11836
11909
  if (config.USE_KEY_SERVICE) {
@@ -11846,11 +11919,15 @@ function getScanDocAIConfig() {
11846
11919
  if (config.USE_KEY_SERVICE === false) {
11847
11920
  return new InactiveServiceConfig();
11848
11921
  }
11849
- //
11850
- if (ServiceConfig.CONFIG === undefined) {
11851
- throw new Error("Service config not created!");
11922
+ if (TokenServiceConfig.CONFIG !== undefined) {
11923
+ return TokenServiceConfig.CONFIG;
11852
11924
  }
11853
- return ServiceConfig.CONFIG;
11925
+ if (ServiceConfig.CONFIG !== undefined) {
11926
+ return ServiceConfig.CONFIG;
11927
+ }
11928
+ const err = new Error("Service config not created (missing token or static key)!");
11929
+ err.status = 401;
11930
+ throw err;
11854
11931
  }
11855
11932
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (createScanDocAIConfig);
11856
11933
 
@@ -11960,7 +12037,7 @@ async function callDocumentExtraction(frontImage, backImage, ignoreBackImage) {
11960
12037
  const response = await fetch(`${cfgValues.SCAN_APP_URL}extraction/`, {
11961
12038
  method: "POST",
11962
12039
  headers: {
11963
- Authorization: await serviceConfig.getAccessToken(true),
12040
+ Authorization: await serviceConfig.getAccessToken(false),
11964
12041
  Accept: "application/json",
11965
12042
  "Content-Type": "application/json"
11966
12043
  },
@@ -11987,6 +12064,7 @@ async function callDocumentExtraction(frontImage, backImage, ignoreBackImage) {
11987
12064
  }
11988
12065
  //
11989
12066
  if (response.status === 401 || response.status === 403) {
12067
+ errors = ["Token expired/invalid"];
11990
12068
  await serviceConfig.refreshTokens();
11991
12069
  } else {
11992
12070
  const data = await response.json();
@@ -12070,7 +12148,7 @@ async function callDocumentValidation(images, blur_values) {
12070
12148
  }
12071
12149
  //
12072
12150
  if (response.status === 401 || response.status === 403) {
12073
- errors = ["Backend error"];
12151
+ errors = ["Token expired/invalid"];
12074
12152
  await serviceConfig.refreshTokens();
12075
12153
  } else {
12076
12154
  const data = await response.json();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "scandoc-ai-components",
3
3
  "author": "ScanDoc-AI",
4
- "version": "0.0.99",
4
+ "version": "0.1.1",
5
5
  "private": false,
6
6
  "description": "Pure JavaScript package for integrating ScanDoc-AI services.",
7
7
  "keywords": [