fix: analytics and deprecated warning
This commit is contained in:
@@ -13,8 +13,9 @@ import { accountRouter } from "./routers/account";
|
||||
import { downloadsRouter } from "./routers/downloads";
|
||||
import { cairnDbRouter } from "./routers/cairn";
|
||||
import { appleNotificationsRouter } from "./routers/apple-notifications";
|
||||
import { createTRPCRouter, createTRPCContext } from "./utils";
|
||||
import { createTRPCRouter, createTRPCContext, t } from "./utils";
|
||||
import type { H3Event } from "h3";
|
||||
import type { APIEvent } from "@solidjs/start/server";
|
||||
|
||||
export const appRouter = createTRPCRouter({
|
||||
auth: authRouter,
|
||||
@@ -36,12 +37,24 @@ export const appRouter = createTRPCRouter({
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
||||
/** Server-side caller factory using the modern tRPC pattern */
|
||||
export const createCallerFactory = t.createCallerFactory(appRouter);
|
||||
|
||||
/**
|
||||
* Create a server-side caller for tRPC procedures
|
||||
* This allows calling tRPC procedures directly on the server with proper context
|
||||
* Create a server-side caller for tRPC procedures from H3Event (vinxi/http getEvent)
|
||||
* Used in server functions within route files
|
||||
*/
|
||||
export const createCaller = async (event: H3Event) => {
|
||||
const apiEvent = { nativeEvent: event, request: event.node.req } as any;
|
||||
const ctx = await createTRPCContext(apiEvent);
|
||||
return appRouter.createCaller(ctx);
|
||||
return createCallerFactory(ctx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a server-side caller for tRPC procedures from APIEvent
|
||||
* Used in API route handlers
|
||||
*/
|
||||
export const createServerCaller = async (event: APIEvent) => {
|
||||
const ctx = await createTRPCContext(event);
|
||||
return createCallerFactory(ctx);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
getAnalyticsSummary,
|
||||
getPathAnalytics,
|
||||
cleanupOldAnalytics,
|
||||
logVisit,
|
||||
getPerformanceStats,
|
||||
enrichAnalyticsEntry
|
||||
} from "~/server/analytics";
|
||||
@@ -13,6 +12,26 @@ import { ConnectionFactory } from "~/server/database";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { getRequestIP } from "vinxi/http";
|
||||
|
||||
/** Safely get a header value from either Fetch API Headers or Node.js IncomingHttpHeaders */
|
||||
function getHeader(
|
||||
headers: Record<string, string | string[] | undefined> | Headers | undefined,
|
||||
name: string
|
||||
): string | undefined {
|
||||
if (!headers) return undefined;
|
||||
|
||||
// Check if it's a Fetch API Headers object (has .get method)
|
||||
if (typeof (headers as Headers).get === "function") {
|
||||
return (headers as Headers).get(name) || undefined;
|
||||
}
|
||||
|
||||
// Otherwise treat as Node.js IncomingHttpHeaders (plain object)
|
||||
const value = (headers as Record<string, string | string[] | undefined>)[
|
||||
name.toLowerCase()
|
||||
];
|
||||
if (Array.isArray(value)) return value[0];
|
||||
return value;
|
||||
}
|
||||
|
||||
export const analyticsRouter = createTRPCRouter({
|
||||
logPerformance: publicProcedure
|
||||
.input(
|
||||
@@ -71,14 +90,12 @@ export const analyticsRouter = createTRPCRouter({
|
||||
} else {
|
||||
const req = ctx.event.nativeEvent.node?.req || ctx.event.nativeEvent;
|
||||
const userAgent =
|
||||
req.headers?.["user-agent"] ||
|
||||
ctx.event.request?.headers?.get("user-agent") ||
|
||||
undefined;
|
||||
getHeader(req.headers, "user-agent") ||
|
||||
getHeader(ctx.event.request?.headers, "user-agent");
|
||||
const referrer =
|
||||
req.headers?.referer ||
|
||||
req.headers?.referrer ||
|
||||
ctx.event.request?.headers?.get("referer") ||
|
||||
undefined;
|
||||
getHeader(req.headers, "referer") ||
|
||||
getHeader(req.headers, "referrer") ||
|
||||
getHeader(ctx.event.request?.headers, "referer");
|
||||
const ipAddress = getRequestIP(ctx.event.nativeEvent) || undefined;
|
||||
const enriched = enrichAnalyticsEntry({
|
||||
userId: ctx.userId,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { createCallerFactory, appRouter } from "~/server/api/root";
|
||||
import { createTRPCContext } from "~/server/api/utils";
|
||||
|
||||
vi.mock("~/server/apple-notification", () => ({
|
||||
@@ -17,9 +17,10 @@ vi.mock("~/server/apple-notification-store", () => ({
|
||||
|
||||
describe("apple notification router", () => {
|
||||
it("verifies and stores notifications", async () => {
|
||||
const caller = appRouter.createCaller(
|
||||
await createTRPCContext({ nativeEvent: { node: { req: {} } } } as any)
|
||||
);
|
||||
const ctx = await createTRPCContext({
|
||||
nativeEvent: { node: { req: {} } }
|
||||
} as any);
|
||||
const caller = createCallerFactory(ctx);
|
||||
|
||||
const result = await caller.appleNotifications.verifyAndStore.mutate({
|
||||
signedPayload: "test"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { createCallerFactory } from "~/server/api/root";
|
||||
import { createTRPCContext } from "~/server/api/utils";
|
||||
|
||||
// Mock the S3 client and getSignedUrl function
|
||||
@@ -33,9 +33,8 @@ process.env.VITE_DOWNLOAD_BUCKET_STRING = "test-bucket";
|
||||
|
||||
describe("downloads router", () => {
|
||||
it("should return a signed URL for valid asset names", async () => {
|
||||
const caller = appRouter.createCaller(
|
||||
await createTRPCContext({ nativeEvent: {} } as any)
|
||||
);
|
||||
const ctx = await createTRPCContext({ nativeEvent: {} } as any);
|
||||
const caller = createCallerFactory(ctx);
|
||||
|
||||
const result = await caller.downloads.getDownloadUrl.query({
|
||||
asset_name: "lineage"
|
||||
@@ -46,9 +45,8 @@ describe("downloads router", () => {
|
||||
});
|
||||
|
||||
it("should throw NOT_FOUND for invalid asset names", async () => {
|
||||
const caller = appRouter.createCaller(
|
||||
await createTRPCContext({ nativeEvent: {} } as any)
|
||||
);
|
||||
const ctx = await createTRPCContext({ nativeEvent: {} } as any);
|
||||
const caller = createCallerFactory(ctx);
|
||||
|
||||
try {
|
||||
await caller.downloads.getDownloadUrl.query({
|
||||
|
||||
@@ -12,6 +12,26 @@ export type Context = {
|
||||
cairnUserId: string | null;
|
||||
};
|
||||
|
||||
/** Safely get a header value from either Fetch API Headers or Node.js IncomingHttpHeaders */
|
||||
function getHeader(
|
||||
headers: Record<string, string | string[] | undefined> | Headers | undefined,
|
||||
name: string
|
||||
): string | undefined {
|
||||
if (!headers) return undefined;
|
||||
|
||||
// Check if it's a Fetch API Headers object (has .get method)
|
||||
if (typeof (headers as Headers).get === "function") {
|
||||
return (headers as Headers).get(name) || undefined;
|
||||
}
|
||||
|
||||
// Otherwise treat as Node.js IncomingHttpHeaders (plain object)
|
||||
const value = (headers as Record<string, string | string[] | undefined>)[
|
||||
name.toLowerCase()
|
||||
];
|
||||
if (Array.isArray(value)) return value[0];
|
||||
return value;
|
||||
}
|
||||
|
||||
async function createContextInner(event: APIEvent): Promise<Context> {
|
||||
const payload = await getAuthPayloadFromEvent(event.nativeEvent);
|
||||
|
||||
@@ -27,19 +47,16 @@ async function createContextInner(event: APIEvent): Promise<Context> {
|
||||
const path = req.url || event.request?.url || "unknown";
|
||||
const method = req.method || event.request?.method || "GET";
|
||||
const userAgent =
|
||||
req.headers?.["user-agent"] ||
|
||||
event.request?.headers?.get("user-agent") ||
|
||||
undefined;
|
||||
getHeader(req.headers, "user-agent") ||
|
||||
getHeader(event.request?.headers, "user-agent");
|
||||
const referrer =
|
||||
req.headers?.referer ||
|
||||
req.headers?.referrer ||
|
||||
event.request?.headers?.get("referer") ||
|
||||
undefined;
|
||||
getHeader(req.headers, "referer") ||
|
||||
getHeader(req.headers, "referrer") ||
|
||||
getHeader(event.request?.headers, "referer");
|
||||
const ipAddress = getRequestIP(event.nativeEvent) || undefined;
|
||||
const authHeader =
|
||||
event.request?.headers?.get("authorization") ||
|
||||
req.headers?.authorization ||
|
||||
req.headers?.Authorization ||
|
||||
getHeader(req.headers, "authorization") ||
|
||||
getHeader(event.request?.headers, "authorization") ||
|
||||
null;
|
||||
|
||||
let cairnUserId: string | null = null;
|
||||
|
||||
Reference in New Issue
Block a user