@jaak.ai/stamps 2.2.0-dev.9 → 2.2.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/README.md +188 -8
- package/dist/cjs/jaak-stamps.cjs.entry.js +69 -24
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/collection/components/my-component/my-component.css +23 -2
- package/dist/collection/components/my-component/my-component.js +28 -15
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +41 -9
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/LicenseValidationService.js +1 -1
- package/dist/collection/services/LicenseValidationService.js.map +1 -1
- package/dist/components/jaak-stamps.js +69 -24
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps.entry.js +69 -24
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-34bcebb1.entry.js +7 -0
- package/dist/jaak-stamps-webcomponent/p-34bcebb1.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +2 -1
- package/dist/types/components.d.ts +2 -2
- package/dist/types/services/LicenseValidationService.d.ts +1 -1
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-dfecb452.entry.js +0 -7
- package/dist/jaak-stamps-webcomponent/p-dfecb452.entry.js.map +0 -1
|
@@ -377,17 +377,30 @@ export class CameraService {
|
|
|
377
377
|
}
|
|
378
378
|
const constraints = { ...videoConstraints };
|
|
379
379
|
if (capabilities.width && capabilities.height) {
|
|
380
|
-
const maxWidth = Math.min(capabilities.width.max, 1920);
|
|
381
|
-
const maxHeight = Math.min(capabilities.height.max, 1080);
|
|
382
380
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
381
|
+
const isMobileDevice = this.deviceType === 'mobile' ||
|
|
382
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
383
|
+
// Optimize resolution based on device type to prevent "slow motion" effect
|
|
384
|
+
// on devices with high-resolution cameras
|
|
385
|
+
let targetWidth;
|
|
386
|
+
let targetHeight;
|
|
387
|
+
if (isMobileDevice && !isTablet) {
|
|
388
|
+
// Mobile phones: Use 720p max to ensure smooth detection performance
|
|
389
|
+
targetWidth = Math.min(capabilities.width.max, 1280);
|
|
390
|
+
targetHeight = Math.min(capabilities.height.max, 720);
|
|
391
|
+
}
|
|
392
|
+
else if (isTablet) {
|
|
393
|
+
// Tablets: Can handle slightly higher resolution
|
|
394
|
+
targetWidth = Math.min(capabilities.width.max, 1280);
|
|
395
|
+
targetHeight = Math.min(capabilities.height.max, 720);
|
|
386
396
|
}
|
|
387
397
|
else {
|
|
388
|
-
|
|
389
|
-
|
|
398
|
+
// Desktop: Can handle full HD
|
|
399
|
+
targetWidth = Math.min(capabilities.width.max, 1920);
|
|
400
|
+
targetHeight = Math.min(capabilities.height.max, 1080);
|
|
390
401
|
}
|
|
402
|
+
constraints.width = { ideal: targetWidth };
|
|
403
|
+
constraints.height = { ideal: targetHeight };
|
|
391
404
|
}
|
|
392
405
|
// Configure autofocus if camera has the capability
|
|
393
406
|
const capabilitiesAny = capabilities;
|
|
@@ -407,9 +420,28 @@ export class CameraService {
|
|
|
407
420
|
await this.detectDeviceType();
|
|
408
421
|
}
|
|
409
422
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
423
|
+
const isMobileDevice = this.deviceType === 'mobile' ||
|
|
424
|
+
/Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
425
|
+
// Optimized fallback constraints for device type
|
|
426
|
+
let fallbackWidth;
|
|
427
|
+
let fallbackHeight;
|
|
428
|
+
if (isMobileDevice && !isTablet) {
|
|
429
|
+
// Mobile phones: Use 720p for smooth performance
|
|
430
|
+
fallbackWidth = 1280;
|
|
431
|
+
fallbackHeight = 720;
|
|
432
|
+
}
|
|
433
|
+
else if (isTablet) {
|
|
434
|
+
fallbackWidth = 1280;
|
|
435
|
+
fallbackHeight = 720;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
// Desktop
|
|
439
|
+
fallbackWidth = 1920;
|
|
440
|
+
fallbackHeight = 1080;
|
|
441
|
+
}
|
|
410
442
|
const fallbackConstraints = {
|
|
411
|
-
width: { ideal:
|
|
412
|
-
height: { ideal:
|
|
443
|
+
width: { ideal: fallbackWidth },
|
|
444
|
+
height: { ideal: fallbackHeight }
|
|
413
445
|
};
|
|
414
446
|
if (this.selectedCameraId) {
|
|
415
447
|
fallbackConstraints.deviceId = { exact: this.selectedCameraId };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"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","sourcesContent":["import { ICameraService, CameraInfo } from './interfaces/ICameraService';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n\n // Optimization: Static caches for performance\n private static cameraCapabilitiesCache = new Map<string, boolean | string>();\n private static deviceEnumerationCache: {\n devices: MediaDeviceInfo[];\n timestamp: number;\n } | null = null;\n private static readonly CACHE_DURATION = 30000; // 30 seconds\n \n // Stream management for optimization\n private currentStreamPromise?: Promise<MediaStream>;\n private lastStreamConstraints?: MediaTrackConstraints;\n\n constructor(\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n // Check cache first for optimization\n const now = Date.now();\n if (CameraService.deviceEnumerationCache &&\n (now - CameraService.deviceEnumerationCache.timestamp) < CameraService.CACHE_DURATION) {\n this.availableCameras = CameraService.deviceEnumerationCache.devices;\n await this.setInitialCameraPreference();\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n return this.availableCameras;\n }\n\n const permissionStatus = await this.checkCameraPermission();\n\n if (permissionStatus === 'denied') {\n return [];\n }\n\n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n const allCameras = devices.filter(device => device.kind === 'videoinput');\n\n // Filter out virtual cameras\n this.availableCameras = allCameras.filter(camera => {\n const isVirtual = this.isVirtualCamera(camera);\n if (isVirtual) {\n console.log(`Virtual camera detected and filtered: ${camera.label}`);\n }\n return !isVirtual;\n });\n\n // Check if there are physical cameras available\n if (this.availableCameras.length === 0) {\n console.log('No physical cameras available');\n this.eventBus.emit('error', new Error('Cámaras virtuales no están permitidas. Use una cámara física.'));\n return [];\n }\n\n // Cache the results for optimization\n CameraService.deviceEnumerationCache = {\n devices: this.availableCameras,\n timestamp: now\n };\n\n await this.setInitialCameraPreference();\n\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n\n return this.availableCameras;\n } catch (error) {\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n try {\n const finalConstraints = constraints || await this.getMaxResolution();\n\n // Optimization: Check if we can reuse existing stream with same constraints\n if (this.currentStreamPromise && this.constraintsEqual(finalConstraints, this.lastStreamConstraints)) {\n return await this.currentStreamPromise;\n }\n\n // Create new stream promise for lazy loading\n this.currentStreamPromise = navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n this.lastStreamConstraints = finalConstraints;\n\n const stream = await this.currentStreamPromise;\n\n // Validate that active stream is not from a virtual camera\n const videoTrack = stream.getVideoTracks()[0];\n if (videoTrack) {\n const settings = videoTrack.getSettings();\n const deviceId = settings.deviceId;\n if (deviceId) {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const currentDevice = devices.find(device => device.deviceId === deviceId);\n if (currentDevice && this.isVirtualCamera(currentDevice)) {\n console.log(`Virtual camera detected in active stream: ${currentDevice.label}`);\n stream.getTracks().forEach(track => track.stop());\n throw new Error('Cámaras virtuales no están permitidas. Use una cámara física.');\n }\n }\n }\n\n return stream;\n } catch (error) {\n\n // Fallback to basic constraints if getMaxResolution fails\n const basicConstraints: MediaTrackConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 }\n };\n\n // Only add facingMode if not on desktop to avoid OverconstrainedError\n if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {\n basicConstraints.facingMode = this.preferredCameraFacing;\n }\n\n this.currentStreamPromise = navigator.mediaDevices.getUserMedia({\n video: basicConstraints,\n audio: false\n });\n\n this.lastStreamConstraints = basicConstraints;\n\n const stream = await this.currentStreamPromise;\n\n // Validate fallback stream as well\n const videoTrack = stream.getVideoTracks()[0];\n if (videoTrack) {\n const settings = videoTrack.getSettings();\n const deviceId = settings.deviceId;\n if (deviceId) {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const currentDevice = devices.find(device => device.deviceId === deviceId);\n if (currentDevice && this.isVirtualCamera(currentDevice)) {\n console.log(`Virtual camera detected in fallback stream: ${currentDevice.label}`);\n stream.getTracks().forEach(track => track.stop());\n throw new Error('Cámaras virtuales no están permitidas. Use una cámara física.');\n }\n }\n }\n\n return stream;\n }\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n await this.enumerateDevices();\n return;\n }\n\n // Validate that the target camera is not virtual\n if (this.isVirtualCamera(selectedCamera)) {\n console.log(`Attempted to switch to virtual camera: ${selectedCamera.label}`);\n this.eventBus.emit('error', new Error('No se puede cambiar a cámara virtual'));\n return;\n }\n\n await this.setSelectedCamera(cameraId);\n }\n\n\n\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n async getCameraInfo(): Promise<{\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n }> {\n const availableCamerasWithAutofocus = await Promise.all(\n this.availableCameras.map(async (camera) => {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n return {\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId,\n hasAutofocus\n };\n })\n );\n\n return {\n availableCameras: availableCamerasWithAutofocus,\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private async setInitialCameraPreference(): Promise<void> {\n if (this.availableCameras.length === 0) return;\n \n \n if (this.preferredCamera === 'front') {\n await this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n await this.selectBackCamera();\n } else {\n await this.selectAutoCamera();\n }\n \n }\n\n private async checkCameraAutofocus(deviceId: string): Promise<boolean> {\n try {\n // Check cache first for optimization\n if (CameraService.cameraCapabilitiesCache.has(deviceId)) {\n const cached = CameraService.cameraCapabilitiesCache.get(deviceId)!;\n return typeof cached === 'boolean' ? cached : false;\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { deviceId: { exact: deviceId } }\n });\n \n const videoTrack = stream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities() as any;\n \n stream.getTracks().forEach(track => track.stop());\n \n const hasFocusMode = capabilities.focusMode && Array.isArray(capabilities.focusMode) && capabilities.focusMode.length > 0;\n const hasAutofocus = hasFocusMode && (\n capabilities.focusMode.includes('continuous') || \n capabilities.focusMode.includes('auto')\n );\n \n // Cache the result for future use\n CameraService.cameraCapabilitiesCache.set(deviceId, hasAutofocus);\n \n return hasAutofocus;\n } catch (error) {\n // Cache negative result to avoid repeated failures\n CameraService.cameraCapabilitiesCache.set(deviceId, false);\n return false;\n }\n }\n\n private async selectFrontCamera(): Promise<void> {\n this.preferredCameraFacing = 'user';\n \n const frontCameras = this.availableCameras.filter(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('front') || \n label.includes('user') ||\n label.includes('selfie') ||\n label.includes('frontal') ||\n (!label.includes('back') && !label.includes('rear') && !label.includes('environment'));\n });\n \n let selectedCamera = null;\n \n if (frontCameras.length > 0) {\n for (const camera of frontCameras) {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n if (hasAutofocus) {\n selectedCamera = camera;\n break;\n }\n }\n \n if (!selectedCamera) {\n selectedCamera = frontCameras[0];\n }\n }\n \n this.selectedCameraId = selectedCamera ? selectedCamera.deviceId : this.availableCameras[0].deviceId;\n }\n\n private async selectBackCamera(): Promise<void> {\n this.preferredCameraFacing = 'environment';\n \n const backCameras = this.availableCameras.filter(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('back') || \n label.includes('rear') ||\n label.includes('environment') ||\n label.includes('trasera') ||\n label.includes('posterior');\n });\n \n let selectedCamera = null;\n \n if (backCameras.length > 0) {\n for (const camera of backCameras) {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n if (hasAutofocus) {\n selectedCamera = camera;\n break;\n }\n }\n \n if (!selectedCamera) {\n selectedCamera = backCameras[0];\n }\n } else if (this.availableCameras.length > 1) {\n const lastCamera = this.availableCameras[this.availableCameras.length - 1];\n const hasAutofocus = await this.checkCameraAutofocus(lastCamera.deviceId);\n selectedCamera = hasAutofocus ? lastCamera : this.availableCameras[this.availableCameras.length - 1];\n }\n \n this.selectedCameraId = selectedCamera ? selectedCamera.deviceId : this.availableCameras[0].deviceId;\n }\n\n private async selectAutoCamera(): Promise<void> {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n await this.selectBackCamera();\n } else {\n // For desktop, prefer front camera (usually built-in webcam)\n await this.selectFrontCamera();\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const videoConstraints: MediaTrackConstraints = {};\n \n // Priority 1: Always use deviceId if available (ensures specific camera with autofocus)\n if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n } \n // Priority 2: Use facingMode as fallback when no specific camera is selected\n else if (this.preferredCameraFacing) {\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n videoConstraints.facingMode = facingConstraint;\n } \n // Priority 3: Fallback to preferredCamera setting\n else {\n if (this.preferredCamera === 'front') {\n videoConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n videoConstraints.facingMode = \"environment\"; \n } else {\n videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n // Optimization: Use cached capabilities if available\n let capabilities: MediaTrackCapabilities;\n \n if (this.selectedCameraId && CameraService.cameraCapabilitiesCache.has(this.selectedCameraId + '_caps')) {\n capabilities = JSON.parse(CameraService.cameraCapabilitiesCache.get(this.selectedCameraId + '_caps') as string);\n } else {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: videoConstraints });\n const videoTrack = tempStream.getVideoTracks()[0];\n capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n // Cache capabilities for future use\n if (this.selectedCameraId) {\n CameraService.cameraCapabilitiesCache.set(this.selectedCameraId + '_caps', JSON.stringify(capabilities));\n }\n }\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n if (capabilities.width && capabilities.height) {\n const maxWidth = Math.min(capabilities.width.max, 1920);\n const maxHeight = Math.min(capabilities.height.max, 1080);\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n constraints.width = { ideal: Math.min(maxWidth, 1280) };\n constraints.height = { ideal: Math.min(maxHeight, 720) };\n } else {\n constraints.width = { ideal: maxWidth };\n constraints.height = { ideal: maxHeight };\n }\n }\n \n // Configure autofocus if camera has the capability\n const capabilitiesAny = capabilities as any;\n if (capabilitiesAny.focusMode && Array.isArray(capabilitiesAny.focusMode)) {\n if (capabilitiesAny.focusMode.includes('continuous')) {\n (constraints as any).focusMode = 'continuous';\n } else if (capabilitiesAny.focusMode.includes('auto')) {\n (constraints as any).focusMode = 'auto';\n }\n }\n \n return constraints;\n } catch (err) {\n // Fallback logic with minimal temporary streams\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: isTablet ? 1280 : 1920 },\n height: { ideal: isTablet ? 720 : 1080 }\n };\n \n if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n fallbackConstraints.facingMode = facingConstraint;\n } else {\n if (this.preferredCamera === 'front') {\n fallbackConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n fallbackConstraints.facingMode = \"environment\"; \n } else {\n fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n return fallbackConstraints;\n }\n }\n\n\n // Optimization helper methods\n private constraintsEqual(a?: MediaTrackConstraints, b?: MediaTrackConstraints): boolean {\n if (!a || !b) return false;\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n // Cleanup method for optimization\n public static clearCaches(): void {\n CameraService.cameraCapabilitiesCache.clear();\n CameraService.deviceEnumerationCache = null;\n }\n\n // Method to invalidate device cache when needed\n public invalidateDeviceCache(): void {\n CameraService.deviceEnumerationCache = null;\n }\n\n private isVirtualCamera(device: MediaDeviceInfo): boolean {\n const label = device.label.toLowerCase();\n const virtualCameraIndicators = [\n 'obs',\n 'virtual',\n 'snap camera',\n 'manycam',\n 'xsplit',\n 'camtwist',\n 'ecamm',\n 'nvidia broadcast',\n 'droidcam',\n 'iriun',\n 'elgato',\n 'streamlabs',\n 'wirecast',\n 'zoom virtual',\n 'teams virtual',\n 'mmhmm',\n 'camo',\n 'reincubate camo',\n 'webcamoid',\n 'splitcam',\n 'cheese',\n 'guvcview',\n 'yawcam',\n 'webcam 7',\n 'altserver'\n ];\n\n return virtualCameraIndicators.some(indicator => label.includes(indicator));\n }\n\n}"]}
|
|
1
|
+
{"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"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","sourcesContent":["import { ICameraService, CameraInfo } from './interfaces/ICameraService';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n\n // Optimization: Static caches for performance\n private static cameraCapabilitiesCache = new Map<string, boolean | string>();\n private static deviceEnumerationCache: {\n devices: MediaDeviceInfo[];\n timestamp: number;\n } | null = null;\n private static readonly CACHE_DURATION = 30000; // 30 seconds\n \n // Stream management for optimization\n private currentStreamPromise?: Promise<MediaStream>;\n private lastStreamConstraints?: MediaTrackConstraints;\n\n constructor(\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n // Check cache first for optimization\n const now = Date.now();\n if (CameraService.deviceEnumerationCache &&\n (now - CameraService.deviceEnumerationCache.timestamp) < CameraService.CACHE_DURATION) {\n this.availableCameras = CameraService.deviceEnumerationCache.devices;\n await this.setInitialCameraPreference();\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n return this.availableCameras;\n }\n\n const permissionStatus = await this.checkCameraPermission();\n\n if (permissionStatus === 'denied') {\n return [];\n }\n\n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n\n const devices = await navigator.mediaDevices.enumerateDevices();\n const allCameras = devices.filter(device => device.kind === 'videoinput');\n\n // Filter out virtual cameras\n this.availableCameras = allCameras.filter(camera => {\n const isVirtual = this.isVirtualCamera(camera);\n if (isVirtual) {\n console.log(`Virtual camera detected and filtered: ${camera.label}`);\n }\n return !isVirtual;\n });\n\n // Check if there are physical cameras available\n if (this.availableCameras.length === 0) {\n console.log('No physical cameras available');\n this.eventBus.emit('error', new Error('Cámaras virtuales no están permitidas. Use una cámara física.'));\n return [];\n }\n\n // Cache the results for optimization\n CameraService.deviceEnumerationCache = {\n devices: this.availableCameras,\n timestamp: now\n };\n\n await this.setInitialCameraPreference();\n\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n\n return this.availableCameras;\n } catch (error) {\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n try {\n const finalConstraints = constraints || await this.getMaxResolution();\n\n // Optimization: Check if we can reuse existing stream with same constraints\n if (this.currentStreamPromise && this.constraintsEqual(finalConstraints, this.lastStreamConstraints)) {\n return await this.currentStreamPromise;\n }\n\n // Create new stream promise for lazy loading\n this.currentStreamPromise = navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n this.lastStreamConstraints = finalConstraints;\n\n const stream = await this.currentStreamPromise;\n\n // Validate that active stream is not from a virtual camera\n const videoTrack = stream.getVideoTracks()[0];\n if (videoTrack) {\n const settings = videoTrack.getSettings();\n const deviceId = settings.deviceId;\n if (deviceId) {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const currentDevice = devices.find(device => device.deviceId === deviceId);\n if (currentDevice && this.isVirtualCamera(currentDevice)) {\n console.log(`Virtual camera detected in active stream: ${currentDevice.label}`);\n stream.getTracks().forEach(track => track.stop());\n throw new Error('Cámaras virtuales no están permitidas. Use una cámara física.');\n }\n }\n }\n\n return stream;\n } catch (error) {\n\n // Fallback to basic constraints if getMaxResolution fails\n const basicConstraints: MediaTrackConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 }\n };\n\n // Only add facingMode if not on desktop to avoid OverconstrainedError\n if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {\n basicConstraints.facingMode = this.preferredCameraFacing;\n }\n\n this.currentStreamPromise = navigator.mediaDevices.getUserMedia({\n video: basicConstraints,\n audio: false\n });\n\n this.lastStreamConstraints = basicConstraints;\n\n const stream = await this.currentStreamPromise;\n\n // Validate fallback stream as well\n const videoTrack = stream.getVideoTracks()[0];\n if (videoTrack) {\n const settings = videoTrack.getSettings();\n const deviceId = settings.deviceId;\n if (deviceId) {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const currentDevice = devices.find(device => device.deviceId === deviceId);\n if (currentDevice && this.isVirtualCamera(currentDevice)) {\n console.log(`Virtual camera detected in fallback stream: ${currentDevice.label}`);\n stream.getTracks().forEach(track => track.stop());\n throw new Error('Cámaras virtuales no están permitidas. Use una cámara física.');\n }\n }\n }\n\n return stream;\n }\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n await this.enumerateDevices();\n return;\n }\n\n // Validate that the target camera is not virtual\n if (this.isVirtualCamera(selectedCamera)) {\n console.log(`Attempted to switch to virtual camera: ${selectedCamera.label}`);\n this.eventBus.emit('error', new Error('No se puede cambiar a cámara virtual'));\n return;\n }\n\n await this.setSelectedCamera(cameraId);\n }\n\n\n\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n async getCameraInfo(): Promise<{\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n }> {\n const availableCamerasWithAutofocus = await Promise.all(\n this.availableCameras.map(async (camera) => {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n return {\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId,\n hasAutofocus\n };\n })\n );\n\n return {\n availableCameras: availableCamerasWithAutofocus,\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private async setInitialCameraPreference(): Promise<void> {\n if (this.availableCameras.length === 0) return;\n \n \n if (this.preferredCamera === 'front') {\n await this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n await this.selectBackCamera();\n } else {\n await this.selectAutoCamera();\n }\n \n }\n\n private async checkCameraAutofocus(deviceId: string): Promise<boolean> {\n try {\n // Check cache first for optimization\n if (CameraService.cameraCapabilitiesCache.has(deviceId)) {\n const cached = CameraService.cameraCapabilitiesCache.get(deviceId)!;\n return typeof cached === 'boolean' ? cached : false;\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { deviceId: { exact: deviceId } }\n });\n \n const videoTrack = stream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities() as any;\n \n stream.getTracks().forEach(track => track.stop());\n \n const hasFocusMode = capabilities.focusMode && Array.isArray(capabilities.focusMode) && capabilities.focusMode.length > 0;\n const hasAutofocus = hasFocusMode && (\n capabilities.focusMode.includes('continuous') || \n capabilities.focusMode.includes('auto')\n );\n \n // Cache the result for future use\n CameraService.cameraCapabilitiesCache.set(deviceId, hasAutofocus);\n \n return hasAutofocus;\n } catch (error) {\n // Cache negative result to avoid repeated failures\n CameraService.cameraCapabilitiesCache.set(deviceId, false);\n return false;\n }\n }\n\n private async selectFrontCamera(): Promise<void> {\n this.preferredCameraFacing = 'user';\n \n const frontCameras = this.availableCameras.filter(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('front') || \n label.includes('user') ||\n label.includes('selfie') ||\n label.includes('frontal') ||\n (!label.includes('back') && !label.includes('rear') && !label.includes('environment'));\n });\n \n let selectedCamera = null;\n \n if (frontCameras.length > 0) {\n for (const camera of frontCameras) {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n if (hasAutofocus) {\n selectedCamera = camera;\n break;\n }\n }\n \n if (!selectedCamera) {\n selectedCamera = frontCameras[0];\n }\n }\n \n this.selectedCameraId = selectedCamera ? selectedCamera.deviceId : this.availableCameras[0].deviceId;\n }\n\n private async selectBackCamera(): Promise<void> {\n this.preferredCameraFacing = 'environment';\n \n const backCameras = this.availableCameras.filter(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('back') || \n label.includes('rear') ||\n label.includes('environment') ||\n label.includes('trasera') ||\n label.includes('posterior');\n });\n \n let selectedCamera = null;\n \n if (backCameras.length > 0) {\n for (const camera of backCameras) {\n const hasAutofocus = await this.checkCameraAutofocus(camera.deviceId);\n if (hasAutofocus) {\n selectedCamera = camera;\n break;\n }\n }\n \n if (!selectedCamera) {\n selectedCamera = backCameras[0];\n }\n } else if (this.availableCameras.length > 1) {\n const lastCamera = this.availableCameras[this.availableCameras.length - 1];\n const hasAutofocus = await this.checkCameraAutofocus(lastCamera.deviceId);\n selectedCamera = hasAutofocus ? lastCamera : this.availableCameras[this.availableCameras.length - 1];\n }\n \n this.selectedCameraId = selectedCamera ? selectedCamera.deviceId : this.availableCameras[0].deviceId;\n }\n\n private async selectAutoCamera(): Promise<void> {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n await this.selectBackCamera();\n } else {\n // For desktop, prefer front camera (usually built-in webcam)\n await this.selectFrontCamera();\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const videoConstraints: MediaTrackConstraints = {};\n \n // Priority 1: Always use deviceId if available (ensures specific camera with autofocus)\n if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n } \n // Priority 2: Use facingMode as fallback when no specific camera is selected\n else if (this.preferredCameraFacing) {\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n videoConstraints.facingMode = facingConstraint;\n } \n // Priority 3: Fallback to preferredCamera setting\n else {\n if (this.preferredCamera === 'front') {\n videoConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n videoConstraints.facingMode = \"environment\"; \n } else {\n videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n // Optimization: Use cached capabilities if available\n let capabilities: MediaTrackCapabilities;\n \n if (this.selectedCameraId && CameraService.cameraCapabilitiesCache.has(this.selectedCameraId + '_caps')) {\n capabilities = JSON.parse(CameraService.cameraCapabilitiesCache.get(this.selectedCameraId + '_caps') as string);\n } else {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: videoConstraints });\n const videoTrack = tempStream.getVideoTracks()[0];\n capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n // Cache capabilities for future use\n if (this.selectedCameraId) {\n CameraService.cameraCapabilitiesCache.set(this.selectedCameraId + '_caps', JSON.stringify(capabilities));\n }\n }\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n if (capabilities.width && capabilities.height) {\n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const isMobileDevice = this.deviceType === 'mobile' ||\n /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\n\n // Optimize resolution based on device type to prevent \"slow motion\" effect\n // on devices with high-resolution cameras\n let targetWidth: number;\n let targetHeight: number;\n\n if (isMobileDevice && !isTablet) {\n // Mobile phones: Use 720p max to ensure smooth detection performance\n targetWidth = Math.min(capabilities.width.max, 1280);\n targetHeight = Math.min(capabilities.height.max, 720);\n } else if (isTablet) {\n // Tablets: Can handle slightly higher resolution\n targetWidth = Math.min(capabilities.width.max, 1280);\n targetHeight = Math.min(capabilities.height.max, 720);\n } else {\n // Desktop: Can handle full HD\n targetWidth = Math.min(capabilities.width.max, 1920);\n targetHeight = Math.min(capabilities.height.max, 1080);\n }\n\n constraints.width = { ideal: targetWidth };\n constraints.height = { ideal: targetHeight };\n }\n \n // Configure autofocus if camera has the capability\n const capabilitiesAny = capabilities as any;\n if (capabilitiesAny.focusMode && Array.isArray(capabilitiesAny.focusMode)) {\n if (capabilitiesAny.focusMode.includes('continuous')) {\n (constraints as any).focusMode = 'continuous';\n } else if (capabilitiesAny.focusMode.includes('auto')) {\n (constraints as any).focusMode = 'auto';\n }\n }\n \n return constraints;\n } catch (err) {\n // Fallback logic with minimal temporary streams\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const isMobileDevice = this.deviceType === 'mobile' ||\n /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);\n\n // Optimized fallback constraints for device type\n let fallbackWidth: number;\n let fallbackHeight: number;\n\n if (isMobileDevice && !isTablet) {\n // Mobile phones: Use 720p for smooth performance\n fallbackWidth = 1280;\n fallbackHeight = 720;\n } else if (isTablet) {\n fallbackWidth = 1280;\n fallbackHeight = 720;\n } else {\n // Desktop\n fallbackWidth = 1920;\n fallbackHeight = 1080;\n }\n\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: fallbackWidth },\n height: { ideal: fallbackHeight }\n };\n \n if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n fallbackConstraints.facingMode = facingConstraint;\n } else {\n if (this.preferredCamera === 'front') {\n fallbackConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n fallbackConstraints.facingMode = \"environment\"; \n } else {\n fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n return fallbackConstraints;\n }\n }\n\n\n // Optimization helper methods\n private constraintsEqual(a?: MediaTrackConstraints, b?: MediaTrackConstraints): boolean {\n if (!a || !b) return false;\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n // Cleanup method for optimization\n public static clearCaches(): void {\n CameraService.cameraCapabilitiesCache.clear();\n CameraService.deviceEnumerationCache = null;\n }\n\n // Method to invalidate device cache when needed\n public invalidateDeviceCache(): void {\n CameraService.deviceEnumerationCache = null;\n }\n\n private isVirtualCamera(device: MediaDeviceInfo): boolean {\n const label = device.label.toLowerCase();\n const virtualCameraIndicators = [\n 'obs',\n 'virtual',\n 'snap camera',\n 'manycam',\n 'xsplit',\n 'camtwist',\n 'ecamm',\n 'nvidia broadcast',\n 'droidcam',\n 'iriun',\n 'elgato',\n 'streamlabs',\n 'wirecast',\n 'zoom virtual',\n 'teams virtual',\n 'mmhmm',\n 'camo',\n 'reincubate camo',\n 'webcamoid',\n 'splitcam',\n 'cheese',\n 'guvcview',\n 'yawcam',\n 'webcam 7',\n 'altserver'\n ];\n\n return virtualCameraIndicators.some(indicator => label.includes(indicator));\n }\n\n}"]}
|
|
@@ -9,7 +9,7 @@ export class LicenseValidationService {
|
|
|
9
9
|
static ENVIRONMENT_URLS = {
|
|
10
10
|
dev: 'https://api.dev.jaak.ai',
|
|
11
11
|
qa: 'https://api.qa.jaak.ai',
|
|
12
|
-
|
|
12
|
+
sandbox: 'https://api.sandbox.jaak.ai',
|
|
13
13
|
prod: 'https://services.api.jaak.ai',
|
|
14
14
|
};
|
|
15
15
|
constructor(environment = 'prod') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LicenseValidationService.js","sourceRoot":"","sources":["../../src/services/LicenseValidationService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgCH,MAAM,OAAO,wBAAwB;IAC3B,WAAW,GAAW,0BAA0B,CAAC;IACjD,OAAO,CAAS;IAExB,iCAAiC;IACzB,MAAM,CAAU,gBAAgB,GAAgC;QACtE,GAAG,EAAE,yBAAyB;QAC9B,EAAE,EAAE,wBAAwB;QAC5B,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,8BAA8B;KACrC,CAAC;IAEF,YAAY,cAA2B,MAAM;QAC3C,IAAI,CAAC,OAAO,GAAG,wBAAwB,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,OAAgB,EAChB,QAAgB,iBAAiB;QAEjC,mCAAmC;QACnC,MAAM,gBAAgB,GAAG,OAAO,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QAE3D,qBAAqB;QACrB,MAAM,WAAW,GAA6B;YAC5C,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,OAAO;YACnD,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE;gBACR,WAAW,EAAE,OAAO;aACrB;SACF,CAAC;QAEF,MAAM,OAAO,GAAgB;YAC3B,cAAc,EAAE,kBAAkB;SACnC,CAAC;QAEF,oDAAoD;QACpD,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM,gBAAgB,IAAI,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC;QAE9E,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE;gBACjE,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;aAClC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC1D,MAAM;oBACJ,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,2BAA2B;oBACrD,iBAAiB,EAAE,SAAS,CAAC,iBAAiB,IAAI,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE;oBACnG,WAAW,EAAE,QAAQ,CAAC,MAAM;iBACH,CAAC;YAC9B,CAAC;YAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC3C,kCAAkC;YAClC,OAAO;gBACL,GAAG,YAAY;gBACf,OAAO,EAAE,gBAAgB;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAAa,CAAC,KAAK,EAAE,CAAC;gBACzB,MAAM,KAAK,CAAC;YACd,CAAC;YAED,MAAM;gBACJ,KAAK,EAAE,eAAe;gBACtB,iBAAiB,EAAE,iDAAiD;gBACpE,WAAW,EAAE,CAAC;aACW,CAAC;QAC9B,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IAED;;OAEG;IACK,cAAc;QACpB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,yBAAyB,CAAC,OAAe;QAC9C,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,+BAA+B;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAErE,sCAAsC;QACtC,IAAI,OAAO,CAAC,MAAM,KAAK,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC;QAC/B,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,iEAAiE,EAAE,OAAO,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC","sourcesContent":["/**\n * License Validation Service\n * Handles license validation for the jaak-stamps webcomponent\n */\n\nexport type Environment = 'dev' | 'qa' | '
|
|
1
|
+
{"version":3,"file":"LicenseValidationService.js","sourceRoot":"","sources":["../../src/services/LicenseValidationService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * License Validation Service\n * Handles license validation for the jaak-stamps webcomponent\n */\n\nexport type Environment = 'dev' | 'qa' | 'sandbox' | 'prod';\n\nexport interface LicenseValidationRequest {\n license: string;\n origin: string;\n app_id?: string;\n product?: string;\n product_version?: string;\n metadata?: {\n [key: string]: any;\n };\n}\n\nexport interface LicenseValidationResponse {\n access_token: string;\n token_type: string;\n expires_at: string;\n session_id: string;\n jti: string;\n step: number;\n license: string;\n traceId?: string; // Generated or provided traceId\n}\n\nexport interface LicenseValidationError {\n error: string;\n error_description?: string;\n status_code?: number;\n}\n\nexport class LicenseValidationService {\n private apiEndpoint: string = '/api/v1/license/validate';\n private baseUrl: string;\n\n // Environment-specific base URLs\n private static readonly ENVIRONMENT_URLS: Record<Environment, string> = {\n dev: 'https://api.dev.jaak.ai',\n qa: 'https://api.qa.jaak.ai',\n sandbox: 'https://api.sandbox.jaak.ai',\n prod: 'https://services.api.jaak.ai',\n };\n\n constructor(environment: Environment = 'prod') {\n this.baseUrl = LicenseValidationService.ENVIRONMENT_URLS[environment];\n }\n\n /**\n * Validate license with the API\n * @param license License key to validate\n * @param traceId Optional trace ID from W3C Trace Context\n * @param appId Optional application ID\n * @param metadata Optional additional metadata\n * @returns Promise<LicenseValidationResponse>\n */\n async validateLicense(\n license: string,\n traceId?: string,\n appId: string = 'jaak-stamps-web',\n ): Promise<LicenseValidationResponse> {\n // Generate traceId if not provided\n const effectiveTraceId = traceId || this.generateTraceId();\n\n // Build request body\n const requestBody: LicenseValidationRequest = {\n license: traceId ? `L${effectiveTraceId}` : license,\n origin: 'web',\n app_id: appId,\n product: 'kyc',\n metadata: {\n sdk_version: '2.1.0',\n },\n };\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n };\n\n // Add traceparent header with the effective traceId\n headers['traceparent'] = `00-${effectiveTraceId}-${this.generateSpanId()}-01`;\n\n try {\n const response = await fetch(`${this.baseUrl}${this.apiEndpoint}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw {\n error: errorData.error || 'license_validation_failed',\n error_description: errorData.error_description || `HTTP ${response.status}: ${response.statusText}`,\n status_code: response.status,\n } as LicenseValidationError;\n }\n\n const responseData = await response.json();\n // Add the traceId to the response\n return {\n ...responseData,\n traceId: effectiveTraceId,\n };\n } catch (error) {\n if ((error as any).error) {\n throw error;\n }\n\n throw {\n error: 'network_error',\n error_description: 'Failed to connect to license validation service',\n status_code: 0,\n } as LicenseValidationError;\n }\n }\n\n /**\n * Generate a random trace ID for W3C Trace Context (32 hex characters)\n */\n private generateTraceId(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Generate a random span ID for W3C Trace Context (16 hex characters)\n */\n private generateSpanId(): string {\n const array = new Uint8Array(8);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Extract trace ID from license field\n * License format: \"L<32-hex-chars>\"\n * Example: \"Ld79223833a2fd91971e4c14a33298904\" -> \"d79223833a2fd91971e4c14a33298904\"\n */\n static extractTraceIdFromLicense(license: string): string | null {\n if (!license || typeof license !== 'string') {\n return null;\n }\n\n // Remove \"L\" prefix if present\n const traceId = license.startsWith('L') ? license.slice(1) : license;\n\n // Validate format (32 hex characters)\n if (traceId.length === 32 && /^[a-f0-9]{32}$/i.test(traceId)) {\n return traceId.toLowerCase();\n }\n\n console.warn('[LicenseValidationService] Invalid license format for trace ID:', license);\n return null;\n }\n}\n"]}
|