aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/browser-extension/src/OptionsPage.tsx7
-rw-r--r--apps/browser-extension/src/SignInPage.tsx2
-rw-r--r--apps/browser-extension/src/utils/providers.tsx44
-rw-r--r--apps/browser-extension/src/utils/settings.ts1
-rw-r--r--apps/mobile/app/signin.tsx2
-rw-r--r--apps/mobile/lib/providers.tsx51
-rw-r--r--apps/mobile/lib/session.ts8
-rw-r--r--apps/mobile/lib/settings.ts1
-rw-r--r--packages/shared-react/package.json4
-rw-r--r--packages/shared-react/providers/trpc-provider.tsx50
-rw-r--r--pnpm-lock.yaml6
11 files changed, 84 insertions, 92 deletions
diff --git a/apps/browser-extension/src/OptionsPage.tsx b/apps/browser-extension/src/OptionsPage.tsx
index 9670558e..24785857 100644
--- a/apps/browser-extension/src/OptionsPage.tsx
+++ b/apps/browser-extension/src/OptionsPage.tsx
@@ -17,6 +17,8 @@ export default function OptionsPage() {
},
);
+ const { mutate: deleteKey } = api.apiKeys.revoke.useMutation();
+
const invalidateWhoami = api.useUtils().users.whoami.refetch;
useEffect(() => {
@@ -39,7 +41,10 @@ export default function OptionsPage() {
}
const onLogout = () => {
- setSettings((s) => ({ ...s, apiKey: "" }));
+ if (settings.apiKeyId) {
+ deleteKey({ id: settings.apiKeyId });
+ }
+ setSettings((s) => ({ ...s, apiKey: "", apiKeyId: undefined }));
invalidateWhoami();
navigate("/notconfigured");
};
diff --git a/apps/browser-extension/src/SignInPage.tsx b/apps/browser-extension/src/SignInPage.tsx
index a9b77e83..aa8699ae 100644
--- a/apps/browser-extension/src/SignInPage.tsx
+++ b/apps/browser-extension/src/SignInPage.tsx
@@ -15,7 +15,7 @@ export default function SignInPage() {
isPending,
} = api.apiKeys.exchange.useMutation({
onSuccess: (resp) => {
- setSettings((s) => ({ ...s, apiKey: resp.key }));
+ setSettings((s) => ({ ...s, apiKey: resp.key, apiKeyId: resp.id }));
navigate("/options");
},
});
diff --git a/apps/browser-extension/src/utils/providers.tsx b/apps/browser-extension/src/utils/providers.tsx
index 7b14b22c..4ca17016 100644
--- a/apps/browser-extension/src/utils/providers.tsx
+++ b/apps/browser-extension/src/utils/providers.tsx
@@ -1,47 +1,9 @@
-import { useEffect, useState } from "react";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { httpBatchLink } from "@trpc/client";
-import superjson from "superjson";
+import { TRPCProvider } from "@hoarder/shared-react/providers/trpc-provider";
-import usePluginSettings, { getPluginSettings } from "./settings";
-import { api } from "./trpc";
-
-function getTRPCClient(address: string) {
- return api.createClient({
- links: [
- httpBatchLink({
- url: `${address}/api/trpc`,
- async headers() {
- const settings = await getPluginSettings();
- return {
- Authorization: `Bearer ${settings.apiKey}`,
- };
- },
- transformer: superjson,
- }),
- ],
- });
-}
+import usePluginSettings from "./settings";
export function Providers({ children }: { children: React.ReactNode }) {
const { settings } = usePluginSettings();
- const [queryClient] = useState(() => new QueryClient());
-
- const [trpcClient, setTrpcClient] = useState<
- ReturnType<typeof getTRPCClient>
- >(getTRPCClient(settings.address));
-
- useEffect(() => {
- setTrpcClient(getTRPCClient(settings.address));
- }, [settings.address]);
- return (
- <api.Provider
- key={settings.address}
- client={trpcClient}
- queryClient={queryClient}
- >
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
- </api.Provider>
- );
+ return <TRPCProvider settings={settings}>{children}</TRPCProvider>;
}
diff --git a/apps/browser-extension/src/utils/settings.ts b/apps/browser-extension/src/utils/settings.ts
index f20e9827..ef290555 100644
--- a/apps/browser-extension/src/utils/settings.ts
+++ b/apps/browser-extension/src/utils/settings.ts
@@ -2,6 +2,7 @@ import { useChromeStorageSync } from "use-chrome-storage";
export interface Settings {
apiKey: string;
+ apiKeyId?: string;
address: string;
}
diff --git a/apps/mobile/app/signin.tsx b/apps/mobile/app/signin.tsx
index 283528df..80a5f219 100644
--- a/apps/mobile/app/signin.tsx
+++ b/apps/mobile/app/signin.tsx
@@ -22,7 +22,7 @@ export default function Signin() {
const { mutate: login, isPending } = api.apiKeys.exchange.useMutation({
onSuccess: (resp) => {
- setSettings({ ...settings, apiKey: resp.key });
+ setSettings({ ...settings, apiKey: resp.key, apiKeyId: resp.id });
},
onError: (e) => {
if (e.data?.code === "UNAUTHORIZED") {
diff --git a/apps/mobile/lib/providers.tsx b/apps/mobile/lib/providers.tsx
index ed04b9bf..c2a573f5 100644
--- a/apps/mobile/lib/providers.tsx
+++ b/apps/mobile/lib/providers.tsx
@@ -1,52 +1,11 @@
-import { useEffect, useMemo } from "react";
+import { useEffect } from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
import { ToastProvider } from "@/components/ui/Toast";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { httpBatchLink } from "@trpc/client";
-import superjson from "superjson";
-import type { Settings } from "./settings";
-import useAppSettings from "./settings";
-import { api } from "./trpc";
-
-function getTRPCClient(settings: Settings) {
- return api.createClient({
- links: [
- httpBatchLink({
- url: `${settings.address}/api/trpc`,
- headers() {
- return {
- Authorization: settings?.apiKey
- ? `Bearer ${settings.apiKey}`
- : undefined,
- };
- },
- transformer: superjson,
- }),
- ],
- });
-}
-
-function TrpcProvider({
- children,
- settings,
-}: {
- settings: Settings;
- children: React.ReactNode;
-}) {
- const queryClient = useMemo(() => new QueryClient(), [settings]);
-
- const trpcClient = useMemo(() => getTRPCClient(settings), [settings]);
+import { TRPCProvider } from "@hoarder/shared-react/providers/trpc-provider";
- return (
- <api.Provider client={trpcClient} queryClient={queryClient}>
- <QueryClientProvider client={queryClient}>
- <ToastProvider>{children}</ToastProvider>
- </QueryClientProvider>
- </api.Provider>
- );
-}
+import useAppSettings from "./settings";
export function Providers({ children }: { children: React.ReactNode }) {
const { settings, isLoading, load } = useAppSettings();
@@ -62,9 +21,9 @@ export function Providers({ children }: { children: React.ReactNode }) {
return (
<SafeAreaProvider>
- <TrpcProvider settings={settings}>
+ <TRPCProvider settings={settings}>
<ToastProvider>{children}</ToastProvider>
- </TrpcProvider>
+ </TRPCProvider>
</SafeAreaProvider>
);
}
diff --git a/apps/mobile/lib/session.ts b/apps/mobile/lib/session.ts
index bafb3a09..8eb646cb 100644
--- a/apps/mobile/lib/session.ts
+++ b/apps/mobile/lib/session.ts
@@ -1,12 +1,18 @@
import { useCallback } from "react";
import useAppSettings from "./settings";
+import { api } from "./trpc";
export function useSession() {
const { settings, setSettings } = useAppSettings();
+ const { mutate: deleteKey } = api.apiKeys.revoke.useMutation();
+
const logout = useCallback(() => {
- setSettings({ ...settings, apiKey: undefined });
+ if (settings.apiKeyId) {
+ deleteKey({ id: settings.apiKeyId });
+ }
+ setSettings({ ...settings, apiKey: undefined, apiKeyId: undefined });
}, [settings, setSettings]);
return {
diff --git a/apps/mobile/lib/settings.ts b/apps/mobile/lib/settings.ts
index 3ec53231..efb5593a 100644
--- a/apps/mobile/lib/settings.ts
+++ b/apps/mobile/lib/settings.ts
@@ -5,6 +5,7 @@ const SETTING_NAME = "settings";
export interface Settings {
apiKey?: string;
+ apiKeyId?: string;
address: string;
}
diff --git a/packages/shared-react/package.json b/packages/shared-react/package.json
index 46a2adb5..5e0a1d23 100644
--- a/packages/shared-react/package.json
+++ b/packages/shared-react/package.json
@@ -5,7 +5,9 @@
"private": true,
"dependencies": {
"@hoarder/trpc": "workspace:^0.1.0",
- "@tanstack/react-query": "^5.24.8"
+ "@tanstack/react-query": "^5.24.8",
+ "superjson": "^2.2.1",
+ "@trpc/client": "11.0.0-next-beta.308"
},
"devDependencies": {
"@hoarder/eslint-config": "workspace:^0.2.0",
diff --git a/packages/shared-react/providers/trpc-provider.tsx b/packages/shared-react/providers/trpc-provider.tsx
new file mode 100644
index 00000000..2cd8661b
--- /dev/null
+++ b/packages/shared-react/providers/trpc-provider.tsx
@@ -0,0 +1,50 @@
+import { useMemo } from "react";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { httpBatchLink } from "@trpc/client";
+import superjson from "superjson";
+
+import { api } from "../trpc";
+
+interface Settings {
+ apiKey?: string;
+ address: string;
+}
+
+function getTRPCClient(settings: Settings) {
+ return api.createClient({
+ links: [
+ httpBatchLink({
+ url: `${settings.address}/api/trpc`,
+ headers() {
+ return {
+ Authorization: settings.apiKey
+ ? `Bearer ${settings.apiKey}`
+ : undefined,
+ };
+ },
+ transformer: superjson,
+ }),
+ ],
+ });
+}
+
+export function TRPCProvider({
+ settings,
+ children,
+}: {
+ settings: Settings;
+ children: React.ReactNode;
+}) {
+ const queryClient = useMemo(() => new QueryClient(), [settings]);
+ const trpcClient = useMemo(() => getTRPCClient(settings), [settings]);
+
+ return (
+ <api.Provider
+ key={settings.address}
+ client={trpcClient}
+ queryClient={queryClient}
+ >
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
+ </api.Provider>
+ );
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 00b895e6..caeed82f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -796,6 +796,9 @@ importers:
'@tanstack/react-query':
specifier: ^5.24.8
version: 5.24.8(react@18.2.0)
+ '@trpc/client':
+ specifier: 11.0.0-next-beta.308
+ version: 11.0.0-next-beta.308(@trpc/server@11.0.0-next-beta.308)
react:
specifier: '*'
version: 18.2.0
@@ -805,6 +808,9 @@ importers:
react-native-web:
specifier: '*'
version: 0.19.10(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+ superjson:
+ specifier: ^2.2.1
+ version: 2.2.1
devDependencies:
'@hoarder/eslint-config':
specifier: workspace:^0.2.0