Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions e2e/recognize-app/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import baseConfig from '../../eslint.config.mjs';

export default [
{
ignores: [
'node_modules',
'*.md',
'LICENSE',
'.swcrc',
'.babelrc',
'.env*',
'.bin',
'dist',
'.eslintignore',
'*.html',
'*.svg',
'*.css',
'public',
'*.json',
'*.d.ts',
],
},
...baseConfig,
];
18 changes: 18 additions & 0 deletions e2e/recognize-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@forgerock/recognize-app",
"version": "0.0.1",
"private": true,
"scripts": {
"build": "pnpm nx nxBuild",
"lint": "pnpm nx nxLint",
"preview": "pnpm nx nxPreview",
"serve": "pnpm nx nxServe"
},
"dependencies": {
"@forgerock/journey-client": "workspace:*",
"@forgerock/recognize": "workspace:*"
},
"nx": {
"tags": ["scope:e2e"]
}
}
14 changes: 14 additions & 0 deletions e2e/recognize-app/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Recognize E2E Test Index | Ping Identity JavaScript SDK</title>
</head>
<body>
<div id="app">
<h2>Recognize E2E Test Index | Ping Identity JavaScript SDK</h2>
</div>
<script type="module" src="index.ts"></script>
</body>
</html>
37 changes: 37 additions & 0 deletions e2e/recognize-app/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { recognize } from '@forgerock/recognize';
import './styles.css';

const client = recognize({
authorizationToken: 'USER_AUTHORIZATION_FROM_CUSTOMER',
customer: 'CUSTOMER_NAME',
key: 'IMAGE_ENCRYPTION_PUBLIC_KEY',
keyID: 'IMAGE_ENCRYPTION_KEY_ID',
transactionData: 'DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED',
wsURL: 'KEYLESS_AUTHENTICATION_SERVICE_URL',
});

client.subscribe({
next: (event) => {
console.log('[recognize]', event.type, event.detail);
},
error: (err) => {
console.error('[recognize] error', {
code: err.code,
message: err.message,
name: err.name,
cause: err.cause,
});
},
complete: (detail) => {
console.log('[recognize] complete', detail);
},
});

const appEl = document.getElementById('app');
if (appEl) {
client
.init({ mode: 'mount', container: appEl, type: 'auth', username: 'USERNAME' })
.then((err) => {
if (err) console.error('[recognize] init error', err);
});
Comment on lines +32 to +36

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle the rejected init() promise path.

Only the fulfilled path is handled. If init() rejects, this can become an unhandled rejection and destabilize/flaky-fail E2E runs.

Proposed fix
 if (appEl) {
   client
     .init({ mode: 'mount', container: appEl, type: 'auth', username: 'USERNAME' })
     .then((err) => {
       if (err) console.error('[recognize] init error', err);
-    });
+    })
+    .catch((err) => {
+      console.error('[recognize] init rejected', err);
+    });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
client
.init({ mode: 'mount', container: appEl, type: 'auth', username: 'USERNAME' })
.then((err) => {
if (err) console.error('[recognize] init error', err);
});
client
.init({ mode: 'mount', container: appEl, type: 'auth', username: 'USERNAME' })
.then((err) => {
if (err) console.error('[recognize] init error', err);
})
.catch((err) => {
console.error('[recognize] init rejected', err);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/recognize-app/src/index.ts` around lines 32 - 36, The client.init()
promise chain in the mount initialization section only handles the fulfilled
path with .then(), leaving promise rejections unhandled which can cause flaky
E2E test failures. Add a .catch() handler after the .then() block to properly
handle any rejections that occur during the init() call, ensuring errors from
rejected promises are logged and don't destabilize the test execution.

}
11 changes: 11 additions & 0 deletions e2e/recognize-app/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
body {
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
margin: 0;
padding: 2rem;
}

#app {
max-width: 960px;
margin: 0 auto;
}
29 changes: 29 additions & 0 deletions e2e/recognize-app/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"types": ["node"],
"rootDir": "src",
"module": "esnext",
"moduleResolution": "bundler",
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
},
"exclude": [
"out-tsc",
"dist",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"eslint.config.js",
"eslint.config.cjs",
"eslint.config.mjs"
],
"include": ["src/**/*.ts"],
"references": [
{
"path": "../../packages/recognize/tsconfig.lib.json"
},
{
"path": "../../packages/journey-client/tsconfig.lib.json"
}
]
}
10 changes: 10 additions & 0 deletions e2e/recognize-app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}
33 changes: 33 additions & 0 deletions e2e/recognize-app/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { defineConfig } from 'vite';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));

export default defineConfig(() => ({
root: __dirname + '/src',
cacheDir: '../../node_modules/.vite/e2e/recognize-app',
publicDir: __dirname + '/public',
server: {
port: 8443,
host: 'localhost',
},
preview: {
port: 8443,
host: 'localhost',
},
plugins: [],
build: {
outDir: __dirname + '/dist',
emptyOutDir: true,
reportCompressedSize: true,
rollupOptions: {
input: {
main: resolve(__dirname + '/src', 'index.html'),
},
output: {
entryFileNames: '[name]/main.js',
},
},
},
}));
11 changes: 11 additions & 0 deletions packages/recognize/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# recognize

This library was generated with [Nx](https://nx.dev).

## Building

Run `nx build recognize` to build the library.

## Running unit tests

Run `nx test recognize` to execute the unit tests via [Vitest](https://vitest.dev/).
26 changes: 26 additions & 0 deletions packages/recognize/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import baseConfig from '../../eslint.config.mjs';

export default [
...baseConfig,
{
files: ['**/*.json'],
rules: {
'@nx/dependency-checks': [
'error',
{
ignoredFiles: [
'{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
'{projectRoot}/src/lib/recognize-sdk/**/*',
],
},
],
},
languageOptions: {
parser: await import('jsonc-eslint-parser'),
},
},
{
ignores: ['**/out-tsc'],
},
];
45 changes: 45 additions & 0 deletions packages/recognize/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@forgerock/recognize",
"version": "0.0.1",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./dist/src/index.js",
"default": "./dist/src/index.js"
},
"./package.json": "./package.json"
},
"main": "./dist/src/index.js",
"module": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
},
"devDependencies": {
"@aracna/web-components": "^1.1.18"
},
"nx": {
"tags": ["scope:package"],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "packages/recognize/dist",
"main": "packages/recognize/src/index.ts",
"tsConfig": "packages/recognize/tsconfig.lib.json",
"generatePackageJson": false,
"assets": [
{
"input": "packages/recognize/src/lib/recognize-sdk",
"glob": "**/*",
"output": "./src/lib/recognize-sdk"
}
]
}
}
}
}
}
18 changes: 18 additions & 0 deletions packages/recognize/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export { recognize, RecognizeError } from './lib/recognize.js';
export { RecognizeErrorCode } from './lib/defs/recognize-error-code.js';
export type {
RecognizeSessionType,
RecognizeWebComponent,
RecognizeWebComponentClient,
RecognizeWebComponentCompleteData,
RecognizeWebComponentConfiguration,
RecognizeWebComponentEvent,
RecognizeWebComponentFrameResultsEventDetail,
RecognizeWebComponentInitOptions,
RecognizeWebComponentObserver,
RecognizeWebComponentStepChangeEventDetail,
RecognizeWebComponentUnsubscribe,
RecognizeWebComponentVideoFrameQualityEventDetail,
RecognizeWebComponentWebSocketCloseEventDetail,
RecognizeWebComponentWebSocketOpenEventDetail,
} from './lib/recognize.types.js';
13 changes: 13 additions & 0 deletions packages/recognize/src/lib/classes/recognize-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { RecognizeErrorCode } from '../defs/recognize-error-code.js';

/** @public */
export class RecognizeError extends Error {
code: RecognizeErrorCode;

constructor(code: RecognizeErrorCode, options?: ErrorOptions) {
super(RecognizeErrorCode[code], options);

this.code = code;
this.name = 'RecognizeError';
}
}
11 changes: 11 additions & 0 deletions packages/recognize/src/lib/defs/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** @internal */
export const CAMERA_ONLY_DISABLE_STEPS: string[] = [
'bootstrap',
'camera-instructions',
'done',
'error',
'microphone-permission',
'server-computation',
'stm-choice',
'stm-qrcode',
];
54 changes: 54 additions & 0 deletions packages/recognize/src/lib/defs/recognize-error-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
*
* Copyright © 2026 Ping Identity Corporation. All right reserved.
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*
*/

/** @public */
export enum RecognizeErrorCode {
SDK_ERROR = 1000,
SDK_NOT_CONFIGURED = 1001,
SDK_INVALID_CONFIGURATION = 1002,
SDK_LOGGING_CONFIGURATION_FAILED = 1003,
SDK_STORAGE_FAILED = 1004,
SDK_USER_CANCELLED = 1005,
SDK_TIMEOUT = 1006,
SDK_NO_NETWORK_CONNECTION = 1007,
SDK_DYNAMIC_LINKING_PAYLOAD_MALFORMED = 1008,
SDK_ARTIFACT_RETRIEVE_FAILED = 1009,
SDK_INVALID_CLIENT_STATE = 1010,
SDK_WEB_SOCKET_ERROR = 1011,
SDK_OUTDATED_APP = 1012,
SDK_WEB_ASSEMBLY_IMPORT_FAILED = 1013,
SDK_WEB_ASSEMBLY_IMPORT_NOT_FULFILLED = 1014,
SDK_WEB_ASSEMBLY_ERROR = 1015,
SDK_INVALID_CUSTOMER_PROPERTIES = 1016,
CAMERA_ERROR = 2000,
CAMERA_NOT_FOUND = 2001,
CAMERA_PERMISSION_DENIED = 2002,
CAMERA_NOT_SUPPORTED = 2003,
CORE_ERROR = 3000,
CORE_NOT_ENOUGH_API_KEY_SEATS = 3001,
CORE_USER_ALREADY_ENROLLED = 3002,
CORE_USER_NOT_ENROLLED = 3003,
CORE_FACE_NOT_MATCHING = 3004,
CORE_NOT_ENOUGH_CIRCUITS = 3005,
CORE_SECRET_NOT_FOUND = 3006,
CORE_USER_LOCKED_OUT = 3007,
CORE_CUSTOMER_NOT_FOUND = 3008,
BIOM_ERROR = 4000,
BIOM_REJECTED = 4001,
BIOM_GENUINE_PRESENCE_NOT_ESTABLISHED = 4002,
BIOM_LIVENESS_ENVIRONMENT_AWARE_NOT_SUPPORTED = 4003,
BIOM_DEVICE_ENVIRONMENT_AWARE_NOT_SUPPORTED = 4004,
SERVER_ERROR = 5000,
SERVER_ENCRYPTION_FAILED = 5001,
SERVER_RECOGNITION_FAILED = 5002,
SERVER_AUTHORIZATION_FAILED = 5003,
SERVER_TIMEOUT = 5004,
SECURITY_ERROR = 6000,
SECURITY_DEVICE_NOT_GENUINE = 6001,
}
Loading
Loading