Skip to content

Commit 3b11985

Browse files
committed
login handling fixes
1 parent 1e75c9c commit 3b11985

File tree

16 files changed

+291
-205
lines changed

16 files changed

+291
-205
lines changed

Taskfile.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ tasks:
104104
- '[ -n "$GOOGLE_CLIENT_ID" ] && [ -n "$GOOGLE_CLIENT_SECRET" ] && dasel put -f supabase/config.toml -t string -v ''{{.GOOGLE_CLIENT_ID}}'' ''auth.external.google.client_id'' || true'
105105
- '[ -n "$GOOGLE_CLIENT_ID" ] && [ -n "$GOOGLE_CLIENT_SECRET" ] && dasel put -f supabase/config.toml -t string -v ''{{.GOOGLE_CLIENT_SECRET}}'' ''auth.external.google.secret'' || true'
106106
- '[ -n "$GOOGLE_CLIENT_ID" ] && [ -n "$GOOGLE_CLIENT_SECRET" ] && dasel put -f supabase/config.toml -t bool -v false ''auth.external.google.skip_nonce_check'' || true'
107+
- dasel put -f supabase/config.toml -t bool -v true 'auth.hook.custom_access_token.enabled'
108+
- dasel put -f supabase/config.toml -t string -v 'pg-functions://postgres/public/custom_access_token_hook' 'auth.hook.custom_access_token.uri'
107109
- dprint fmt supabase/config.toml
108110
- task: supabase-start:capture
109111
- supabase migration up --local

apps/api/src/integration/stripe-sync.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { StripeSync } from "@supabase/stripe-sync-engine";
33
import { env } from "../env";
44

55
export const stripeSync = new StripeSync({
6+
schema: "stripe",
67
poolConfig: { connectionString: env.DATABASE_URL },
78
stripeSecretKey: env.STRIPE_SECRET_KEY,
89
stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
10+
backfillRelatedEntities: true,
911
});

apps/api/src/routes/llm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ llm.post(
138138

139139
return c.json(response, 200);
140140
} catch (error) {
141+
console.error(error);
141142
Metrics.upstreamLatency("openrouter", performance.now() - startTime);
142143
const isAPIError =
143144
error instanceof Error &&

apps/api/src/routes/webhook.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { resolver, validator } from "hono-openapi/zod";
55
import { z } from "zod";
66

77
import { syncBillingBridge } from "../billing";
8+
import { env } from "../env";
89
import type { AppBindings } from "../hono-bindings";
910
import { stripeSync } from "../integration/stripe-sync";
10-
import { Metrics } from "../metrics";
1111
import { API_TAGS } from "./constants";
1212

1313
const WebhookSuccessSchema = z.object({
@@ -69,12 +69,31 @@ webhook.post(
6969

7070
try {
7171
await stripeSync.processWebhook(rawBody, signature);
72+
} catch (error) {
73+
if (env.NODE_ENV !== "production") {
74+
console.error(error);
75+
} else {
76+
if (
77+
error instanceof Error &&
78+
error.message === "Unhandled webhook event"
79+
) {
80+
// stripe-sync-engine doesn't support this event type, skip silently
81+
} else {
82+
Sentry.captureException(error, {
83+
tags: { webhook: "stripe", event_type: stripeEvent.type },
84+
});
85+
return c.json({ error: "stripe_sync_failed" }, 500);
86+
}
87+
}
88+
}
89+
90+
try {
7291
await syncBillingBridge(stripeEvent);
7392
} catch (error) {
7493
Sentry.captureException(error, {
7594
tags: { webhook: "stripe", event_type: stripeEvent.type },
7695
});
77-
return c.json({ error: "stripe_billing_sync_failed" }, 500);
96+
return c.json({ error: "billing_bridge_sync_failed" }, 500);
7897
}
7998

8099
return c.json({ ok: true }, 200);

apps/desktop/src/auth.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const AuthContext = createContext<{
9191
session: Session | null;
9292
signIn: () => Promise<void>;
9393
signOut: () => Promise<void>;
94+
refreshSession: () => Promise<void>;
9495
handleAuthCallback: (url: string) => Promise<void>;
9596
getHeaders: () => Record<string, string> | null;
9697
getAvatarUrl: () => Promise<string>;
@@ -237,6 +238,20 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
237238
}
238239
};
239240

241+
const refreshSession = async () => {
242+
if (!supabase) {
243+
return;
244+
}
245+
246+
const { data, error } = await supabase.auth.refreshSession();
247+
if (error) {
248+
return;
249+
}
250+
if (data.session) {
251+
setSession(data.session);
252+
}
253+
};
254+
240255
const getHeaders = useCallback(() => {
241256
if (!session) {
242257
return null;
@@ -267,6 +282,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
267282
supabase,
268283
signIn,
269284
signOut,
285+
refreshSession,
270286
handleAuthCallback,
271287
getHeaders,
272288
getAvatarUrl,

apps/desktop/src/billing.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,27 @@ export function BillingProvider({ children }: { children: ReactNode }) {
2525

2626
const isPro = useMemo(() => {
2727
if (!auth?.session?.access_token) {
28+
console.log("[BillingProvider] no access_token, isPro=false");
2829
return false;
2930
}
3031

32+
console.log(auth.session);
33+
3134
try {
3235
const decoded = jwtDecode<{ is_pro?: boolean }>(
3336
auth.session.access_token,
3437
);
35-
return decoded.is_pro ?? false;
36-
} catch {
38+
console.log(decoded);
39+
const result = decoded.is_pro ?? false;
40+
console.log(
41+
"[BillingProvider] decoded JWT, is_pro claim:",
42+
decoded.is_pro,
43+
"-> isPro:",
44+
result,
45+
);
46+
return result;
47+
} catch (e) {
48+
console.error("[BillingProvider] failed to decode JWT:", e);
3749
return false;
3850
}
3951
}, [auth?.session?.access_token]);

apps/desktop/src/components/main/sidebar/profile/auth.tsx

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import { LogIn, LogOut } from "lucide-react";
1+
import { LogIn } from "lucide-react";
22
import { useCallback } from "react";
33

44
import { commands as windowsCommands } from "@hypr/plugin-windows";
55
import { Button } from "@hypr/ui/components/ui/button";
66

7-
type AuthSectionProps = {
8-
isAuthenticated: boolean;
9-
onSignOut: () => Promise<void> | void;
10-
};
11-
12-
export function AuthSection({ isAuthenticated, onSignOut }: AuthSectionProps) {
7+
export function AuthSection({ isAuthenticated }: { isAuthenticated: boolean }) {
138
const handleOpenAccount = useCallback(async () => {
149
await windowsCommands.windowShow({ type: "settings" });
1510
await windowsCommands.windowNavigate(
@@ -19,18 +14,7 @@ export function AuthSection({ isAuthenticated, onSignOut }: AuthSectionProps) {
1914
}, []);
2015

2116
if (isAuthenticated) {
22-
return (
23-
<div className="px-1 py-2">
24-
<Button
25-
onClick={() => onSignOut()}
26-
variant="outline"
27-
className="w-full"
28-
>
29-
<LogOut className="w-4 h-4 mr-2" />
30-
Log out
31-
</Button>
32-
</div>
33-
);
17+
return null;
3418
}
3519

3620
return (

apps/desktop/src/components/main/sidebar/profile/index.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ export function ProfileSection({ onExpandChange }: ProfileSectionProps = {}) {
5353
onExpandChange?.(isExpanded);
5454
}, [isExpanded, onExpandChange]);
5555

56-
const handleSignOut = useCallback(async () => {
57-
await auth?.signOut();
58-
closeMenu();
59-
}, [auth, closeMenu]);
60-
6156
useEffect(() => {
6257
if (!isExpanded && currentView !== "main") {
6358
const timer = setTimeout(() => {
@@ -206,10 +201,7 @@ export function ProfileSection({ onExpandChange }: ProfileSectionProps = {}) {
206201
<MenuItem key={item.label} {...item} />
207202
))}
208203

209-
<AuthSection
210-
isAuthenticated={isAuthenticated}
211-
onSignOut={handleSignOut}
212-
/>
204+
<AuthSection isAuthenticated={isAuthenticated} />
213205
</motion.div>
214206
) : (
215207
<motion.div

0 commit comments

Comments
 (0)