Skip to content

Commit

Permalink
feat: idkit state and error handling improvements (#194)
Browse files Browse the repository at this point in the history
* fix: clear result and errorCode on bridge reset

solves an issue where reopening the IDKit widget would resubmit the same proof to the callback functions

* feat: error on request timeout

throws connection_failed error if pollForUpdates gets a 404 from bridge (meaning request has expired)

* feat: handle errors thrown in handleVerify

ensures that handleVerify callbacks are processed async so the promise can reject on thrown errors and display them nicely in IDKit

* feat: ensure returned credentialType is acceptable

checks to ensure the credential_type in the proof returned from the bridge is one of the configured credential_types, and displays the relevant error if not

this should only happen when manually selecting the wrong credential in the simulator, but good to have anyway

* feat: log error when disallowed credential is returned

* fix: document `async` in handleVerify callback runner
  • Loading branch information
0xPenryn authored Dec 6, 2023
1 parent eb053c6 commit 2e1157f
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
11 changes: 10 additions & 1 deletion packages/core/src/bridge.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { create } from 'zustand'
import { buffer_decode } from './lib/utils'
import { AppErrorCodes } from '@/types/bridge'
import { VerificationState } from '@/types/bridge'
import type { AppErrorCodes } from '@/types/bridge'
import type { ISuccessResult } from '@/types/result'
import { encodeAction, generateSignal } from '@/lib/hashing'
import { CredentialType, type IDKitConfig } from '@/types/config'
Expand Down Expand Up @@ -112,6 +112,13 @@ export const useWorldBridgeStore = create<WorldBridgeStore>((set, get) => ({

const res = await fetch(`${get().bridge_url}/response/${get().requestId}`)

if (!res.ok) {
return set({
errorCode: AppErrorCodes.ConnectionFailed,
verificationState: VerificationState.Failed,
})
}

const { response, status } = (await res.json()) as BridgeResponse

if (status != ResponseStatus.Completed) {
Expand Down Expand Up @@ -141,6 +148,8 @@ export const useWorldBridgeStore = create<WorldBridgeStore>((set, get) => ({
set({
iv: null,
key: null,
result: null,
errorCode: null,
requestId: null,
connectorURI: null,
verificationState: VerificationState.PreparingClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,17 @@ const WorldIDState = () => {
}

if (result) {
if (!credential_types?.includes(result.credential_type)) {
console.error(
'Credential type returned does not match configured credential_types. This should only happen when manually selecting disallowed credentials in the Worldcoin Simulator.'
)
setStage(IDKITStage.ERROR)
setErrorState({ code: AppErrorCodes.CredentialUnavailable })
return
}
return handleVerify(result)
}
}, [result, reset, handleVerify, verificationState, setStage, errorCode, setErrorState])
}, [result, handleVerify, verificationState, setStage, errorCode, setErrorState, credential_types])

return (
<div className="-mt-6 space-y-6">
Expand Down
5 changes: 4 additions & 1 deletion packages/react/src/store/idkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ const useIDKitStore = createWithEqualityFn<IDKitStore>()(
handleVerify: (result: ISuccessResult) => {
set({ stage: IDKITStage.HOST_APP_VERIFICATION, processing: false })

Promise.all(Object.values(get().verifyCallbacks).map(cb => cb?.(result))).then(
// the `async` added below ensures that we properly handle errors thrown by the callbacks if they are defined as synchronous functions
// without it, if `handleVerify` was a synchronous function and it threw an error, the error would not be caught by the promise chain to be properly displayed in IDKit
// this has no effect on the callbacks if they are defined as asynchronous functions
Promise.all(Object.values(get().verifyCallbacks).map(async cb => cb?.(result))).then(
() => {
set({ stage: IDKITStage.SUCCESS, result })

Expand Down

0 comments on commit 2e1157f

Please sign in to comment.