aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.husky/pre-commit2
-rw-r--r--apps/browser-extension/package.json1
-rw-r--r--apps/browser-extension/src/BookmarkSavedPage.tsx9
-rw-r--r--apps/browser-extension/src/Layout.tsx4
-rw-r--r--apps/browser-extension/src/NotConfiguredPage.tsx3
-rw-r--r--apps/browser-extension/src/OptionsPage.tsx7
-rw-r--r--apps/browser-extension/src/SavePage.tsx3
-rw-r--r--apps/browser-extension/src/SignInPage.tsx5
-rw-r--r--apps/browser-extension/src/main.tsx13
-rw-r--r--apps/browser-extension/src/utils/providers.tsx7
-rw-r--r--apps/browser-extension/src/utils/trpc.ts1
-rw-r--r--apps/browser-extension/vite.config.ts5
-rw-r--r--apps/mobile/app.json5
-rw-r--r--apps/mobile/app/dashboard/(tabs)/_layout.tsx4
-rw-r--r--apps/mobile/app/dashboard/(tabs)/index.tsx13
-rw-r--r--apps/mobile/app/dashboard/(tabs)/lists.tsx8
-rw-r--r--apps/mobile/app/dashboard/(tabs)/search.tsx2
-rw-r--r--apps/mobile/app/dashboard/(tabs)/settings.tsx2
-rw-r--r--apps/mobile/app/dashboard/archive.tsx7
-rw-r--r--apps/mobile/app/dashboard/favourites.tsx2
-rw-r--r--apps/mobile/app/dashboard/lists/[slug].tsx2
-rw-r--r--apps/mobile/app/dashboard/tags/[slug].tsx2
-rw-r--r--apps/mobile/app/index.tsx18
-rw-r--r--apps/mobile/app/signin.tsx4
-rw-r--r--apps/mobile/components/Logo.tsx17
-rw-r--r--apps/mobile/components/bookmarks/BookmarkList.tsx8
-rw-r--r--apps/mobile/components/ui/PageTitle.tsx2
-rw-r--r--apps/mobile/index.ts2
-rw-r--r--apps/mobile/lib/upload.ts48
-rw-r--r--apps/mobile/package.json1
-rw-r--r--apps/mobile/tailwind.config.ts1
-rw-r--r--apps/workers/crawlerWorker.ts11
-rw-r--r--apps/workers/exit.ts2
-rw-r--r--apps/workers/index.ts7
-rw-r--r--apps/workers/inference.ts10
-rw-r--r--apps/workers/openaiWorker.ts28
-rw-r--r--apps/workers/package.json2
-rw-r--r--apps/workers/searchWorker.ts2
-rw-r--r--packages/shared/assetdb.ts19
-rw-r--r--packages/shared/logger.ts1
-rw-r--r--packages/shared/package.json5
-rw-r--r--packages/shared/search.ts32
-rw-r--r--packages/trpc/auth.ts3
-rw-r--r--packages/trpc/index.ts19
-rw-r--r--packages/trpc/package.json2
-rw-r--r--packages/trpc/routers/_app.ts1
-rw-r--r--packages/trpc/routers/admin.ts6
-rw-r--r--packages/trpc/routers/apiKeys.ts10
-rw-r--r--packages/trpc/routers/bookmarks.test.ts6
-rw-r--r--packages/trpc/routers/bookmarks.ts44
-rw-r--r--packages/trpc/routers/lists.ts3
-rw-r--r--packages/trpc/routers/users.test.ts10
-rw-r--r--packages/trpc/testUtils.ts7
-rw-r--r--packages/trpc/tsconfig.json3
-rw-r--r--packages/trpc/types/bookmarks.ts3
-rw-r--r--packages/trpc/vitest.config.ts2
-rw-r--r--tooling/eslint/base.js1
57 files changed, 255 insertions, 192 deletions
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 09be6810..1c6782b0 100644
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,3 +1,3 @@
pnpm typecheck
-pnpm format
+pnpm format --check
pnpm lint
diff --git a/apps/browser-extension/package.json b/apps/browser-extension/package.json
index cc5068b7..35c899bc 100644
--- a/apps/browser-extension/package.json
+++ b/apps/browser-extension/package.json
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
+ "format": "prettier .",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
diff --git a/apps/browser-extension/src/BookmarkSavedPage.tsx b/apps/browser-extension/src/BookmarkSavedPage.tsx
index 5ff2cd39..54f62796 100644
--- a/apps/browser-extension/src/BookmarkSavedPage.tsx
+++ b/apps/browser-extension/src/BookmarkSavedPage.tsx
@@ -1,9 +1,10 @@
-import { Link, useNavigate, useParams } from "react-router-dom";
-import { api } from "./utils/trpc";
-import usePluginSettings from "./utils/settings";
+import { useState } from "react";
import { ArrowUpRightFromSquare, Trash } from "lucide-react";
+import { Link, useNavigate, useParams } from "react-router-dom";
+
import Spinner from "./Spinner";
-import { useState } from "react";
+import usePluginSettings from "./utils/settings";
+import { api } from "./utils/trpc";
export default function BookmarkSavedPage() {
const { bookmarkId } = useParams();
diff --git a/apps/browser-extension/src/Layout.tsx b/apps/browser-extension/src/Layout.tsx
index 3eb85abd..bf760362 100644
--- a/apps/browser-extension/src/Layout.tsx
+++ b/apps/browser-extension/src/Layout.tsx
@@ -1,6 +1,6 @@
-import { Outlet } from "react-router-dom";
import { Home, RefreshCw, Settings, X } from "lucide-react";
-import { useNavigate } from "react-router-dom";
+import { Outlet, useNavigate } from "react-router-dom";
+
import usePluginSettings from "./utils/settings";
export default function Layout() {
diff --git a/apps/browser-extension/src/NotConfiguredPage.tsx b/apps/browser-extension/src/NotConfiguredPage.tsx
index cad87303..298e9f5e 100644
--- a/apps/browser-extension/src/NotConfiguredPage.tsx
+++ b/apps/browser-extension/src/NotConfiguredPage.tsx
@@ -1,7 +1,8 @@
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
-import usePluginSettings from "./utils/settings";
+
import Logo from "./Logo";
+import usePluginSettings from "./utils/settings";
export default function NotConfiguredPage() {
const navigate = useNavigate();
diff --git a/apps/browser-extension/src/OptionsPage.tsx b/apps/browser-extension/src/OptionsPage.tsx
index 6407b3cc..9670558e 100644
--- a/apps/browser-extension/src/OptionsPage.tsx
+++ b/apps/browser-extension/src/OptionsPage.tsx
@@ -1,9 +1,10 @@
import React, { useEffect } from "react";
-import usePluginSettings from "./utils/settings";
-import { api } from "./utils/trpc";
-import Spinner from "./Spinner";
import { useNavigate } from "react-router-dom";
+
import Logo from "./Logo";
+import Spinner from "./Spinner";
+import usePluginSettings from "./utils/settings";
+import { api } from "./utils/trpc";
export default function OptionsPage() {
const navigate = useNavigate();
diff --git a/apps/browser-extension/src/SavePage.tsx b/apps/browser-extension/src/SavePage.tsx
index 638af149..9cc1521a 100644
--- a/apps/browser-extension/src/SavePage.tsx
+++ b/apps/browser-extension/src/SavePage.tsx
@@ -1,7 +1,8 @@
import { useEffect, useState } from "react";
+import { Navigate } from "react-router-dom";
+
import Spinner from "./Spinner";
import { api } from "./utils/trpc";
-import { Navigate } from "react-router-dom";
export default function SavePage() {
const [error, setError] = useState<string | undefined>(undefined);
diff --git a/apps/browser-extension/src/SignInPage.tsx b/apps/browser-extension/src/SignInPage.tsx
index 5c49965c..a9b77e83 100644
--- a/apps/browser-extension/src/SignInPage.tsx
+++ b/apps/browser-extension/src/SignInPage.tsx
@@ -1,8 +1,9 @@
import { useState } from "react";
-import { api } from "./utils/trpc";
-import usePluginSettings from "./utils/settings";
import { useNavigate } from "react-router-dom";
+
import Logo from "./Logo";
+import usePluginSettings from "./utils/settings";
+import { api } from "./utils/trpc";
export default function SignInPage() {
const navigate = useNavigate();
diff --git a/apps/browser-extension/src/main.tsx b/apps/browser-extension/src/main.tsx
index 085a5a69..65456012 100644
--- a/apps/browser-extension/src/main.tsx
+++ b/apps/browser-extension/src/main.tsx
@@ -1,14 +1,17 @@
import ReactDOM from "react-dom/client";
+
import "./index.css";
-import OptionsPage from "./OptionsPage.tsx";
-import NotConfiguredPage from "./NotConfiguredPage.tsx";
-import { Providers } from "./utils/providers.tsx";
+
+import { HashRouter, Route, Routes } from "react-router-dom";
+
+import BookmarkDeletedPage from "./BookmarkDeletedPage.tsx";
import BookmarkSavedPage from "./BookmarkSavedPage.tsx";
-import { HashRouter, Routes, Route } from "react-router-dom";
import Layout from "./Layout.tsx";
+import NotConfiguredPage from "./NotConfiguredPage.tsx";
+import OptionsPage from "./OptionsPage.tsx";
import SavePage from "./SavePage.tsx";
-import BookmarkDeletedPage from "./BookmarkDeletedPage.tsx";
import SignInPage from "./SignInPage.tsx";
+import { Providers } from "./utils/providers.tsx";
function App() {
return (
diff --git a/apps/browser-extension/src/utils/providers.tsx b/apps/browser-extension/src/utils/providers.tsx
index d20f2512..7b14b22c 100644
--- a/apps/browser-extension/src/utils/providers.tsx
+++ b/apps/browser-extension/src/utils/providers.tsx
@@ -1,10 +1,11 @@
+import { useEffect, useState } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink } from "@trpc/client";
-import { useEffect, useState } from "react";
-import { api } from "./trpc";
-import usePluginSettings, { getPluginSettings } from "./settings";
import superjson from "superjson";
+import usePluginSettings, { getPluginSettings } from "./settings";
+import { api } from "./trpc";
+
function getTRPCClient(address: string) {
return api.createClient({
links: [
diff --git a/apps/browser-extension/src/utils/trpc.ts b/apps/browser-extension/src/utils/trpc.ts
index da21a55a..9b025df1 100644
--- a/apps/browser-extension/src/utils/trpc.ts
+++ b/apps/browser-extension/src/utils/trpc.ts
@@ -1,4 +1,5 @@
import { createTRPCReact } from "@trpc/react-query";
+
import type { AppRouter } from "@hoarder/trpc/routers/_app";
export const api = createTRPCReact<AppRouter>();
diff --git a/apps/browser-extension/vite.config.ts b/apps/browser-extension/vite.config.ts
index 29c6bc6e..42ecc28d 100644
--- a/apps/browser-extension/vite.config.ts
+++ b/apps/browser-extension/vite.config.ts
@@ -1,6 +1,7 @@
-import { defineConfig } from "vite";
-import react from "@vitejs/plugin-react-swc";
import { crx } from "@crxjs/vite-plugin";
+import react from "@vitejs/plugin-react-swc";
+import { defineConfig } from "vite";
+
import manifest from "./manifest.json";
// https://vitejs.dev/config/
diff --git a/apps/mobile/app.json b/apps/mobile/app.json
index 028286e4..fec59de5 100644
--- a/apps/mobile/app.json
+++ b/apps/mobile/app.json
@@ -39,10 +39,7 @@
"NSExtensionActivationSupportsMovieWithMaxCount": 0,
"NSExtensionActivationSupportsText": true
},
- "androidIntentFilters": [
- "text/*",
- "image/*"
- ]
+ "androidIntentFilters": ["text/*", "image/*"]
}
],
"expo-secure-store",
diff --git a/apps/mobile/app/dashboard/(tabs)/_layout.tsx b/apps/mobile/app/dashboard/(tabs)/_layout.tsx
index fe40215e..7967b5c6 100644
--- a/apps/mobile/app/dashboard/(tabs)/_layout.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/_layout.tsx
@@ -1,8 +1,8 @@
import React, { useEffect } from "react";
+import { Platform } from "react-native";
+import * as NavigationBar from "expo-navigation-bar";
import { Tabs } from "expo-router";
import { ClipboardList, Home, Search, Settings } from "lucide-react-native";
-import { Platform } from "react-native";
-import * as NavigationBar from 'expo-navigation-bar';
export default function TabLayout() {
useEffect(() => {
diff --git a/apps/mobile/app/dashboard/(tabs)/index.tsx b/apps/mobile/app/dashboard/(tabs)/index.tsx
index 804eb0b5..5dccc845 100644
--- a/apps/mobile/app/dashboard/(tabs)/index.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/index.tsx
@@ -3,21 +3,21 @@ import * as Haptics from "expo-haptics";
import * as ImagePicker from "expo-image-picker";
import { useRouter } from "expo-router";
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import PageTitle from "@/components/ui/PageTitle";
+import { useToast } from "@/components/ui/Toast";
import useAppSettings from "@/lib/settings";
import { useUploadAsset } from "@/lib/upload";
import { MenuView } from "@react-native-menu/menu";
import { SquarePen } from "lucide-react-native";
-import { useToast } from "@/components/ui/Toast";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
function HeaderRight() {
- const {toast} = useToast();
+ const { toast } = useToast();
const router = useRouter();
const { settings } = useAppSettings();
const { uploadAsset } = useUploadAsset(settings, {
onError: (e) => {
- toast({message: e, variant: "destructive"});
+ toast({ message: e, variant: "destructive" });
},
});
return (
@@ -69,7 +69,10 @@ function HeaderRight() {
shouldOpenOnLongPress={false}
>
<View className="my-auto px-4">
- <SquarePen color="rgb(0, 122, 255)" onPress={() => Haptics.selectionAsync()} />
+ <SquarePen
+ color="rgb(0, 122, 255)"
+ onPress={() => Haptics.selectionAsync()}
+ />
</View>
</MenuView>
);
diff --git a/apps/mobile/app/dashboard/(tabs)/lists.tsx b/apps/mobile/app/dashboard/(tabs)/lists.tsx
index 0350ebd2..767b9256 100644
--- a/apps/mobile/app/dashboard/(tabs)/lists.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/lists.tsx
@@ -1,10 +1,10 @@
import { useEffect, useState } from "react";
import { FlatList, Pressable, Text, View } from "react-native";
import { Link } from "expo-router";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
+import PageTitle from "@/components/ui/PageTitle";
import { api } from "@/lib/trpc";
import { ChevronRight } from "lucide-react-native";
-import PageTitle from "@/components/ui/PageTitle";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
export default function Lists() {
const [refreshing, setRefreshing] = useState(false);
@@ -51,9 +51,7 @@ export default function Lists() {
return (
<CustomSafeAreaView>
<FlatList
- ListHeaderComponent={
- <PageTitle title="Lists" />
- }
+ ListHeaderComponent={<PageTitle title="Lists" />}
contentContainerStyle={{
gap: 5,
}}
diff --git a/apps/mobile/app/dashboard/(tabs)/search.tsx b/apps/mobile/app/dashboard/(tabs)/search.tsx
index bcaee5af..0a4dcbfd 100644
--- a/apps/mobile/app/dashboard/(tabs)/search.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/search.tsx
@@ -1,13 +1,13 @@
import { useState } from "react";
import { View } from "react-native";
import BookmarkList from "@/components/bookmarks/BookmarkList";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
import { Input } from "@/components/ui/Input";
import PageTitle from "@/components/ui/PageTitle";
import { api } from "@/lib/trpc";
import { keepPreviousData } from "@tanstack/react-query";
import { useDebounce } from "use-debounce";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
export default function Search() {
const [search, setSearch] = useState("");
diff --git a/apps/mobile/app/dashboard/(tabs)/settings.tsx b/apps/mobile/app/dashboard/(tabs)/settings.tsx
index 0dbf7da6..c2db2846 100644
--- a/apps/mobile/app/dashboard/(tabs)/settings.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/settings.tsx
@@ -1,9 +1,9 @@
import { Text, View } from "react-native";
import { Button } from "@/components/ui/Button";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import PageTitle from "@/components/ui/PageTitle";
import { useSession } from "@/lib/session";
import { api } from "@/lib/trpc";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
export default function Dashboard() {
const { logout } = useSession();
diff --git a/apps/mobile/app/dashboard/archive.tsx b/apps/mobile/app/dashboard/archive.tsx
index e622a3e4..2fe5d274 100644
--- a/apps/mobile/app/dashboard/archive.tsx
+++ b/apps/mobile/app/dashboard/archive.tsx
@@ -1,11 +1,14 @@
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
-import PageTitle from "@/components/ui/PageTitle";
import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
+import PageTitle from "@/components/ui/PageTitle";
export default function Archive() {
return (
<CustomSafeAreaView>
- <UpdatingBookmarkList query={{archived: true}} header={<PageTitle title="🗄️ Archive" />} />
+ <UpdatingBookmarkList
+ query={{ archived: true }}
+ header={<PageTitle title="🗄️ Archive" />}
+ />
</CustomSafeAreaView>
);
}
diff --git a/apps/mobile/app/dashboard/favourites.tsx b/apps/mobile/app/dashboard/favourites.tsx
index 213cc918..abda5cfa 100644
--- a/apps/mobile/app/dashboard/favourites.tsx
+++ b/apps/mobile/app/dashboard/favourites.tsx
@@ -1,6 +1,6 @@
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
-import PageTitle from "@/components/ui/PageTitle";
import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
+import PageTitle from "@/components/ui/PageTitle";
export default function Favourites() {
return (
diff --git a/apps/mobile/app/dashboard/lists/[slug].tsx b/apps/mobile/app/dashboard/lists/[slug].tsx
index c0b86a0f..d42cc653 100644
--- a/apps/mobile/app/dashboard/lists/[slug].tsx
+++ b/apps/mobile/app/dashboard/lists/[slug].tsx
@@ -1,10 +1,10 @@
import { View } from "react-native";
import { Stack, useLocalSearchParams } from "expo-router";
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
import PageTitle from "@/components/ui/PageTitle";
import { api } from "@/lib/trpc";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
export default function ListView() {
const { slug } = useLocalSearchParams();
diff --git a/apps/mobile/app/dashboard/tags/[slug].tsx b/apps/mobile/app/dashboard/tags/[slug].tsx
index 26aa47ec..ea1ef63d 100644
--- a/apps/mobile/app/dashboard/tags/[slug].tsx
+++ b/apps/mobile/app/dashboard/tags/[slug].tsx
@@ -1,10 +1,10 @@
import { View } from "react-native";
import { Stack, useLocalSearchParams } from "expo-router";
import UpdatingBookmarkList from "@/components/bookmarks/UpdatingBookmarkList";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
import PageTitle from "@/components/ui/PageTitle";
import { api } from "@/lib/trpc";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
export default function TagView() {
const { slug } = useLocalSearchParams();
diff --git a/apps/mobile/app/index.tsx b/apps/mobile/app/index.tsx
index 235b19e4..dbbea97e 100644
--- a/apps/mobile/app/index.tsx
+++ b/apps/mobile/app/index.tsx
@@ -1,16 +1,16 @@
-import { useIsLoggedIn } from "@/lib/session";
import { Redirect } from "expo-router";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
+import { useIsLoggedIn } from "@/lib/session";
export default function App() {
const isLoggedIn = useIsLoggedIn();
- if (isLoggedIn === undefined) {
- // Wait until it's loaded
- return <FullPageSpinner />;
- } else if (isLoggedIn) {
- return <Redirect href="dashboard" />
- } else {
- return <Redirect href="signin" />
- }
+ if (isLoggedIn === undefined) {
+ // Wait until it's loaded
+ return <FullPageSpinner />;
+ } else if (isLoggedIn) {
+ return <Redirect href="dashboard" />;
+ } else {
+ return <Redirect href="signin" />;
+ }
}
diff --git a/apps/mobile/app/signin.tsx b/apps/mobile/app/signin.tsx
index 2255424e..8402bd43 100644
--- a/apps/mobile/app/signin.tsx
+++ b/apps/mobile/app/signin.tsx
@@ -69,9 +69,7 @@ export default function Signin() {
value={settings.address}
autoCapitalize="none"
keyboardType="url"
- onChangeText={(e) =>
- setSettings({ ...settings, address: e })
- }
+ onChangeText={(e) => setSettings({ ...settings, address: e })}
/>
</View>
<View className="gap-2">
diff --git a/apps/mobile/components/Logo.tsx b/apps/mobile/components/Logo.tsx
index 9fdd1083..ba949ed4 100644
--- a/apps/mobile/components/Logo.tsx
+++ b/apps/mobile/components/Logo.tsx
@@ -1,11 +1,9 @@
-import * as React from "react"
-import type { SvgProps} from "react-native-svg";
-import Svg, { Path } from "react-native-svg"
+import type { SvgProps } from "react-native-svg";
+import * as React from "react";
+import Svg, { Path } from "react-native-svg";
+
const Logo = (props: SvgProps) => (
- <Svg
- viewBox="0 0 507 96"
- {...props}
- >
+ <Svg viewBox="0 0 507 96" {...props}>
<Path
d="M341.09 287.81c-.72-2.79-1.89-5.27-3.51-7.42s-3.74-3.9-6.34-5.26-6.5-2.32-10.33-2.04c-14.17 1.03-14.91 13.45-16.19 15.72l-.23-7v-24.46h-19.44v73.7h19.44v-22.5c0-3.4.89-7.2 2.63-9.5 1.73-2.3 4.2-2.5 7.45-2.5 1.66 0 3.01.32 4.07.96s1.91 1.51 2.55 2.6c.64 1.1 1.07 2.36 1.3 3.8.23 1.43.34 2.94.34 4.52v22.62h19.33v-34.87c0-2.79-.36-5.58-1.07-8.37m68.79 1.58c-1.66-3.69-3.92-6.83-6.79-9.39-2.87-2.57-6.19-4.53-9.96-5.89-3.78-1.36-7.81-2.04-12.11-2.04s-8.25.68-12.06 2.04-7.13 3.32-9.96 5.89c-2.83 2.56-5.07 5.7-6.73 9.39q-2.49 5.55-2.49 12.45c0 4.6.83 8.78 2.49 12.51 1.66 3.74 3.9 6.91 6.73 9.51s6.15 4.62 9.96 6.05q5.715 2.16 12.06 2.16c4.23 0 8.33-.72 12.11-2.16 3.77-1.43 7.09-3.45 9.96-6.05s5.13-5.77 6.79-9.51q2.49-5.595 2.49-12.51c0-4.61-.83-8.75-2.49-12.45m-16.24 17.77c-.57 1.74-1.42 3.31-2.55 4.7-1.13 1.4-2.53 2.51-4.19 3.34s-3.58 1.24-5.77 1.24-4.11-.41-5.77-1.24-3.06-1.94-4.19-3.34a14.6 14.6 0 0 1-2.55-4.7c-.56-1.73-.85-3.51-.85-5.32s.29-3.58.85-5.32c.57-1.73 1.4-3.26 2.49-4.58 1.1-1.32 2.47-2.4 4.13-3.23s3.59-1.24 5.78-1.24 4.11.41 5.77 1.24 3.06 1.91 4.19 3.23 2 2.85 2.6 4.58c.6 1.74.91 3.51.91 5.32s-.29 3.59-.85 5.32m73.12-18.62c-.95-3.73-2.44-6.83-4.47-9.28q-3.06-3.675-7.98-5.43c-3.29-1.17-7.3-1.76-12.06-1.76s-9.11.8-13.52 2.38c-4.42 1.59-8.29 3.96-11.61 7.13l9.4 10.08c1.73-1.59 3.83-2.95 6.28-4.08s5-1.7 7.64-1.7c2.87 0 5.28.66 7.25 1.98 1.96 1.33 2.94 3.38 2.94 6.17v.91c-4.08 0-8.26.22-12.57.68-4.3.45-8.2 1.36-11.71 2.71-3.51 1.36-6.38 3.29-8.6 5.78-2.23 2.49-3.34 5.77-3.34 9.84 0 3.33.64 6.12 1.92 8.38s2.93 4.08 4.93 5.43c1.99 1.36 4.2 2.34 6.62 2.95 2.41.6 4.75.9 7.01.9 3.4 0 5.93-.34 8.66-1.97 4.32-2.57 7.31-13.68 7.31-13.68l.33 8.28v6h16.98v-28.41c0-5.13-.47-9.56-1.41-13.3zm-15.57 19.08c0 3.54-1 6.35-2.99 8.43-2.01 2.07-4.89 3.11-8.66 3.11-.91 0-1.85-.09-2.83-.28-.99-.19-1.85-.51-2.61-.96a5.9 5.9 0 0 1-1.87-1.81c-.49-.76-.73-1.66-.73-2.72 0-1.66.53-3 1.58-4.02 1.06-1.02 2.4-1.79 4.02-2.32q2.43-.795 5.55-1.08c2.07-.18 4.13-.28 6.17-.28h2.37zm60.17-35.21c-.72-.07-1.46-.11-2.21-.11-3.47 0-6.53.91-9.17 2.74-2.64 1.82-4.68 10.18-6.11 13.06h-.23v-14.15h-17.88v56.14l18.56.22v-28.95c0-1.13.23-2.45.68-3.95.45-1.51 1.19-2.9 2.21-4.18s2.37-2.37 4.07-3.28c1.7-.9 3.79-1.35 6.28-1.35.76 0 1.53.04 2.32.11.67.07 1.36.18 2.05.36.13.03.26.06.39.1l.06-1.16.73-15.26c-.45-.15-1.04-.26-1.75-.34"
transform="translate(-173 -247)"
@@ -15,6 +13,5 @@ const Logo = (props: SvgProps) => (
transform="translate(-173 -247)"
/>
</Svg>
-)
-export default Logo
-
+);
+export default Logo;
diff --git a/apps/mobile/components/bookmarks/BookmarkList.tsx b/apps/mobile/components/bookmarks/BookmarkList.tsx
index 9176f66d..7477992d 100644
--- a/apps/mobile/components/bookmarks/BookmarkList.tsx
+++ b/apps/mobile/components/bookmarks/BookmarkList.tsx
@@ -16,11 +16,11 @@ export default function BookmarkList({
isRefreshing,
}: {
bookmarks: ZBookmark[];
- onRefresh: () => void,
- isRefreshing: boolean,
- fetchNextPage?: () => void,
+ onRefresh: () => void;
+ isRefreshing: boolean;
+ fetchNextPage?: () => void;
header?: React.ReactElement;
- isFetchingNextPage?: boolean,
+ isFetchingNextPage?: boolean;
}) {
const flatListRef = useRef(null);
useScrollToTop(flatListRef);
diff --git a/apps/mobile/components/ui/PageTitle.tsx b/apps/mobile/components/ui/PageTitle.tsx
index 1d1a8400..57b19e7d 100644
--- a/apps/mobile/components/ui/PageTitle.tsx
+++ b/apps/mobile/components/ui/PageTitle.tsx
@@ -1,4 +1,4 @@
-import {Text} from "react-native";
+import { Text } from "react-native";
export default function PageTitle({ title }: { title: string }) {
return <Text className="p-4 text-4xl font-bold">{title}</Text>;
diff --git a/apps/mobile/index.ts b/apps/mobile/index.ts
index 5b834183..80d3d998 100644
--- a/apps/mobile/index.ts
+++ b/apps/mobile/index.ts
@@ -1 +1 @@
-import 'expo-router/entry';
+import "expo-router/entry";
diff --git a/apps/mobile/lib/upload.ts b/apps/mobile/lib/upload.ts
index d511becc..56b2c7a5 100644
--- a/apps/mobile/lib/upload.ts
+++ b/apps/mobile/lib/upload.ts
@@ -1,38 +1,40 @@
import { useMutation } from "@tanstack/react-query";
+import type { ZBookmark } from "@hoarder/trpc/types/bookmarks";
+import {
+ zUploadErrorSchema,
+ zUploadResponseSchema,
+} from "@hoarder/trpc/types/uploads";
+
import type { Settings } from "./settings";
import { api } from "./trpc";
-import type { ZBookmark } from "@hoarder/trpc/types/bookmarks";
-import { zUploadResponseSchema, zUploadErrorSchema } from "@hoarder/trpc/types/uploads";
export function useUploadAsset(
settings: Settings,
- options: { onSuccess?: (bookmark: ZBookmark) => void; onError?: (e: string) => void },
+ options: {
+ onSuccess?: (bookmark: ZBookmark) => void;
+ onError?: (e: string) => void;
+ },
) {
const invalidateAllBookmarks =
api.useUtils().bookmarks.getBookmarks.invalidate;
- const {
- mutate: createBookmark,
- isPending: isCreatingBookmark,
- } = api.bookmarks.createBookmark.useMutation({
- onSuccess: (d) => {
- invalidateAllBookmarks();
- if (options.onSuccess) {
- options.onSuccess(d);
- }
- },
- onError: (e) => {
- if (options.onError) {
- options.onError(e.message);
- }
- },
- });
+ const { mutate: createBookmark, isPending: isCreatingBookmark } =
+ api.bookmarks.createBookmark.useMutation({
+ onSuccess: (d) => {
+ invalidateAllBookmarks();
+ if (options.onSuccess) {
+ options.onSuccess(d);
+ }
+ },
+ onError: (e) => {
+ if (options.onError) {
+ options.onError(e.message);
+ }
+ },
+ });
- const {
- mutate: uploadAsset,
- isPending: isUploading,
- } = useMutation({
+ const { mutate: uploadAsset, isPending: isUploading } = useMutation({
mutationFn: async (file: { type: string; name: string; uri: string }) => {
const formData = new FormData();
// @ts-expect-error This is a valid api in react native
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index 15b2057b..04fd8821 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -8,6 +8,7 @@
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
+ "format": "prettier .",
"lint": "eslint .",
"typecheck": "tsc --noEmit"
},
diff --git a/apps/mobile/tailwind.config.ts b/apps/mobile/tailwind.config.ts
index 9eb1eb4a..8d6f3785 100644
--- a/apps/mobile/tailwind.config.ts
+++ b/apps/mobile/tailwind.config.ts
@@ -1,4 +1,5 @@
import type { Config } from "tailwindcss";
+
import base from "@hoarder/tailwind-config/native";
const config = {
diff --git a/apps/workers/crawlerWorker.ts b/apps/workers/crawlerWorker.ts
index 3f7bff94..d1ebbdaa 100644
--- a/apps/workers/crawlerWorker.ts
+++ b/apps/workers/crawlerWorker.ts
@@ -1,8 +1,10 @@
import assert from "assert";
import * as dns from "dns";
+import type { Job } from "bullmq";
+import type { Browser } from "puppeteer";
import { Readability } from "@mozilla/readability";
import { Mutex } from "async-mutex";
-import { Job, Worker } from "bullmq";
+import { Worker } from "bullmq";
import DOMPurify from "dompurify";
import { eq } from "drizzle-orm";
import { isShuttingDown } from "exit";
@@ -15,11 +17,11 @@ import metascraperReadability from "metascraper-readability";
import metascraperTitle from "metascraper-title";
import metascraperTwitter from "metascraper-twitter";
import metascraperUrl from "metascraper-url";
-import { Browser } from "puppeteer";
import puppeteer from "puppeteer-extra";
import AdblockerPlugin from "puppeteer-extra-plugin-adblocker";
import StealthPlugin from "puppeteer-extra-plugin-stealth";
+import type { ZCrawlLinkRequest } from "@hoarder/shared/queues";
import { db } from "@hoarder/db";
import { bookmarkLinks } from "@hoarder/db/schema";
import serverConfig from "@hoarder/shared/config";
@@ -29,7 +31,6 @@ import {
OpenAIQueue,
queueConnectionDetails,
SearchIndexingQueue,
- ZCrawlLinkRequest,
zCrawlLinkRequestSchema,
} from "@hoarder/shared/queues";
@@ -83,7 +84,7 @@ async function launchBrowser() {
}, 5000);
return;
}
- browser.on("disconnected", async (): Promise<void> => {
+ browser.on("disconnected", () => {
if (isShuttingDown) {
logger.info(
"The puppeteer browser got disconnected. But we're shutting down so won't restart it.",
@@ -93,7 +94,7 @@ async function launchBrowser() {
logger.info(
"The puppeteer browser got disconnected. Will attempt to launch it again.",
);
- await launchBrowser();
+ launchBrowser();
});
});
}
diff --git a/apps/workers/exit.ts b/apps/workers/exit.ts
index 156cf2c6..29bfa5ef 100644
--- a/apps/workers/exit.ts
+++ b/apps/workers/exit.ts
@@ -3,7 +3,7 @@ import logger from "@hoarder/shared/logger";
export let isShuttingDown = false;
export const shutdownPromise = new Promise((resolve) => {
- process.on('SIGTERM', () => {
+ process.on("SIGTERM", () => {
logger.info("Received SIGTERM, shutting down ...");
isShuttingDown = true;
resolve("");
diff --git a/apps/workers/index.ts b/apps/workers/index.ts
index 4db524ef..24bdc67b 100644
--- a/apps/workers/index.ts
+++ b/apps/workers/index.ts
@@ -1,14 +1,15 @@
import "dotenv/config";
+
import { CrawlerWorker } from "./crawlerWorker";
+import { shutdownPromise } from "./exit";
import { OpenAiWorker } from "./openaiWorker";
import { SearchIndexingWorker } from "./searchWorker";
-import { shutdownPromise } from "./exit";
async function main() {
const [crawler, openai, search] = [
await CrawlerWorker.build(),
- await OpenAiWorker.build(),
- await SearchIndexingWorker.build(),
+ OpenAiWorker.build(),
+ SearchIndexingWorker.build(),
];
await Promise.any([
diff --git a/apps/workers/inference.ts b/apps/workers/inference.ts
index 3b0b5943..13b10aba 100644
--- a/apps/workers/inference.ts
+++ b/apps/workers/inference.ts
@@ -124,7 +124,9 @@ class OllamaInferenceClient implements InferenceClient {
// Using stream + accumulating the response so far is a workaround.
// https://github.com/ollama/ollama-js/issues/72
totalTokens = NaN;
- logger.warn(`Got an exception from ollama, will still attempt to deserialize the response we got so far: ${e}`)
+ logger.warn(
+ `Got an exception from ollama, will still attempt to deserialize the response we got so far: ${e}`,
+ );
}
return { response, totalTokens };
@@ -139,6 +141,10 @@ class OllamaInferenceClient implements InferenceClient {
_contentType: string,
image: string,
): Promise<InferenceResponse> {
- return await this.runModel(serverConfig.inference.imageModel, prompt, image);
+ return await this.runModel(
+ serverConfig.inference.imageModel,
+ prompt,
+ image,
+ );
}
}
diff --git a/apps/workers/openaiWorker.ts b/apps/workers/openaiWorker.ts
index ee48d148..bb8015a5 100644
--- a/apps/workers/openaiWorker.ts
+++ b/apps/workers/openaiWorker.ts
@@ -1,7 +1,9 @@
-import { Job, Worker } from "bullmq";
+import type { Job } from "bullmq";
+import { Worker } from "bullmq";
import { and, eq, inArray } from "drizzle-orm";
import { z } from "zod";
+import type { ZOpenAIRequest } from "@hoarder/shared/queues";
import { db } from "@hoarder/db";
import { bookmarks, bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema";
import { readAsset } from "@hoarder/shared/assetdb";
@@ -10,11 +12,11 @@ import {
OpenAIQueue,
queueConnectionDetails,
SearchIndexingQueue,
- ZOpenAIRequest,
zOpenAIRequestSchema,
} from "@hoarder/shared/queues";
-import { InferenceClient, InferenceClientFactory } from "./inference";
+import type { InferenceClient } from "./inference";
+import { InferenceClientFactory } from "./inference";
const openAIResponseSchema = z.object({
tags: z.array(z.string()),
@@ -41,7 +43,7 @@ async function attemptMarkTaggingStatus(
}
export class OpenAiWorker {
- static async build() {
+ static build() {
logger.info("Starting inference worker ...");
const worker = new Worker<ZOpenAIRequest, void>(
OpenAIQueue.name,
@@ -52,16 +54,16 @@ export class OpenAiWorker {
},
);
- worker.on("completed", async (job): Promise<void> => {
+ worker.on("completed", (job) => {
const jobId = job?.id ?? "unknown";
logger.info(`[inference][${jobId}] Completed successfully`);
- await attemptMarkTaggingStatus(job?.data, "success");
+ attemptMarkTaggingStatus(job?.data, "success");
});
- worker.on("failed", async (job, error): Promise<void> => {
+ worker.on("failed", (job, error) => {
const jobId = job?.id ?? "unknown";
logger.error(`[inference][${jobId}] inference job failed: ${error}`);
- await attemptMarkTaggingStatus(job?.data, "failure");
+ attemptMarkTaggingStatus(job?.data, "failure");
});
return worker;
@@ -90,11 +92,11 @@ function buildPrompt(
bookmark: NonNullable<Awaited<ReturnType<typeof fetchBookmark>>>,
) {
const truncateContent = (content: string) => {
- let words = content.split(" ");
- if (words.length > 1500) {
- words = words.slice(1500);
- content = words.join(" ");
- }
+ let words = content.split(" ");
+ if (words.length > 1500) {
+ words = words.slice(1500);
+ content = words.join(" ");
+ }
return content;
};
if (bookmark.link) {
diff --git a/apps/workers/package.json b/apps/workers/package.json
index 27a02f88..c9de43a4 100644
--- a/apps/workers/package.json
+++ b/apps/workers/package.json
@@ -44,6 +44,8 @@
"scripts": {
"start": "tsx watch index.ts",
"start:prod": "tsx index.ts",
+ "lint": "eslint .",
+ "format": "prettier . --ignore-path ../../.prettierignore",
"typecheck": "tsc --noEmit"
},
"eslintConfig": {
diff --git a/apps/workers/searchWorker.ts b/apps/workers/searchWorker.ts
index ae916441..79b0c8c1 100644
--- a/apps/workers/searchWorker.ts
+++ b/apps/workers/searchWorker.ts
@@ -14,7 +14,7 @@ import {
import { getSearchIdxClient } from "@hoarder/shared/search";
export class SearchIndexingWorker {
- static async build() {
+ static build() {
logger.info("Starting search indexing worker ...");
const worker = new Worker<ZSearchIndexingRequest, void>(
SearchIndexingQueue.name,
diff --git a/packages/shared/assetdb.ts b/packages/shared/assetdb.ts
index 0840eec2..8fd4da16 100644
--- a/packages/shared/assetdb.ts
+++ b/packages/shared/assetdb.ts
@@ -22,7 +22,7 @@ export async function saveAsset({
}: {
userId: string;
assetId: string;
- asset: Buffer,
+ asset: Buffer;
metadata: z.infer<typeof zAssetMetadataSchema>;
}) {
const assetDir = getAssetDir(userId, assetId);
@@ -30,7 +30,10 @@ export async function saveAsset({
await Promise.all([
fs.promises.writeFile(path.join(assetDir, "asset.bin"), asset),
- fs.promises.writeFile(path.join(assetDir, "metadata.json"), JSON.stringify(metadata)),
+ fs.promises.writeFile(
+ path.join(assetDir, "metadata.json"),
+ JSON.stringify(metadata),
+ ),
]);
}
@@ -42,14 +45,16 @@ export async function readAsset({
assetId: string;
}) {
const assetDir = getAssetDir(userId, assetId);
-
- const [asset, metadataStr] = await Promise.all([
+
+ const [asset, metadataStr] = await Promise.all([
fs.promises.readFile(path.join(assetDir, "asset.bin")),
- fs.promises.readFile(path.join(assetDir, "metadata.json"), {encoding: "utf8"}),
+ fs.promises.readFile(path.join(assetDir, "metadata.json"), {
+ encoding: "utf8",
+ }),
]);
const metadata = zAssetMetadataSchema.parse(JSON.parse(metadataStr));
- return {asset, metadata};
+ return { asset, metadata };
}
export async function deleteAsset({
@@ -60,5 +65,5 @@ export async function deleteAsset({
assetId: string;
}) {
const assetDir = getAssetDir(userId, assetId);
- await fs.promises.rm(path.join(assetDir), {recursive: true});
+ await fs.promises.rm(path.join(assetDir), { recursive: true });
}
diff --git a/packages/shared/logger.ts b/packages/shared/logger.ts
index 471ec7ab..f406b447 100644
--- a/packages/shared/logger.ts
+++ b/packages/shared/logger.ts
@@ -1,4 +1,5 @@
import winston from "winston";
+
import serverConfig from "./config";
const logger = winston.createLogger({
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 716248e8..032f3db5 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -15,6 +15,11 @@
"@hoarder/prettier-config": "workspace:^0.1.0",
"@hoarder/tsconfig": "workspace:^0.1.0"
},
+ "scripts": {
+ "typecheck": "tsc --noEmit",
+ "format": "prettier . --ignore-path ../../.prettierignore",
+ "lint": "eslint ."
+ },
"main": "index.ts",
"eslintConfig": {
"root": true,
diff --git a/packages/shared/search.ts b/packages/shared/search.ts
index 8422d79e..7cd81061 100644
--- a/packages/shared/search.ts
+++ b/packages/shared/search.ts
@@ -1,7 +1,9 @@
-import { MeiliSearch, Index } from "meilisearch";
-import serverConfig from "./config";
+import type { Index } from "meilisearch";
+import { MeiliSearch } from "meilisearch";
import { z } from "zod";
+import serverConfig from "./config";
+
export const zBookmarkIdxSchema = z.object({
id: z.string(),
userId: z.string(),
@@ -51,15 +53,29 @@ export async function getSearchIdxClient(): Promise<Index<ZBookmarkIdx> | null>
const desiredSortableAttributes = ["createdAt"].sort();
const settings = await idxFound.getSettings();
- if (JSON.stringify(settings.filterableAttributes?.sort()) != JSON.stringify(desiredFilterableAttributes)) {
- console.log(`[meilisearch] Updating desired filterable attributes to ${desiredFilterableAttributes} from ${settings.filterableAttributes}`);
- const taskId = await idxFound.updateFilterableAttributes(desiredFilterableAttributes);
+ if (
+ JSON.stringify(settings.filterableAttributes?.sort()) !=
+ JSON.stringify(desiredFilterableAttributes)
+ ) {
+ console.log(
+ `[meilisearch] Updating desired filterable attributes to ${desiredFilterableAttributes} from ${settings.filterableAttributes}`,
+ );
+ const taskId = await idxFound.updateFilterableAttributes(
+ desiredFilterableAttributes,
+ );
await searchClient.waitForTask(taskId.taskUid);
}
- if (JSON.stringify(settings.sortableAttributes?.sort()) != JSON.stringify(desiredSortableAttributes)) {
- console.log(`[meilisearch] Updating desired sortable attributes to ${desiredSortableAttributes} from ${settings.sortableAttributes}`);
- const taskId = await idxFound.updateSortableAttributes(desiredSortableAttributes);
+ if (
+ JSON.stringify(settings.sortableAttributes?.sort()) !=
+ JSON.stringify(desiredSortableAttributes)
+ ) {
+ console.log(
+ `[meilisearch] Updating desired sortable attributes to ${desiredSortableAttributes} from ${settings.sortableAttributes}`,
+ );
+ const taskId = await idxFound.updateSortableAttributes(
+ desiredSortableAttributes,
+ );
await searchClient.waitForTask(taskId.taskUid);
}
idxClient = idxFound;
diff --git a/packages/trpc/auth.ts b/packages/trpc/auth.ts
index c766dd9a..846c07b6 100644
--- a/packages/trpc/auth.ts
+++ b/packages/trpc/auth.ts
@@ -1,7 +1,8 @@
import { randomBytes } from "crypto";
-import { apiKeys } from "@hoarder/db/schema";
import * as bcrypt from "bcryptjs";
+
import { db } from "@hoarder/db";
+import { apiKeys } from "@hoarder/db/schema";
// API Keys
diff --git a/packages/trpc/index.ts b/packages/trpc/index.ts
index 51c713c0..4055fa5d 100644
--- a/packages/trpc/index.ts
+++ b/packages/trpc/index.ts
@@ -1,20 +1,21 @@
-import { db } from "@hoarder/db";
-import serverConfig from "@hoarder/shared/config";
-import { TRPCError, initTRPC } from "@trpc/server";
+import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";
-type User = {
+import type { db } from "@hoarder/db";
+import serverConfig from "@hoarder/shared/config";
+
+interface User {
id: string;
name?: string | null | undefined;
email?: string | null | undefined;
role: "admin" | "user" | null;
-};
+}
-export type Context = {
+export interface Context {
user: User | null;
db: typeof db;
-};
+}
// Avoid exporting the entire t-object
// since it's not very descriptive.
@@ -29,7 +30,7 @@ const t = initTRPC.context<Context>().create({
data: {
...shape.data,
zodError:
- error.code === 'BAD_REQUEST' && error.cause instanceof ZodError
+ error.code === "BAD_REQUEST" && error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
@@ -53,7 +54,7 @@ export const publicProcedure = procedure;
export const authedProcedure = procedure.use(function isAuthed(opts) {
const user = opts.ctx.user;
- if (!user || !user.id) {
+ if (!user?.id) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
diff --git a/packages/trpc/package.json b/packages/trpc/package.json
index 411397dc..ec858ca5 100644
--- a/packages/trpc/package.json
+++ b/packages/trpc/package.json
@@ -6,6 +6,8 @@
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit",
+ "format": "prettier . --ignore-path ../../.prettierignore",
+ "lint": "eslint .",
"test": "vitest"
},
"dependencies": {
diff --git a/packages/trpc/routers/_app.ts b/packages/trpc/routers/_app.ts
index 780fd76d..577b523e 100644
--- a/packages/trpc/routers/_app.ts
+++ b/packages/trpc/routers/_app.ts
@@ -5,6 +5,7 @@ import { bookmarksAppRouter } from "./bookmarks";
import { listsAppRouter } from "./lists";
import { tagsAppRouter } from "./tags";
import { usersAppRouter } from "./users";
+
export const appRouter = router({
bookmarks: bookmarksAppRouter,
apiKeys: apiKeysAppRouter,
diff --git a/packages/trpc/routers/admin.ts b/packages/trpc/routers/admin.ts
index 8a7b592d..4a7c6a80 100644
--- a/packages/trpc/routers/admin.ts
+++ b/packages/trpc/routers/admin.ts
@@ -1,6 +1,6 @@
-import { adminProcedure, router } from "../index";
-import { z } from "zod";
import { count } from "drizzle-orm";
+import { z } from "zod";
+
import { bookmarks, users } from "@hoarder/db/schema";
import {
LinkCrawlerQueue,
@@ -8,6 +8,8 @@ import {
SearchIndexingQueue,
} from "@hoarder/shared/queues";
+import { adminProcedure, router } from "../index";
+
export const adminAppRouter = router({
stats: adminProcedure
.output(
diff --git a/packages/trpc/routers/apiKeys.ts b/packages/trpc/routers/apiKeys.ts
index 3093b433..deeb108f 100644
--- a/packages/trpc/routers/apiKeys.ts
+++ b/packages/trpc/routers/apiKeys.ts
@@ -1,9 +1,11 @@
-import { generateApiKey, validatePassword } from "../auth";
-import { authedProcedure, publicProcedure, router } from "../index";
+import { TRPCError } from "@trpc/server";
+import { and, eq } from "drizzle-orm";
import { z } from "zod";
+
import { apiKeys } from "@hoarder/db/schema";
-import { eq, and } from "drizzle-orm";
-import { TRPCError } from "@trpc/server";
+
+import { generateApiKey, validatePassword } from "../auth";
+import { authedProcedure, publicProcedure, router } from "../index";
const zApiKeySchema = z.object({
id: z.string(),
diff --git a/packages/trpc/routers/bookmarks.test.ts b/packages/trpc/routers/bookmarks.test.ts
index 724a9998..58f4739d 100644
--- a/packages/trpc/routers/bookmarks.test.ts
+++ b/packages/trpc/routers/bookmarks.test.ts
@@ -1,5 +1,7 @@
-import { CustomTestContext, defaultBeforeEach } from "../testUtils";
-import { expect, describe, test, beforeEach, assert } from "vitest";
+import { assert, beforeEach, describe, expect, test } from "vitest";
+
+import type { CustomTestContext } from "../testUtils";
+import { defaultBeforeEach } from "../testUtils";
beforeEach<CustomTestContext>(defaultBeforeEach(true));
diff --git a/packages/trpc/routers/bookmarks.ts b/packages/trpc/routers/bookmarks.ts
index 4fb29c4c..9611829f 100644
--- a/packages/trpc/routers/bookmarks.ts
+++ b/packages/trpc/routers/bookmarks.ts
@@ -21,19 +21,19 @@ import {
} from "@hoarder/shared/queues";
import { getSearchIdxClient } from "@hoarder/shared/search";
-import { authedProcedure, Context, router } from "../index";
+import type { Context } from "../index";
+import type { ZBookmark, ZBookmarkContent } from "../types/bookmarks";
+import type { ZBookmarkTags } from "../types/tags";
+import { authedProcedure, router } from "../index";
import {
DEFAULT_NUM_BOOKMARKS_PER_PAGE,
zBareBookmarkSchema,
- ZBookmark,
- ZBookmarkContent,
zBookmarkSchema,
zGetBookmarksRequestSchema,
zGetBookmarksResponseSchema,
zNewBookmarkRequestSchema,
zUpdateBookmarksRequestSchema,
} from "../types/bookmarks";
-import { ZBookmarkTags } from "../types/tags";
export const ensureBookmarkOwnership = experimental_trpcMiddleware<{
ctx: Context;
@@ -423,29 +423,29 @@ export const bookmarksAppRouter = router({
input.ids ? inArray(bookmarks.id, input.ids) : undefined,
input.tagId !== undefined
? exists(
- ctx.db
- .select()
- .from(tagsOnBookmarks)
- .where(
- and(
- eq(tagsOnBookmarks.bookmarkId, bookmarks.id),
- eq(tagsOnBookmarks.tagId, input.tagId),
+ ctx.db
+ .select()
+ .from(tagsOnBookmarks)
+ .where(
+ and(
+ eq(tagsOnBookmarks.bookmarkId, bookmarks.id),
+ eq(tagsOnBookmarks.tagId, input.tagId),
+ ),
),
- ),
- )
+ )
: undefined,
input.listId !== undefined
? exists(
- ctx.db
- .select()
- .from(bookmarksInLists)
- .where(
- and(
- eq(bookmarksInLists.bookmarkId, bookmarks.id),
- eq(bookmarksInLists.listId, input.listId),
+ ctx.db
+ .select()
+ .from(bookmarksInLists)
+ .where(
+ and(
+ eq(bookmarksInLists.bookmarkId, bookmarks.id),
+ eq(bookmarksInLists.listId, input.listId),
+ ),
),
- ),
- )
+ )
: undefined,
input.cursor ? lte(bookmarks.createdAt, input.cursor) : undefined,
),
diff --git a/packages/trpc/routers/lists.ts b/packages/trpc/routers/lists.ts
index db5bb38e..fb6d8637 100644
--- a/packages/trpc/routers/lists.ts
+++ b/packages/trpc/routers/lists.ts
@@ -5,7 +5,8 @@ import { z } from "zod";
import { SqliteError } from "@hoarder/db";
import { bookmarkLists, bookmarksInLists } from "@hoarder/db/schema";
-import { authedProcedure, Context, router } from "../index";
+import type { Context } from "../index";
+import { authedProcedure, router } from "../index";
import { zBookmarkListSchema } from "../types/lists";
import { ensureBookmarkOwnership } from "./bookmarks";
diff --git a/packages/trpc/routers/users.test.ts b/packages/trpc/routers/users.test.ts
index 87814407..ea342d33 100644
--- a/packages/trpc/routers/users.test.ts
+++ b/packages/trpc/routers/users.test.ts
@@ -1,9 +1,7 @@
-import {
- CustomTestContext,
- defaultBeforeEach,
- getApiCaller,
-} from "../testUtils";
-import { expect, describe, test, beforeEach, assert } from "vitest";
+import { assert, beforeEach, describe, expect, test } from "vitest";
+
+import type { CustomTestContext } from "../testUtils";
+import { defaultBeforeEach, getApiCaller } from "../testUtils";
beforeEach<CustomTestContext>(defaultBeforeEach(false));
diff --git a/packages/trpc/testUtils.ts b/packages/trpc/testUtils.ts
index d5f24def..67fbddcc 100644
--- a/packages/trpc/testUtils.ts
+++ b/packages/trpc/testUtils.ts
@@ -1,7 +1,8 @@
-import { users } from "@hoarder/db/schema";
import { getInMemoryDB } from "@hoarder/db/drizzle";
-import { appRouter } from "./routers/_app";
+import { users } from "@hoarder/db/schema";
+
import { createCallerFactory } from "./index";
+import { appRouter } from "./routers/_app";
export function getTestDB() {
return getInMemoryDB(true);
@@ -63,7 +64,7 @@ export async function buildTestContext(
};
}
-export function defaultBeforeEach(seedDB: boolean = true) {
+export function defaultBeforeEach(seedDB = true) {
return async (context: object) => {
Object.assign(context, await buildTestContext(seedDB));
};
diff --git a/packages/trpc/tsconfig.json b/packages/trpc/tsconfig.json
index 80329662..dbd0afdc 100644
--- a/packages/trpc/tsconfig.json
+++ b/packages/trpc/tsconfig.json
@@ -5,6 +5,5 @@
"exclude": ["node_modules"],
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
- },
+ }
}
-
diff --git a/packages/trpc/types/bookmarks.ts b/packages/trpc/types/bookmarks.ts
index 1b78d6da..b6c8691f 100644
--- a/packages/trpc/types/bookmarks.ts
+++ b/packages/trpc/types/bookmarks.ts
@@ -1,4 +1,5 @@
import { z } from "zod";
+
import { zBookmarkTagSchema } from "./tags";
export const zBookmarkedLinkSchema = z.object({
@@ -30,7 +31,7 @@ export const zBookmarkContentSchema = z.discriminatedUnion("type", [
zBookmarkedLinkSchema,
zBookmarkedTextSchema,
zBookmarkedAssetSchema,
- z.object({type: z.literal("unknown")}),
+ z.object({ type: z.literal("unknown") }),
]);
export type ZBookmarkContent = z.infer<typeof zBookmarkContentSchema>;
diff --git a/packages/trpc/vitest.config.ts b/packages/trpc/vitest.config.ts
index c3d02f71..41fd70c4 100644
--- a/packages/trpc/vitest.config.ts
+++ b/packages/trpc/vitest.config.ts
@@ -1,7 +1,7 @@
/// <reference types="vitest" />
-import { defineConfig } from "vitest/config";
import tsconfigPaths from "vite-tsconfig-paths";
+import { defineConfig } from "vitest/config";
// https://vitejs.dev/config/
export default defineConfig({
diff --git a/tooling/eslint/base.js b/tooling/eslint/base.js
index 7a4f9377..285993ef 100644
--- a/tooling/eslint/base.js
+++ b/tooling/eslint/base.js
@@ -38,6 +38,7 @@ const config = {
"**/.eslintrc.cjs",
".next",
"dist",
+ "build",
"pnpm-lock.yaml",
],
reportUnusedDisableDirectives: true,