Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/app/(dashboard)/settings/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { createClient } from "@/utils/supabase/server";
import { revalidatePath } from "next/cache";
import OpenAI from "openai";
import { MODEL_DESIGNATIONS } from '@/lib/ai-models';

interface SecurityResult {
success: boolean;
Expand Down Expand Up @@ -111,11 +110,11 @@ interface ApiTestResult {
});

const response = await openai.chat.completions.create({
model: MODEL_DESIGNATIONS.FAST_CHEAP_FREE,
model: 'gpt-5-mini-2025-08-07',
messages: [{ role: 'user', content: 'Say this is a test!' }],
response_format: { type: "text" },
temperature: 1,
max_tokens: 8000,
max_tokens: 256,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0
Expand Down
9 changes: 6 additions & 3 deletions src/app/auth/callback/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ export async function GET(request: NextRequest) {
const next = requestUrl.searchParams.get('next')

if (code) {
// Ensure you pass cookies correctly. For App Router, it's a function.
const supabase = await createClient()
await supabase.auth.exchangeCodeForSession(code)
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (error) {
// Redirect to login with error indication if code exchange fails
return NextResponse.redirect(new URL('/auth/login?error=auth_callback_failed', requestUrl.origin))
}
}

// URL to redirect to after sign in process completes
Expand All @@ -20,6 +23,6 @@ export async function GET(request: NextRequest) {

// Construct the full redirect URL
return NextResponse.redirect(new URL(redirectPath, requestUrl.origin))
}
}


10 changes: 9 additions & 1 deletion src/app/auth/login/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ export async function deleteUserAccount(formData: FormData) {

if (profileError) throw new Error(profileError.message)

// Delete user's jobs
const { error: jobError } = await serviceClient
.from('jobs')
.delete()
.eq('user_id', user.id)

if (jobError) throw new Error(jobError.message)

// Delete user's resumes
const { error: resumeError } = await serviceClient
.from('resumes')
Expand All @@ -375,4 +383,4 @@ export async function deleteUserAccount(formData: FormData) {
}

redirect('/')
}
}
35 changes: 14 additions & 21 deletions src/utils/actions/cover-letter/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,28 +89,21 @@ export async function generate(input: string, config?: AIConfig) {
`;

(async () => {
const { textStream } = streamText({
model: aiClient as LanguageModelV1,
system,
prompt: input,
onFinish: ({ usage }) => {
const { promptTokens, completionTokens, totalTokens } = usage;

// your own logic, e.g. for saving the chat history or recording usage
console.log('----------Usage:----------');
console.log('Prompt tokens:', promptTokens);
console.log('Completion tokens:', completionTokens);
console.log('Total tokens:', totalTokens);
},

});

for await (const delta of textStream) {
stream.update(delta);
try {
const { textStream } = streamText({
model: aiClient as LanguageModelV1,
system,
prompt: input,
});

for await (const delta of textStream) {
stream.update(delta);
}

stream.done();
} catch (err) {
stream.error(err instanceof Error ? err : new Error('Failed to generate cover letter'));
}


stream.done();
})();

return { output: stream.value };
Expand Down
16 changes: 12 additions & 4 deletions src/utils/actions/jobs/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ export async function deleteJob(jobId: string): Promise<void> {
const { data: affectedResumes } = await supabase
.from('resumes')
.select('id')
.eq('job_id', jobId);
.eq('job_id', jobId)
.eq('user_id', user.id);

// Delete the job
const { error: deleteError } = await supabase
.from('jobs')
.delete()
.eq('id', jobId);
.eq('id', jobId)
.eq('user_id', user.id);

if (deleteError) {
console.error('Delete error:', deleteError);
Expand Down Expand Up @@ -138,11 +140,17 @@ export async function getJobListings({

export async function deleteTailoredJob(jobId: string): Promise<void> {
const supabase = await createClient();
const { data: { user }, error: userError } = await supabase.auth.getUser();

if (userError || !user) {
throw new Error('User not authenticated');
}

const { error } = await supabase
.from('jobs')
.update({ is_active: false })
.eq('id', jobId);
.eq('id', jobId)
.eq('user_id', user.id);

if (error) {
throw new Error('Failed to delete job');
Expand Down Expand Up @@ -186,4 +194,4 @@ export async function createEmptyJob(): Promise<Job> {

revalidatePath('/', 'layout');
return data;
}
}
2 changes: 0 additions & 2 deletions src/utils/actions/profiles/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export async function importResume(data: Partial<Profile>): Promise<Profile> {
const { data: { user }, error: userError } = await supabase.auth.getUser();

if (userError || !user) {
void userError
throw new Error(`Failed to fetch current profile: ${userError?.message || 'Unknown error'}`);
}

Expand All @@ -49,7 +48,6 @@ export async function importResume(data: Partial<Profile>): Promise<Profile> {
.single();

if (fetchError) {
void fetchError
throw new Error(`Failed to fetch current profile: ${fetchError.message}`);
}

Expand Down
6 changes: 1 addition & 5 deletions src/utils/actions/resumes/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,6 @@ export async function createTailoredResume(
companyName: string,
tailoredContent: z.infer<typeof simplifiedResumeSchema>
) {
console.log('[createTailoredResume] Received jobId:', jobId);
console.log('[createTailoredResume] baseResume ID:', baseResume?.id);
console.log('[createTailoredResume] Is jobId valid UUID?:', /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(jobId || ''));

const supabase = await createClient();
const { data: { user }, error: userError } = await supabase.auth.getUser();

Expand Down Expand Up @@ -452,7 +448,7 @@ export async function countResumes(type: 'base' | 'tailored' | 'all'): Promise<n
throw new Error('Failed to count resumes');
}

return count || -1;
return count ?? 0;
}


Expand Down
17 changes: 1 addition & 16 deletions src/utils/actions/stripe/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ export async function getSubscriptionStatus() {
throw new Error('User not authenticated');
}

console.log(' looking for user ', user.id);

const { data: subscription, error: subscriptionError } = await supabase
.from('subscriptions')
.select(`
Expand All @@ -264,10 +262,9 @@ export async function getSubscriptionStatus() {

if (subscriptionError) {
// If no subscription found, return a default free plan instead of throwing
void subscriptionError
if (subscriptionError.code === 'PGRST116') {
return {
subscription_plan: 'Free',
subscription_plan: 'free',
subscription_status: 'active',
current_period_end: null,
trial_end: null,
Expand Down Expand Up @@ -305,18 +302,6 @@ export async function checkSubscriptionPlan() {
const subscriptionState = getSubscriptionAccessState(data);
const effectivePlan = data ? subscriptionState.effectivePlan : '';

console.log('🧮 checkSubscriptionPlan', {
userId: user.id,
subscription_plan: data?.subscription_plan,
subscription_status: data?.subscription_status,
stripe_subscription_id: data?.stripe_subscription_id,
current_period_end: data?.current_period_end,
trial_end: data?.trial_end,
isTrialing: subscriptionState.isTrialing,
hasProAccess: subscriptionState.hasProAccess,
effectivePlan,
});

return {
plan: effectivePlan,
status: data?.subscription_status || '',
Expand Down
18 changes: 6 additions & 12 deletions src/utils/actions/subscriptions/actions.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
'use server';

export async function getSubscriptionStatus() {
// Existing getSubscriptionStatus implementation
}

export async function createCheckoutSession(priceId: string) {
void priceId
// Existing createCheckoutSession implementation
}

export async function cancelSubscription() {
// Existing cancelSubscription implementation
}
// NOTE: Subscription management is handled in src/utils/actions/stripe/actions.ts
// This file previously contained stub functions that were never implemented.
// The actual implementations live in the stripe actions module:
// - getSubscriptionStatus → stripe/actions.ts
// - createCheckoutSession → handled via Stripe checkout flow
// - cancelSubscription → handled via Stripe portal
4 changes: 2 additions & 2 deletions src/utils/ai-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const HIDDEN_MODELS: Record<string, HiddenModel> = {
* Initializes an AI client based on the provided configuration
* Falls back to default OpenAI configuration if no config is provided
*/
export function initializeAIClient(config?: AIConfig, isPro?: boolean, useThinking?: boolean) {
void useThinking; // Keep for future use
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function initializeAIClient(config?: AIConfig, isPro?: boolean, _useThinking?: boolean) {

// Handle Pro subscription with environment variables
if (isPro && config) {
Expand Down