From dcaff1d91c7789dd1003313e73172b605cd420c5 Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Sat, 18 May 2024 12:25:33 +0200 Subject: [PATCH] feat: add async suffix eslint rule (#485) --- .../app/[locale]/auth/login/_login-form.tsx | 6 +- .../boards/(content)/(default)/_definition.ts | 2 +- .../boards/(content)/(default)/page.tsx | 2 +- .../boards/(content)/[name]/_definition.tsx | 2 +- .../[locale]/boards/(content)/[name]/page.tsx | 2 +- .../[locale]/boards/(content)/_creator.tsx | 8 +-- .../boards/(content)/_header-actions.tsx | 4 +- .../src/app/[locale]/boards/[name]/layout.tsx | 2 +- .../settings/_access/group-select-modal.tsx | 6 +- .../settings/_access/user-select-modal.tsx | 6 +- .../[locale]/boards/[name]/settings/page.tsx | 10 ++-- .../app/[locale]/boards/_layout-creator.tsx | 4 +- .../[locale]/init/user/_init-user-form.tsx | 4 +- .../manage/apps/_app-delete-button.tsx | 4 +- .../manage/apps/edit/[id]/_app-edit-form.tsx | 4 +- .../manage/apps/new/_app-new-form.tsx | 4 +- .../_components/board-card-menu-dropdown.tsx | 5 +- .../_components/create-board-button.tsx | 4 +- .../src/app/[locale]/manage/boards/page.tsx | 5 +- .../integrations/_integration-buttons.tsx | 4 +- .../edit/[id]/_integration-edit-form.tsx | 8 +-- .../new/_integration-new-form.tsx | 8 +-- .../users/[userId]/_delete-user-button.tsx | 5 +- .../users/[userId]/_profile-avatar-form.tsx | 8 +-- .../manage/users/[userId]/_profile-form.tsx | 4 +- .../security/_change-password-form.tsx | 4 +- .../users/groups/[id]/_delete-group.tsx | 5 +- .../users/groups/[id]/_rename-group-form.tsx | 4 +- .../groups/[id]/_transfer-group-ownership.tsx | 1 + .../groups/[id]/members/_add-group-member.tsx | 5 +- .../[id]/members/_remove-group-member.tsx | 7 ++- .../manage/users/groups/_add-group.tsx | 4 +- apps/nextjs/src/app/revalidatePathAction.ts | 2 +- .../components/board/permissions/server.ts | 4 +- apps/tasks/src/jobs/queue.ts | 4 +- apps/tasks/src/lib/queue/client.ts | 2 +- apps/tasks/src/lib/queue/worker.ts | 6 +- apps/websocket/src/main.ts | 2 + packages/api/src/router/board.ts | 12 ++-- packages/api/src/router/group.ts | 6 +- packages/api/src/router/integration.ts | 8 +-- packages/api/src/router/test/app.spec.ts | 8 +-- packages/api/src/router/test/board.spec.ts | 56 +++++++++---------- .../router/test/board/board-access.spec.ts | 13 +++-- packages/api/src/router/test/group.spec.ts | 37 ++++++------ .../api/src/router/test/integration.spec.ts | 32 +++++------ packages/api/src/router/test/invite.spec.ts | 4 +- packages/api/src/router/test/user.spec.ts | 16 +++--- packages/api/src/router/user.ts | 22 ++++---- packages/auth/callbacks.ts | 4 +- packages/auth/index.ts | 5 +- packages/auth/providers/credentials.ts | 1 + .../auth/providers/test/credentials.spec.ts | 10 ++-- packages/auth/security.ts | 4 +- packages/auth/session.ts | 6 +- packages/auth/test/callbacks.spec.ts | 6 +- packages/auth/test/security.spec.ts | 26 ++++----- packages/redis/src/lib/channel.ts | 28 +++++----- packages/widgets/src/app/serverData.ts | 4 +- tooling/eslint/base.js | 42 ++++++++++++++ 60 files changed, 296 insertions(+), 225 deletions(-) diff --git a/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx b/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx index dac9fa9a4..ec5edf3a5 100644 --- a/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx +++ b/apps/nextjs/src/app/[locale]/auth/login/_login-form.tsx @@ -35,7 +35,7 @@ export const LoginForm = () => { }, }); - const handleSubmit = async (values: FormType) => { + const handleSubmitAsync = async (values: FormType) => { setIsLoading(true); setError(undefined); await signIn("credentials", { @@ -66,7 +66,9 @@ export const LoginForm = () => { return ( -
void handleSubmit(values))}> + void handleSubmitAsync(values))} + > ({ - async getInitialBoard() { + async getInitialBoardAsync() { return await api.board.getDefaultBoard(); }, }); diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/(default)/page.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/(default)/page.tsx index 1ff09b28b..2aacb5b36 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/(default)/page.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/(default)/page.tsx @@ -1,6 +1,6 @@ import definition from "./_definition"; -const { generateMetadata, page } = definition; +const { generateMetadataAsync: generateMetadata, page } = definition; export default page; diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/_definition.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/_definition.tsx index 5235b8971..82e53110d 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/_definition.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/_definition.tsx @@ -3,7 +3,7 @@ import { api } from "@homarr/api/server"; import { createBoardContentPage } from "../_creator"; export default createBoardContentPage<{ locale: string; name: string }>({ - async getInitialBoard({ name }) { + async getInitialBoardAsync({ name }) { return await api.board.getBoardByName({ name }); }, }); diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx index 1ff09b28b..2aacb5b36 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx @@ -1,6 +1,6 @@ import definition from "./_definition"; -const { generateMetadata, page } = definition; +const { generateMetadataAsync: generateMetadata, page } = definition; export default page; diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx index 761e4ffc4..badc80a07 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx @@ -14,24 +14,24 @@ import { BoardContentHeaderActions } from "./_header-actions"; export type Params = Record; interface Props { - getInitialBoard: (params: TParams) => Promise; + getInitialBoardAsync: (params: TParams) => Promise; } export const createBoardContentPage = < TParams extends Record, >({ - getInitialBoard, + getInitialBoardAsync: getInitialBoard, }: Props) => { return { layout: createBoardLayout({ headerActions: , - getInitialBoard, + getInitialBoardAsync: getInitialBoard, isBoardContentPage: true, }), page: () => { return ; }, - generateMetadata: async ({ + generateMetadataAsync: async ({ params, }: { params: TParams; diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx index d251d6e27..33abb0661 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx @@ -22,7 +22,7 @@ import { } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { editModeAtom } from "~/components/board/editMode"; import { ItemSelectModal } from "~/components/board/items/item-select-modal"; import { useBoardPermissions } from "~/components/board/permissions/client"; @@ -131,7 +131,7 @@ const EditModeMenu = () => { message: t("notification.success.message"), }); void utils.board.getBoardByName.invalidate({ name: board.name }); - void revalidatePathAction(`/boards/${board.name}`); + void revalidatePathActionAsync(`/boards/${board.name}`); setEditMode(false); }, onError() { diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx index 108e7f222..42107bf2d 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx @@ -5,7 +5,7 @@ import { createBoardLayout } from "../_layout-creator"; export default createBoardLayout<{ locale: string; name: string }>({ headerActions: , - async getInitialBoard({ name }) { + async getInitialBoardAsync({ name }) { return await api.board.getBoardByName({ name }); }, isBoardContentPage: false, diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_access/group-select-modal.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_access/group-select-modal.tsx index 1e9a60b31..27a76627c 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_access/group-select-modal.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_access/group-select-modal.tsx @@ -22,7 +22,7 @@ export const GroupSelectModal = createModal( const { data: groups, isPending } = clientApi.group.selectable.useQuery(); const [loading, setLoading] = useState(false); const form = useForm(); - const handleSubmit = async (values: GroupSelectFormType) => { + const handleSubmitAsync = async (values: GroupSelectFormType) => { const currentGroup = groups?.find((group) => group.id === values.groupId); if (!currentGroup) return; setLoading(true); @@ -38,7 +38,9 @@ export const GroupSelectModal = createModal( const confirmLabel = innerProps.confirmLabel ?? t("common.action.add"); return ( - void handleSubmit(values))}> + void handleSubmitAsync(values))} + > { +const getBoardAndPermissionsAsync = async (params: Props["params"]) => { try { const board = await api.board.getBoardByName({ name: params.name }); - const { hasFullAccess } = await getBoardPermissions(board); + const { hasFullAccess } = await getBoardPermissionsAsync(board); const permissions = hasFullAccess ? await api.board.getBoardPermissions({ id: board.id }) : { @@ -73,8 +73,8 @@ export default async function BoardSettingsPage({ params, searchParams, }: Props) { - const { board, permissions } = await getBoardAndPermissions(params); - const { hasFullAccess } = await getBoardPermissions(board); + const { board, permissions } = await getBoardAndPermissionsAsync(params); + const { hasFullAccess } = await getBoardPermissionsAsync(board); const t = await getScopedI18n("board.setting"); return ( diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx index 30dcd1e30..a4559b33b 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx @@ -16,13 +16,13 @@ import { BoardMantineProvider } from "./(content)/_theme"; interface CreateBoardLayoutProps { headerActions: JSX.Element; - getInitialBoard: (params: TParams) => Promise; + getInitialBoardAsync: (params: TParams) => Promise; isBoardContentPage: boolean; } export const createBoardLayout = ({ headerActions, - getInitialBoard, + getInitialBoardAsync: getInitialBoard, isBoardContentPage, }: CreateBoardLayoutProps) => { const Layout = async ({ diff --git a/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx b/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx index 417a209fa..30a30e7de 100644 --- a/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx +++ b/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx @@ -29,7 +29,7 @@ export const InitUserForm = () => { }, }); - const handleSubmit = async (values: FormType) => { + const handleSubmitAsync = async (values: FormType) => { await mutateAsync(values, { onSuccess: () => { showSuccessNotification({ @@ -51,7 +51,7 @@ export const InitUserForm = () => { void handleSubmit(values), + (values) => void handleSubmitAsync(values), (err) => console.log(err), )} > diff --git a/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx b/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx index 7f582e8ac..210185589 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx @@ -13,7 +13,7 @@ import { } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "../../../revalidatePathAction"; +import { revalidatePathActionAsync } from "../../../revalidatePathAction"; interface AppDeleteButtonProps { app: RouterOutputs["app"]["all"][number]; @@ -37,7 +37,7 @@ export const AppDeleteButton = ({ app }: AppDeleteButtonProps) => { title: t("notification.success.title"), message: t("notification.success.message"), }); - void revalidatePathAction("/manage/apps"); + void revalidatePathActionAsync("/manage/apps"); }, onError: () => { showErrorNotification({ diff --git a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx index 92fd4d412..870411a14 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/_app-edit-form.tsx @@ -13,7 +13,7 @@ import type { TranslationFunction } from "@homarr/translation"; import { useScopedI18n } from "@homarr/translation/client"; import type { validation, z } from "@homarr/validation"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { AppForm } from "../../_form"; interface AppEditFormProps { @@ -30,7 +30,7 @@ export const AppEditForm = ({ app }: AppEditFormProps) => { title: t("success.title"), message: t("success.message"), }); - void revalidatePathAction("/manage/apps").then(() => { + void revalidatePathActionAsync("/manage/apps").then(() => { router.push("/manage/apps"); }); }, diff --git a/apps/nextjs/src/app/[locale]/manage/apps/new/_app-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/apps/new/_app-new-form.tsx index 78827cbac..733a350de 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/new/_app-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/new/_app-new-form.tsx @@ -12,7 +12,7 @@ import type { TranslationFunction } from "@homarr/translation"; import { useScopedI18n } from "@homarr/translation/client"; import type { validation, z } from "@homarr/validation"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { AppForm } from "../_form"; export const AppNewForm = () => { @@ -25,7 +25,7 @@ export const AppNewForm = () => { title: t("success.title"), message: t("success.message"), }); - void revalidatePathAction("/manage/apps").then(() => { + void revalidatePathActionAsync("/manage/apps").then(() => { router.push("/manage/apps"); }); }, diff --git a/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx b/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx index beda37acf..6a97c81ca 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx @@ -10,7 +10,7 @@ import { clientApi } from "@homarr/api/client"; import { useConfirmModal } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { useBoardPermissions } from "~/components/board/permissions/client"; const iconProps = { @@ -42,7 +42,7 @@ export const BoardCardMenuDropdown = ({ const { mutateAsync, isPending } = clientApi.board.deleteBoard.useMutation({ onSettled: async () => { - await revalidatePathAction("/manage/boards"); + await revalidatePathActionAsync("/manage/boards"); }, }); @@ -52,6 +52,7 @@ export const BoardCardMenuDropdown = ({ children: t("delete.confirm.description", { name: board.name, }), + // eslint-disable-next-line no-restricted-syntax onConfirm: async () => { await mutateAsync({ id: board.id, diff --git a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx index af16171b9..1c0331da6 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx @@ -8,7 +8,7 @@ import { clientApi } from "@homarr/api/client"; import { useModalAction } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { AddBoardModal } from "~/components/manage/boards/add-board-modal"; interface CreateBoardButtonProps { @@ -21,7 +21,7 @@ export const CreateBoardButton = ({ boardNames }: CreateBoardButtonProps) => { const { mutateAsync, isPending } = clientApi.board.createBoard.useMutation({ onSettled: async () => { - await revalidatePathAction("/manage/boards"); + await revalidatePathActionAsync("/manage/boards"); }, }); diff --git a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx index 774e09975..ac254468d 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx @@ -20,7 +20,7 @@ import { api } from "@homarr/api/server"; import { getScopedI18n } from "@homarr/translation/server"; import { UserAvatar } from "@homarr/ui"; -import { getBoardPermissions } from "~/components/board/permissions/server"; +import { getBoardPermissionsAsync } from "~/components/board/permissions/server"; import { BoardCardMenuDropdown } from "./_components/board-card-menu-dropdown"; import { CreateBoardButton } from "./_components/create-board-button"; @@ -53,7 +53,8 @@ interface BoardCardProps { const BoardCard = async ({ board }: BoardCardProps) => { const t = await getScopedI18n("management.page.board"); - const { hasChangeAccess: isMenuVisible } = await getBoardPermissions(board); + const { hasChangeAccess: isMenuVisible } = + await getBoardPermissionsAsync(board); const visibility = board.isPublic ? "public" : "private"; const VisibilityIcon = board.isPublic ? IconWorld : IconLock; diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_integration-buttons.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_integration-buttons.tsx index d1809d246..a2d4a7ad2 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_integration-buttons.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_integration-buttons.tsx @@ -12,7 +12,7 @@ import { } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "../../../revalidatePathAction"; +import { revalidatePathActionAsync } from "../../../revalidatePathAction"; interface DeleteIntegrationActionButtonProps { count: number; @@ -49,7 +49,7 @@ export const DeleteIntegrationActionButton = ({ if (count === 1) { router.replace("/manage/integrations"); } - void revalidatePathAction("/manage/integrations"); + void revalidatePathActionAsync("/manage/integrations"); }, onError: () => { showErrorNotification({ diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx index 5487fa999..14519e686 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx @@ -20,7 +20,7 @@ import { useI18n } from "@homarr/translation/client"; import type { z } from "@homarr/validation"; import { validation } from "@homarr/validation"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; import { SecretCard } from "../../_integration-secret-card"; import { IntegrationSecretInput } from "../../_integration-secret-inputs"; import { @@ -66,7 +66,7 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { integration.secrets.map((secret) => [secret.kind, secret]), ); - const handleSubmit = async (values: FormType) => { + const handleSubmitAsync = async (values: FormType) => { if (isDirty) return; await mutateAsync( { @@ -83,7 +83,7 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { title: t("integration.page.edit.notification.success.title"), message: t("integration.page.edit.notification.success.message"), }); - void revalidatePathAction("/manage/integrations").then(() => + void revalidatePathActionAsync("/manage/integrations").then(() => router.push("/manage/integrations"), ); }, @@ -98,7 +98,7 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { }; return ( - void handleSubmit(values))}> + void handleSubmitAsync(values))}> diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx index def3f38f7..039af27eb 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx @@ -34,7 +34,7 @@ import { TestConnectionNoticeAlert, useTestConnectionDirty, } from "../_integration-test-connection"; -import { revalidatePathAction } from "../../../../revalidatePathAction"; +import { revalidatePathActionAsync } from "../../../../revalidatePathAction"; interface NewIntegrationFormProps { searchParams: Partial> & { @@ -67,7 +67,7 @@ export const NewIntegrationForm = ({ }); const { mutateAsync, isPending } = clientApi.integration.create.useMutation(); - const handleSubmit = async (values: FormType) => { + const handleSubmitAsync = async (values: FormType) => { if (isDirty) return; await mutateAsync( { @@ -80,7 +80,7 @@ export const NewIntegrationForm = ({ title: t("integration.page.create.notification.success.title"), message: t("integration.page.create.notification.success.message"), }); - void revalidatePathAction("/manage/integrations").then(() => + void revalidatePathActionAsync("/manage/integrations").then(() => router.push("/manage/integrations"), ); }, @@ -95,7 +95,7 @@ export const NewIntegrationForm = ({ }; return ( - void handleSubmit(value))}> + void handleSubmitAsync(value))}> diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_delete-user-button.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_delete-user-button.tsx index 6ef7e4ead..9f501d5c7 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_delete-user-button.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_delete-user-button.tsx @@ -9,7 +9,7 @@ import { clientApi } from "@homarr/api/client"; import { useConfirmModal } from "@homarr/modals"; import { useI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface DeleteUserButtonProps { user: RouterOutputs["user"]["getById"]; @@ -21,7 +21,7 @@ export const DeleteUserButton = ({ user }: DeleteUserButtonProps) => { const { mutateAsync: mutateUserDeletionAsync } = clientApi.user.delete.useMutation({ async onSuccess() { - await revalidatePathAction("/manage/users").then(() => + await revalidatePathActionAsync("/manage/users").then(() => router.push("/manage/users"), ); }, @@ -33,6 +33,7 @@ export const DeleteUserButton = ({ user }: DeleteUserButtonProps) => { openConfirmModal({ title: t("user.action.delete.label"), children: t("user.action.delete.confirm", { username: user.name }), + // eslint-disable-next-line no-restricted-syntax async onConfirm() { await mutateUserDeletionAsync(user.id); }, diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-avatar-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-avatar-form.tsx index 3880fb9d4..df7f974b0 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-avatar-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-avatar-form.tsx @@ -15,7 +15,7 @@ import { import { useI18n, useScopedI18n } from "@homarr/translation/client"; import { UserAvatar } from "@homarr/ui"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface UserProfileAvatarForm { user: RouterOutputs["user"]["getById"]; @@ -44,7 +44,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => { { async onSuccess() { // Revalidate all as the avatar is used in multiple places - await revalidatePathAction("/"); + await revalidatePathActionAsync("/"); showSuccessNotification({ message: tManageAvatar( "changeImage.notification.success.message", @@ -87,7 +87,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => { { async onSuccess() { // Revalidate all as the avatar is used in multiple places - await revalidatePathAction("/"); + await revalidatePathActionAsync("/"); showSuccessNotification({ message: tManageAvatar( "removeImage.notification.success.message", @@ -161,7 +161,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => { ); }; -const fileToBase64Async = (file: File): Promise => +const fileToBase64Async = async (file: File): Promise => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-form.tsx index af2028300..517bfc92c 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/_profile-form.tsx @@ -13,7 +13,7 @@ import { import { useI18n } from "@homarr/translation/client"; import { validation } from "@homarr/validation"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface UserProfileFormProps { user: RouterOutputs["user"]["getById"]; @@ -23,7 +23,7 @@ export const UserProfileForm = ({ user }: UserProfileFormProps) => { const t = useI18n(); const { mutate, isPending } = clientApi.user.editProfile.useMutation({ async onSettled() { - await revalidatePathAction("/manage/users"); + await revalidatePathActionAsync("/manage/users"); }, onSuccess() { showSuccessNotification({ diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_change-password-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_change-password-form.tsx index ff031fd20..0f1c310eb 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_change-password-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/security/_change-password-form.tsx @@ -13,7 +13,7 @@ import { import { useI18n } from "@homarr/translation/client"; import { validation } from "@homarr/validation"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface ChangePasswordFormProps { user: RouterOutputs["user"]["getById"]; @@ -24,7 +24,7 @@ export const ChangePasswordForm = ({ user }: ChangePasswordFormProps) => { const t = useI18n(); const { mutate, isPending } = clientApi.user.changePassword.useMutation({ async onSettled() { - await revalidatePathAction(`/manage/users/${user.id}`); + await revalidatePathActionAsync(`/manage/users/${user.id}`); }, onSuccess() { showSuccessNotification({ diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_delete-group.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_delete-group.tsx index 7ee9efdda..a0dfe6cbb 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_delete-group.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_delete-group.tsx @@ -12,7 +12,7 @@ import { } from "@homarr/notifications"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface DeleteGroupProps { group: { @@ -34,6 +34,7 @@ export const DeleteGroup = ({ group }: DeleteGroupProps) => { children: tDelete("confirm", { name: group.name, }), + // eslint-disable-next-line no-restricted-syntax async onConfirm() { await mutateAsync( { @@ -41,7 +42,7 @@ export const DeleteGroup = ({ group }: DeleteGroupProps) => { }, { onSuccess() { - void revalidatePathAction("/manage/users/groups"); + void revalidatePathActionAsync("/manage/users/groups"); router.push("/manage/users/groups"); showSuccessNotification({ title: tRoot("common.notification.delete.success"), diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx index bab0a365f..da0f9195c 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_rename-group-form.tsx @@ -11,7 +11,7 @@ import { } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface RenameGroupFormProps { group: { @@ -38,7 +38,7 @@ export const RenameGroupForm = ({ group }: RenameGroupFormProps) => { }, { onSuccess() { - void revalidatePathAction(`/users/groups/${group.id}`); + void revalidatePathActionAsync(`/users/groups/${group.id}`); showSuccessNotification({ title: t("common.notification.update.success"), message: t("group.action.update.notification.success.message", { diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_transfer-group-ownership.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_transfer-group-ownership.tsx index 4d7781abb..89bafb3e5 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_transfer-group-ownership.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_transfer-group-ownership.tsx @@ -43,6 +43,7 @@ export const TransferGroupOwnership = ({ name: group.name, username: name, }), + // eslint-disable-next-line no-restricted-syntax onConfirm: async () => { await mutateAsync( { diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_add-group-member.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_add-group-member.tsx index af34e25f7..b1b585629 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_add-group-member.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_add-group-member.tsx @@ -8,7 +8,7 @@ import { useModalAction } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; import { UserSelectModal } from "~/app/[locale]/boards/[name]/settings/_access/user-select-modal"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface AddGroupMemberProps { groupId: string; @@ -26,12 +26,13 @@ export const AddGroupMember = ({ const handleAddMember = useCallback(() => { openModal( { + // eslint-disable-next-line no-restricted-syntax async onSelect({ id }) { await mutateAsync({ userId: id, groupId, }); - await revalidatePathAction( + await revalidatePathActionAsync( `/manage/users/groups/${groupId}}/members`, ); }, diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_remove-group-member.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_remove-group-member.tsx index b951cc29d..6c8ea272e 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_remove-group-member.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/_remove-group-member.tsx @@ -7,7 +7,7 @@ import { clientApi } from "@homarr/api/client"; import { useConfirmModal } from "@homarr/modals"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; interface RemoveGroupMemberProps { groupId: string; @@ -29,12 +29,15 @@ export const RemoveGroupMember = ({ children: tRemoveMember("confirm", { user: user.name ?? "", }), + // eslint-disable-next-line no-restricted-syntax onConfirm: async () => { await mutateAsync({ groupId, userId: user.id, }); - await revalidatePathAction(`/manage/users/groups/${groupId}/members`); + await revalidatePathActionAsync( + `/manage/users/groups/${groupId}/members`, + ); }, }); }, [ diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/_add-group.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/_add-group.tsx index 063ac5833..e126e7503 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/_add-group.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/_add-group.tsx @@ -12,7 +12,7 @@ import { } from "@homarr/notifications"; import { useI18n } from "@homarr/translation/client"; -import { revalidatePathAction } from "~/app/revalidatePathAction"; +import { revalidatePathActionAsync } from "~/app/revalidatePathAction"; export const AddGroup = () => { const t = useI18n(); @@ -44,7 +44,7 @@ const AddGroupModal = createModal(({ actions }) => { mutate(values, { onSuccess() { actions.closeModal(); - void revalidatePathAction("/manage/users/groups"); + void revalidatePathActionAsync("/manage/users/groups"); showSuccessNotification({ title: t("common.notification.create.success"), message: t("group.action.create.notification.success.message"), diff --git a/apps/nextjs/src/app/revalidatePathAction.ts b/apps/nextjs/src/app/revalidatePathAction.ts index d8ce6420b..7b388546d 100644 --- a/apps/nextjs/src/app/revalidatePathAction.ts +++ b/apps/nextjs/src/app/revalidatePathAction.ts @@ -2,6 +2,6 @@ import { revalidatePath } from "next/cache"; -export async function revalidatePathAction(path: string) { +export async function revalidatePathActionAsync(path: string) { return new Promise((resolve) => resolve(revalidatePath(path, "page"))); } diff --git a/apps/nextjs/src/components/board/permissions/server.ts b/apps/nextjs/src/components/board/permissions/server.ts index 36fd6a6b7..7a8294509 100644 --- a/apps/nextjs/src/components/board/permissions/server.ts +++ b/apps/nextjs/src/components/board/permissions/server.ts @@ -2,7 +2,9 @@ import { auth } from "@homarr/auth/next"; import type { BoardPermissionsProps } from "@homarr/auth/shared"; import { constructBoardPermissions } from "@homarr/auth/shared"; -export const getBoardPermissions = async (board: BoardPermissionsProps) => { +export const getBoardPermissionsAsync = async ( + board: BoardPermissionsProps, +) => { const session = await auth(); return constructBoardPermissions(board, session); }; diff --git a/apps/tasks/src/jobs/queue.ts b/apps/tasks/src/jobs/queue.ts index 6a266c608..8eeb6f4e5 100644 --- a/apps/tasks/src/jobs/queue.ts +++ b/apps/tasks/src/jobs/queue.ts @@ -1,8 +1,8 @@ import { EVERY_MINUTE } from "../lib/cron-job/constants"; import { createCronJob } from "../lib/cron-job/creator"; -import { queueWorker } from "../lib/queue/worker"; +import { queueWorkerAsync } from "../lib/queue/worker"; // This job processes queues, it runs every minute. export const queuesJob = createCronJob(EVERY_MINUTE).withCallback(async () => { - await queueWorker(); + await queueWorkerAsync(); }); diff --git a/apps/tasks/src/lib/queue/client.ts b/apps/tasks/src/lib/queue/client.ts index 58895999e..6b65885e0 100644 --- a/apps/tasks/src/lib/queue/client.ts +++ b/apps/tasks/src/lib/queue/client.ts @@ -39,7 +39,7 @@ export const createQueueClient = (queues: TQueues) => { const queue = queueRegistry.get(name); if (!queue) return; - await queueChannel.add({ + await queueChannel.addAsync({ name, data, executionDate: diff --git a/apps/tasks/src/lib/queue/worker.ts b/apps/tasks/src/lib/queue/worker.ts index b03830c45..40d9dde9b 100644 --- a/apps/tasks/src/lib/queue/worker.ts +++ b/apps/tasks/src/lib/queue/worker.ts @@ -6,15 +6,15 @@ import { queueRegistry } from "~/queues"; * This function reads all the queue executions that are due and processes them. * Those executions are stored in the redis queue channel. */ -export const queueWorker = async () => { +export const queueWorkerAsync = async () => { const now = new Date(); - const executions = await queueChannel.filter((item) => { + const executions = await queueChannel.filterAsync((item) => { return item.executionDate < now; }); for (const execution of executions) { const queue = queueRegistry.get(execution.name); if (!queue) continue; await queue.callback(execution.data); - await queueChannel.markAsDone(execution._id); + await queueChannel.markAsDoneAsync(execution._id); } }; diff --git a/apps/websocket/src/main.ts b/apps/websocket/src/main.ts index d2b4015b6..0b4e8d166 100644 --- a/apps/websocket/src/main.ts +++ b/apps/websocket/src/main.ts @@ -13,6 +13,8 @@ const wss = new WebSocketServer({ const handler = applyWSSHandler({ wss, router: appRouter, + // ignore error on next line because the createContext must be set with this name + // eslint-disable-next-line no-restricted-syntax createContext: async ({ req }) => { try { const headers = Object.entries(req.headers).map( diff --git a/packages/api/src/router/board.ts b/packages/api/src/router/board.ts index 00042ef8f..b00263b7a 100644 --- a/packages/api/src/router/board.ts +++ b/packages/api/src/router/board.ts @@ -128,7 +128,7 @@ export const boardRouter = createTRPCRouter({ "full-access", ); - await noBoardWithSimilarName(ctx.db, input.name, [input.id]); + await noBoardWithSimilarNameAsync(ctx.db, input.name, [input.id]); await ctx.db .update(boards) @@ -164,7 +164,7 @@ export const boardRouter = createTRPCRouter({ const boardWhere = eq(boards.name, "default"); await throwIfActionForbiddenAsync(ctx, boardWhere, "board-view"); - return await getFullBoardWithWhere( + return await getFullBoardWithWhereAsync( ctx.db, boardWhere, ctx.session?.user.id ?? null, @@ -176,7 +176,7 @@ export const boardRouter = createTRPCRouter({ const boardWhere = eq(boards.name, input.name); await throwIfActionForbiddenAsync(ctx, boardWhere, "board-view"); - return await getFullBoardWithWhere( + return await getFullBoardWithWhereAsync( ctx.db, boardWhere, ctx.session?.user.id ?? null, @@ -229,7 +229,7 @@ export const boardRouter = createTRPCRouter({ ); await ctx.db.transaction(async (transaction) => { - const dbBoard = await getFullBoardWithWhere( + const dbBoard = await getFullBoardWithWhereAsync( transaction, eq(boards.id, input.id), ctx.session.user.id, @@ -523,7 +523,7 @@ export const boardRouter = createTRPCRouter({ }), }); -const noBoardWithSimilarName = async ( +const noBoardWithSimilarNameAsync = async ( db: Database, name: string, ignoredIds: string[] = [], @@ -549,7 +549,7 @@ const noBoardWithSimilarName = async ( } }; -const getFullBoardWithWhere = async ( +const getFullBoardWithWhereAsync = async ( db: Database, where: SQL, userId: string | null, diff --git a/packages/api/src/router/group.ts b/packages/api/src/router/group.ts index 8b1451946..19785b32d 100644 --- a/packages/api/src/router/group.ts +++ b/packages/api/src/router/group.ts @@ -106,7 +106,7 @@ export const groupRouter = createTRPCRouter({ .input(validation.group.create) .mutation(async ({ input, ctx }) => { const normalizedName = normalizeName(input.name); - await checkSimilarNameAndThrow(ctx.db, normalizedName); + await checkSimilarNameAndThrowAsync(ctx.db, normalizedName); const id = createId(); await ctx.db.insert(groups).values({ @@ -123,7 +123,7 @@ export const groupRouter = createTRPCRouter({ await throwIfGroupNotFoundAsync(ctx.db, input.id); const normalizedName = normalizeName(input.name); - await checkSimilarNameAndThrow(ctx.db, normalizedName, input.id); + await checkSimilarNameAndThrowAsync(ctx.db, normalizedName, input.id); await ctx.db .update(groups) @@ -206,7 +206,7 @@ export const groupRouter = createTRPCRouter({ const normalizeName = (name: string) => name.trim(); -const checkSimilarNameAndThrow = async ( +const checkSimilarNameAndThrowAsync = async ( db: Database, name: string, ignoreId?: string, diff --git a/packages/api/src/router/integration.ts b/packages/api/src/router/integration.ts index 28c4415fb..f0b27f99d 100644 --- a/packages/api/src/router/integration.ts +++ b/packages/api/src/router/integration.ts @@ -139,9 +139,9 @@ export const integrationRouter = createTRPCRouter({ (secret) => secret.kind === changedSecret.kind, ) ) { - await addSecret(ctx.db, secretInput); + await addSecretAsync(ctx.db, secretInput); } else { - await updateSecret(ctx.db, secretInput); + await updateSecretAsync(ctx.db, secretInput); } } } @@ -276,7 +276,7 @@ interface UpdateSecretInput { value: string; kind: IntegrationSecretKind; } -const updateSecret = async (db: Database, input: UpdateSecretInput) => { +const updateSecretAsync = async (db: Database, input: UpdateSecretInput) => { await db .update(integrationSecrets) .set({ @@ -296,7 +296,7 @@ interface AddSecretInput { value: string; kind: IntegrationSecretKind; } -const addSecret = async (db: Database, input: AddSecretInput) => { +const addSecretAsync = async (db: Database, input: AddSecretInput) => { await db.insert(integrationSecrets).values({ kind: input.kind, value: encryptSecret(input.value), diff --git a/packages/api/src/router/test/app.spec.ts b/packages/api/src/router/test/app.spec.ts index 2ea48013b..db9550d0c 100644 --- a/packages/api/src/router/test/app.spec.ts +++ b/packages/api/src/router/test/app.spec.ts @@ -78,8 +78,8 @@ describe("byId should return an app by id", () => { session: null, }); - const act = async () => await caller.byId({ id: "2" }); - await expect(act()).rejects.toThrow("App not found"); + const actAsync = async () => await caller.byId({ id: "2" }); + await expect(actAsync()).rejects.toThrow("App not found"); }); }); @@ -174,7 +174,7 @@ describe("update should update an app", () => { session: null, }); - const act = async () => + const actAsync = async () => await caller.update({ id: createId(), name: "Mantine", @@ -182,7 +182,7 @@ describe("update should update an app", () => { description: null, href: null, }); - await expect(act()).rejects.toThrow("App not found"); + await expect(actAsync()).rejects.toThrow("App not found"); }); }); diff --git a/packages/api/src/router/test/board.spec.ts b/packages/api/src/router/test/board.spec.ts index a91ec395b..7ae949058 100644 --- a/packages/api/src/router/test/board.spec.ts +++ b/packages/api/src/router/test/board.spec.ts @@ -37,7 +37,7 @@ const defaultSession = { // Mock the auth module to return an empty session vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session })); -const createRandomUser = async (db: Database) => { +const createRandomUserAsync = async (db: Database) => { const userId = createId(); await db.insert(users).values({ id: userId, @@ -51,8 +51,8 @@ describe("getAllBoards should return all boards accessable to the current user", const db = createDb(); const caller = boardRouter.createCaller({ db, session: null }); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(boards).values([ { @@ -91,8 +91,8 @@ describe("getAllBoards should return all boards accessable to the current user", }, }); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(boards).values([ { @@ -122,8 +122,8 @@ describe("getAllBoards should return all boards accessable to the current user", const db = createDb(); const caller = boardRouter.createCaller({ db, session: defaultSession }); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(users).values({ id: defaultCreatorId, }); @@ -170,8 +170,8 @@ describe("getAllBoards should return all boards accessable to the current user", session: defaultSession, }); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(users).values({ id: defaultCreatorId, }); @@ -237,8 +237,8 @@ describe("getAllBoards should return all boards accessable to the current user", session: defaultSession, }); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(users).values({ id: defaultCreatorId, }); @@ -322,10 +322,10 @@ describe("createBoard should create a new board", () => { const caller = boardRouter.createCaller({ db, session: defaultSession }); // Act - const act = async () => await caller.createBoard({ name: "newBoard" }); + const actAsync = async () => await caller.createBoard({ name: "newBoard" }); // Assert - await expect(act()).rejects.toThrowError("Permission denied"); + await expect(actAsync()).rejects.toThrowError("Permission denied"); }); }); @@ -383,11 +383,11 @@ describe("rename board should rename board", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.renameBoard({ id: boardId, name: "Newname" }); // Assert - await expect(act()).rejects.toThrowError( + await expect(actAsync()).rejects.toThrowError( "Board with similar name already exists", ); }); @@ -398,11 +398,11 @@ describe("rename board should rename board", () => { const caller = boardRouter.createCaller({ db, session: defaultSession }); // Act - const act = async () => + const actAsync = async () => await caller.renameBoard({ id: "nonExistentBoardId", name: "newName" }); // Assert - await expect(act()).rejects.toThrowError("Board not found"); + await expect(actAsync()).rejects.toThrowError("Board not found"); }); }); @@ -485,11 +485,11 @@ describe("deleteBoard should delete board", () => { const caller = boardRouter.createCaller({ db, session: defaultSession }); // Act - const act = async () => + const actAsync = async () => await caller.deleteBoard({ id: "nonExistentBoardId" }); // Assert - await expect(act()).rejects.toThrowError("Board not found"); + await expect(actAsync()).rejects.toThrowError("Board not found"); }); }); @@ -552,11 +552,11 @@ describe("getBoardByName should return board by name", () => { await createFullBoardAsync(db, "default"); // Act - const act = async () => + const actAsync = async () => await caller.getBoardByName({ name: "nonExistentBoard" }); // Assert - await expect(act()).rejects.toThrowError("Board not found"); + await expect(actAsync()).rejects.toThrowError("Board not found"); }); }); @@ -633,7 +633,7 @@ describe("savePartialBoardSettings should save general settings", () => { const db = createDb(); const caller = boardRouter.createCaller({ db, session: defaultSession }); - const act = async () => + const actAsync = async () => await caller.savePartialBoardSettings({ pageTitle: "newPageTitle", metaTitle: "newMetaTitle", @@ -642,7 +642,7 @@ describe("savePartialBoardSettings should save general settings", () => { id: "nonExistentBoardId", }); - await expect(act()).rejects.toThrowError("Board not found"); + await expect(actAsync()).rejects.toThrowError("Board not found"); }); }); @@ -1151,13 +1151,13 @@ describe("saveBoard should save full board", () => { const db = createDb(); const caller = boardRouter.createCaller({ db, session: defaultSession }); - const act = async () => + const actAsync = async () => await caller.saveBoard({ id: "nonExistentBoardId", sections: [], }); - await expect(act()).rejects.toThrowError("Board not found"); + await expect(actAsync()).rejects.toThrowError("Board not found"); }); }); @@ -1168,8 +1168,8 @@ describe("getBoardPermissions should return board permissions", () => { const caller = boardRouter.createCaller({ db, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); - const user1 = await createRandomUser(db); - const user2 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); + const user2 = await createRandomUserAsync(db); await db.insert(users).values({ id: defaultCreatorId, }); @@ -1250,7 +1250,7 @@ describe("saveUserBoardPermissions should save user board permissions", () => { const caller = boardRouter.createCaller({ db, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); - const user1 = await createRandomUser(db); + const user1 = await createRandomUserAsync(db); await db.insert(users).values({ id: defaultCreatorId, }); diff --git a/packages/api/src/router/test/board/board-access.spec.ts b/packages/api/src/router/test/board/board-access.spec.ts index 794a2a0ea..6a9a8b520 100644 --- a/packages/api/src/router/test/board/board-access.spec.ts +++ b/packages/api/src/router/test/board/board-access.spec.ts @@ -9,7 +9,10 @@ import { throwIfActionForbiddenAsync } from "../../board/board-access"; const defaultCreatorId = createId(); -const expectActToBe = async (act: () => Promise, success: boolean) => { +const expectActToBeAsync = async ( + act: () => Promise, + success: boolean, +) => { if (!success) { await expect(act()).rejects.toThrow("Board not found"); return; @@ -55,7 +58,7 @@ describe("throwIfActionForbiddenAsync should check access to board and return bo ); // Assert - await expectActToBe(act, expectedResult); + await expectActToBeAsync(act, expectedResult); }, ); @@ -92,7 +95,7 @@ describe("throwIfActionForbiddenAsync should check access to board and return bo ); // Assert - await expectActToBe(act, expectedResult); + await expectActToBeAsync(act, expectedResult); }, ); @@ -129,7 +132,7 @@ describe("throwIfActionForbiddenAsync should check access to board and return bo ); // Assert - await expectActToBe(act, expectedResult); + await expectActToBeAsync(act, expectedResult); }, ); @@ -166,7 +169,7 @@ describe("throwIfActionForbiddenAsync should check access to board and return bo ); // Assert - await expectActToBe(act, expectedResult); + await expectActToBeAsync(act, expectedResult); }, ); diff --git a/packages/api/src/router/test/group.spec.ts b/packages/api/src/router/test/group.spec.ts index b52aa7630..130040a09 100644 --- a/packages/api/src/router/test/group.spec.ts +++ b/packages/api/src/router/test/group.spec.ts @@ -196,10 +196,10 @@ describe("byId should return group by id including members and permissions", () }); // Act - const act = async () => await caller.getById({ id: "1" }); + const actAsync = async () => await caller.getById({ id: "1" }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); @@ -235,13 +235,13 @@ describe("create should create group in database", () => { const longName = "a".repeat(65); // Act - const act = async () => + const actAsync = async () => await caller.createGroup({ name: longName, }); // Assert - await expect(act()).rejects.toThrow("too_big"); + await expect(actAsync()).rejects.toThrow("too_big"); }); test.each([ @@ -262,10 +262,11 @@ describe("create should create group in database", () => { }); // Act - const act = async () => await caller.createGroup({ name: nameToCreate }); + const actAsync = async () => + await caller.createGroup({ name: nameToCreate }); // Assert - await expect(act()).rejects.toThrow("similar name"); + await expect(actAsync()).rejects.toThrow("similar name"); }, ); }); @@ -330,14 +331,14 @@ describe("update should update name with value that is no duplicate", () => { ]); // Act - const act = async () => + const actAsync = async () => await caller.updateGroup({ id: groupId, name: updateValue, }); // Assert - await expect(act()).rejects.toThrow("similar name"); + await expect(actAsync()).rejects.toThrow("similar name"); }, ); @@ -408,14 +409,14 @@ describe("savePermissions should save permissions for group", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.savePermissions({ groupId: createId(), permissions: ["integration-create", "board-full-access"], }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); @@ -468,14 +469,14 @@ describe("transferOwnership should transfer ownership of group", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.transferOwnership({ groupId: createId(), userId: createId(), }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); @@ -520,13 +521,13 @@ describe("deleteGroup should delete group", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.deleteGroup({ id: createId(), }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); @@ -580,14 +581,14 @@ describe("addMember should add member to group", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.addMember({ groupId: createId(), userId: createId(), }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); @@ -644,14 +645,14 @@ describe("removeMember should remove member from group", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.removeMember({ groupId: createId(), userId: createId(), }); // Assert - await expect(act()).rejects.toThrow("Group not found"); + await expect(actAsync()).rejects.toThrow("Group not found"); }); }); diff --git a/packages/api/src/router/test/integration.spec.ts b/packages/api/src/router/test/integration.spec.ts index a1ac61aad..ca6d0eb3f 100644 --- a/packages/api/src/router/test/integration.spec.ts +++ b/packages/api/src/router/test/integration.spec.ts @@ -76,8 +76,8 @@ describe("byId should return an integration by id", () => { session: null, }); - const act = async () => await caller.byId({ id: "2" }); - await expect(act()).rejects.toThrow("Integration not found"); + const actAsync = async () => await caller.byId({ id: "2" }); + await expect(actAsync()).rejects.toThrow("Integration not found"); }); it("should only return the public secret values", async () => { @@ -258,14 +258,14 @@ describe("update should update an integration", () => { session: null, }); - const act = async () => + const actAsync = async () => await caller.update({ id: createId(), name: "Pi Hole", url: "http://hole.local", secrets: [], }); - await expect(act()).rejects.toThrow("Integration not found"); + await expect(actAsync()).rejects.toThrow("Integration not found"); }); }); @@ -343,8 +343,8 @@ describe("testConnection should test the connection to an integration", () => { secrets, }; - const act = async () => await caller.testConnection(input); - await expect(act()).rejects.toThrow("SECRETS_NOT_DEFINED"); + const actAsync = async () => await caller.testConnection(input); + await expect(actAsync()).rejects.toThrow("SECRETS_NOT_DEFINED"); }, ); @@ -373,8 +373,8 @@ describe("testConnection should test the connection to an integration", () => { secrets, }; - const act = async () => await caller.testConnection(input); - await expect(act()).resolves.toBeUndefined(); + const actAsync = async () => await caller.testConnection(input); + await expect(actAsync()).resolves.toBeUndefined(); }, ); @@ -395,8 +395,8 @@ describe("testConnection should test the connection to an integration", () => { ], }; - const act = async () => await caller.testConnection(input); - await expect(act()).resolves.toBeUndefined(); + const actAsync = async () => await caller.testConnection(input); + await expect(actAsync()).resolves.toBeUndefined(); }); it("should be successful when overriding one of the secrets for an existing nzbGet integration", async () => { @@ -439,8 +439,8 @@ describe("testConnection should test the connection to an integration", () => { ], }; - const act = async () => await caller.testConnection(input); - await expect(act()).resolves.toBeUndefined(); + const actAsync = async () => await caller.testConnection(input); + await expect(actAsync()).resolves.toBeUndefined(); }); it("should fail when a required secret is missing for an existing nzbGet integration", async () => { @@ -477,8 +477,8 @@ describe("testConnection should test the connection to an integration", () => { ], }; - const act = async () => await caller.testConnection(input); - await expect(act()).rejects.toThrow("SECRETS_NOT_DEFINED"); + const actAsync = async () => await caller.testConnection(input); + await expect(actAsync()).rejects.toThrow("SECRETS_NOT_DEFINED"); }); it("should fail when the updating integration does not exist", async () => { @@ -488,7 +488,7 @@ describe("testConnection should test the connection to an integration", () => { session: null, }); - const act = async () => + const actAsync = async () => await caller.testConnection({ id: createId(), kind: "nzbGet", @@ -498,6 +498,6 @@ describe("testConnection should test the connection to an integration", () => { { kind: "password", value: "Password123!" }, ], }); - await expect(act()).rejects.toThrow("SECRETS_NOT_DEFINED"); + await expect(actAsync()).rejects.toThrow("SECRETS_NOT_DEFINED"); }); }); diff --git a/packages/api/src/router/test/invite.spec.ts b/packages/api/src/router/test/invite.spec.ts index 8c3f7be69..59f2fad68 100644 --- a/packages/api/src/router/test/invite.spec.ts +++ b/packages/api/src/router/test/invite.spec.ts @@ -183,9 +183,9 @@ describe("delete should remove invite by id", () => { }); // Act - const act = async () => await caller.deleteInvite({ id: createId() }); + const actAsync = async () => await caller.deleteInvite({ id: createId() }); // Assert - await expect(act()).rejects.toThrow("not found"); + await expect(actAsync()).rejects.toThrow("not found"); }); }); diff --git a/packages/api/src/router/test/user.spec.ts b/packages/api/src/router/test/user.spec.ts index 9e1c68406..6873f74c6 100644 --- a/packages/api/src/router/test/user.spec.ts +++ b/packages/api/src/router/test/user.spec.ts @@ -27,14 +27,14 @@ describe("initUser should initialize the first user", () => { password: "test", }); - const act = async () => + const actAsync = async () => await caller.initUser({ username: "test", password: "12345678", confirmPassword: "12345678", }); - await expect(act()).rejects.toThrow("User already exists"); + await expect(actAsync()).rejects.toThrow("User already exists"); }); it("should create a user if none exists", async () => { @@ -66,14 +66,14 @@ describe("initUser should initialize the first user", () => { session: null, }); - const act = async () => + const actAsync = async () => await caller.initUser({ username: "test", password: "12345678", confirmPassword: "12345679", }); - await expect(act()).rejects.toThrow("Passwords do not match"); + await expect(actAsync()).rejects.toThrow("Passwords do not match"); }); it("should not create a user if the password is too short", async () => { @@ -83,14 +83,14 @@ describe("initUser should initialize the first user", () => { session: null, }); - const act = async () => + const actAsync = async () => await caller.initUser({ username: "test", password: "1234567", confirmPassword: "1234567", }); - await expect(act()).rejects.toThrow("too_small"); + await expect(actAsync()).rejects.toThrow("too_small"); }); }); @@ -175,7 +175,7 @@ describe("register should create a user with valid invitation", () => { }); // Act - const act = async () => + const actAsync = async () => await caller.register({ inviteId, token: inviteToken, @@ -186,7 +186,7 @@ describe("register should create a user with valid invitation", () => { }); // Assert - await expect(act()).rejects.toThrow("Invalid invite"); + await expect(actAsync()).rejects.toThrow("Invalid invite"); }, ); }); diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index 02bffd3f3..70e2cbd88 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -1,7 +1,7 @@ import { TRPCError } from "@trpc/server"; import { observable } from "@trpc/server/observable"; -import { createSalt, hashPassword } from "@homarr/auth"; +import { createSaltAsync, hashPasswordAsync } from "@homarr/auth"; import type { Database } from "@homarr/db"; import { and, createId, eq, schema } from "@homarr/db"; import { invites, users } from "@homarr/db/schema/sqlite"; @@ -27,7 +27,7 @@ export const userRouter = createTRPCRouter({ }); } - await createUser(ctx.db, input); + await createUserAsync(ctx.db, input); }), register: publicProcedure .input(validation.user.registrationApi) @@ -51,14 +51,14 @@ export const userRouter = createTRPCRouter({ }); } - await createUser(ctx.db, input); + await createUserAsync(ctx.db, input); // Delete invite as it's used await ctx.db.delete(invites).where(inviteWhere); }), create: publicProcedure .input(validation.user.create) .mutation(async ({ ctx, input }) => { - await createUser(ctx.db, input); + await createUserAsync(ctx.db, input); }), setProfileImage: protectedProcedure .input( @@ -209,7 +209,7 @@ export const userRouter = createTRPCRouter({ }); } - const previousPasswordHash = await hashPassword( + const previousPasswordHash = await hashPasswordAsync( input.previousPassword, dbUser.salt ?? "", ); @@ -223,8 +223,8 @@ export const userRouter = createTRPCRouter({ } } - const salt = await createSalt(); - const hashedPassword = await hashPassword(input.password, salt); + const salt = await createSaltAsync(); + const hashedPassword = await hashPasswordAsync(input.password, salt); await ctx.db .update(users) .set({ @@ -233,7 +233,7 @@ export const userRouter = createTRPCRouter({ .where(eq(users.id, input.userId)); }), setMessage: publicProcedure.input(z.string()).mutation(async ({ input }) => { - await exampleChannel.publish({ message: input }); + await exampleChannel.publishAsync({ message: input }); }), test: publicProcedure.subscription(() => { return observable<{ message: string }>((emit) => { @@ -244,12 +244,12 @@ export const userRouter = createTRPCRouter({ }), }); -const createUser = async ( +const createUserAsync = async ( db: Database, input: z.infer, ) => { - const salt = await createSalt(); - const hashedPassword = await hashPassword(input.password, salt); + const salt = await createSaltAsync(); + const hashedPassword = await hashPasswordAsync(input.password, salt); const userId = createId(); await db.insert(schema.users).values({ diff --git a/packages/auth/callbacks.ts b/packages/auth/callbacks.ts index eb90555f1..ddad44996 100644 --- a/packages/auth/callbacks.ts +++ b/packages/auth/callbacks.ts @@ -14,7 +14,7 @@ import { sessionTokenCookieName, } from "./session"; -export const getCurrentUserPermissions = async ( +export const getCurrentUserPermissionsAsync = async ( db: Database, userId: string, ) => { @@ -47,7 +47,7 @@ export const createSessionCallback = ( ...session.user, id: user.id, name: user.name, - permissions: await getCurrentUserPermissions(db, user.id), + permissions: await getCurrentUserPermissionsAsync(db, user.id), }, }; }; diff --git a/packages/auth/index.ts b/packages/auth/index.ts index 0e6b90fd9..0a555056c 100644 --- a/packages/auth/index.ts +++ b/packages/auth/index.ts @@ -20,4 +20,7 @@ export * from "./security"; export const createHandlers = (isCredentialsRequest: boolean) => createConfiguration(isCredentialsRequest); -export { getSessionFromToken, sessionTokenCookieName } from "./session"; +export { + getSessionFromTokenAsync as getSessionFromToken, + sessionTokenCookieName, +} from "./session"; diff --git a/packages/auth/providers/credentials.ts b/packages/auth/providers/credentials.ts index 42bec2497..edfd5eb62 100644 --- a/packages/auth/providers/credentials.ts +++ b/packages/auth/providers/credentials.ts @@ -22,6 +22,7 @@ export const createCredentialsConfiguration = (db: Database) => type: "password", }, }, + // eslint-disable-next-line no-restricted-syntax async authorize(credentials) { const data = await validation.user.signIn.parseAsync(credentials); diff --git a/packages/auth/providers/test/credentials.spec.ts b/packages/auth/providers/test/credentials.spec.ts index 3feb4a919..09b42d32d 100644 --- a/packages/auth/providers/test/credentials.spec.ts +++ b/packages/auth/providers/test/credentials.spec.ts @@ -4,18 +4,18 @@ import { createId } from "@homarr/db"; import { users } from "@homarr/db/schema/sqlite"; import { createDb } from "@homarr/db/test"; -import { createSalt, hashPassword } from "../../security"; +import { createSaltAsync, hashPasswordAsync } from "../../security"; import { createCredentialsConfiguration } from "../credentials"; describe("Credentials authorization", () => { it("should authorize user with correct credentials", async () => { const db = createDb(); const userId = createId(); - const salt = await createSalt(); + const salt = await createSaltAsync(); await db.insert(users).values({ id: userId, name: "test", - password: await hashPassword("test", salt), + password: await hashPasswordAsync("test", salt), salt, }); const result = await createCredentialsConfiguration(db).authorize({ @@ -38,11 +38,11 @@ describe("Credentials authorization", () => { it(`should not authorize user with incorrect credentials (${password})`, async () => { const db = createDb(); const userId = createId(); - const salt = await createSalt(); + const salt = await createSaltAsync(); await db.insert(users).values({ id: userId, name: "test", - password: await hashPassword("test", salt), + password: await hashPasswordAsync("test", salt), salt, }); const result = await createCredentialsConfiguration(db).authorize({ diff --git a/packages/auth/security.ts b/packages/auth/security.ts index 90366c7ea..cc0c16c6b 100644 --- a/packages/auth/security.ts +++ b/packages/auth/security.ts @@ -1,9 +1,9 @@ import bcrypt from "bcrypt"; -export const createSalt = async () => { +export const createSaltAsync = async () => { return bcrypt.genSalt(10); }; -export const hashPassword = async (password: string, salt: string) => { +export const hashPasswordAsync = async (password: string, salt: string) => { return bcrypt.hash(password, salt); }; diff --git a/packages/auth/session.ts b/packages/auth/session.ts index 45b026859..40dbf874c 100644 --- a/packages/auth/session.ts +++ b/packages/auth/session.ts @@ -3,7 +3,7 @@ import type { Session } from "@auth/core/types"; import type { Database } from "@homarr/db"; -import { getCurrentUserPermissions } from "./callbacks"; +import { getCurrentUserPermissionsAsync } from "./callbacks"; export const sessionMaxAgeInSeconds = 30 * 24 * 60 * 60; // 30 days export const sessionTokenCookieName = "next-auth.session-token"; @@ -16,7 +16,7 @@ export const generateSessionToken = () => { return randomUUID(); }; -export const getSessionFromToken = async ( +export const getSessionFromTokenAsync = async ( db: Database, token: string | undefined, ): Promise => { @@ -48,7 +48,7 @@ export const getSessionFromToken = async ( return { user: { ...session.user, - permissions: await getCurrentUserPermissions(db, session.user.id), + permissions: await getCurrentUserPermissionsAsync(db, session.user.id), }, expires: session.expires.toISOString(), }; diff --git a/packages/auth/test/callbacks.spec.ts b/packages/auth/test/callbacks.spec.ts index ffb8fb5d4..679669627 100644 --- a/packages/auth/test/callbacks.spec.ts +++ b/packages/auth/test/callbacks.spec.ts @@ -18,7 +18,7 @@ import * as definitions from "@homarr/definitions"; import { createSessionCallback, createSignInCallback, - getCurrentUserPermissions, + getCurrentUserPermissionsAsync, } from "../callbacks"; describe("getCurrentUserPermissions", () => { @@ -30,7 +30,7 @@ describe("getCurrentUserPermissions", () => { }); const userId = "1"; - const result = await getCurrentUserPermissions(db, userId); + const result = await getCurrentUserPermissionsAsync(db, userId); expect(result).toEqual([]); }); test("should return permissions for user", async () => { @@ -56,7 +56,7 @@ describe("getCurrentUserPermissions", () => { permission: "admin", }); - const result = await getCurrentUserPermissions(db, mockId); + const result = await getCurrentUserPermissionsAsync(db, mockId); expect(result).toEqual(["board-create"]); expect(getPermissionsWithChildrenMock).toHaveBeenCalledWith(["admin"]); }); diff --git a/packages/auth/test/security.spec.ts b/packages/auth/test/security.spec.ts index f0f186966..fed59513b 100644 --- a/packages/auth/test/security.spec.ts +++ b/packages/auth/test/security.spec.ts @@ -1,16 +1,16 @@ import { describe, expect, it } from "vitest"; -import { createSalt, hashPassword } from "../security"; +import { createSaltAsync, hashPasswordAsync } from "../security"; describe("createSalt should return a salt", () => { it("should return a salt", async () => { - const result = await createSalt(); + const result = await createSaltAsync(); expect(result).toBeDefined(); expect(result.length).toBeGreaterThan(25); }); it("should return a different salt each time", async () => { - const result1 = await createSalt(); - const result2 = await createSalt(); + const result1 = await createSaltAsync(); + const result2 = await createSaltAsync(); expect(result1).not.toEqual(result2); }); }); @@ -18,8 +18,8 @@ describe("createSalt should return a salt", () => { describe("hashPassword should return a hash", () => { it("should return a hash", async () => { const password = "password"; - const salt = await createSalt(); - const result = await hashPassword(password, salt); + const salt = await createSaltAsync(); + const result = await hashPasswordAsync(password, salt); expect(result).toBeDefined(); expect(result.length).toBeGreaterThan(55); expect(result).not.toEqual(password); @@ -27,20 +27,20 @@ describe("hashPassword should return a hash", () => { it("should return a different hash each time", async () => { const password = "password"; const password2 = "another password"; - const salt = await createSalt(); + const salt = await createSaltAsync(); - const result1 = await hashPassword(password, salt); - const result2 = await hashPassword(password2, salt); + const result1 = await hashPasswordAsync(password, salt); + const result2 = await hashPasswordAsync(password2, salt); expect(result1).not.toEqual(result2); }); it("should return a different hash for the same password with different salts", async () => { const password = "password"; - const salt1 = await createSalt(); - const salt2 = await createSalt(); + const salt1 = await createSaltAsync(); + const salt2 = await createSaltAsync(); - const result1 = await hashPassword(password, salt1); - const result2 = await hashPassword(password, salt2); + const result1 = await hashPasswordAsync(password, salt1); + const result2 = await hashPasswordAsync(password, salt2); expect(result1).not.toEqual(result2); }); diff --git a/packages/redis/src/lib/channel.ts b/packages/redis/src/lib/channel.ts index b3e792c4f..a80a8fb19 100644 --- a/packages/redis/src/lib/channel.ts +++ b/packages/redis/src/lib/channel.ts @@ -46,7 +46,7 @@ export const createSubPubChannel = (name: string) => { * Publish data to the channel with last data saved. * @param data data to be published */ - publish: async (data: TData) => { + publishAsync: async (data: TData) => { await lastDataClient.set(lastChannelName, superjson.stringify(data)); await publisher.publish(channelName, superjson.stringify(data)); }, @@ -64,11 +64,11 @@ type WithId = TItem & { _id: string }; */ export const createQueueChannel = (name: string) => { const queueChannelName = `queue:${name}`; - const getData = async () => { + const getDataAsync = async () => { const data = await queueClient.get(queueChannelName); return data ? superjson.parse[]>(data) : []; }; - const setData = async (data: WithId[]) => { + const setDataAsync = async (data: WithId[]) => { await queueClient.set(queueChannelName, superjson.stringify(data)); }; @@ -77,22 +77,22 @@ export const createQueueChannel = (name: string) => { * Add a new queue execution. * @param data data to be stored in the queue execution to run it later */ - add: async (data: TItem) => { - const items = await getData(); + addAsync: async (data: TItem) => { + const items = await getDataAsync(); items.push({ _id: createId(), ...data }); - await setData(items); + await setDataAsync(items); }, /** * Get all queue executions. */ - all: getData, + all: getDataAsync, /** * Get a queue execution by its id. * @param id id of the queue execution (stored under _id key) * @returns queue execution or undefined if not found */ - byId: async (id: string) => { - const items = await getData(); + byIdAsync: async (id: string) => { + const items = await getDataAsync(); return items.find((item) => item._id === id); }, /** @@ -100,17 +100,17 @@ export const createQueueChannel = (name: string) => { * @param filter callback function that returns true if the item should be included in the result * @returns filtered queue executions */ - filter: async (filter: (item: WithId) => boolean) => { - const items = await getData(); + filterAsync: async (filter: (item: WithId) => boolean) => { + const items = await getDataAsync(); return items.filter(filter); }, /** * Marks an queue execution as done, by deleting it. * @param id id of the queue execution (stored under _id key) */ - markAsDone: async (id: string) => { - const items = await getData(); - await setData(items.filter((item) => item._id !== id)); + markAsDoneAsync: async (id: string) => { + const items = await getDataAsync(); + await setDataAsync(items.filter((item) => item._id !== id)); }, }; }; diff --git a/packages/widgets/src/app/serverData.ts b/packages/widgets/src/app/serverData.ts index 3783692e2..730d449a5 100644 --- a/packages/widgets/src/app/serverData.ts +++ b/packages/widgets/src/app/serverData.ts @@ -4,7 +4,9 @@ import { api } from "@homarr/api/server"; import type { WidgetProps } from "../definition"; -export default async function getServerData({ options }: WidgetProps<"app">) { +export default async function getServerDataAsync({ + options, +}: WidgetProps<"app">) { try { const app = await api.app.byId({ id: options.appId }); return { app }; diff --git a/tooling/eslint/base.js b/tooling/eslint/base.js index 8a222151c..fe08052ed 100644 --- a/tooling/eslint/base.js +++ b/tooling/eslint/base.js @@ -40,6 +40,48 @@ const config = { { checksVoidReturn: { attributes: false } }, ], "import/consistent-type-specifier-style": ["error", "prefer-top-level"], + "no-restricted-syntax": [ + "error", + { + selector: "FunctionDeclaration[async=false][id.name=/Async$/]", + message: "Function ending in 'Async' must be declared async", + }, + { + selector: + "FunctionDeclaration[async=true][id.name=/^[a-z].*$/][id.name=/ ^(?!generateMetadata$)[a-z].*$/][id.name!=/Async$/]", + message: + "Async function name must end in 'Async' (function declaration)", + }, + { + selector: "MethodDefinition[value.async=false][key.name=/Async$/]", + message: "Method ending in 'Async' must be declared async", + }, + { + selector: "MethodDefinition[value.async=true][key.name!=/Async$/]", + message: "Async method name must end in 'Async'", + }, + { + selector: + "Property[value.type=/FunctionExpression$/][value.async=false][key.name=/Async$/]", + message: "Function ending in 'Async' must be declared async", + }, + { + selector: + "Property[value.type=/FunctionExpression$/][value.async=true][key.name!=/^on(Success|Settled)$/][key.name!=/Async$/]", + message: "Async function name must end in 'Async' (property)", + }, + { + selector: + "VariableDeclarator[init.type=/FunctionExpression$/][init.async=false][id.name=/Async$/]", + message: "Function ending in 'Async' must be declared async", + }, + { + selector: + "VariableDeclarator[init.type=/FunctionExpression$/][init.async=true][id.name=/^[a-z].*$/][id.name!=/Async$/]", + message: + "Async function name must end in 'Async' (variable declarator)", + }, + ], }, ignorePatterns: [ "**/.eslintrc.cjs",