Skip to content

Commit

Permalink
feat: error handling (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
m1guelpf authored Nov 10, 2023
1 parent f09401f commit 3360eaf
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 16 deletions.
7 changes: 6 additions & 1 deletion example-nextjs/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback } from "react";
import { IDKitWidget } from "@worldcoin/idkit";
import styles from "../styles/Home.module.css";
import type { ISuccessResult } from "@worldcoin/idkit";
import type { ISuccessResult, IErrorState } from "@worldcoin/idkit";

export default function Home() {
const handleProof = useCallback((result: ISuccessResult) => {
Expand All @@ -15,12 +15,17 @@ export default function Home() {
console.log(result);
};

const onError = (error: IErrorState) => {
console.log(error);
};

return (
<div className={styles.container}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", minHeight: "100vh" }}>
<IDKitWidget
action="my_action"
signal="my_signal"
onError={onError}
onSuccess={onSuccess}
handleVerify={handleProof}
app_id="get_this_from_the_dev_portal"
Expand Down
7 changes: 6 additions & 1 deletion example-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CredentialType, IDKitWidget, ISuccessResult } from "@worldcoin/idkit";
import { CredentialType, IDKitWidget, IErrorState, ISuccessResult } from "@worldcoin/idkit";

function App() {
const handleProof = (result: ISuccessResult) => {
Expand All @@ -12,6 +12,10 @@ function App() {
console.log(result);
};

const onError = (error: IErrorState) => {
console.log(error);
};

const urlParams = new URLSearchParams(window.location.search);
const credential_types = (urlParams.get("credential_types")?.split(",") as CredentialType[]) ?? [
CredentialType.Orb,
Expand All @@ -33,6 +37,7 @@ function App() {
>
<IDKitWidget
action={action}
onError={onError}
signal="my_signal"
onSuccess={onSuccess}
handleVerify={handleProof}
Expand Down
8 changes: 4 additions & 4 deletions idkit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import useIDKit from './hooks/useIDKit'
import { CredentialType } from '@/types'
import QRCode from './components/QRCode'
import type { ISuccessResult } from '@/types'
import { solidityEncode } from './lib/hashing'
import { VerificationState } from './types/app'
import type { AppErrorCodes } from './types/app'
import IDKitWidget from '@/components/IDKitWidget'
import SignInButton from './components/SignInButton'
import useAppConnection from '@/services/walletconnect'
import type { WidgetProps, Config } from '@/types/config'
import { VerificationState, AppErrorCodes } from './types/app'
import type { ISuccessResult, IErrorState } from '@/types'
import SignInWithWorldID from './components/SignInWithWorldID'
import { hashToField, validateABILikeEncoding, generateExternalNullifier } from './lib/hashing'

Expand All @@ -19,8 +20,7 @@ const internal = {
QRCode,
useAppConnection,
VerificationState,
AppErrorCodes,
}

export { IDKitWidget, useIDKit, solidityEncode, internal, SignInWithWorldID, CredentialType, SignInButton }
export type { ISuccessResult, Config, WidgetProps }
export type { ISuccessResult, Config, WidgetProps, IErrorState, AppErrorCodes }
36 changes: 27 additions & 9 deletions idkit/src/store/idkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ export type IDKitStore = {
methods: VerificationMethods[]
errorState: IErrorState | null
verifyCallbacks:
| Record<ConfigSource, CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult> | undefined>
| Record<ConfigSource, CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult>>
| Record<string, never>
successCallbacks:
| Record<ConfigSource, CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult> | undefined>
| Record<ConfigSource, CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult>>
| Record<string, never>
errorCallbacks: Record<ConfigSource, CallbackFn<IErrorState>> | Record<string, never>

computed: {
canGoBack: (stage: IDKITStage) => boolean
Expand All @@ -49,6 +50,7 @@ export type IDKitStore = {
cb: CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult>,
source: ConfigSource
) => void
addErrorCallback: (cb: CallbackFn<IErrorState>, source: ConfigSource) => void
addVerificationCallback: (
cb: CallbackFn<IExperimentalSuccessResult> | CallbackFn<ISuccessResult>,
source: ConfigSource
Expand All @@ -75,6 +77,7 @@ const useIDKitStore = create<IDKitStore>()((set, get) => ({
autoClose: true,
errorState: null,
processing: false,
errorCallbacks: {},
verifyCallbacks: {},
successCallbacks: {},
stage: IDKITStage.WORLD_ID,
Expand Down Expand Up @@ -133,10 +136,18 @@ const useIDKitStore = create<IDKitStore>()((set, get) => ({
return state
})
},
addErrorCallback: (cb: CallbackFn<IErrorState>, source: ConfigSource) => {
set(state => {
state.errorCallbacks[source] = cb

return state
})
},
setOptions: (
{
handleVerify,
onSuccess,
onError,
signal,
action,
app_id,
Expand Down Expand Up @@ -169,6 +180,7 @@ const useIDKitStore = create<IDKitStore>()((set, get) => ({
}))

get().addSuccessCallback(onSuccess, source)
if (onError) get().addErrorCallback(onError, source)
if (handleVerify) get().addVerificationCallback(handleVerify, source)
},
handleVerify: (result: IExperimentalSuccessResult | ISuccessResult) => {
Expand Down Expand Up @@ -206,16 +218,22 @@ const useIDKitStore = create<IDKitStore>()((set, get) => ({
return set({ open })
}

if (get().stage == IDKITStage.SUCCESS) {
const result = get().result
const errorState = get().errorState
if (get().stage === IDKITStage.ERROR && errorState) {
const callbacks = get().errorCallbacks

requestAnimationFrame(() => Object.values(callbacks).forEach(cb => void cb(errorState)))
}

const result = get().result
if (get().stage == IDKITStage.SUCCESS && result) {
const callbacks = get().successCallbacks

if (result)
requestAnimationFrame(() =>
Object.values(callbacks).forEach(
cb => void (cb as CallbackFn<IExperimentalSuccessResult | ISuccessResult>)(result)
)
requestAnimationFrame(() =>
Object.values(callbacks).forEach(
cb => void (cb as CallbackFn<IExperimentalSuccessResult | ISuccessResult>)(result)
)
)
}

set({
Expand Down
12 changes: 11 additions & 1 deletion idkit/src/types/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import type { AbiEncodedValue, CallbackFn, CredentialType, IExperimentalSuccessResult, ISuccessResult } from '.'
import type {
CallbackFn,
IErrorState,
CredentialType,
ISuccessResult,
AbiEncodedValue,
IExperimentalSuccessResult,
} from '.'

export type VerificationMethods = 'orb' | 'phone'
export enum ConfigSource {
Expand Down Expand Up @@ -28,6 +35,9 @@ export type WidgetConfig = {
theme?: 'dark' | 'light'
/** Whether opt-in telemetry is enabled. Very few events are sent, with no PII to help improve the project. Defaults to `false`. */
enableTelemetry?: boolean

/** Function to trigger when verification is not successful. Should receive a single parameter of type `IErrorState` which contains the error details. */
onError?: CallbackFn<IErrorState>
} & (
| {
/** Optionally enable the experimental verification flow. This flow is not recommended for production apps. */
Expand Down
2 changes: 2 additions & 0 deletions idkit/src/vanilla.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export const open = () => {
// eslint-disable-next-line compat/compat -- Promise is polyfilled
return new Promise((resolve, reject) => {
if (!isInitialized) return reject(__('IDKitWidget is not initialized'))

useIDKitStore.getState().addErrorCallback(reject, ConfigSource.MANUAL)
useIDKitStore.getState().addSuccessCallback(resolve, ConfigSource.MANUAL)
useIDKitStore.setState({ open: true })
})
Expand Down

1 comment on commit 3360eaf

@vercel
Copy link

@vercel vercel bot commented on 3360eaf Nov 10, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.