Skip to content

Commit d94e134

Browse files
committed
more cleanup
1 parent 2563264 commit d94e134

File tree

10 files changed

+85
-53
lines changed

10 files changed

+85
-53
lines changed

apps/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@databuddy/rpc": "workspace:*",
2727
"@databuddy/shared": "workspace:*",
2828
"@elysiajs/cors": "^1.4.0",
29+
"@mendable/firecrawl-js": "^4.8.2",
2930
"@openrouter/ai-sdk-provider": "^1.4.0",
3031
"@opentelemetry/api": "^1.9.0",
3132
"@opentelemetry/exporter-trace-otlp-proto": "^0.208.0",

apps/api/src/ai/agents.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,18 @@ import { models } from "./config/models";
99
import { buildAnalyticsInstructions } from "./prompts/analytics";
1010
import { buildReflectionInstructions } from "./prompts/reflection";
1111
import { buildTriageInstructions } from "./prompts/triage";
12-
import { analyticsTools } from "./tools";
12+
import { executeSqlQueryTool } from "./tools/execute-sql-query";
13+
import { getTopPagesTool } from "./tools/get-top-pages";
14+
import { webSearchTool } from "./tools/web-search";
15+
16+
/**
17+
* Tools available to analytics agents.
18+
*/
19+
const analyticsTools = {
20+
get_top_pages: getTopPagesTool,
21+
execute_sql_query: executeSqlQueryTool,
22+
web_search: webSearchTool,
23+
} as const;
1324

1425
/**
1526
* Analytics specialist agent.

apps/api/src/ai/prompts/analytics.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ const ANALYTICS_RULES = `<agent-specific-rules>
1818
**Tools Usage:**
1919
- Use get_top_pages for page analytics
2020
- Use execute_sql_query for custom analytics queries
21-
- CRITICAL: execute_sql_query must ONLY use SELECT/WITH and parameter placeholders (e.g., {websiteId:String}) with values passed via params. Never interpolate strings.
22-
- Example: execute_sql_query({ sql: "SELECT ... WHERE client_id = {websiteId:String}", params: { websiteId: "<use website_id from context>" } })
21+
- CRITICAL: execute_sql_query must ONLY use SELECT/WITH and parameter placeholders (e.g., {limit:UInt32}) with values passed via params. websiteId is automatically included. Never interpolate strings.
22+
- Example: execute_sql_query({ websiteId: "<use website_id from context>", sql: "SELECT ... WHERE client_id = {websiteId:String}", params: { limit: 10 } })
2323
2424
**Insights & Recommendations:**
2525
- Provide 2-3 actionable recommendations based on findings

apps/api/src/ai/tools/execute-sql-query.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,30 @@ import {
1414
*/
1515
export const executeSqlQueryTool = tool({
1616
description:
17-
"Executes a validated, read-only ClickHouse SQL query against analytics data. Only SELECT and WITH statements are allowed for security. IMPORTANT: Use parameterized queries with {paramName:Type} syntax (e.g., {websiteId:String}, {limit:UInt32}). Never use string interpolation or concatenation.",
17+
"Executes a validated, read-only ClickHouse SQL query against analytics data. Only SELECT and WITH statements are allowed for security. IMPORTANT: Use parameterized queries with {paramName:Type} syntax (e.g., {limit:UInt32}). The websiteId is automatically included as a parameter. Never use string interpolation or concatenation.",
1818
inputSchema: z.object({
19+
websiteId: z.string().describe("The website ID to query - automatically added to params"),
1920
sql: z
2021
.string()
2122
.describe(
22-
"The SQL query to execute. Must be a SELECT or WITH statement. Use parameterized queries with {paramName:Type} syntax. Example: SELECT * FROM analytics.events WHERE client_id = {websiteId:String} LIMIT {limit:UInt32}"
23+
"The SQL query to execute. Must be a SELECT or WITH statement. Use parameterized queries with {paramName:Type} syntax. The websiteId parameter is automatically available. Example: SELECT * FROM analytics.events WHERE client_id = {websiteId:String} LIMIT {limit:UInt32}"
2324
),
2425
params: z
2526
.record(z.string(), z.unknown())
2627
.optional()
2728
.describe(
28-
"Query parameters object matching the parameter names in the SQL query."
29+
"Additional query parameters object matching the parameter names in the SQL query. websiteId is automatically included."
2930
),
3031
}),
31-
execute: async ({ sql, params }): Promise<QueryResult> => {
32+
execute: async ({ sql, websiteId, params }): Promise<QueryResult> => {
3233
if (!validateSQL(sql)) {
3334
throw new Error(SQL_VALIDATION_ERROR);
3435
}
3536

3637
const result = await executeTimedQuery(
3738
"Execute SQL Tool",
3839
sql,
39-
params ?? {}
40+
{ websiteId, ...(params ?? {}) }
4041
);
4142

4243
return result;

apps/api/src/ai/tools/index.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import FirecrawlApp from "@mendable/firecrawl-js";
2+
import { tool } from "ai";
3+
import { z } from "zod";
4+
5+
/**
6+
* Web search tool using Firecrawl for scraping and crawling websites.
7+
* Provides markdown and HTML content from crawled URLs.
8+
*/
9+
export const webSearchTool = tool({
10+
description:
11+
"Search the web for up-to-date information by crawling and scraping websites",
12+
inputSchema: z.object({
13+
urlToCrawl: z
14+
.url()
15+
.min(1)
16+
.max(100)
17+
.describe("The URL to crawl (including http:// or https://)"),
18+
}),
19+
execute: async ({ urlToCrawl }) => {
20+
const app = new FirecrawlApp({
21+
apiKey: process.env.FIRECRAWL_API_KEY,
22+
});
23+
24+
const crawlResponse = await app.scrape(urlToCrawl, {
25+
formats: ["markdown", "html"],
26+
});
27+
28+
return crawlResponse;
29+
},
30+
});

apps/api/src/routes/agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,5 @@ export const agent = new Elysia({ prefix: "/v1/agent" })
188188
}
189189
});
190190
},
191-
{ body: AgentRequestSchema }
191+
{ body: AgentRequestSchema, idleTimeout: 60_000 }
192192
);

apps/dashboard/app/(main)/websites/[id]/agent/_components/agent-messages.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,28 @@ function getToolState(part: MessagePart) {
7777
return "input-available";
7878
}
7979

80-
function formatToolOutput(output: unknown) {
80+
function formatToolOutput(output: unknown, toolName?: string) {
8181
if (output === undefined) {
8282
return null;
8383
}
84+
85+
if (
86+
toolName === "web_search" &&
87+
typeof output === "object" &&
88+
output !== null
89+
) {
90+
const webData = output as { data?: unknown[] };
91+
if (Array.isArray(webData.data)) {
92+
return {
93+
summary: `Scraped ${webData.data.length} page(s)`,
94+
results: webData.data.map((page, index) => ({
95+
page: index + 1,
96+
...(typeof page === "object" ? page : { content: page }),
97+
})),
98+
};
99+
}
100+
}
101+
84102
if (typeof output === "string" || typeof output === "object") {
85103
return output as string | Record<string, unknown>;
86104
}
@@ -156,7 +174,7 @@ function ToolMessage({
156174
{toolPart.input !== undefined && <ToolInput input={toolPart.input} />}
157175
<ToolOutput
158176
errorText={toolPart.errorText}
159-
output={formatToolOutput(toolPart.output)}
177+
output={formatToolOutput(toolPart.output, toolPart.toolName)}
160178
/>
161179
</ToolContent>
162180
</Tool>

apps/dashboard/app/(main)/websites/[id]/agent/_components/hooks/use-agent-chat.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,11 @@ export function useAgentChat() {
5050
[websiteId, stableChatId]
5151
);
5252

53-
// Use useChat from SDK - it's the single source of truth
54-
const { messages: sdkMessages, status: sdkStatus } = useChat<UIMessage>({
53+
const { messages, status } = useChat<UIMessage>({
5554
id: stableChatId,
5655
transport,
5756
});
5857

59-
// Simply use SDK messages directly - no complex syncing needed
60-
const messages = sdkMessages;
61-
62-
// Map SDK status to our status type
63-
const mappedStatus = sdkStatus === "ready" ? "idle" : sdkStatus as "idle" | "submitted" | "streaming" | "error";
64-
const status = mappedStatus;
65-
6658
const {
6759
sendMessage: sdkSendMessage,
6860
reset: sdkReset,

bun.lock

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"@databuddy/rpc": "workspace:*",
4848
"@databuddy/shared": "workspace:*",
4949
"@elysiajs/cors": "^1.4.0",
50+
"@mendable/firecrawl-js": "^4.8.2",
5051
"@openrouter/ai-sdk-provider": "^1.4.0",
5152
"@opentelemetry/api": "^1.9.0",
5253
"@opentelemetry/exporter-trace-otlp-proto": "^0.208.0",
@@ -1003,6 +1004,8 @@
10031004

10041005
"@mdx-js/mdx": ["@mdx-js/[email protected]", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="],
10051006

1007+
"@mendable/firecrawl-js": ["@mendable/[email protected]", "", { "dependencies": { "axios": "^1.12.2", "typescript-event-target": "^1.1.1", "zod": "^3.23.8", "zod-to-json-schema": "^3.23.0" } }, "sha512-raSaSz97Kknx427ZVm1RKetUdYHf6wVSSGcmallv1DxcHQWXEGQIDlLOFevC6PrLo5MoKPMLc7UeES6qBHseaA=="],
1008+
10061009
"@mermaid-js/parser": ["@mermaid-js/[email protected]", "", { "dependencies": { "langium": "3.3.1" } }, "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA=="],
10071010

10081011
"@msgpack/msgpack": ["@msgpack/[email protected]", "", {}, "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ=="],
@@ -1967,7 +1970,7 @@
19671970

19681971
"agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
19691972

1970-
"ai": ["[email protected].106", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-M5obwavxSJJ3tGlAFqI6eltYNJB0D20X6gIBCFx/KVorb/X1fxVVfiZZpZb+Gslu4340droSOjT0aKQFCarNVg=="],
1973+
"ai": ["[email protected].107", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-laZlS9ZC/DZfSaxPgrBqI4mM+kxRvTPBBQfa74ceBFskkunZKEsaGVFNEs4cfyGa3nCCCl1WO/fjxixp4V8Zag=="],
19711974

19721975
"ajv": ["[email protected]", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
19731976

@@ -3873,6 +3876,8 @@
38733876

38743877
"typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
38753878

3879+
"typescript-event-target": ["[email protected]", "", {}, "sha512-dFSOFBKV6uwaloBCCUhxlD3Pr/P1a/tJdcmPrTXCHlEFD3faj0mztjcGn6VBAhQ0/Bdy8K3VWrrqwbt/ffsYsg=="],
3880+
38763881
"ua-is-frozen": ["[email protected]", "", {}, "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw=="],
38773882

38783883
"ua-parser-js": ["[email protected]", "", { "dependencies": { "detect-europe-js": "^0.1.2", "is-standalone-pwa": "^0.1.1", "ua-is-frozen": "^0.1.2" }, "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-EmaxXfltJaDW75SokrY4/lXMrVyXomE/0FpIIqP2Ctic93gK7rlme55Cwkz8l3YZ6gqf94fCU7AnIkidd/KXPg=="],
@@ -4043,6 +4048,10 @@
40434048

40444049
"zwitch": ["[email protected]", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
40454050

4051+
"@ai-sdk-tools/store/ai": ["[email protected]", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-M5obwavxSJJ3tGlAFqI6eltYNJB0D20X6gIBCFx/KVorb/X1fxVVfiZZpZb+Gslu4340droSOjT0aKQFCarNVg=="],
4052+
4053+
"@ai-sdk/react/ai": ["[email protected]", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-M5obwavxSJJ3tGlAFqI6eltYNJB0D20X6gIBCFx/KVorb/X1fxVVfiZZpZb+Gslu4340droSOjT0aKQFCarNVg=="],
4054+
40464055
"@anthropic-ai/tokenizer/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="],
40474056

40484057
"@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -4065,8 +4074,6 @@
40654074

40664075
"@databuddy/dashboard/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ=="],
40674076

4068-
"@databuddy/dashboard/ai": ["[email protected]", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-laZlS9ZC/DZfSaxPgrBqI4mM+kxRvTPBBQfa74ceBFskkunZKEsaGVFNEs4cfyGa3nCCCl1WO/fjxixp4V8Zag=="],
4069-
40704077
"@databuddy/dashboard/framer-motion": ["[email protected]", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-gUHGl2e4VG66jOcH0JHhuJQr6ZNwrET9g31ZG0xdXzT0CznP7fHX4P8Bcvuc4MiUB90ysNnWX2ukHRIggkl6hQ=="],
40714078

40724079
"@databuddy/dashboard/ultracite": ["[email protected]", "", { "dependencies": { "@clack/prompts": "^0.11.0", "deepmerge": "^4.3.1", "jsonc-parser": "^3.3.1", "nypm": "^0.6.1", "trpc-cli": "^0.10.2", "vitest": "^3.2.4", "zod": "^4.1.5" }, "bin": { "ultracite": "dist/index.js" } }, "sha512-3eFcYZsI21RJdBkQhS6062NaxE268tx+NxfRzNRMZoJHrAPwLrGS87t9ru4IkUEbVKEElrnUM5TOpH1Z3mZkYQ=="],
@@ -4095,8 +4102,6 @@
40954102

40964103
"@databuddy/redis/zod": ["[email protected]", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],
40974104

4098-
"@databuddy/rpc/ai": ["[email protected]", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-laZlS9ZC/DZfSaxPgrBqI4mM+kxRvTPBBQfa74ceBFskkunZKEsaGVFNEs4cfyGa3nCCCl1WO/fjxixp4V8Zag=="],
4099-
41004105
"@databuddy/rpc/autumn-js": ["[email protected]", "", { "dependencies": { "axios": "^1.10.0", "chalk": "^5.4.1", "commander": "^14.0.0", "ink": "^6.0.1", "jiti": "^2.4.2", "open": "^10.1.2", "rou3": "^0.6.1", "swr": "^2.3.3", "zod": "^3.24.1" }, "peerDependencies": { "better-auth": "^1.2.12", "better-call": "^1.0.12" }, "optionalPeers": ["better-auth", "better-call"] }, "sha512-Xmb6jvrr6EgN0UbHZZ0Er0OiLW/IbPPf02lbTNbTCuHePoSEaMQ3cxkvADpNRFf5NBo3Oos2rG2QVaDzkzIejg=="],
41014106

41024107
"@databuddy/rpc/drizzle-orm": ["[email protected]", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="],
@@ -4105,8 +4110,6 @@
41054110

41064111
"@databuddy/sdk/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="],
41074112

4108-
"@databuddy/sdk/ai": ["[email protected]", "", { "dependencies": { "@ai-sdk/gateway": "2.0.18", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-laZlS9ZC/DZfSaxPgrBqI4mM+kxRvTPBBQfa74ceBFskkunZKEsaGVFNEs4cfyGa3nCCCl1WO/fjxixp4V8Zag=="],
4109-
41104113
"@databuddy/sdk/tokenlens": ["[email protected]", "", { "dependencies": { "@tokenlens/core": "2.0.0-alpha.3", "@tokenlens/fetch": "2.0.0-alpha.3", "@tokenlens/helpers": "2.0.0-alpha.3", "@tokenlens/tokenizer": "2.0.0-alpha.3" } }, "sha512-bN+2JgJDDjl3hgFT4Grr2YPgEELT6M6QqDxgWxSvzZLjCTLS4erf9jsOpBXBRNISpDhc0IFYFFcANdIdjxMBfA=="],
41114114

41124115
"@databuddy/validation/zod": ["[email protected]", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="],
@@ -4171,6 +4174,8 @@
41714174

41724175
"@isaacs/cliui/wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
41734176

4177+
"@mendable/firecrawl-js/zod": ["[email protected]", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
4178+
41744179
"@neondatabase/serverless/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ=="],
41754180

41764181
"@next/eslint-plugin-next/fast-glob": ["[email protected]", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="],

0 commit comments

Comments
 (0)