feat(user): ✨ Revokable API tokens
This commit is contained in:
60
apps/builder/services/user/apiTokens.ts
Normal file
60
apps/builder/services/user/apiTokens.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { ApiToken } from 'db'
|
||||
import { fetcher } from 'services/utils'
|
||||
import useSWR, { KeyedMutator } from 'swr'
|
||||
import { isNotEmpty, sendRequest } from 'utils'
|
||||
|
||||
export type ApiTokenFromServer = { id: string; name: string; createdAt: string }
|
||||
|
||||
type ReturnedProps = {
|
||||
apiTokens?: ApiTokenFromServer[]
|
||||
isLoading: boolean
|
||||
mutate: KeyedMutator<ServerResponse>
|
||||
}
|
||||
|
||||
type ServerResponse = {
|
||||
apiTokens: ApiTokenFromServer[]
|
||||
}
|
||||
export const useApiTokens = ({
|
||||
userId,
|
||||
onError,
|
||||
}: {
|
||||
userId?: string
|
||||
onError: (error: Error) => void
|
||||
}): ReturnedProps => {
|
||||
const { data, error, mutate } = useSWR<ServerResponse, Error>(
|
||||
userId ? `/api/users/${userId}/api-tokens` : null,
|
||||
fetcher,
|
||||
{
|
||||
dedupingInterval: isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||
? 0
|
||||
: undefined,
|
||||
}
|
||||
)
|
||||
if (error) onError(error)
|
||||
return {
|
||||
apiTokens: data?.apiTokens,
|
||||
isLoading: !error && !data,
|
||||
mutate,
|
||||
}
|
||||
}
|
||||
|
||||
export const createApiToken = (userId: string, { name }: { name: string }) =>
|
||||
sendRequest<{ apiToken: ApiTokenFromServer & { token: string } }>({
|
||||
url: `/api/users/${userId}/api-tokens`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
name,
|
||||
},
|
||||
})
|
||||
|
||||
export const deleteApiToken = ({
|
||||
userId,
|
||||
tokenId,
|
||||
}: {
|
||||
userId: string
|
||||
tokenId: string
|
||||
}) =>
|
||||
sendRequest<{ apiToken: ApiToken }>({
|
||||
url: `/api/users/${userId}/api-tokens/${tokenId}`,
|
||||
method: 'DELETE',
|
||||
})
|
@ -123,17 +123,17 @@ export const timeSince = (date: string) => {
|
||||
}
|
||||
interval = seconds / 86400
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + ' days'
|
||||
return Math.floor(interval) + 'd'
|
||||
}
|
||||
interval = seconds / 3600
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + ' hours'
|
||||
return Math.floor(interval) + 'h'
|
||||
}
|
||||
interval = seconds / 60
|
||||
if (interval > 1) {
|
||||
return Math.floor(interval) + ' minutes'
|
||||
return Math.floor(interval) + 'm'
|
||||
}
|
||||
return Math.floor(seconds) + ' seconds'
|
||||
return Math.floor(seconds) + 's'
|
||||
}
|
||||
|
||||
export const isCloudProdInstance = () =>
|
||||
|
Reference in New Issue
Block a user