Skip to content

Commit 80f6dd1

Browse files
feat: optimize error and event handling
1 parent 43da855 commit 80f6dd1

8 files changed

Lines changed: 87 additions & 106 deletions

File tree

packages/recognize/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"dependencies": {
1818
"tslib": "^2.3.0"
1919
},
20+
"devDependencies": {
21+
"@aracna/web-components": "^1.1.18"
22+
},
2023
"nx": {
2124
"tags": ["scope:package"],
2225
"targets": {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { RecognizeErrorCode } from '../defs/recognize-error-code.js';
2+
3+
/** @public */
4+
export class RecognizeError extends Error {
5+
code: RecognizeErrorCode;
6+
7+
constructor(code: RecognizeErrorCode, cause?: Error) {
8+
super(code);
9+
10+
this.code = code;
11+
this.cause = cause;
12+
this.name = 'RecognizeError';
13+
}
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/** @internal */
2+
export const CAMERA_ONLY_DISABLE_STEPS: string[] = [
3+
'bootstrap',
4+
'camera-instructions',
5+
'done',
6+
'error',
7+
'microphone-permission',
8+
'server-computation',
9+
'stm-choice',
10+
'stm-qrcode',
11+
];

packages/recognize/src/lib/functions/create-recognize-error.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,28 @@
77
*
88
*/
99

10+
import { RecognizeError } from '../classes/recognize-error.js';
1011
import { RecognizeErrorCode } from '../defs/recognize-error-code.js';
1112
import { RECOGNIZE_SDK_TO_RECOGNIZE_PROXY_ERROR_MAP } from '../defs/recognize-sdk-to-recognize-proxy-error-map.js';
12-
import type { RecognizeError } from '../recognize.types.js';
1313

1414
/** @public */
1515
export const createRecognizeError = (
1616
codeOrSdkError: RecognizeErrorCode | ErrorEvent,
1717
cause?: Error,
1818
): RecognizeError => {
19-
let code: RecognizeErrorCode;
20-
let errorCause: Error | undefined;
21-
2219
if (codeOrSdkError instanceof ErrorEvent) {
23-
const reason = (codeOrSdkError as ErrorEvent & { reason?: string }).reason;
24-
code =
25-
(reason && RECOGNIZE_SDK_TO_RECOGNIZE_PROXY_ERROR_MAP[reason]) ||
26-
RecognizeErrorCode.SDK_ERROR;
27-
errorCause = codeOrSdkError.error instanceof Error ? codeOrSdkError.error : undefined;
20+
if (codeOrSdkError.error instanceof Error) {
21+
let code: RecognizeErrorCode;
22+
23+
code =
24+
RECOGNIZE_SDK_TO_RECOGNIZE_PROXY_ERROR_MAP[codeOrSdkError.error.message] ||
25+
RecognizeErrorCode.SDK_ERROR;
26+
27+
return new RecognizeError(code, codeOrSdkError.error);
28+
}
2829
} else {
29-
code = codeOrSdkError;
30-
errorCause = cause;
30+
return new RecognizeError(codeOrSdkError, cause);
3131
}
3232

33-
const error: RecognizeError = Object.assign(new Error(code), {
34-
name: 'RecognizeError',
35-
code,
36-
cause: errorCause,
37-
});
38-
return error;
33+
return new RecognizeError(RecognizeErrorCode.SDK_ERROR, cause);
3934
};

packages/recognize/src/lib/recognize-sdk/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,7 @@ export declare interface KeylessWebSocketOpenEventDetail {
10961096
}
10971097

10981098
/** @internal */
1099-
declare class RootElement extends AracnaBaseElement {
1099+
declare class RootElement extends AracnaBaseElement<RootElementEventMap> {
11001100
appearanceController: KeylessAppearanceController;
11011101
localizationController: KeylessLocalizationController;
11021102
loggerController: KeylessLoggerController;

packages/recognize/src/lib/recognize.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,7 @@ describe('recognize — error observer', () => {
191191
await client.init({ mode: 'mount', container, type: 'auth', username: 'user' });
192192
const el = container.querySelector('kl-auth')!;
193193

194-
const event = new ErrorEvent('error', { error: new Error('raw') });
195-
Object.defineProperty(event, 'reason', { value: 'MEDIA_STREAM_NOT_ALLOWED' });
194+
const event = new ErrorEvent('error', { error: new Error('MEDIA_STREAM_NOT_ALLOWED') });
196195
el.dispatchEvent(event);
197196

198197
const receivedError = errorFn.mock.calls[0][0];

packages/recognize/src/lib/recognize.ts

Lines changed: 40 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -7,112 +7,67 @@
77
*
88
*/
99

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';
2012
import { RecognizeErrorCode } from './defs/recognize-error-code.js';
2113
import { createRecognizeError } from './functions/create-recognize-error.js';
14+
import type { KeylessFinishedEvent } from './recognize-sdk/index.js';
2215
import type {
23-
RecognizeError,
16+
RecognizeRootElement,
2417
RecognizeWcClient,
2518
RecognizeWcConfig,
2619
RecognizeWcInitOptions,
2720
RecognizeWcObserver,
2821
RecognizeWcUnsubscribe,
2922
} from './recognize.types.js';
3023

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-
4424
/**
4525
* @function recognize - Returns a client to interact with the PingOne Recognize SDK web components
4626
* @param {RecognizeWcConfig} config - Configuration for the PingOne Recognize SDK
4727
* @returns {RecognizeWcClient}
4828
*/
4929
export function recognize(config: RecognizeWcConfig): RecognizeWcClient {
5030
const effectiveConfig: RecognizeWcConfig = { disableSteps: CAMERA_ONLY_DISABLE_STEPS, ...config };
51-
let element: RootEl | null = null;
52-
let abortController: AbortController | null = null;
5331
const observers: Set<RecognizeWcObserver> = new Set();
5432

33+
let element: RecognizeRootElement | null = null;
34+
let abortController: AbortController | null = null;
35+
5536
const dispatch = (type: string, detail: unknown): void => {
5637
for (const observer of observers) {
5738
observer.next({ type, detail } as Parameters<RecognizeWcObserver['next']>[0]);
5839
}
5940
};
6041

61-
const attachListeners = (el: RootEl): void => {
42+
const attachListeners = (el: RecognizeRootElement): void => {
6243
abortController = new AbortController();
6344
const { signal } = abortController;
6445

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 });
11368
};
11469

115-
const applyConfig = (el: RootEl): void => {
70+
const applyConfig = (el: RecognizeRootElement): void => {
11671
const target = el as unknown as Record<string, unknown>;
11772
for (const [k, v] of Object.entries(effectiveConfig)) {
11873
if (v !== undefined) {
@@ -141,22 +96,28 @@ export function recognize(config: RecognizeWcConfig): RecognizeWcClient {
14196
}
14297

14398
if (options.mode === 'attach') {
144-
const tag = (options.element as HTMLElement).tagName;
99+
const tag = options.element.tagName;
100+
145101
if (tag !== 'KL-AUTH' && tag !== 'KL-ENROLL') {
146102
throw new Error(
147103
`recognize: invalid element <${tag.toLowerCase()}> — options.element must be a <kl-auth> or <kl-enroll> custom element`,
148104
);
149105
}
150-
element = options.element as RootEl;
106+
107+
element = options.element as RecognizeRootElement;
151108
element.username = options.username;
109+
152110
applyConfig(element);
153111
attachListeners(element);
154112
} else {
155113
const tag = options.type === 'auth' ? 'kl-auth' : 'kl-enroll';
156-
element = document.createElement(tag) as RootEl;
114+
115+
element = document.createElement(tag) as RecognizeRootElement;
157116
element.username = options.username;
117+
158118
applyConfig(element);
159119
attachListeners(element);
120+
160121
options.container.appendChild(element);
161122
}
162123
},

packages/recognize/src/lib/recognize.types.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,20 @@
77
*
88
*/
99

10+
import type { RecognizeError } from './classes/recognize-error.js';
1011
import type {
12+
KeylessAuthElement,
13+
KeylessEnrollElement,
1114
KeylessFinishedEventDetail,
1215
KeylessFrameResultsEventDetail,
1316
KeylessStepChangeEventDetail,
1417
KeylessVideoFrameQualityEventDetail,
1518
KeylessWebSocketCloseEventDetail,
1619
KeylessWebSocketOpenEventDetail,
1720
} from './recognize-sdk/index.js';
18-
import type { RecognizeErrorCode } from './defs/recognize-error-code.js';
1921

2022
/** @public */
21-
export interface RecognizeError extends Error {
22-
code: RecognizeErrorCode;
23-
cause?: Error;
24-
}
23+
export type RecognizeRootElement = KeylessAuthElement | KeylessEnrollElement;
2524

2625
/** @public */
2726
export type RecognizeSessionType = 'auth' | 'enroll';
@@ -33,8 +32,7 @@ export interface RecognizeWcStepChangeEventDetail extends KeylessStepChangeEvent
3332
export interface RecognizeWcFrameResultsEventDetail extends KeylessFrameResultsEventDetail {}
3433

3534
/** @public */
36-
export interface RecognizeWcVideoFrameQualityEventDetail
37-
extends KeylessVideoFrameQualityEventDetail {}
35+
export interface RecognizeWcVideoFrameQualityEventDetail extends KeylessVideoFrameQualityEventDetail {}
3836

3937
/** @public */
4038
export interface RecognizeWcWebSocketOpenEventDetail extends KeylessWebSocketOpenEventDetail {}

0 commit comments

Comments
 (0)