@@ -2,7 +2,86 @@ import "server-only";
22
33import { NextRequest , NextResponse } from "next/server" ;
44import { BetaAnalyticsDataClient } from "@google-analytics/data" ;
5- import serviceAccount from "../../../../../service-account" ;
5+ // import serviceAccount from "../../../../utils/service-account";
6+ interface ServiceAccountConfig {
7+ type ?: string ;
8+ project_id ?: string ;
9+ private_key_id ?: string ;
10+ private_key ?: string ;
11+ client_email ?: string ;
12+ client_id ?: string ;
13+ auth_uri ?: string ;
14+ token_uri ?: string ;
15+ auth_provider_x509_cert_url ?: string ;
16+ client_x509_cert_url ?: string ;
17+ universe_domain ?: string ;
18+ }
19+
20+ let decodedFromB64 : ServiceAccountConfig | null = null ;
21+
22+ if ( process . env . GOOGLE_SERVICE_ACCOUNT_B64 ) {
23+ try {
24+ decodedFromB64 = JSON . parse (
25+ Buffer . from ( process . env . GOOGLE_SERVICE_ACCOUNT_B64 , "base64" ) . toString (
26+ "utf8"
27+ )
28+ ) ;
29+ } catch ( error ) {
30+ console . error ( "Failed to decode GOOGLE_SERVICE_ACCOUNT_B64:" , error ) ;
31+ }
32+ }
33+
34+ // Helper function to properly format private key
35+ function formatPrivateKey ( key : string | undefined ) : string | undefined {
36+ if ( ! key ) return undefined ;
37+
38+ // First, handle the case where the key might be wrapped in quotes
39+ let formatted = key . replace ( / ^ " | " $ / g, '' ) ;
40+
41+ // If it's already properly formatted (has newlines), just return it
42+ if ( formatted . includes ( '\n' ) && formatted . includes ( '-----BEGIN PRIVATE KEY-----' ) ) {
43+ return formatted ;
44+ }
45+
46+ // Handle literal "\n" strings (common in .env files)
47+ if ( formatted . includes ( '\\n' ) ) {
48+ formatted = formatted . replace ( / \\ n / g, '\n' ) ;
49+ } else {
50+ // If no newlines and no literal "\n", it might be a single line string
51+ // Try to insert newlines around headers if they exist but are on the same line
52+ formatted = formatted
53+ . replace ( '-----BEGIN PRIVATE KEY-----' , '-----BEGIN PRIVATE KEY-----\n' )
54+ . replace ( '-----END PRIVATE KEY-----' , '\n-----END PRIVATE KEY-----' ) ;
55+
56+ // If the body is still one long string, we might need to chunk it (PEM format usually requires 64 char lines)
57+ // However, Node's crypto usually handles single-line bodies if headers are correct.
58+ // Let's at least ensure headers are on their own lines.
59+ }
60+
61+ // Remove any extra whitespace but preserve the structure
62+ formatted = formatted . trim ( ) ;
63+
64+ return formatted ;
65+ }
66+
67+ const serviceAccount = decodedFromB64 ?? {
68+ type : process . env . GOOGLE_TYPE ,
69+ project_id : process . env . GOOGLE_PROJECT_ID ,
70+ private_key_id : process . env . GOOGLE_PRIVATE_KEY_ID ,
71+ private_key : formatPrivateKey ( process . env . GOOGLE_PRIVATE_KEY ) ,
72+ client_email : process . env . GOOGLE_CLIENT_EMAIL ,
73+ client_id : process . env . GOOGLE_CLIENT_ID ,
74+ auth_uri : process . env . GOOGLE_AUTH_URI ,
75+ token_uri : process . env . GOOGLE_TOKEN_URI ,
76+ auth_provider_x509_cert_url : process . env . GOOGLE_AUTH_PROVIDER_CERT_URL ,
77+ client_x509_cert_url : process . env . GOOGLE_CLIENT_CERT_URL ,
78+ universe_domain : process . env . GOOGLE_UNIVERSE_DOMAIN ,
79+ } ;
80+
81+ // Ensure private_key is properly formatted even if decoded from base64
82+ if ( serviceAccount . private_key && typeof serviceAccount . private_key === "string" ) {
83+ serviceAccount . private_key = formatPrivateKey ( serviceAccount . private_key ) ;
84+ } console . log ( "Analytics Route Module Loading..." ) ;
685
786const PROPERTY_ID = ( process . env . GOOGLE_ANALYTICS_PROPERTY_ID || "496861567" ) . replace ( / [ ' " ] / g, '' ) ;
887
@@ -64,7 +143,19 @@ export const dynamic = "force-dynamic";
64143
65144export async function GET ( request : NextRequest ) {
66145 try {
146+ console . log ( "Analytics Route Handler Called" ) ;
67147 const { searchParams } = new URL ( request . url ) ;
148+
149+ // Health check for debugging deployment
150+ if ( searchParams . get ( "test" ) === "true" ) {
151+ return NextResponse . json ( {
152+ status : "ok" ,
153+ message : "Analytics route is reachable" ,
154+ hasServiceAccount : ! ! serviceAccount ,
155+ hasClientEmail : ! ! serviceAccount ?. client_email
156+ } ) ;
157+ }
158+
68159 const pagePath = searchParams . get ( "path" ) ;
69160 const startDateParam = searchParams . get ( "startDate" ) ;
70161 const endDateParam = searchParams . get ( "endDate" ) ;
@@ -174,5 +265,3 @@ dimensionFilter: {
174265 return NextResponse . json ( { error : message } , { status : 500 } ) ;
175266 }
176267}
177-
178-
0 commit comments