Merge remote-tracking branch 'origin/main' into cloudflare

This commit is contained in:
javayhu 2025-08-03 15:20:14 +08:00
commit 62eb4124be
32 changed files with 478 additions and 689 deletions

View File

@ -181,8 +181,9 @@ FAL_API_KEY=""
FIREWORKS_API_KEY="" FIREWORKS_API_KEY=""
OPENAI_API_KEY="" OPENAI_API_KEY=""
REPLICATE_API_TOKEN="" REPLICATE_API_TOKEN=""
GOOGLE_API_KEY="" GOOGLE_GENERATIVE_AI_API_KEY=""
DEEPSEEK_API_KEY="" DEEPSEEK_API_KEY=""
OPENROUTER_API_KEY=""
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Web Content Analyzer (Firecrawl) # Web Content Analyzer (Firecrawl)

View File

@ -25,13 +25,12 @@
"knip": "knip" "knip": "knip"
}, },
"dependencies": { "dependencies": {
"@ai-sdk/deepseek": "^0.2.16", "@ai-sdk/deepseek": "^1.0.0",
"@ai-sdk/fal": "^0.1.12", "@ai-sdk/fal": "^1.0.0",
"@ai-sdk/fireworks": "^0.2.14", "@ai-sdk/fireworks": "^1.0.0",
"@ai-sdk/google": "^1.2.22", "@ai-sdk/google": "^2.0.0",
"@ai-sdk/google-vertex": "^2.2.24", "@ai-sdk/openai": "^2.0.0",
"@ai-sdk/openai": "^1.1.13", "@ai-sdk/replicate": "^1.0.0",
"@ai-sdk/replicate": "^0.2.8",
"@base-ui-components/react": "1.0.0-beta.0", "@base-ui-components/react": "1.0.0-beta.0",
"@better-fetch/fetch": "^1.1.18", "@better-fetch/fetch": "^1.1.18",
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
@ -43,6 +42,7 @@
"@mendable/firecrawl-js": "^1.29.1", "@mendable/firecrawl-js": "^1.29.1",
"@next/third-parties": "^15.3.0", "@next/third-parties": "^15.3.0",
"@openpanel/nextjs": "^1.0.7", "@openpanel/nextjs": "^1.0.7",
"@openrouter/ai-sdk-provider": "^1.0.0-beta.6",
"@orama/orama": "^3.1.4", "@orama/orama": "^3.1.4",
"@orama/tokenizers": "^3.1.4", "@orama/tokenizers": "^3.1.4",
"@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-accordion": "^1.2.3",
@ -83,7 +83,7 @@
"@vercel/analytics": "^1.5.0", "@vercel/analytics": "^1.5.0",
"@vercel/speed-insights": "^1.2.0", "@vercel/speed-insights": "^1.2.0",
"@widgetbot/react-embed": "^1.9.0", "@widgetbot/react-embed": "^1.9.0",
"ai": "^4.1.45", "ai": "^5.0.0",
"better-auth": "^1.1.19", "better-auth": "^1.1.19",
"canvas-confetti": "^1.9.3", "canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
@ -98,9 +98,9 @@
"drizzle-orm": "^0.39.3", "drizzle-orm": "^0.39.3",
"embla-carousel-react": "^8.5.2", "embla-carousel-react": "^8.5.2",
"framer-motion": "^12.4.7", "framer-motion": "^12.4.7",
"fumadocs-core": "^15.5.3", "fumadocs-core": "^15.6.7",
"fumadocs-mdx": "^11.6.8", "fumadocs-mdx": "^11.7.3",
"fumadocs-ui": "^15.5.3", "fumadocs-ui": "^15.6.7",
"inngest": "^3.40.1", "inngest": "^3.40.1",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.483.0", "lucide-react": "^0.483.0",
@ -133,7 +133,7 @@
"use-intl": "^3.26.5", "use-intl": "^3.26.5",
"use-media": "^1.5.0", "use-media": "^1.5.0",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"zod": "^3.24.2", "zod": "^4.0.14",
"zustand": "^5.0.3" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {

959
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ const actionClient = createSafeActionClient();
// Newsletter schema for validation // Newsletter schema for validation
const newsletterSchema = z.object({ const newsletterSchema = z.object({
email: z.string().email({ message: 'Please enter a valid email address' }), email: z.email({ error: 'Please enter a valid email address' }),
}); });
// Create a safe action to check if a user is subscribed to the newsletter // Create a safe action to check if a user is subscribed to the newsletter

View File

@ -18,10 +18,10 @@ const actionClient = createSafeActionClient();
// Checkout schema for validation // Checkout schema for validation
// metadata is optional, and may contain referral information if you need // metadata is optional, and may contain referral information if you need
const checkoutSchema = z.object({ const checkoutSchema = z.object({
userId: z.string().min(1, { message: 'User ID is required' }), userId: z.string().min(1, { error: 'User ID is required' }),
planId: z.string().min(1, { message: 'Plan ID is required' }), planId: z.string().min(1, { error: 'Plan ID is required' }),
priceId: z.string().min(1, { message: 'Price ID is required' }), priceId: z.string().min(1, { error: 'Price ID is required' }),
metadata: z.record(z.string()).optional(), metadata: z.record(z.string(), z.string()).optional(),
}); });
/** /**

View File

@ -18,10 +18,10 @@ const actionClient = createSafeActionClient();
// Credit checkout schema for validation // Credit checkout schema for validation
// metadata is optional, and may contain referral information if you need // metadata is optional, and may contain referral information if you need
const creditCheckoutSchema = z.object({ const creditCheckoutSchema = z.object({
userId: z.string().min(1, { message: 'User ID is required' }), userId: z.string().min(1, { error: 'User ID is required' }),
packageId: z.string().min(1, { message: 'Package ID is required' }), packageId: z.string().min(1, { error: 'Package ID is required' }),
priceId: z.string().min(1, { message: 'Price ID is required' }), priceId: z.string().min(1, { error: 'Price ID is required' }),
metadata: z.record(z.string()).optional(), metadata: z.record(z.string(), z.string()).optional(),
}); });
/** /**

View File

@ -16,10 +16,10 @@ const actionClient = createSafeActionClient();
// Portal schema for validation // Portal schema for validation
const portalSchema = z.object({ const portalSchema = z.object({
userId: z.string().min(1, { message: 'User ID is required' }), userId: z.string().min(1, { error: 'User ID is required' }),
returnUrl: z returnUrl: z
.string() .string()
.url({ message: 'Return URL must be a valid URL' }) .url({ error: 'Return URL must be a valid URL' })
.optional(), .optional(),
}); });

View File

@ -10,7 +10,7 @@ const actionClient = createSafeActionClient();
// Input schema // Input schema
const schema = z.object({ const schema = z.object({
userId: z.string().min(1, { message: 'User ID is required' }), userId: z.string().min(1, { error: 'User ID is required' }),
}); });
/** /**
@ -47,6 +47,18 @@ export const getActiveSubscriptionAction = actionClient
}; };
} }
// Check if Stripe environment variables are configured
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
const stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
if (!stripeSecretKey || !stripeWebhookSecret) {
console.log('Stripe environment variables not configured, return');
return {
success: true,
data: null, // No subscription = free plan
};
}
try { try {
// Find the user's most recent active subscription // Find the user's most recent active subscription
const subscriptions = await getSubscriptions({ const subscriptions = await getSubscriptions({

View File

@ -14,7 +14,7 @@ const actionClient = createSafeActionClient();
// Input schema // Input schema
const schema = z.object({ const schema = z.object({
userId: z.string().min(1, { message: 'User ID is required' }), userId: z.string().min(1, { error: 'User ID is required' }),
}); });
/** /**

View File

@ -17,13 +17,13 @@ const actionClient = createSafeActionClient();
const contactFormSchema = z.object({ const contactFormSchema = z.object({
name: z name: z
.string() .string()
.min(3, { message: 'Name must be at least 3 characters' }) .min(3, { error: 'Name must be at least 3 characters' })
.max(30, { message: 'Name must not exceed 30 characters' }), .max(30, { error: 'Name must not exceed 30 characters' }),
email: z.string().email({ message: 'Please enter a valid email address' }), email: z.email({ error: 'Please enter a valid email address' }),
message: z message: z
.string() .string()
.min(10, { message: 'Message must be at least 10 characters' }) .min(10, { error: 'Message must be at least 10 characters' })
.max(500, { message: 'Message must not exceed 500 characters' }), .max(500, { error: 'Message must not exceed 500 characters' }),
}); });
// Create a safe action for contact form submission // Create a safe action for contact form submission

View File

@ -11,7 +11,7 @@ const actionClient = createSafeActionClient();
// Newsletter schema for validation // Newsletter schema for validation
const newsletterSchema = z.object({ const newsletterSchema = z.object({
email: z.string().email({ message: 'Please enter a valid email address' }), email: z.email({ error: 'Please enter a valid email address' }),
}); });
// Create a safe action for newsletter subscription // Create a safe action for newsletter subscription

View File

@ -10,7 +10,7 @@ const actionClient = createSafeActionClient();
// Newsletter schema for validation // Newsletter schema for validation
const newsletterSchema = z.object({ const newsletterSchema = z.object({
email: z.string().email({ message: 'Please enter a valid email address' }), email: z.email({ error: 'Please enter a valid email address' }),
}); });
// Create a safe action for newsletter unsubscription // Create a safe action for newsletter unsubscription

View File

@ -9,7 +9,7 @@ const actionClient = createSafeActionClient();
// Captcha validation schema // Captcha validation schema
const captchaSchema = z.object({ const captchaSchema = z.object({
captchaToken: z.string().min(1, { message: 'Captcha token is required' }), captchaToken: z.string().min(1, { error: 'Captcha token is required' }),
}); });
// Create a safe action for captcha validation // Create a safe action for captcha validation

View File

@ -61,7 +61,6 @@ export function ImagePlayground({
const providerToModel = { const providerToModel = {
replicate: selectedModels.replicate, replicate: selectedModels.replicate,
// vertex: selectedModels.vertex,
openai: selectedModels.openai, openai: selectedModels.openai,
fireworks: selectedModels.fireworks, fireworks: selectedModels.fireworks,
fal: selectedModels.fal, fal: selectedModels.fal,

View File

@ -15,7 +15,6 @@ import {
FireworksIcon, FireworksIcon,
OpenAIIcon, OpenAIIcon,
ReplicateIcon, ReplicateIcon,
// VertexIcon,
falAILogo, falAILogo,
} from '../lib/logos'; } from '../lib/logos';
import type { ProviderKey } from '../lib/provider-config'; import type { ProviderKey } from '../lib/provider-config';
@ -40,7 +39,6 @@ interface ModelSelectProps {
const PROVIDER_ICONS = { const PROVIDER_ICONS = {
openai: OpenAIIcon, openai: OpenAIIcon,
replicate: ReplicateIcon, replicate: ReplicateIcon,
// vertex: VertexIcon,
fireworks: FireworksIcon, fireworks: FireworksIcon,
fal: falAILogo, fal: falAILogo,
} as const; } as const;
@ -48,7 +46,6 @@ const PROVIDER_ICONS = {
const PROVIDER_LINKS = { const PROVIDER_LINKS = {
openai: 'openai', openai: 'openai',
replicate: 'replicate', replicate: 'replicate',
// vertex: 'google-vertex',
fireworks: 'fireworks', fireworks: 'fireworks',
fal: 'fal', fal: 'fal',
} as const; } as const;

View File

@ -62,55 +62,6 @@ export const ReplicateIcon = ({ size = 16 }) => {
); );
}; };
export const VertexIcon = ({ size = 16 }) => {
return (
<svg
height={size}
width={size}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
style={{ color: 'currentcolor' }}
>
<g transform="scale(0.8) translate(65,65)">
<path
d="M128,249c-8.8,0-16-7.2-16-16v-105c0-8.8,7.2-16,16-16s16,7.2,16,16v105c0,8.8-7.2,16-16,16Z"
fill="white"
/>
<path
d="M256,464c-3,0-6-.8-8.6-2.5l-176-112c-7.5-4.7-9.7-14.6-4.9-22.1,4.8-7.5,14.6-9.6,22.1-4.9l167.4,106.5,167.4-106.5c7.5-4.7,17.3-2.5,22.1,4.9,4.7,7.5,2.5,17.3-4.9,22.1l-176,112c-2.6,1.7-5.6,2.5-8.6,2.5h0Z"
fill="white"
/>
<path
d="M256,394c-8.8,0-16-7.2-16-16v-73.1c0-8.8,7.2-16,16-16s16,7.2,16,16v73.1c0,8.8-7.2,16-16,16Z"
fill="white"
/>
<circle cx="128" cy="64" r="16" fill="white" />
<circle cx="128" cy="297" r="16" fill="white" />
<path
d="M384.2,314c-8.8,0-16-7.1-16-16l-.2-106c0-8.8,7.1-16,16-16h0c8.8,0,16,7.1,16,16l.2,106c0,8.8-7.1,16-16,16h0Z"
fill="white"
/>
<circle cx="384" cy="64" r="16" fill="white" />
<circle cx="384" cy="128" r="16" fill="white" />
<path
d="M320,225c-8.8,0-16-7.2-16-16v-103c0-8.8,7.2-16,16-16s16,7.2,16,16v103c0,8.8-7.2,16-16,16Z"
fill="white"
/>
<circle cx="256" cy="177" r="16" fill="white" />
<circle cx="256" cy="241" r="16" fill="white" />
<circle cx="320" cy="273" r="16" fill="white" />
<circle cx="320" cy="337" r="16" fill="white" />
<path
d="M192,225c-8.8,0-16-7.2-16-16v-103c0-8.8,7.2-16,16-16s16,7.2,16,16v103c0,8.8-7.2,16-16,16Z"
fill="white"
/>
<circle cx="192" cy="273" r="16" fill="white" />
<circle cx="192" cy="337" r="16" fill="white" />
</g>
</svg>
);
};
export const falAILogo = ({ size = 16 }: { size: number }) => { export const falAILogo = ({ size = 16 }: { size: number }) => {
return ( return (
<svg <svg

View File

@ -1,9 +1,4 @@
export type ProviderKey = export type ProviderKey = 'replicate' | 'openai' | 'fireworks' | 'fal';
| 'replicate'
// | 'vertex'
| 'openai'
| 'fireworks'
| 'fal';
export type ModelMode = 'performance' | 'quality'; export type ModelMode = 'performance' | 'quality';
export const PROVIDERS: Record< export const PROVIDERS: Record<
@ -37,12 +32,6 @@ export const PROVIDERS: Record<
'stability-ai/stable-diffusion-3.5-large-turbo', 'stability-ai/stable-diffusion-3.5-large-turbo',
], ],
}, },
// vertex: {
// displayName: 'Vertex AI',
// iconPath: '/provider-icons/vertex.svg',
// color: 'from-green-500 to-emerald-500',
// models: ['imagen-3.0-generate-001', 'imagen-3.0-fast-generate-001'],
// },
// https://ai-sdk.dev/providers/ai-sdk-providers/openai#image-models // https://ai-sdk.dev/providers/ai-sdk-providers/openai#image-models
openai: { openai: {
displayName: 'OpenAI', displayName: 'OpenAI',
@ -92,14 +81,12 @@ export const PROVIDERS: Record<
export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = { export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = {
performance: { performance: {
replicate: 'black-forest-labs/flux-1.1-pro', replicate: 'black-forest-labs/flux-1.1-pro',
// vertex: 'imagen-3.0-fast-generate-001',
openai: 'dall-e-3', openai: 'dall-e-3',
fireworks: 'accounts/fireworks/models/flux-1-schnell-fp8', fireworks: 'accounts/fireworks/models/flux-1-schnell-fp8',
fal: 'fal-ai/flux/dev', fal: 'fal-ai/flux/dev',
}, },
quality: { quality: {
replicate: 'stability-ai/stable-diffusion-3.5-large', replicate: 'stability-ai/stable-diffusion-3.5-large',
// vertex: 'imagen-3.0-generate-001',
openai: 'dall-e-3', openai: 'dall-e-3',
fireworks: 'accounts/fireworks/models/flux-1-dev-fp8', fireworks: 'accounts/fireworks/models/flux-1-dev-fp8',
fal: 'fal-ai/flux-pro/v1.1-ultra', fal: 'fal-ai/flux-pro/v1.1-ultra',
@ -108,7 +95,6 @@ export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = {
export const PROVIDER_ORDER: ProviderKey[] = [ export const PROVIDER_ORDER: ProviderKey[] = [
'replicate', 'replicate',
// 'vertex',
'openai', 'openai',
'fireworks', 'fireworks',
'fal', 'fal',

View File

@ -40,7 +40,7 @@ import { useDebounce } from '../utils/performance';
// Form schema for URL input // Form schema for URL input
const urlFormSchema = z.object({ const urlFormSchema = z.object({
url: z.string().url().optional(), // Allow empty string for initial state url: z.url().optional(), // Allow empty string for initial state
}); });
type UrlFormData = z.infer<typeof urlFormSchema>; type UrlFormData = z.infer<typeof urlFormSchema>;
@ -164,6 +164,7 @@ export function UrlInputForm({
<SelectItem value="openai">OpenAI GPT-4o</SelectItem> <SelectItem value="openai">OpenAI GPT-4o</SelectItem>
<SelectItem value="gemini">Google Gemini</SelectItem> <SelectItem value="gemini">Google Gemini</SelectItem>
<SelectItem value="deepseek">DeepSeek</SelectItem> <SelectItem value="deepseek">DeepSeek</SelectItem>
<SelectItem value="openrouter">OpenRouter</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>

View File

@ -117,6 +117,13 @@ export const webContentAnalyzerConfig = {
temperature: 0.1, temperature: 0.1,
maxTokens: 2000, maxTokens: 2000,
}, },
openrouter: {
model: 'openrouter/horizon-beta',
// model: 'x-ai/grok-3-beta',
// model: 'openai/gpt-4o-mini',
temperature: 0.1,
maxTokens: 2000,
},
} as const; } as const;
/** /**

View File

@ -97,9 +97,8 @@ export interface LoadingStatesProps {
// URL Validation Schema // URL Validation Schema
export const urlSchema = z export const urlSchema = z
.string() .url()
.min(1, 'URL is required') .min(1, 'URL is required')
.url('Please enter a valid URL')
.refine( .refine(
(url) => url.startsWith('http://') || url.startsWith('https://'), (url) => url.startsWith('http://') || url.startsWith('https://'),
'URL must start with http:// or https://' 'URL must start with http:// or https://'
@ -114,13 +113,13 @@ export const analysisResultsSchema = z.object({
pricing: z.string().default('Not specified'), pricing: z.string().default('Not specified'),
useCases: z.array(z.string()).default([]), useCases: z.array(z.string()).default([]),
url: urlSchema, url: urlSchema,
analyzedAt: z.string().datetime(), analyzedAt: z.iso.datetime(),
}); });
// API Request Schema // API Request Schema
export const analyzeContentRequestSchema = z.object({ export const analyzeContentRequestSchema = z.object({
url: urlSchema, url: urlSchema,
modelProvider: z.enum(['openai', 'gemini', 'deepseek']), modelProvider: z.enum(['openai', 'gemini', 'deepseek', 'openrouter']),
}); });
// API Response Schema // API Response Schema

View File

@ -1,12 +1,17 @@
import { UpdateAvatarCard } from '@/components/settings/profile/update-avatar-card'; import { UpdateAvatarCard } from '@/components/settings/profile/update-avatar-card';
import { UpdateNameCard } from '@/components/settings/profile/update-name-card'; import { UpdateNameCard } from '@/components/settings/profile/update-name-card';
import { websiteConfig } from '@/config/website';
export default function ProfilePage() { export default function ProfilePage() {
const enableUpdateAvatar = websiteConfig.features.enableUpdateAvatar;
return ( return (
<div className="flex flex-col gap-8"> <div className="flex flex-col gap-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8"> {enableUpdateAvatar && (
<UpdateAvatarCard /> <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
</div> <UpdateAvatarCard />
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8"> <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<UpdateNameCard /> <UpdateNameCard />
</div> </div>

View File

@ -1,10 +1,10 @@
'use client'; 'use client';
import { ActiveThemeProvider } from '@/components/layout/active-theme-provider'; import { ActiveThemeProvider } from '@/components/layout/active-theme-provider';
import { CreditsProvider } from '@/components/layout/credits-provider';
import { PaymentProvider } from '@/components/layout/payment-provider'; import { PaymentProvider } from '@/components/layout/payment-provider';
import { TooltipProvider } from '@/components/ui/tooltip'; import { TooltipProvider } from '@/components/ui/tooltip';
import { websiteConfig } from '@/config/website'; import { websiteConfig } from '@/config/website';
import { CreditsProvider } from '@/providers/credits-provider';
import type { Translations } from 'fumadocs-ui/i18n'; import type { Translations } from 'fumadocs-ui/i18n';
import { RootProvider } from 'fumadocs-ui/provider'; import { RootProvider } from 'fumadocs-ui/provider';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';

View File

@ -23,6 +23,7 @@ import { createDeepSeek } from '@ai-sdk/deepseek';
import { createGoogleGenerativeAI } from '@ai-sdk/google'; import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createOpenAI } from '@ai-sdk/openai'; import { createOpenAI } from '@ai-sdk/openai';
import FirecrawlApp from '@mendable/firecrawl-js'; import FirecrawlApp from '@mendable/firecrawl-js';
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { generateObject } from 'ai'; import { generateObject } from 'ai';
import { type NextRequest, NextResponse } from 'next/server'; import { type NextRequest, NextResponse } from 'next/server';
import { z } from 'zod'; import { z } from 'zod';
@ -218,7 +219,7 @@ async function analyzeContent(
break; break;
case 'gemini': case 'gemini':
model = createGoogleGenerativeAI({ model = createGoogleGenerativeAI({
apiKey: process.env.GOOGLE_API_KEY, apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
}).chat(webContentAnalyzerConfig.gemini.model); }).chat(webContentAnalyzerConfig.gemini.model);
temperature = webContentAnalyzerConfig.gemini.temperature; temperature = webContentAnalyzerConfig.gemini.temperature;
maxTokens = webContentAnalyzerConfig.gemini.maxTokens; maxTokens = webContentAnalyzerConfig.gemini.maxTokens;
@ -230,6 +231,13 @@ async function analyzeContent(
temperature = webContentAnalyzerConfig.deepseek.temperature; temperature = webContentAnalyzerConfig.deepseek.temperature;
maxTokens = webContentAnalyzerConfig.deepseek.maxTokens; maxTokens = webContentAnalyzerConfig.deepseek.maxTokens;
break; break;
case 'openrouter':
model = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
}).chat(webContentAnalyzerConfig.openrouter.model);
temperature = webContentAnalyzerConfig.openrouter.temperature;
maxTokens = webContentAnalyzerConfig.openrouter.maxTokens;
break;
default: default:
throw new WebContentAnalyzerError( throw new WebContentAnalyzerError(
ErrorType.VALIDATION, ErrorType.VALIDATION,
@ -254,7 +262,7 @@ async function analyzeContent(
- Ensure the title and description are meaningful and based on the actual content - Ensure the title and description are meaningful and based on the actual content
`, `,
temperature, temperature,
maxTokens, maxOutputTokens: maxTokens,
}); });
return { return {
@ -336,7 +344,7 @@ export async function POST(req: NextRequest) {
if (!urlValidation.success) { if (!urlValidation.success) {
const urlError = new WebContentAnalyzerError( const urlError = new WebContentAnalyzerError(
ErrorType.VALIDATION, ErrorType.VALIDATION,
urlValidation.error.errors[0]?.message || 'Invalid URL', urlValidation.error.issues[0]?.message || 'Invalid URL',
'Please enter a valid URL starting with http:// or https://', 'Please enter a valid URL starting with http:// or https://',
ErrorSeverity.MEDIUM, ErrorSeverity.MEDIUM,
false false

View File

@ -32,7 +32,7 @@ export const ForgotPasswordForm = ({ className }: { className?: string }) => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const ForgotPasswordSchema = z.object({ const ForgotPasswordSchema = z.object({
email: z.string().email({ email: z.email({
message: t('emailRequired'), message: t('emailRequired'),
}), }),
}); });

View File

@ -69,7 +69,7 @@ export const LoginForm = ({
: z.string().optional(); : z.string().optional();
const LoginSchema = z.object({ const LoginSchema = z.object({
email: z.string().email({ email: z.email({
message: t('emailRequired'), message: t('emailRequired'),
}), }),
password: z.string().min(1, { password: z.string().min(1, {

View File

@ -64,7 +64,7 @@ export const RegisterForm = ({
: z.string().optional(); : z.string().optional();
const RegisterSchema = z.object({ const RegisterSchema = z.object({
email: z.string().email({ email: z.email({
message: t('emailRequired'), message: t('emailRequired'),
}), }),
password: z.string().min(1, { password: z.string().min(1, {

View File

@ -40,7 +40,7 @@ export function ContactFormCard() {
// Create a schema for contact form validation // Create a schema for contact form validation
const formSchema = z.object({ const formSchema = z.object({
name: z.string().min(3, t('nameMinLength')).max(30, t('nameMaxLength')), name: z.string().min(3, t('nameMinLength')).max(30, t('nameMaxLength')),
email: z.string().email(t('emailValidation')), email: z.email(t('emailValidation')),
message: z message: z
.string() .string()
.min(10, t('messageMinLength')) .min(10, t('messageMinLength'))

View File

@ -29,7 +29,7 @@ export function NewsletterForm() {
// newsletter schema // newsletter schema
const NewsletterFormSchema = z.object({ const NewsletterFormSchema = z.object({
email: z.string().email({ email: z.email({
message: t('emailValidation'), message: t('emailValidation'),
}), }),
}); });

View File

@ -38,7 +38,7 @@ export function WaitlistFormCard() {
// Create a schema for waitlist form validation // Create a schema for waitlist form validation
const formSchema = z.object({ const formSchema = z.object({
email: z.string().email({ message: t('emailValidation') }), email: z.email({ message: t('emailValidation') }),
}); });
// Initialize the form // Initialize the form

View File

@ -36,6 +36,7 @@ export const websiteConfig: WebsiteConfig = {
enableDiscordWidget: false, enableDiscordWidget: false,
enableCrispChat: process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true', enableCrispChat: process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true',
enableUpgradeCard: true, enableUpgradeCard: true,
enableUpdateAvatar: true,
enableAffonsoAffiliate: false, enableAffonsoAffiliate: false,
enablePromotekitAffiliate: false, enablePromotekitAffiliate: false,
enableDatafastRevenueTrack: false, enableDatafastRevenueTrack: false,

View File

@ -71,6 +71,7 @@ export interface FeaturesConfig {
enableDiscordWidget?: boolean; // Whether to enable the discord widget, deprecated enableDiscordWidget?: boolean; // Whether to enable the discord widget, deprecated
enableCrispChat?: boolean; // Whether to enable the crisp chat enableCrispChat?: boolean; // Whether to enable the crisp chat
enableUpgradeCard?: boolean; // Whether to enable the upgrade card in the sidebar enableUpgradeCard?: boolean; // Whether to enable the upgrade card in the sidebar
enableUpdateAvatar?: boolean; // Whether to enable the update avatar in settings
enableAffonsoAffiliate?: boolean; // Whether to enable affonso affiliate enableAffonsoAffiliate?: boolean; // Whether to enable affonso affiliate
enablePromotekitAffiliate?: boolean; // Whether to enable promotekit affiliate enablePromotekitAffiliate?: boolean; // Whether to enable promotekit affiliate
enableDatafastRevenueTrack?: boolean; // Whether to enable datafast revenue tracking enableDatafastRevenueTrack?: boolean; // Whether to enable datafast revenue tracking