import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { type NextRequest, NextResponse } from 'next/server' import { usageLimitsRequestSchema } from '@/lib/api/contracts/usage-limits' import { AuthType, checkHybridAuth } from '@/lib/auth/hybrid' import { checkServerSideUsageLimits } from '@/lib/billing' import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription' import { getUserStorageLimit, getUserStorageUsage } from '@/lib/billing/storage' import { RateLimiter } from '@/lib/core/rate-limiter' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' import { createErrorResponse } from '@/app/api/workflows/utils' const logger = createLogger('UsageLimitsAPI') export const GET = withRouteHandler(async (request: NextRequest) => { usageLimitsRequestSchema.parse({}) try { const auth = await checkHybridAuth(request, { requireWorkflowId: false }) if (!auth.success || !auth.userId) { return createErrorResponse('Authentication required', 401) } const authenticatedUserId = auth.userId const userSubscription = await getHighestPrioritySubscription(authenticatedUserId) const rateLimiter = new RateLimiter() const triggerType = auth.authType === AuthType.API_KEY ? 'api' : 'manual' const [syncStatus, asyncStatus] = await Promise.all([ rateLimiter.getRateLimitStatusWithSubscription( authenticatedUserId, userSubscription, triggerType, false ), rateLimiter.getRateLimitStatusWithSubscription( authenticatedUserId, userSubscription, triggerType, true ), ]) const [usageCheck, storageUsage, storageLimit] = await Promise.all([ checkServerSideUsageLimits(authenticatedUserId), getUserStorageUsage(authenticatedUserId), getUserStorageLimit(authenticatedUserId), ]) // Same computation as `limit` (one source, one tier) — the pair can never // disagree under replication lag or mixed baseline/ledger tiers. const currentPeriodCost = usageCheck.currentUsage return NextResponse.json({ success: true, rateLimit: { sync: { isLimited: syncStatus.remaining === 0, requestsPerMinute: syncStatus.requestsPerMinute, maxBurst: syncStatus.maxBurst, remaining: syncStatus.remaining, resetAt: syncStatus.resetAt, }, async: { isLimited: asyncStatus.remaining === 0, requestsPerMinute: asyncStatus.requestsPerMinute, maxBurst: asyncStatus.maxBurst, remaining: asyncStatus.remaining, resetAt: asyncStatus.resetAt, }, authType: triggerType, }, usage: { currentPeriodCost, limit: usageCheck.limit, plan: userSubscription?.plan || 'free', }, storage: { usedBytes: storageUsage, limitBytes: storageLimit, percentUsed: storageLimit > 0 ? (storageUsage / storageLimit) * 100 : 0, }, }) } catch (error) { logger.error('Error checking usage limits:', error) return createErrorResponse(getErrorMessage(error, 'Failed to check usage limits'), 500) } })