fix: analytics and deprecated warning
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import type { APIEvent } from "@solidjs/start/server";
|
import type { APIEvent } from "@solidjs/start/server";
|
||||||
import { appRouter } from "~/server/api/root";
|
import { createServerCaller } from "~/server/api/root";
|
||||||
import { createTRPCContext } from "~/server/api/utils";
|
|
||||||
|
|
||||||
export async function GET(event: APIEvent) {
|
export async function GET(event: APIEvent) {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
@@ -31,8 +30,7 @@ export async function GET(event: APIEvent) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("[GitHub OAuth Callback] Creating tRPC caller...");
|
console.log("[GitHub OAuth Callback] Creating tRPC caller...");
|
||||||
const ctx = await createTRPCContext(event);
|
const caller = await createServerCaller(event);
|
||||||
const caller = appRouter.createCaller(ctx);
|
|
||||||
|
|
||||||
console.log("[GitHub OAuth Callback] Calling githubCallback procedure...");
|
console.log("[GitHub OAuth Callback] Calling githubCallback procedure...");
|
||||||
const result = await caller.auth.githubCallback({ code });
|
const result = await caller.auth.githubCallback({ code });
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { APIEvent } from "@solidjs/start/server";
|
import type { APIEvent } from "@solidjs/start/server";
|
||||||
import { appRouter } from "~/server/api/root";
|
import { createServerCaller } from "~/server/api/root";
|
||||||
import { createTRPCContext } from "~/server/api/utils";
|
|
||||||
|
|
||||||
export async function GET(event: APIEvent) {
|
export async function GET(event: APIEvent) {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
@@ -31,8 +30,7 @@ export async function GET(event: APIEvent) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("[Google OAuth Callback] Creating tRPC caller...");
|
console.log("[Google OAuth Callback] Creating tRPC caller...");
|
||||||
const ctx = await createTRPCContext(event);
|
const caller = await createServerCaller(event);
|
||||||
const caller = appRouter.createCaller(ctx);
|
|
||||||
|
|
||||||
console.log("[Google OAuth Callback] Calling googleCallback procedure...");
|
console.log("[Google OAuth Callback] Calling googleCallback procedure...");
|
||||||
const result = await caller.auth.googleCallback({ code });
|
const result = await caller.auth.googleCallback({ code });
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { APIEvent } from "@solidjs/start/server";
|
import type { APIEvent } from "@solidjs/start/server";
|
||||||
import { appRouter } from "~/server/api/root";
|
import { createServerCaller } from "~/server/api/root";
|
||||||
import { createTRPCContext } from "~/server/api/utils";
|
|
||||||
|
|
||||||
export async function GET(event: APIEvent) {
|
export async function GET(event: APIEvent) {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
@@ -27,8 +26,7 @@ export async function GET(event: APIEvent) {
|
|||||||
try {
|
try {
|
||||||
console.log("[Email Login Callback] Creating tRPC caller...");
|
console.log("[Email Login Callback] Creating tRPC caller...");
|
||||||
// Create tRPC caller to invoke the emailLogin procedure
|
// Create tRPC caller to invoke the emailLogin procedure
|
||||||
const ctx = await createTRPCContext(event);
|
const caller = await createServerCaller(event);
|
||||||
const caller = appRouter.createCaller(ctx);
|
|
||||||
|
|
||||||
console.log("[Email Login Callback] Calling emailLogin procedure...");
|
console.log("[Email Login Callback] Calling emailLogin procedure...");
|
||||||
// Call the email login handler - rememberMe will be read from JWT payload
|
// Call the email login handler - rememberMe will be read from JWT payload
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { APIEvent } from "@solidjs/start/server";
|
import type { APIEvent } from "@solidjs/start/server";
|
||||||
import { appRouter } from "~/server/api/root";
|
import { createServerCaller } from "~/server/api/root";
|
||||||
import { createTRPCContext } from "~/server/api/utils";
|
|
||||||
|
|
||||||
export async function GET(event: APIEvent) {
|
export async function GET(event: APIEvent) {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
@@ -57,20 +56,19 @@ export async function GET(event: APIEvent) {
|
|||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { "Content-Type": "text/html" },
|
headers: { "Content-Type": "text/html" }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create tRPC caller to invoke the emailVerification procedure
|
// Create tRPC caller to invoke the emailVerification procedure
|
||||||
const ctx = await createTRPCContext(event);
|
const caller = await createServerCaller(event);
|
||||||
const caller = appRouter.createCaller(ctx);
|
|
||||||
|
|
||||||
// Call the email verification handler
|
// Call the email verification handler
|
||||||
const result = await caller.auth.emailVerification({
|
const result = await caller.auth.emailVerification({
|
||||||
email,
|
email,
|
||||||
token,
|
token
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -129,7 +127,7 @@ export async function GET(event: APIEvent) {
|
|||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { "Content-Type": "text/html" },
|
headers: { "Content-Type": "text/html" }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -139,8 +137,10 @@ export async function GET(event: APIEvent) {
|
|||||||
console.error("Email verification callback error:", error);
|
console.error("Email verification callback error:", error);
|
||||||
|
|
||||||
// Check if it's a token expiration error
|
// Check if it's a token expiration error
|
||||||
const errorMessage = error instanceof Error ? error.message : "server_error";
|
const errorMessage =
|
||||||
const isTokenError = errorMessage.includes("expired") || errorMessage.includes("invalid");
|
error instanceof Error ? error.message : "server_error";
|
||||||
|
const isTokenError =
|
||||||
|
errorMessage.includes("expired") || errorMessage.includes("invalid");
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
`
|
`
|
||||||
@@ -192,7 +192,7 @@ export async function GET(event: APIEvent) {
|
|||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
status: 400,
|
status: 400,
|
||||||
headers: { "Content-Type": "text/html" },
|
headers: { "Content-Type": "text/html" }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ import { accountRouter } from "./routers/account";
|
|||||||
import { downloadsRouter } from "./routers/downloads";
|
import { downloadsRouter } from "./routers/downloads";
|
||||||
import { cairnDbRouter } from "./routers/cairn";
|
import { cairnDbRouter } from "./routers/cairn";
|
||||||
import { appleNotificationsRouter } from "./routers/apple-notifications";
|
import { appleNotificationsRouter } from "./routers/apple-notifications";
|
||||||
import { createTRPCRouter, createTRPCContext } from "./utils";
|
import { createTRPCRouter, createTRPCContext, t } from "./utils";
|
||||||
import type { H3Event } from "h3";
|
import type { H3Event } from "h3";
|
||||||
|
import type { APIEvent } from "@solidjs/start/server";
|
||||||
|
|
||||||
export const appRouter = createTRPCRouter({
|
export const appRouter = createTRPCRouter({
|
||||||
auth: authRouter,
|
auth: authRouter,
|
||||||
@@ -36,12 +37,24 @@ export const appRouter = createTRPCRouter({
|
|||||||
|
|
||||||
export type AppRouter = typeof appRouter;
|
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
|
* Create a server-side caller for tRPC procedures from H3Event (vinxi/http getEvent)
|
||||||
* This allows calling tRPC procedures directly on the server with proper context
|
* Used in server functions within route files
|
||||||
*/
|
*/
|
||||||
export const createCaller = async (event: H3Event) => {
|
export const createCaller = async (event: H3Event) => {
|
||||||
const apiEvent = { nativeEvent: event, request: event.node.req } as any;
|
const apiEvent = { nativeEvent: event, request: event.node.req } as any;
|
||||||
const ctx = await createTRPCContext(apiEvent);
|
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,
|
getAnalyticsSummary,
|
||||||
getPathAnalytics,
|
getPathAnalytics,
|
||||||
cleanupOldAnalytics,
|
cleanupOldAnalytics,
|
||||||
logVisit,
|
|
||||||
getPerformanceStats,
|
getPerformanceStats,
|
||||||
enrichAnalyticsEntry
|
enrichAnalyticsEntry
|
||||||
} from "~/server/analytics";
|
} from "~/server/analytics";
|
||||||
@@ -13,6 +12,26 @@ import { ConnectionFactory } from "~/server/database";
|
|||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import { getRequestIP } from "vinxi/http";
|
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({
|
export const analyticsRouter = createTRPCRouter({
|
||||||
logPerformance: publicProcedure
|
logPerformance: publicProcedure
|
||||||
.input(
|
.input(
|
||||||
@@ -71,14 +90,12 @@ export const analyticsRouter = createTRPCRouter({
|
|||||||
} else {
|
} else {
|
||||||
const req = ctx.event.nativeEvent.node?.req || ctx.event.nativeEvent;
|
const req = ctx.event.nativeEvent.node?.req || ctx.event.nativeEvent;
|
||||||
const userAgent =
|
const userAgent =
|
||||||
req.headers?.["user-agent"] ||
|
getHeader(req.headers, "user-agent") ||
|
||||||
ctx.event.request?.headers?.get("user-agent") ||
|
getHeader(ctx.event.request?.headers, "user-agent");
|
||||||
undefined;
|
|
||||||
const referrer =
|
const referrer =
|
||||||
req.headers?.referer ||
|
getHeader(req.headers, "referer") ||
|
||||||
req.headers?.referrer ||
|
getHeader(req.headers, "referrer") ||
|
||||||
ctx.event.request?.headers?.get("referer") ||
|
getHeader(ctx.event.request?.headers, "referer");
|
||||||
undefined;
|
|
||||||
const ipAddress = getRequestIP(ctx.event.nativeEvent) || undefined;
|
const ipAddress = getRequestIP(ctx.event.nativeEvent) || undefined;
|
||||||
const enriched = enrichAnalyticsEntry({
|
const enriched = enrichAnalyticsEntry({
|
||||||
userId: ctx.userId,
|
userId: ctx.userId,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, vi } from "vitest";
|
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";
|
import { createTRPCContext } from "~/server/api/utils";
|
||||||
|
|
||||||
vi.mock("~/server/apple-notification", () => ({
|
vi.mock("~/server/apple-notification", () => ({
|
||||||
@@ -17,9 +17,10 @@ vi.mock("~/server/apple-notification-store", () => ({
|
|||||||
|
|
||||||
describe("apple notification router", () => {
|
describe("apple notification router", () => {
|
||||||
it("verifies and stores notifications", async () => {
|
it("verifies and stores notifications", async () => {
|
||||||
const caller = appRouter.createCaller(
|
const ctx = await createTRPCContext({
|
||||||
await createTRPCContext({ nativeEvent: { node: { req: {} } } } as any)
|
nativeEvent: { node: { req: {} } }
|
||||||
);
|
} as any);
|
||||||
|
const caller = createCallerFactory(ctx);
|
||||||
|
|
||||||
const result = await caller.appleNotifications.verifyAndStore.mutate({
|
const result = await caller.appleNotifications.verifyAndStore.mutate({
|
||||||
signedPayload: "test"
|
signedPayload: "test"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, vi } from "vitest";
|
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";
|
import { createTRPCContext } from "~/server/api/utils";
|
||||||
|
|
||||||
// Mock the S3 client and getSignedUrl function
|
// Mock the S3 client and getSignedUrl function
|
||||||
@@ -33,9 +33,8 @@ process.env.VITE_DOWNLOAD_BUCKET_STRING = "test-bucket";
|
|||||||
|
|
||||||
describe("downloads router", () => {
|
describe("downloads router", () => {
|
||||||
it("should return a signed URL for valid asset names", async () => {
|
it("should return a signed URL for valid asset names", async () => {
|
||||||
const caller = appRouter.createCaller(
|
const ctx = await createTRPCContext({ nativeEvent: {} } as any);
|
||||||
await createTRPCContext({ nativeEvent: {} } as any)
|
const caller = createCallerFactory(ctx);
|
||||||
);
|
|
||||||
|
|
||||||
const result = await caller.downloads.getDownloadUrl.query({
|
const result = await caller.downloads.getDownloadUrl.query({
|
||||||
asset_name: "lineage"
|
asset_name: "lineage"
|
||||||
@@ -46,9 +45,8 @@ describe("downloads router", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should throw NOT_FOUND for invalid asset names", async () => {
|
it("should throw NOT_FOUND for invalid asset names", async () => {
|
||||||
const caller = appRouter.createCaller(
|
const ctx = await createTRPCContext({ nativeEvent: {} } as any);
|
||||||
await createTRPCContext({ nativeEvent: {} } as any)
|
const caller = createCallerFactory(ctx);
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await caller.downloads.getDownloadUrl.query({
|
await caller.downloads.getDownloadUrl.query({
|
||||||
|
|||||||
@@ -12,6 +12,26 @@ export type Context = {
|
|||||||
cairnUserId: string | null;
|
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> {
|
async function createContextInner(event: APIEvent): Promise<Context> {
|
||||||
const payload = await getAuthPayloadFromEvent(event.nativeEvent);
|
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 path = req.url || event.request?.url || "unknown";
|
||||||
const method = req.method || event.request?.method || "GET";
|
const method = req.method || event.request?.method || "GET";
|
||||||
const userAgent =
|
const userAgent =
|
||||||
req.headers?.["user-agent"] ||
|
getHeader(req.headers, "user-agent") ||
|
||||||
event.request?.headers?.get("user-agent") ||
|
getHeader(event.request?.headers, "user-agent");
|
||||||
undefined;
|
|
||||||
const referrer =
|
const referrer =
|
||||||
req.headers?.referer ||
|
getHeader(req.headers, "referer") ||
|
||||||
req.headers?.referrer ||
|
getHeader(req.headers, "referrer") ||
|
||||||
event.request?.headers?.get("referer") ||
|
getHeader(event.request?.headers, "referer");
|
||||||
undefined;
|
|
||||||
const ipAddress = getRequestIP(event.nativeEvent) || undefined;
|
const ipAddress = getRequestIP(event.nativeEvent) || undefined;
|
||||||
const authHeader =
|
const authHeader =
|
||||||
event.request?.headers?.get("authorization") ||
|
getHeader(req.headers, "authorization") ||
|
||||||
req.headers?.authorization ||
|
getHeader(event.request?.headers, "authorization") ||
|
||||||
req.headers?.Authorization ||
|
|
||||||
null;
|
null;
|
||||||
|
|
||||||
let cairnUserId: string | null = null;
|
let cairnUserId: string | null = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user