@i3m/cloud-vault-client
Version:
A TypeScript/JavaScript implementation of a client for the i3M-Wallet Cloud-Vault server
110 lines (104 loc) • 4.12 kB
text/typescript
import { OpenApiComponents } from '@i3m/cloud-vault-server/types/openapi'
import { AxiosError } from 'axios'
import { } from 'eventsource'
export type VaultErrorData = { // eslint-disable-line @typescript-eslint/consistent-type-definitions
'not-initialized': any
'http-connection-error': {
request: {
method?: string
url?: string
headers?: { [header: string]: string }
data?: any
}
response?: {
status?: number
headers?: { [header: string]: string }
data?: any
}
}
'http-request-canceled': {
request: {
method?: string
url?: string
headers?: { [header: string]: string }
data?: any
}
}
'no-uploaded-storage': any
'sse-connection-error': any
'quota-exceeded': string
conflict: {
localTimestamp?: number // timestamp in milliseconds elapsed from EPOCH when the latest storage has been downloaded by this client
remoteTimestamp?: number // timestamp in milliseconds elapsed from EPOCH when the latest storage has been uploaded by any client
}
unauthorized: any
'invalid-credentials': any
'weak-password': string
'invalid-timestamp': any
error: Error // unknown error generated as an instance of Error
unknown: any // unknown error not as an instance of Error
validation: {
description?: string
data?: any
}
}
export type VaultErrorName = keyof VaultErrorData
export type DataForError<T extends VaultErrorName> = VaultErrorData[T]
export class VaultError<T extends VaultErrorName = VaultErrorName> extends Error {
data: any
message: T
constructor (message: T, data: DataForError<T>, options?: ErrorOptions)
constructor (message: string, data?: any, options?: ErrorOptions) {
super(message, options)
this.name = 'VaultError'
this.data = data
this.message = message as T
}
static from (error: unknown): VaultError {
if (error instanceof VaultError) { return error }
if (error instanceof Object && error.constructor.name === 'Event') { // SSE problem
return new VaultError('sse-connection-error', error, { cause: 'Likely issues connecting to the events endpoint of the cloud vault server' })
}
if (error instanceof AxiosError) {
const err = error.response?.data as OpenApiComponents.Schemas.ApiError | OpenApiComponents.Schemas.ErrorUnauthorized | OpenApiComponents.Schemas.ErrorAlreadyRegistered | OpenApiComponents.Schemas.ErrorInvalidCredentials | OpenApiComponents.Schemas.ErrorNoStorage | OpenApiComponents.Schemas.ErrorNotRegistered | OpenApiComponents.Schemas.ErrorQuotaExceeded | OpenApiComponents.Schemas.ErrorUnauthorized
switch (err.name) {
case 'no-storage':
return new VaultError('no-uploaded-storage', undefined)
case 'invalid-credentials':
return new VaultError('invalid-credentials', undefined)
case 'invalid-timestamp':
return new VaultError('invalid-timestamp', undefined)
case 'quota-exceeded':
return new VaultError('quota-exceeded', err.description)
case 'unauthorized':
case 'not-registered':
return new VaultError('unauthorized', undefined)
default:
break
}
const vaultConnError: VaultErrorData['http-connection-error'] = {
request: {
method: error.config?.method?.toLocaleUpperCase(),
url: error.config?.url,
headers: error.config?.headers,
data: error.config?.data
},
response: {
status: error.response?.status,
headers: error.response?.headers as { [key: string]: string },
data: error.response?.data
}
}
return new VaultError('http-connection-error', vaultConnError)
}
if (error instanceof Error) {
const vaultError = new VaultError('error', error, { cause: error.cause })
vaultError.stack = error.stack
return vaultError
}
return new VaultError('unknown', error)
}
}
export function checkErrorType <T extends VaultErrorName> (err: VaultError, type: T): err is VaultError<T> {
return err.message === type
}