diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts
index 391faad83e..676ccb836c 100644
--- a/app/(chat)/api/chat/route.ts
+++ b/app/(chat)/api/chat/route.ts
@@ -1,4 +1,3 @@
-import { checkBotId } from "botid/server";
import { geolocation, ipAddress } from "@vercel/functions";
import {
convertToModelMessages,
@@ -8,12 +7,13 @@ import {
stepCountIs,
streamText,
} from "ai";
+import { checkBotId } from "botid/server";
import { after } from "next/server";
import { createResumableStreamContext } from "resumable-stream";
import { auth, type UserType } from "@/app/(auth)/auth";
import { entitlementsByUserType } from "@/lib/ai/entitlements";
-import { type RequestHints, systemPrompt } from "@/lib/ai/prompts";
import { allowedModelIds } from "@/lib/ai/models";
+import { type RequestHints, systemPrompt } from "@/lib/ai/prompts";
import { getLanguageModel } from "@/lib/ai/providers";
import { createDocument } from "@/lib/ai/tools/create-document";
import { getWeather } from "@/lib/ai/tools/get-weather";
@@ -85,10 +85,10 @@ export async function POST(request: Request) {
const messageCount = await getMessageCountByUserId({
id: session.user.id,
- differenceInHours: 24,
+ differenceInHours: 1,
});
- if (messageCount > entitlementsByUserType[userType].maxMessagesPerDay) {
+ if (messageCount > entitlementsByUserType[userType].maxMessagesPerHour) {
return new ChatbotError("rate_limit:chat").toResponse();
}
@@ -186,7 +186,7 @@ export async function POST(request: Request) {
});
dataStream.merge(
- result.toUIMessageStream({ sendReasoning: isReasoningModel }),
+ result.toUIMessageStream({ sendReasoning: isReasoningModel })
);
if (titlePromise) {
@@ -237,7 +237,7 @@ export async function POST(request: Request) {
if (
error instanceof Error &&
error.message?.includes(
- "AI Gateway requires a valid credit card on file to service requests",
+ "AI Gateway requires a valid credit card on file to service requests"
)
) {
return "AI Gateway requires a valid credit card on file to service requests. Please visit https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%3Fmodal%3Dadd-credit-card to add a card and unlock your free credits.";
diff --git a/components/ai-elements/web-preview.tsx b/components/ai-elements/web-preview.tsx
index 5245995199..cffa2dd944 100644
--- a/components/ai-elements/web-preview.tsx
+++ b/components/ai-elements/web-preview.tsx
@@ -238,7 +238,7 @@ export const WebPreviewConsole = ({
{logs.length === 0 ? (
No console output
) : (
- logs.map((log, index) => (
+ logs.map((log) => (
{log.timestamp.toLocaleTimeString()}
diff --git a/components/console.tsx b/components/console.tsx
index ddaaf6882b..7b7f7a1917 100644
--- a/components/console.tsx
+++ b/components/console.tsx
@@ -162,9 +162,9 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
) : (
- {consoleOutput.contents.map((content, contentIndex) =>
+ {consoleOutput.contents.map((content) =>
content.type === "image" ? (
-
+
{content.value}
diff --git a/components/elements/web-preview.tsx b/components/elements/web-preview.tsx
index 5181a18afa..588d63bc15 100644
--- a/components/elements/web-preview.tsx
+++ b/components/elements/web-preview.tsx
@@ -227,7 +227,7 @@ export const WebPreviewConsole = ({
{logs.length === 0 ? (
No console output
) : (
- logs.map((log, index) => (
+ logs.map((log) => (
{log.timestamp.toLocaleTimeString()}
diff --git a/lib/ai/entitlements.ts b/lib/ai/entitlements.ts
index 6afbeebc54..fc456f288b 100644
--- a/lib/ai/entitlements.ts
+++ b/lib/ai/entitlements.ts
@@ -1,7 +1,7 @@
import type { UserType } from "@/app/(auth)/auth";
type Entitlements = {
- maxMessagesPerDay: number;
+ maxMessagesPerHour: number;
};
export const entitlementsByUserType: Record = {
@@ -9,14 +9,14 @@ export const entitlementsByUserType: Record = {
* For users without an account
*/
guest: {
- maxMessagesPerDay: 10,
+ maxMessagesPerHour: 10,
},
/*
* For users with an account
*/
regular: {
- maxMessagesPerDay: 10,
+ maxMessagesPerHour: 10,
},
/*
diff --git a/lib/ratelimit.ts b/lib/ratelimit.ts
index cc75ab781d..ca417e92b4 100644
--- a/lib/ratelimit.ts
+++ b/lib/ratelimit.ts
@@ -3,15 +3,15 @@ import { createClient } from "redis";
import { isProductionEnvironment } from "@/lib/constants";
import { ChatbotError } from "@/lib/errors";
-const MAX_MESSAGES_PER_DAY = 10;
-const TTL_SECONDS = 60 * 60 * 24;
+const MAX_MESSAGES = 10;
+const TTL_SECONDS = 60 * 60;
let client: ReturnType | null = null;
function getClient() {
if (!client && process.env.REDIS_URL) {
client = createClient({ url: process.env.REDIS_URL });
- client.on("error", () => {});
+ client.on("error", () => undefined);
client.connect().catch(() => {
client = null;
});
@@ -20,10 +20,14 @@ function getClient() {
}
export async function checkIpRateLimit(ip: string | undefined) {
- if (!isProductionEnvironment || !ip) return;
+ if (!isProductionEnvironment || !ip) {
+ return;
+ }
const redis = getClient();
- if (!redis?.isReady) return;
+ if (!redis?.isReady) {
+ return;
+ }
try {
const key = `ip-rate-limit:${ip}`;
@@ -33,10 +37,12 @@ export async function checkIpRateLimit(ip: string | undefined) {
.expire(key, TTL_SECONDS, "NX")
.exec();
- if (typeof count === "number" && count > MAX_MESSAGES_PER_DAY) {
+ if (typeof count === "number" && count > MAX_MESSAGES) {
throw new ChatbotError("rate_limit:chat");
}
} catch (error) {
- if (error instanceof ChatbotError) throw error;
+ if (error instanceof ChatbotError) {
+ throw error;
+ }
}
}
diff --git a/next.config.ts b/next.config.ts
index e643ad8a53..f0596a54aa 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,5 +1,5 @@
-import type { NextConfig } from "next";
import { withBotId } from "botid/next/config";
+import type { NextConfig } from "next";
const nextConfig: NextConfig = {
cacheComponents: true,
diff --git a/package.json b/package.json
index ca66ed5a1e..15224e88e2 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"@xyflow/react": "^12.10.0",
"ai": "6.0.37",
"bcrypt-ts": "^5.0.2",
- "botid": "1.5.6",
+ "botid": "1.5.11",
"class-variance-authority": "^0.7.1",
"classnames": "^2.5.1",
"clsx": "^2.1.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ed5cba28c8..a4228af3f8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -102,8 +102,8 @@ importers:
specifier: ^5.0.2
version: 5.0.3
botid:
- specifier: 1.5.6
- version: 1.5.6(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.1(react@19.0.1))(react@19.0.1))(react@19.0.1)
+ specifier: 1.5.11
+ version: 1.5.11(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.1(react@19.0.1))(react@19.0.1))(react@19.0.1)
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -2366,6 +2366,9 @@ packages:
'@types/node@22.13.10':
resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==}
+ '@types/node@22.19.13':
+ resolution: {integrity: sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==}
+
'@types/papaparse@5.3.15':
resolution: {integrity: sha512-JHe6vF6x/8Z85nCX4yFdDslN11d+1pr12E526X8WAfhadOeaOTx5AuIkvDKIBopfvlzpzkdMx4YyvSKCM9oqtw==}
@@ -2479,8 +2482,8 @@ packages:
peerDependencies:
acorn: ^8
- acorn@8.15.0:
- resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -2507,8 +2510,8 @@ packages:
resolution: {integrity: sha512-2FcgD12xPbwCoe5i9/HK0jJ1xA1m+QfC1e6htG9Bl/hNOnLyaFmQSlqLKcfe3QdnoMPKpKEGFCbESBTg+SJNOw==}
engines: {node: '>=18'}
- botid@1.5.6:
- resolution: {integrity: sha512-KElecPjc1z6WJ6sCJMw6CvLo/CQclwlLJdobqmtOjVqvCXZZmaWvNafVDwBk0Kf5ordIaorDa3YkIx2OlGx7pg==}
+ botid@1.5.11:
+ resolution: {integrity: sha512-KOO1A3+/vFVJk5aFoG3sNwiogKFPVR+x4aw4gQ1b2e0XoE+i5xp48/EZn+WqR07jRHeDGwHWQUOtV5WVm7xiww==}
peerDependencies:
next: '*'
react: ^18.0.0 || ^19.0.0
@@ -2521,8 +2524,8 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
- bufferutil@4.0.9:
- resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==}
+ bufferutil@4.1.0:
+ resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==}
engines: {node: '>=6.14.2'}
bytes@3.1.2:
@@ -3509,11 +3512,11 @@ packages:
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
engines: {node: '>=4'}
- pg-protocol@1.8.0:
- resolution: {integrity: sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==}
+ pg-protocol@1.12.0:
+ resolution: {integrity: sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==}
- pg-types@4.0.2:
- resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
+ pg-types@4.1.0:
+ resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==}
engines: {node: '>=10'}
picocolors@1.1.1:
@@ -3786,8 +3789,8 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
- resolve@1.22.10:
- resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ resolve@1.22.11:
+ resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
engines: {node: '>= 0.4'}
hasBin: true
@@ -3809,6 +3812,11 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
@@ -3972,6 +3980,9 @@ packages:
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
undici@5.28.5:
resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==}
engines: {node: '>=14.0'}
@@ -4059,8 +4070,8 @@ packages:
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
- ws@8.18.1:
- resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
+ ws@8.19.0:
+ resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -4791,7 +4802,7 @@ snapshots:
'@types/shimmer': 1.2.0
import-in-the-middle: 1.15.0
require-in-the-middle: 7.5.2
- semver: 7.7.3
+ semver: 7.7.4
shimmer: 1.2.1
transitivePeerDependencies:
- supports-color
@@ -5861,6 +5872,11 @@ snapshots:
dependencies:
undici-types: 6.20.0
+ '@types/node@22.19.13':
+ dependencies:
+ undici-types: 6.21.0
+ optional: true
+
'@types/papaparse@5.3.15':
dependencies:
'@types/node': 22.13.10
@@ -5869,9 +5885,9 @@ snapshots:
'@types/pg@8.11.6':
dependencies:
- '@types/node': 22.13.10
- pg-protocol: 1.8.0
- pg-types: 4.0.2
+ '@types/node': 22.19.13
+ pg-protocol: 1.12.0
+ pg-types: 4.1.0
optional: true
'@types/prop-types@15.7.14': {}
@@ -5933,8 +5949,8 @@ snapshots:
'@vercel/postgres@0.10.0':
dependencies:
'@neondatabase/serverless': 0.9.5
- bufferutil: 4.0.9
- ws: 8.18.1(bufferutil@4.0.9)
+ bufferutil: 4.1.0
+ ws: 8.19.0(bufferutil@4.1.0)
transitivePeerDependencies:
- utf-8-validate
optional: true
@@ -5962,11 +5978,11 @@ snapshots:
d3-selection: 3.0.0
d3-zoom: 3.0.0
- acorn-import-attributes@1.9.5(acorn@8.15.0):
+ acorn-import-attributes@1.9.5(acorn@8.16.0):
dependencies:
- acorn: 8.15.0
+ acorn: 8.16.0
- acorn@8.15.0: {}
+ acorn@8.16.0: {}
ai@6.0.37(zod@3.25.76):
dependencies:
@@ -5990,14 +6006,14 @@ snapshots:
bcrypt-ts@5.0.3: {}
- botid@1.5.6(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.1(react@19.0.1))(react@19.0.1))(react@19.0.1):
+ botid@1.5.11(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.1(react@19.0.1))(react@19.0.1))(react@19.0.1):
optionalDependencies:
next: 16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.1(react@19.0.1))(react@19.0.1)
react: 19.0.1
buffer-from@1.1.2: {}
- bufferutil@4.0.9:
+ bufferutil@4.1.0:
dependencies:
node-gyp-build: 4.8.4
optional: true
@@ -6519,8 +6535,8 @@ snapshots:
import-in-the-middle@1.15.0:
dependencies:
- acorn: 8.15.0
- acorn-import-attributes: 1.9.5(acorn@8.15.0)
+ acorn: 8.16.0
+ acorn-import-attributes: 1.9.5(acorn@8.16.0)
cjs-module-lexer: 1.4.3
module-details-from-path: 1.0.4
@@ -7201,10 +7217,10 @@ snapshots:
pg-numeric@1.0.2:
optional: true
- pg-protocol@1.8.0:
+ pg-protocol@1.12.0:
optional: true
- pg-types@4.0.2:
+ pg-types@4.1.0:
dependencies:
pg-int8: 1.0.1
pg-numeric: 1.0.2
@@ -7617,13 +7633,13 @@ snapshots:
dependencies:
debug: 4.4.3
module-details-from-path: 1.0.4
- resolve: 1.22.10
+ resolve: 1.22.11
transitivePeerDependencies:
- supports-color
resolve-pkg-maps@1.0.0: {}
- resolve@1.22.10:
+ resolve@1.22.11:
dependencies:
is-core-module: 2.16.1
path-parse: 1.0.7
@@ -7637,7 +7653,10 @@ snapshots:
scheduler@0.25.0: {}
- semver@7.7.3: {}
+ semver@7.7.3:
+ optional: true
+
+ semver@7.7.4: {}
server-only@0.0.1: {}
@@ -7823,6 +7842,9 @@ snapshots:
undici-types@6.20.0: {}
+ undici-types@6.21.0:
+ optional: true
+
undici@5.28.5:
dependencies:
'@fastify/busboy': 2.1.1
@@ -7923,9 +7945,9 @@ snapshots:
web-namespaces@2.0.1: {}
- ws@8.18.1(bufferutil@4.0.9):
+ ws@8.19.0(bufferutil@4.1.0):
optionalDependencies:
- bufferutil: 4.0.9
+ bufferutil: 4.1.0
optional: true
xtend@4.0.2: {}