Skip to content

Commit 6420965

Browse files
Refactor apps/api service (#2145)
* seems good * Address CodeRabbit review comments - Fix incomplete OpenRouter model identifier (gpt-5.1-chat -> gpt-5.1-chat-latest) - Fix metrics recorded before streaming completes (move success metric after stream completes) - Add null safety for sentrySpan in all routes using optional chaining - Use openrouter/auto instead of empty string for model - Fix baseUrl for hyprnote provider to include path suffix Co-Authored-By: yujonglee <[email protected]> * Revert model identifier back to openai/gpt-5.1-chat Co-Authored-By: yujonglee <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 2bf214c commit 6420965

File tree

24 files changed

+736
-358
lines changed

24 files changed

+736
-358
lines changed

apps/api/src/billing.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// https://github.com/t3dotgg/stripe-recommendations/blob/main/README.md
22
import Stripe from "stripe";
33

4-
import { stripe } from "./stripe";
5-
import { supabaseAdmin } from "./supabase";
4+
import { stripe } from "./integration/stripe";
5+
import { supabaseAdmin } from "./integration/supabase";
66

77
const HANDLED_EVENTS: Stripe.Event.Type[] = [
88
"checkout.session.completed",

apps/api/src/hono-bindings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type * as Sentry from "@sentry/bun";
12
import type Stripe from "stripe";
23

34
export type AppBindings = {
45
Variables: {
56
stripeEvent: Stripe.Event;
7+
sentrySpan: Sentry.Span;
68
};
79
};

apps/api/src/index.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import { logger } from "hono/logger";
1111

1212
import { env } from "./env";
1313
import type { AppBindings } from "./hono-bindings";
14-
import { loadTestOverride } from "./load-test-auth";
14+
import {
15+
loadTestOverride,
16+
sentryMiddleware,
17+
supabaseAuthMiddleware,
18+
verifyStripeWebhook,
19+
} from "./middleware";
1520
import { API_TAGS, routes } from "./routes";
16-
import { sentryMiddleware } from "./sentry/middleware";
17-
import { verifyStripeWebhook } from "./stripe";
18-
import { requireSupabaseAuth } from "./supabase";
1921

2022
const app = new Hono<AppBindings>();
2123

@@ -44,12 +46,12 @@ app.use("*", (c, next) => {
4446
return corsMiddleware(c, next);
4547
});
4648

47-
app.use("/chat/completions", loadTestOverride, requireSupabaseAuth);
49+
app.use("/chat/completions", loadTestOverride, supabaseAuthMiddleware);
4850
app.use("/webhook/stripe", verifyStripeWebhook);
4951

5052
if (env.NODE_ENV !== "development") {
51-
app.use("/listen", loadTestOverride, requireSupabaseAuth);
52-
app.use("/transcribe", loadTestOverride, requireSupabaseAuth);
53+
app.use("/listen", loadTestOverride, supabaseAuthMiddleware);
54+
app.use("/transcribe", loadTestOverride, supabaseAuthMiddleware);
5355
}
5456

5557
app.route("/", routes);

apps/api/src/integration/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from "./supabase";
2+
export * from "./stripe";
3+
export * from "./openrouter";
4+
export * from "./posthog";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { OpenAI as PostHogOpenAI } from "@posthog/ai";
2+
3+
import { env } from "../env";
4+
import { posthog } from "./posthog";
5+
6+
export const openai = new PostHogOpenAI({
7+
baseURL: "https://openrouter.ai/api/v1",
8+
apiKey: env.OPENROUTER_API_KEY,
9+
posthog,
10+
});
11+
12+
const MODELS = {
13+
toolCalling: [
14+
"moonshotai/kimi-k2-0905:exacto",
15+
"anthropic/claude-haiku-4.5",
16+
"openai/gpt-oss-120b:exacto",
17+
],
18+
default: ["moonshotai/kimi-k2-0905", "openai/gpt-5.1-chat"],
19+
} as const;
20+
21+
export function getModels(needsToolCalling: boolean): string[] {
22+
return needsToolCalling ? [...MODELS.toolCalling] : [...MODELS.default];
23+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PostHog } from "posthog-node";
22

3-
import { env } from "./env";
3+
import { env } from "../env";
44

55
export const posthog = new PostHog(env.POSTHOG_API_KEY, {
66
host: "https://us.i.posthog.com",

apps/api/src/integration/stripe.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Stripe from "stripe";
2+
3+
import { env } from "../env";
4+
5+
export const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
6+
apiVersion: "2025-10-29.clover",
7+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createClient } from "@supabase/supabase-js";
2+
3+
import { env } from "../env";
4+
5+
export const supabaseAdmin = createClient(
6+
env.SUPABASE_URL,
7+
env.SUPABASE_SERVICE_ROLE_KEY,
8+
);

apps/api/src/listen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as Sentry from "@sentry/bun";
22
import type { Handler } from "hono";
33
import { upgradeWebSocket } from "hono/bun";
44

5-
import { Metrics } from "./sentry/metrics";
5+
import { Metrics } from "./metrics";
66
import {
77
createProxyFromRequest,
88
normalizeWsData,
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,43 @@
11
import * as Sentry from "@sentry/bun";
22

3-
export const Metrics = {
3+
const billing = {
4+
billingSync: (success: boolean, eventType: string) => {
5+
Sentry.metrics.count("billing.sync", 1, {
6+
attributes: { success: String(success), event_type: eventType },
7+
});
8+
},
9+
};
10+
11+
const stt = {
412
websocketConnected: (provider: string) => {
513
Sentry.metrics.count("websocket.connected", 1, {
614
attributes: { provider },
715
});
816
},
9-
1017
websocketDisconnected: (provider: string, durationMs: number) => {
1118
Sentry.metrics.distribution("websocket.duration", durationMs, {
1219
unit: "millisecond",
1320
attributes: { provider },
1421
});
1522
},
23+
};
1624

17-
billingSync: (success: boolean, eventType: string) => {
18-
Sentry.metrics.count("billing.sync", 1, {
19-
attributes: { success: String(success), event_type: eventType },
20-
});
21-
},
22-
25+
const llm = {
2326
chatCompletion: (streaming: boolean, statusCode: number) => {
2427
Sentry.metrics.count("chat.completion", 1, {
2528
attributes: { streaming: String(streaming), status: String(statusCode) },
2629
});
2730
},
31+
};
2832

33+
export const Metrics = {
34+
...stt,
35+
...llm,
2936
upstreamLatency: (provider: string, durationMs: number) => {
3037
Sentry.metrics.distribution("upstream.latency", durationMs, {
3138
unit: "millisecond",
3239
attributes: { provider },
3340
});
3441
},
42+
...billing,
3543
};

0 commit comments

Comments
 (0)