|
7 | 7 | * |
8 | 8 | */ |
9 | 9 |
|
10 | | -import type { |
11 | | - KeylessAuthElement, |
12 | | - KeylessEnrollElement, |
13 | | - KeylessFinishedEvent, |
14 | | - KeylessFrameResultsEvent, |
15 | | - KeylessStepChangeEvent, |
16 | | - KeylessVideoFrameQualityEvent, |
17 | | - KeylessWebSocketCloseEvent, |
18 | | - KeylessWebSocketOpenEvent, |
19 | | -} from './recognize-sdk/index.js'; |
| 10 | +import type { RecognizeError } from './classes/recognize-error.js'; |
| 11 | +import { CAMERA_ONLY_DISABLE_STEPS } from './defs/constants.js'; |
20 | 12 | import { RecognizeErrorCode } from './defs/recognize-error-code.js'; |
21 | 13 | import { createRecognizeError } from './functions/create-recognize-error.js'; |
| 14 | +import type { KeylessFinishedEvent } from './recognize-sdk/index.js'; |
22 | 15 | import type { |
23 | | - RecognizeError, |
| 16 | + RecognizeRootElement, |
24 | 17 | RecognizeWcClient, |
25 | 18 | RecognizeWcConfig, |
26 | 19 | RecognizeWcInitOptions, |
27 | 20 | RecognizeWcObserver, |
28 | 21 | RecognizeWcUnsubscribe, |
29 | 22 | } from './recognize.types.js'; |
30 | 23 |
|
31 | | -type RootEl = KeylessAuthElement | KeylessEnrollElement; |
32 | | - |
33 | | -const CAMERA_ONLY_DISABLE_STEPS: string[] = [ |
34 | | - 'bootstrap', |
35 | | - 'camera-instructions', |
36 | | - 'done', |
37 | | - 'error', |
38 | | - 'microphone-permission', |
39 | | - 'server-computation', |
40 | | - 'stm-choice', |
41 | | - 'stm-qrcode', |
42 | | -]; |
43 | | - |
44 | 24 | /** |
45 | 25 | * @function recognize - Returns a client to interact with the PingOne Recognize SDK web components |
46 | 26 | * @param {RecognizeWcConfig} config - Configuration for the PingOne Recognize SDK |
47 | 27 | * @returns {RecognizeWcClient} |
48 | 28 | */ |
49 | 29 | export function recognize(config: RecognizeWcConfig): RecognizeWcClient { |
50 | 30 | const effectiveConfig: RecognizeWcConfig = { disableSteps: CAMERA_ONLY_DISABLE_STEPS, ...config }; |
51 | | - let element: RootEl | null = null; |
52 | | - let abortController: AbortController | null = null; |
53 | 31 | const observers: Set<RecognizeWcObserver> = new Set(); |
54 | 32 |
|
| 33 | + let element: RecognizeRootElement | null = null; |
| 34 | + let abortController: AbortController | null = null; |
| 35 | + |
55 | 36 | const dispatch = (type: string, detail: unknown): void => { |
56 | 37 | for (const observer of observers) { |
57 | 38 | observer.next({ type, detail } as Parameters<RecognizeWcObserver['next']>[0]); |
58 | 39 | } |
59 | 40 | }; |
60 | 41 |
|
61 | | - const attachListeners = (el: RootEl): void => { |
| 42 | + const attachListeners = (el: RecognizeRootElement): void => { |
62 | 43 | abortController = new AbortController(); |
63 | 44 | const { signal } = abortController; |
64 | 45 |
|
65 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
66 | | - el.addEventListener( |
67 | | - 'step-change', |
68 | | - (e: KeylessStepChangeEvent) => dispatch('step-change', e.detail), |
69 | | - { signal }, |
70 | | - ); |
71 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
72 | | - el.addEventListener( |
73 | | - 'finished', |
74 | | - (e: KeylessFinishedEvent) => { |
75 | | - for (const observer of observers) observer.complete?.(e.detail); |
76 | | - observers.clear(); |
77 | | - }, |
78 | | - { signal }, |
79 | | - ); |
80 | | - el.addEventListener( |
81 | | - 'error', |
82 | | - (e: ErrorEvent) => { |
83 | | - const err = createRecognizeError(e); |
84 | | - for (const observer of observers) observer.error?.(err); |
85 | | - observers.clear(); |
86 | | - }, |
87 | | - { signal }, |
88 | | - ); |
89 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
90 | | - el.addEventListener( |
91 | | - 'frame-results', |
92 | | - (e: KeylessFrameResultsEvent) => dispatch('frame-results', e.detail), |
93 | | - { signal }, |
94 | | - ); |
95 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
96 | | - el.addEventListener( |
97 | | - 'video-frame-quality', |
98 | | - (e: KeylessVideoFrameQualityEvent) => dispatch('video-frame-quality', e.detail), |
99 | | - { signal }, |
100 | | - ); |
101 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
102 | | - el.addEventListener( |
103 | | - 'ws-open', |
104 | | - (e: KeylessWebSocketOpenEvent) => dispatch('ws-open', e.detail), |
105 | | - { signal }, |
106 | | - ); |
107 | | - // @ts-expect-error — SDK event map not reflected on HTMLElement.addEventListener |
108 | | - el.addEventListener( |
109 | | - 'ws-close', |
110 | | - (e: KeylessWebSocketCloseEvent) => dispatch('ws-close', e.detail), |
111 | | - { signal }, |
112 | | - ); |
| 46 | + const onEvent = (type: string) => { |
| 47 | + return (event: CustomEvent) => dispatch(type, event.detail); |
| 48 | + }; |
| 49 | + |
| 50 | + const onFinished = (event: KeylessFinishedEvent) => { |
| 51 | + for (const observer of observers) observer.complete?.(event.detail); |
| 52 | + observers.clear(); |
| 53 | + }; |
| 54 | + |
| 55 | + const onError = (e: ErrorEvent) => { |
| 56 | + const err = createRecognizeError(e); |
| 57 | + for (const observer of observers) observer.error?.(err); |
| 58 | + observers.clear(); |
| 59 | + }; |
| 60 | + |
| 61 | + el.addEventListener('error', onError, { signal }); |
| 62 | + el.addEventListener('finished', onFinished, { signal }); |
| 63 | + el.addEventListener('step-change', onEvent('step-change'), { signal }); |
| 64 | + el.addEventListener('frame-results', onEvent('frame-results'), { signal }); |
| 65 | + el.addEventListener('video-frame-quality', onEvent('video-frame-quality'), { signal }); |
| 66 | + el.addEventListener('ws-open', onEvent('ws-open'), { signal }); |
| 67 | + el.addEventListener('ws-close', onEvent('ws-close'), { signal }); |
113 | 68 | }; |
114 | 69 |
|
115 | | - const applyConfig = (el: RootEl): void => { |
| 70 | + const applyConfig = (el: RecognizeRootElement): void => { |
116 | 71 | const target = el as unknown as Record<string, unknown>; |
117 | 72 | for (const [k, v] of Object.entries(effectiveConfig)) { |
118 | 73 | if (v !== undefined) { |
@@ -141,22 +96,28 @@ export function recognize(config: RecognizeWcConfig): RecognizeWcClient { |
141 | 96 | } |
142 | 97 |
|
143 | 98 | if (options.mode === 'attach') { |
144 | | - const tag = (options.element as HTMLElement).tagName; |
| 99 | + const tag = options.element.tagName; |
| 100 | + |
145 | 101 | if (tag !== 'KL-AUTH' && tag !== 'KL-ENROLL') { |
146 | 102 | throw new Error( |
147 | 103 | `recognize: invalid element <${tag.toLowerCase()}> — options.element must be a <kl-auth> or <kl-enroll> custom element`, |
148 | 104 | ); |
149 | 105 | } |
150 | | - element = options.element as RootEl; |
| 106 | + |
| 107 | + element = options.element as RecognizeRootElement; |
151 | 108 | element.username = options.username; |
| 109 | + |
152 | 110 | applyConfig(element); |
153 | 111 | attachListeners(element); |
154 | 112 | } else { |
155 | 113 | const tag = options.type === 'auth' ? 'kl-auth' : 'kl-enroll'; |
156 | | - element = document.createElement(tag) as RootEl; |
| 114 | + |
| 115 | + element = document.createElement(tag) as RecognizeRootElement; |
157 | 116 | element.username = options.username; |
| 117 | + |
158 | 118 | applyConfig(element); |
159 | 119 | attachListeners(element); |
| 120 | + |
160 | 121 | options.container.appendChild(element); |
161 | 122 | } |
162 | 123 | }, |
|
0 commit comments