@mastra/brightdata 0.3.0 → 0.3.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -1,10 +1,12 @@
1
1
  Portions of this software are licensed as follows:
2
2
 
3
- - All content that resides under any directory named "ee/" within this
3
+ - All content that resides under any directory named `ee/` within this
4
4
  repository, including but not limited to:
5
- - `packages/core/src/auth/ee/`
6
- - `packages/server/src/server/auth/ee/`
7
- is licensed under the license defined in `ee/LICENSE`.
5
+ - `@mastra/core/auth/ee`
6
+ - `@mastra/core/agent-builder/ee`
7
+ - `@mastra/editor/ee`
8
+
9
+ is licensed under the license defined in [`ee/LICENSE`](https://github.com/mastra-ai/mastra/blob/main/ee/LICENSE).
8
10
 
9
11
  - All third-party components incorporated into the Mastra Software are
10
12
  licensed under the original license provided by the owner of the
package/dist/index.cjs CHANGED
@@ -1,222 +1,190 @@
1
- 'use strict';
2
-
3
- var tools = require('@mastra/core/tools');
4
- var zod = require('zod');
5
-
6
- // src/client.ts
7
- var REQUEST_ENDPOINT = "https://api.brightdata.com/request";
8
- var DEFAULT_SERP_ZONE = "sdk_serp";
9
- var DEFAULT_WEB_UNLOCKER_ZONE = "sdk_unlocker";
10
- var DEFAULT_TIMEOUT = 12e4;
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _mastra_core_tools = require("@mastra/core/tools");
3
+ let zod = require("zod");
4
+ //#region src/client.ts
5
+ const REQUEST_ENDPOINT = "https://api.brightdata.com/request";
6
+ const DEFAULT_SERP_ZONE = "sdk_serp";
7
+ const DEFAULT_WEB_UNLOCKER_ZONE = "sdk_unlocker";
8
+ const DEFAULT_TIMEOUT = 12e4;
11
9
  async function requestBrightData(apiKey, body, timeout = DEFAULT_TIMEOUT) {
12
- const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;
13
- const controller = new AbortController();
14
- const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
15
- try {
16
- const response = await fetch(REQUEST_ENDPOINT, {
17
- body: JSON.stringify(body),
18
- headers: {
19
- Authorization: `Bearer ${apiKey}`,
20
- "Content-Type": "application/json"
21
- },
22
- method: "POST",
23
- signal: controller.signal
24
- });
25
- const responseText = await response.text();
26
- if (!response.ok) {
27
- if (response.status === 401 || response.status === 403) {
28
- throw new Error("invalid API key or insufficient permissions");
29
- }
30
- if (response.status === 400) {
31
- throw new Error(`bad request: ${responseText}`);
32
- }
33
- throw new Error(`request failed with status ${response.status}: ${responseText}`);
34
- }
35
- if (body.format === "json") {
36
- return responseText ? JSON.parse(responseText) : {};
37
- }
38
- return responseText;
39
- } catch (error) {
40
- if (error instanceof Error && error.name === "AbortError") {
41
- throw new Error(`Request timed out after ${effectiveTimeout}ms`);
42
- }
43
- throw error;
44
- } finally {
45
- clearTimeout(timeoutId);
46
- }
10
+ const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;
11
+ const controller = new AbortController();
12
+ const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
13
+ try {
14
+ const response = await fetch(REQUEST_ENDPOINT, {
15
+ body: JSON.stringify(body),
16
+ headers: {
17
+ Authorization: `Bearer ${apiKey}`,
18
+ "Content-Type": "application/json"
19
+ },
20
+ method: "POST",
21
+ signal: controller.signal
22
+ });
23
+ const responseText = await response.text();
24
+ if (!response.ok) {
25
+ if (response.status === 401 || response.status === 403) throw new Error("invalid API key or insufficient permissions");
26
+ if (response.status === 400) throw new Error(`bad request: ${responseText}`);
27
+ throw new Error(`request failed with status ${response.status}: ${responseText}`);
28
+ }
29
+ if (body.format === "json") return responseText ? JSON.parse(responseText) : {};
30
+ return responseText;
31
+ } catch (error) {
32
+ if (error instanceof Error && error.name === "AbortError") throw new Error(`Request timed out after ${effectiveTimeout}ms`);
33
+ throw error;
34
+ } finally {
35
+ clearTimeout(timeoutId);
36
+ }
47
37
  }
48
38
  function buildGoogleSearchUrl(query, options = {}) {
49
- const url = new URL("https://www.google.com/search");
50
- url.searchParams.set("q", query.trim());
51
- if ((options.format ?? "json") === "json") {
52
- url.searchParams.set("brd_json", "1");
53
- }
54
- url.searchParams.set("hl", options.language ?? "en");
55
- if (options.country) {
56
- url.searchParams.set("gl", options.country);
57
- }
58
- if (options.start !== void 0) {
59
- url.searchParams.set("start", String(options.start));
60
- }
61
- return url.toString();
39
+ const url = new URL("https://www.google.com/search");
40
+ url.searchParams.set("q", query.trim());
41
+ if ((options.format ?? "json") === "json") url.searchParams.set("brd_json", "1");
42
+ url.searchParams.set("hl", options.language ?? "en");
43
+ if (options.country) url.searchParams.set("gl", options.country);
44
+ if (options.start !== void 0) url.searchParams.set("start", String(options.start));
45
+ return url.toString();
62
46
  }
63
47
  function toRequestBody(url, zone, options = {}) {
64
- const body = {
65
- format: options.format ?? "raw",
66
- method: options.method ?? "GET",
67
- url,
68
- zone
69
- };
70
- if (options.country) {
71
- body.country = options.country;
72
- }
73
- if (options.dataFormat && options.dataFormat !== "html") {
74
- body.data_format = options.dataFormat;
75
- }
76
- return body;
48
+ const body = {
49
+ format: options.format ?? "raw",
50
+ method: options.method ?? "GET",
51
+ url,
52
+ zone
53
+ };
54
+ if (options.country) body.country = options.country;
55
+ if (options.dataFormat && options.dataFormat !== "html") body.data_format = options.dataFormat;
56
+ return body;
77
57
  }
78
58
  function getBrightDataClient(config) {
79
- const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;
80
- if (!apiKey) {
81
- throw new Error("Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.");
82
- }
83
- const timeout = config?.timeout;
84
- const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;
85
- const webUnlockerZone = config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;
86
- return {
87
- search: {
88
- google: async (query, options = {}) => {
89
- if (options.language && !/^[a-z]{2}$/i.test(options.language)) {
90
- throw new Error('language must be a two-letter code (e.g. "en", "es")');
91
- }
92
- const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;
93
- const url = buildGoogleSearchUrl(query, normalizedOptions);
94
- return requestBrightData(
95
- apiKey,
96
- toRequestBody(url, normalizedOptions.zone ?? serpZone, {
97
- ...normalizedOptions,
98
- format: normalizedOptions.format ?? "json",
99
- method: "GET"
100
- }),
101
- normalizedOptions.timeout ?? timeout
102
- );
103
- }
104
- },
105
- scrapeUrl: async (url, options = {}) => {
106
- const response = await requestBrightData(
107
- apiKey,
108
- toRequestBody(url, options.zone ?? webUnlockerZone, options),
109
- options.timeout ?? timeout
110
- );
111
- return typeof response === "string" ? response : JSON.stringify(response);
112
- },
113
- close: async () => {
114
- }
115
- };
59
+ const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;
60
+ if (!apiKey) throw new Error("Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.");
61
+ const timeout = config?.timeout;
62
+ const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;
63
+ const webUnlockerZone = config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;
64
+ return {
65
+ search: { google: async (query, options = {}) => {
66
+ if (options.language && !/^[a-z]{2}$/i.test(options.language)) throw new Error("language must be a two-letter code (e.g. \"en\", \"es\")");
67
+ const normalizedOptions = options.language ? {
68
+ ...options,
69
+ language: options.language.toLowerCase()
70
+ } : options;
71
+ const url = buildGoogleSearchUrl(query, normalizedOptions);
72
+ return requestBrightData(apiKey, toRequestBody(url, normalizedOptions.zone ?? serpZone, {
73
+ ...normalizedOptions,
74
+ format: normalizedOptions.format ?? "json",
75
+ method: "GET"
76
+ }), normalizedOptions.timeout ?? timeout);
77
+ } },
78
+ scrapeUrl: async (url, options = {}) => {
79
+ const response = await requestBrightData(apiKey, toRequestBody(url, options.zone ?? webUnlockerZone, options), options.timeout ?? timeout);
80
+ return typeof response === "string" ? response : JSON.stringify(response);
81
+ },
82
+ close: async () => {}
83
+ };
116
84
  }
117
85
  async function closeClient(client) {
118
- const close = client.close;
119
- try {
120
- await close.call(client);
121
- } catch {
122
- }
86
+ const close = client.close;
87
+ try {
88
+ await close.call(client);
89
+ } catch {}
123
90
  }
124
- var inputSchema = zod.z.object({
125
- query: zod.z.string().describe("The search query"),
126
- country: zod.z.string().regex(/^[a-z]{2}$/i, "Country must be a 2-letter code").optional().describe('2-letter country code for geo-targeted results (e.g., "us", "gb")'),
127
- language: zod.z.string().regex(/^[a-z]{2}$/i, "Language must be a 2-letter code").optional().describe('Language code for localized Google results (e.g., "en", "es", "fr")'),
128
- start: zod.z.number().int().nonnegative().optional().describe("Result offset for pagination (e.g. 10 to get the second page of 10 results)")
91
+ //#endregion
92
+ //#region src/search.ts
93
+ const inputSchema$1 = zod.z.object({
94
+ query: zod.z.string().describe("The search query"),
95
+ country: zod.z.string().regex(/^[a-z]{2}$/i, "Country must be a 2-letter code").optional().describe("2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")"),
96
+ language: zod.z.string().regex(/^[a-z]{2}$/i, "Language must be a 2-letter code").optional().describe("Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")"),
97
+ start: zod.z.number().int().nonnegative().optional().describe("Result offset for pagination (e.g. 10 to get the second page of 10 results)")
129
98
  });
130
- var outputSchema = zod.z.object({
131
- query: zod.z.string(),
132
- results: zod.z.array(
133
- zod.z.object({
134
- link: zod.z.string(),
135
- title: zod.z.string(),
136
- description: zod.z.string()
137
- })
138
- ),
139
- currentPage: zod.z.number()
99
+ const outputSchema$1 = zod.z.object({
100
+ query: zod.z.string(),
101
+ results: zod.z.array(zod.z.object({
102
+ link: zod.z.string(),
103
+ title: zod.z.string(),
104
+ description: zod.z.string()
105
+ })),
106
+ currentPage: zod.z.number()
140
107
  });
141
108
  function createBrightDataSearchTool(config) {
142
- return tools.createTool({
143
- id: "brightdata-search",
144
- description: "Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.",
145
- inputSchema,
146
- outputSchema,
147
- execute: async (input) => {
148
- const client = getBrightDataClient(config);
149
- try {
150
- const rawResponse = await client.search.google(input.query, {
151
- country: input.country,
152
- language: input.language,
153
- start: input.start
154
- });
155
- const response = typeof rawResponse === "string" ? JSON.parse(rawResponse) : rawResponse;
156
- const organic = Array.isArray(response.organic) ? response.organic : [];
157
- const results = organic.map((entry) => {
158
- if (!entry || typeof entry !== "object") return null;
159
- const e = entry;
160
- const link = typeof e.link === "string" ? e.link.trim() : "";
161
- const title = typeof e.title === "string" ? e.title.trim() : "";
162
- const description = typeof e.description === "string" ? e.description.trim() : "";
163
- if (!link || !title) return null;
164
- return { link, title, description };
165
- }).filter((r) => r !== null);
166
- const parsedPage = Number(response.current_page);
167
- const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;
168
- return {
169
- query: input.query,
170
- results,
171
- currentPage
172
- };
173
- } finally {
174
- await closeClient(client);
175
- }
176
- }
177
- });
109
+ return (0, _mastra_core_tools.createTool)({
110
+ id: "brightdata-search",
111
+ description: "Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.",
112
+ inputSchema: inputSchema$1,
113
+ outputSchema: outputSchema$1,
114
+ execute: async (input) => {
115
+ const client = getBrightDataClient(config);
116
+ try {
117
+ const rawResponse = await client.search.google(input.query, {
118
+ country: input.country,
119
+ language: input.language,
120
+ start: input.start
121
+ });
122
+ const response = typeof rawResponse === "string" ? JSON.parse(rawResponse) : rawResponse;
123
+ const results = (Array.isArray(response.organic) ? response.organic : []).map((entry) => {
124
+ if (!entry || typeof entry !== "object") return null;
125
+ const e = entry;
126
+ const link = typeof e.link === "string" ? e.link.trim() : "";
127
+ const title = typeof e.title === "string" ? e.title.trim() : "";
128
+ const description = typeof e.description === "string" ? e.description.trim() : "";
129
+ if (!link || !title) return null;
130
+ return {
131
+ link,
132
+ title,
133
+ description
134
+ };
135
+ }).filter((r) => r !== null);
136
+ const parsedPage = Number(response.current_page);
137
+ const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;
138
+ return {
139
+ query: input.query,
140
+ results,
141
+ currentPage
142
+ };
143
+ } finally {
144
+ await closeClient(client);
145
+ }
146
+ }
147
+ });
178
148
  }
179
- var inputSchema2 = zod.z.object({
180
- url: zod.z.string().url().describe("The URL to fetch")
181
- });
182
- var outputSchema2 = zod.z.object({
183
- url: zod.z.string(),
184
- content: zod.z.string().describe("Page content as Markdown")
149
+ //#endregion
150
+ //#region src/fetch.ts
151
+ const inputSchema = zod.z.object({ url: zod.z.string().url().describe("The URL to fetch") });
152
+ const outputSchema = zod.z.object({
153
+ url: zod.z.string(),
154
+ content: zod.z.string().describe("Page content as Markdown")
185
155
  });
186
156
  function createBrightDataFetchTool(config) {
187
- return tools.createTool({
188
- id: "brightdata-fetch",
189
- description: "Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.",
190
- inputSchema: inputSchema2,
191
- outputSchema: outputSchema2,
192
- execute: async (input) => {
193
- const client = getBrightDataClient(config);
194
- try {
195
- const content = await client.scrapeUrl(input.url, {
196
- dataFormat: "markdown"
197
- });
198
- return {
199
- url: input.url,
200
- content
201
- };
202
- } finally {
203
- await closeClient(client);
204
- }
205
- }
206
- });
157
+ return (0, _mastra_core_tools.createTool)({
158
+ id: "brightdata-fetch",
159
+ description: "Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.",
160
+ inputSchema,
161
+ outputSchema,
162
+ execute: async (input) => {
163
+ const client = getBrightDataClient(config);
164
+ try {
165
+ const content = await client.scrapeUrl(input.url, { dataFormat: "markdown" });
166
+ return {
167
+ url: input.url,
168
+ content
169
+ };
170
+ } finally {
171
+ await closeClient(client);
172
+ }
173
+ }
174
+ });
207
175
  }
208
-
209
- // src/tools.ts
176
+ //#endregion
177
+ //#region src/tools.ts
210
178
  function createBrightDataTools(config) {
211
- return {
212
- webSearch: createBrightDataSearchTool(config),
213
- webFetch: createBrightDataFetchTool(config)
214
- };
179
+ return {
180
+ webSearch: createBrightDataSearchTool(config),
181
+ webFetch: createBrightDataFetchTool(config)
182
+ };
215
183
  }
216
-
184
+ //#endregion
217
185
  exports.createBrightDataFetchTool = createBrightDataFetchTool;
218
186
  exports.createBrightDataSearchTool = createBrightDataSearchTool;
219
187
  exports.createBrightDataTools = createBrightDataTools;
220
188
  exports.getBrightDataClient = getBrightDataClient;
221
- //# sourceMappingURL=index.cjs.map
189
+
222
190
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/search.ts","../src/fetch.ts","../src/tools.ts"],"names":["z","createTool","inputSchema","outputSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["const REQUEST_ENDPOINT = 'https://api.brightdata.com/request';\nconst DEFAULT_SERP_ZONE = 'sdk_serp';\nconst DEFAULT_WEB_UNLOCKER_ZONE = 'sdk_unlocker';\nconst DEFAULT_TIMEOUT = 120_000;\n\ntype RequestFormat = 'raw' | 'json';\ntype DataFormat = 'html' | 'markdown' | 'screenshot';\n\nexport interface BrightDataClientOptions {\n [key: string]: unknown;\n apiKey?: string;\n timeout?: number;\n webUnlockerZone?: string;\n serpZone?: string;\n}\n\ninterface RequestOptions {\n country?: string;\n dataFormat?: DataFormat;\n format?: RequestFormat;\n method?: string;\n timeout?: number;\n zone?: string;\n}\n\ninterface SearchOptions extends RequestOptions {\n language?: string;\n start?: number;\n}\n\ninterface BrightDataRequestBody {\n country?: string;\n data_format?: Exclude<DataFormat, 'html'>;\n format: RequestFormat;\n method: string;\n url: string;\n zone: string;\n}\n\nexport interface BrightDataClient {\n search: {\n google: (query: string, options?: SearchOptions) => Promise<unknown>;\n };\n scrapeUrl: (url: string, options?: RequestOptions) => Promise<string>;\n close: () => Promise<void>;\n}\n\nasync function requestBrightData(\n apiKey: string,\n body: BrightDataRequestBody,\n timeout = DEFAULT_TIMEOUT,\n): Promise<unknown> {\n const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const response = await fetch(REQUEST_ENDPOINT, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n signal: controller.signal,\n });\n\n const responseText = await response.text();\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n throw new Error('invalid API key or insufficient permissions');\n }\n\n if (response.status === 400) {\n throw new Error(`bad request: ${responseText}`);\n }\n\n throw new Error(`request failed with status ${response.status}: ${responseText}`);\n }\n\n if (body.format === 'json') {\n return responseText ? JSON.parse(responseText) : {};\n }\n\n return responseText;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timed out after ${effectiveTimeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nfunction buildGoogleSearchUrl(query: string, options: SearchOptions = {}) {\n const url = new URL('https://www.google.com/search');\n url.searchParams.set('q', query.trim());\n if ((options.format ?? 'json') === 'json') {\n url.searchParams.set('brd_json', '1');\n }\n url.searchParams.set('hl', options.language ?? 'en');\n\n if (options.country) {\n url.searchParams.set('gl', options.country);\n }\n\n if (options.start !== undefined) {\n url.searchParams.set('start', String(options.start));\n }\n\n return url.toString();\n}\n\nfunction toRequestBody(url: string, zone: string, options: RequestOptions = {}): BrightDataRequestBody {\n const body: BrightDataRequestBody = {\n format: options.format ?? 'raw',\n method: options.method ?? 'GET',\n url,\n zone,\n };\n\n if (options.country) {\n body.country = options.country;\n }\n\n if (options.dataFormat && options.dataFormat !== 'html') {\n body.data_format = options.dataFormat;\n }\n\n return body;\n}\n\nexport function getBrightDataClient(config?: BrightDataClientOptions): BrightDataClient {\n const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;\n if (!apiKey) {\n throw new Error('Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.');\n }\n\n const timeout = config?.timeout;\n const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;\n const webUnlockerZone =\n config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;\n\n return {\n search: {\n google: async (query: string, options: SearchOptions = {}) => {\n if (options.language && !/^[a-z]{2}$/i.test(options.language)) {\n throw new Error('language must be a two-letter code (e.g. \"en\", \"es\")');\n }\n\n const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;\n\n const url = buildGoogleSearchUrl(query, normalizedOptions);\n return requestBrightData(\n apiKey,\n toRequestBody(url, normalizedOptions.zone ?? serpZone, {\n ...normalizedOptions,\n format: normalizedOptions.format ?? 'json',\n method: 'GET',\n }),\n normalizedOptions.timeout ?? timeout,\n );\n },\n },\n scrapeUrl: async (url: string, options: RequestOptions = {}) => {\n const response = await requestBrightData(\n apiKey,\n toRequestBody(url, options.zone ?? webUnlockerZone, options),\n options.timeout ?? timeout,\n );\n\n return typeof response === 'string' ? response : JSON.stringify(response);\n },\n close: async () => {},\n };\n}\n\nexport async function closeClient(client: BrightDataClient): Promise<void> {\n const close = client.close;\n try {\n await close.call(client);\n } catch {\n // best-effort cleanup; never mask the primary tool error from the finally block\n }\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n query: z.string().describe('The search query'),\n country: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Country must be a 2-letter code')\n .optional()\n .describe('2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")'),\n language: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Language must be a 2-letter code')\n .optional()\n .describe('Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")'),\n start: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe('Result offset for pagination (e.g. 10 to get the second page of 10 results)'),\n});\n\nconst outputSchema = z.object({\n query: z.string(),\n results: z.array(\n z.object({\n link: z.string(),\n title: z.string(),\n description: z.string(),\n }),\n ),\n currentPage: z.number(),\n});\n\nexport function createBrightDataSearchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-search',\n description:\n \"Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const rawResponse = await client.search.google(input.query, {\n country: input.country,\n language: input.language,\n start: input.start,\n });\n\n const response: { organic?: unknown; current_page?: unknown } =\n typeof rawResponse === 'string' ? JSON.parse(rawResponse) : rawResponse;\n\n const organic = Array.isArray(response.organic) ? response.organic : [];\n const results = organic\n .map((entry: unknown) => {\n if (!entry || typeof entry !== 'object') return null;\n const e = entry as Record<string, unknown>;\n const link = typeof e.link === 'string' ? e.link.trim() : '';\n const title = typeof e.title === 'string' ? e.title.trim() : '';\n const description = typeof e.description === 'string' ? e.description.trim() : '';\n if (!link || !title) return null;\n return { link, title, description };\n })\n .filter((r): r is { link: string; title: string; description: string } => r !== null);\n\n const parsedPage = Number(response.current_page);\n const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;\n\n return {\n query: input.query,\n results,\n currentPage,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n url: z.string().url().describe('The URL to fetch'),\n});\n\nconst outputSchema = z.object({\n url: z.string(),\n content: z.string().describe('Page content as Markdown'),\n});\n\nexport function createBrightDataFetchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-fetch',\n description:\n \"Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const content = await client.scrapeUrl(input.url, {\n dataFormat: 'markdown',\n });\n\n return {\n url: input.url,\n content,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import type { BrightDataClientOptions } from './client.js';\nimport { createBrightDataFetchTool } from './fetch.js';\nimport { createBrightDataSearchTool } from './search.js';\n\nexport function createBrightDataTools(config?: BrightDataClientOptions) {\n return {\n webSearch: createBrightDataSearchTool(config),\n webFetch: createBrightDataFetchTool(config),\n };\n}\n"]}
1
+ {"version":3,"file":"index.cjs","names":["inputSchema","z","outputSchema","z"],"sources":["../src/client.ts","../src/search.ts","../src/fetch.ts","../src/tools.ts"],"sourcesContent":["const REQUEST_ENDPOINT = 'https://api.brightdata.com/request';\nconst DEFAULT_SERP_ZONE = 'sdk_serp';\nconst DEFAULT_WEB_UNLOCKER_ZONE = 'sdk_unlocker';\nconst DEFAULT_TIMEOUT = 120_000;\n\ntype RequestFormat = 'raw' | 'json';\ntype DataFormat = 'html' | 'markdown' | 'screenshot';\n\nexport interface BrightDataClientOptions {\n [key: string]: unknown;\n apiKey?: string;\n timeout?: number;\n webUnlockerZone?: string;\n serpZone?: string;\n}\n\ninterface RequestOptions {\n country?: string;\n dataFormat?: DataFormat;\n format?: RequestFormat;\n method?: string;\n timeout?: number;\n zone?: string;\n}\n\ninterface SearchOptions extends RequestOptions {\n language?: string;\n start?: number;\n}\n\ninterface BrightDataRequestBody {\n country?: string;\n data_format?: Exclude<DataFormat, 'html'>;\n format: RequestFormat;\n method: string;\n url: string;\n zone: string;\n}\n\nexport interface BrightDataClient {\n search: {\n google: (query: string, options?: SearchOptions) => Promise<unknown>;\n };\n scrapeUrl: (url: string, options?: RequestOptions) => Promise<string>;\n close: () => Promise<void>;\n}\n\nasync function requestBrightData(\n apiKey: string,\n body: BrightDataRequestBody,\n timeout = DEFAULT_TIMEOUT,\n): Promise<unknown> {\n const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const response = await fetch(REQUEST_ENDPOINT, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n signal: controller.signal,\n });\n\n const responseText = await response.text();\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n throw new Error('invalid API key or insufficient permissions');\n }\n\n if (response.status === 400) {\n throw new Error(`bad request: ${responseText}`);\n }\n\n throw new Error(`request failed with status ${response.status}: ${responseText}`);\n }\n\n if (body.format === 'json') {\n return responseText ? JSON.parse(responseText) : {};\n }\n\n return responseText;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timed out after ${effectiveTimeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nfunction buildGoogleSearchUrl(query: string, options: SearchOptions = {}) {\n const url = new URL('https://www.google.com/search');\n url.searchParams.set('q', query.trim());\n if ((options.format ?? 'json') === 'json') {\n url.searchParams.set('brd_json', '1');\n }\n url.searchParams.set('hl', options.language ?? 'en');\n\n if (options.country) {\n url.searchParams.set('gl', options.country);\n }\n\n if (options.start !== undefined) {\n url.searchParams.set('start', String(options.start));\n }\n\n return url.toString();\n}\n\nfunction toRequestBody(url: string, zone: string, options: RequestOptions = {}): BrightDataRequestBody {\n const body: BrightDataRequestBody = {\n format: options.format ?? 'raw',\n method: options.method ?? 'GET',\n url,\n zone,\n };\n\n if (options.country) {\n body.country = options.country;\n }\n\n if (options.dataFormat && options.dataFormat !== 'html') {\n body.data_format = options.dataFormat;\n }\n\n return body;\n}\n\nexport function getBrightDataClient(config?: BrightDataClientOptions): BrightDataClient {\n const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;\n if (!apiKey) {\n throw new Error('Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.');\n }\n\n const timeout = config?.timeout;\n const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;\n const webUnlockerZone =\n config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;\n\n return {\n search: {\n google: async (query: string, options: SearchOptions = {}) => {\n if (options.language && !/^[a-z]{2}$/i.test(options.language)) {\n throw new Error('language must be a two-letter code (e.g. \"en\", \"es\")');\n }\n\n const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;\n\n const url = buildGoogleSearchUrl(query, normalizedOptions);\n return requestBrightData(\n apiKey,\n toRequestBody(url, normalizedOptions.zone ?? serpZone, {\n ...normalizedOptions,\n format: normalizedOptions.format ?? 'json',\n method: 'GET',\n }),\n normalizedOptions.timeout ?? timeout,\n );\n },\n },\n scrapeUrl: async (url: string, options: RequestOptions = {}) => {\n const response = await requestBrightData(\n apiKey,\n toRequestBody(url, options.zone ?? webUnlockerZone, options),\n options.timeout ?? timeout,\n );\n\n return typeof response === 'string' ? response : JSON.stringify(response);\n },\n close: async () => {},\n };\n}\n\nexport async function closeClient(client: BrightDataClient): Promise<void> {\n const close = client.close;\n try {\n await close.call(client);\n } catch {\n // best-effort cleanup; never mask the primary tool error from the finally block\n }\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n query: z.string().describe('The search query'),\n country: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Country must be a 2-letter code')\n .optional()\n .describe('2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")'),\n language: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Language must be a 2-letter code')\n .optional()\n .describe('Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")'),\n start: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe('Result offset for pagination (e.g. 10 to get the second page of 10 results)'),\n});\n\nconst outputSchema = z.object({\n query: z.string(),\n results: z.array(\n z.object({\n link: z.string(),\n title: z.string(),\n description: z.string(),\n }),\n ),\n currentPage: z.number(),\n});\n\nexport function createBrightDataSearchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-search',\n description:\n \"Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const rawResponse = await client.search.google(input.query, {\n country: input.country,\n language: input.language,\n start: input.start,\n });\n\n const response: { organic?: unknown; current_page?: unknown } =\n typeof rawResponse === 'string' ? JSON.parse(rawResponse) : rawResponse;\n\n const organic = Array.isArray(response.organic) ? response.organic : [];\n const results = organic\n .map((entry: unknown) => {\n if (!entry || typeof entry !== 'object') return null;\n const e = entry as Record<string, unknown>;\n const link = typeof e.link === 'string' ? e.link.trim() : '';\n const title = typeof e.title === 'string' ? e.title.trim() : '';\n const description = typeof e.description === 'string' ? e.description.trim() : '';\n if (!link || !title) return null;\n return { link, title, description };\n })\n .filter((r): r is { link: string; title: string; description: string } => r !== null);\n\n const parsedPage = Number(response.current_page);\n const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;\n\n return {\n query: input.query,\n results,\n currentPage,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n url: z.string().url().describe('The URL to fetch'),\n});\n\nconst outputSchema = z.object({\n url: z.string(),\n content: z.string().describe('Page content as Markdown'),\n});\n\nexport function createBrightDataFetchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-fetch',\n description:\n \"Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const content = await client.scrapeUrl(input.url, {\n dataFormat: 'markdown',\n });\n\n return {\n url: input.url,\n content,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import type { BrightDataClientOptions } from './client.js';\nimport { createBrightDataFetchTool } from './fetch.js';\nimport { createBrightDataSearchTool } from './search.js';\n\nexport function createBrightDataTools(config?: BrightDataClientOptions) {\n return {\n webSearch: createBrightDataSearchTool(config),\n webFetch: createBrightDataFetchTool(config),\n };\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,217 +1,186 @@
1
- import { createTool } from '@mastra/core/tools';
2
- import { z } from 'zod';
3
-
4
- // src/client.ts
5
- var REQUEST_ENDPOINT = "https://api.brightdata.com/request";
6
- var DEFAULT_SERP_ZONE = "sdk_serp";
7
- var DEFAULT_WEB_UNLOCKER_ZONE = "sdk_unlocker";
8
- var DEFAULT_TIMEOUT = 12e4;
1
+ import { createTool } from "@mastra/core/tools";
2
+ import { z } from "zod";
3
+ //#region src/client.ts
4
+ const REQUEST_ENDPOINT = "https://api.brightdata.com/request";
5
+ const DEFAULT_SERP_ZONE = "sdk_serp";
6
+ const DEFAULT_WEB_UNLOCKER_ZONE = "sdk_unlocker";
7
+ const DEFAULT_TIMEOUT = 12e4;
9
8
  async function requestBrightData(apiKey, body, timeout = DEFAULT_TIMEOUT) {
10
- const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;
11
- const controller = new AbortController();
12
- const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
13
- try {
14
- const response = await fetch(REQUEST_ENDPOINT, {
15
- body: JSON.stringify(body),
16
- headers: {
17
- Authorization: `Bearer ${apiKey}`,
18
- "Content-Type": "application/json"
19
- },
20
- method: "POST",
21
- signal: controller.signal
22
- });
23
- const responseText = await response.text();
24
- if (!response.ok) {
25
- if (response.status === 401 || response.status === 403) {
26
- throw new Error("invalid API key or insufficient permissions");
27
- }
28
- if (response.status === 400) {
29
- throw new Error(`bad request: ${responseText}`);
30
- }
31
- throw new Error(`request failed with status ${response.status}: ${responseText}`);
32
- }
33
- if (body.format === "json") {
34
- return responseText ? JSON.parse(responseText) : {};
35
- }
36
- return responseText;
37
- } catch (error) {
38
- if (error instanceof Error && error.name === "AbortError") {
39
- throw new Error(`Request timed out after ${effectiveTimeout}ms`);
40
- }
41
- throw error;
42
- } finally {
43
- clearTimeout(timeoutId);
44
- }
9
+ const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;
10
+ const controller = new AbortController();
11
+ const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
12
+ try {
13
+ const response = await fetch(REQUEST_ENDPOINT, {
14
+ body: JSON.stringify(body),
15
+ headers: {
16
+ Authorization: `Bearer ${apiKey}`,
17
+ "Content-Type": "application/json"
18
+ },
19
+ method: "POST",
20
+ signal: controller.signal
21
+ });
22
+ const responseText = await response.text();
23
+ if (!response.ok) {
24
+ if (response.status === 401 || response.status === 403) throw new Error("invalid API key or insufficient permissions");
25
+ if (response.status === 400) throw new Error(`bad request: ${responseText}`);
26
+ throw new Error(`request failed with status ${response.status}: ${responseText}`);
27
+ }
28
+ if (body.format === "json") return responseText ? JSON.parse(responseText) : {};
29
+ return responseText;
30
+ } catch (error) {
31
+ if (error instanceof Error && error.name === "AbortError") throw new Error(`Request timed out after ${effectiveTimeout}ms`);
32
+ throw error;
33
+ } finally {
34
+ clearTimeout(timeoutId);
35
+ }
45
36
  }
46
37
  function buildGoogleSearchUrl(query, options = {}) {
47
- const url = new URL("https://www.google.com/search");
48
- url.searchParams.set("q", query.trim());
49
- if ((options.format ?? "json") === "json") {
50
- url.searchParams.set("brd_json", "1");
51
- }
52
- url.searchParams.set("hl", options.language ?? "en");
53
- if (options.country) {
54
- url.searchParams.set("gl", options.country);
55
- }
56
- if (options.start !== void 0) {
57
- url.searchParams.set("start", String(options.start));
58
- }
59
- return url.toString();
38
+ const url = new URL("https://www.google.com/search");
39
+ url.searchParams.set("q", query.trim());
40
+ if ((options.format ?? "json") === "json") url.searchParams.set("brd_json", "1");
41
+ url.searchParams.set("hl", options.language ?? "en");
42
+ if (options.country) url.searchParams.set("gl", options.country);
43
+ if (options.start !== void 0) url.searchParams.set("start", String(options.start));
44
+ return url.toString();
60
45
  }
61
46
  function toRequestBody(url, zone, options = {}) {
62
- const body = {
63
- format: options.format ?? "raw",
64
- method: options.method ?? "GET",
65
- url,
66
- zone
67
- };
68
- if (options.country) {
69
- body.country = options.country;
70
- }
71
- if (options.dataFormat && options.dataFormat !== "html") {
72
- body.data_format = options.dataFormat;
73
- }
74
- return body;
47
+ const body = {
48
+ format: options.format ?? "raw",
49
+ method: options.method ?? "GET",
50
+ url,
51
+ zone
52
+ };
53
+ if (options.country) body.country = options.country;
54
+ if (options.dataFormat && options.dataFormat !== "html") body.data_format = options.dataFormat;
55
+ return body;
75
56
  }
76
57
  function getBrightDataClient(config) {
77
- const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;
78
- if (!apiKey) {
79
- throw new Error("Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.");
80
- }
81
- const timeout = config?.timeout;
82
- const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;
83
- const webUnlockerZone = config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;
84
- return {
85
- search: {
86
- google: async (query, options = {}) => {
87
- if (options.language && !/^[a-z]{2}$/i.test(options.language)) {
88
- throw new Error('language must be a two-letter code (e.g. "en", "es")');
89
- }
90
- const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;
91
- const url = buildGoogleSearchUrl(query, normalizedOptions);
92
- return requestBrightData(
93
- apiKey,
94
- toRequestBody(url, normalizedOptions.zone ?? serpZone, {
95
- ...normalizedOptions,
96
- format: normalizedOptions.format ?? "json",
97
- method: "GET"
98
- }),
99
- normalizedOptions.timeout ?? timeout
100
- );
101
- }
102
- },
103
- scrapeUrl: async (url, options = {}) => {
104
- const response = await requestBrightData(
105
- apiKey,
106
- toRequestBody(url, options.zone ?? webUnlockerZone, options),
107
- options.timeout ?? timeout
108
- );
109
- return typeof response === "string" ? response : JSON.stringify(response);
110
- },
111
- close: async () => {
112
- }
113
- };
58
+ const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;
59
+ if (!apiKey) throw new Error("Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.");
60
+ const timeout = config?.timeout;
61
+ const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;
62
+ const webUnlockerZone = config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;
63
+ return {
64
+ search: { google: async (query, options = {}) => {
65
+ if (options.language && !/^[a-z]{2}$/i.test(options.language)) throw new Error("language must be a two-letter code (e.g. \"en\", \"es\")");
66
+ const normalizedOptions = options.language ? {
67
+ ...options,
68
+ language: options.language.toLowerCase()
69
+ } : options;
70
+ const url = buildGoogleSearchUrl(query, normalizedOptions);
71
+ return requestBrightData(apiKey, toRequestBody(url, normalizedOptions.zone ?? serpZone, {
72
+ ...normalizedOptions,
73
+ format: normalizedOptions.format ?? "json",
74
+ method: "GET"
75
+ }), normalizedOptions.timeout ?? timeout);
76
+ } },
77
+ scrapeUrl: async (url, options = {}) => {
78
+ const response = await requestBrightData(apiKey, toRequestBody(url, options.zone ?? webUnlockerZone, options), options.timeout ?? timeout);
79
+ return typeof response === "string" ? response : JSON.stringify(response);
80
+ },
81
+ close: async () => {}
82
+ };
114
83
  }
115
84
  async function closeClient(client) {
116
- const close = client.close;
117
- try {
118
- await close.call(client);
119
- } catch {
120
- }
85
+ const close = client.close;
86
+ try {
87
+ await close.call(client);
88
+ } catch {}
121
89
  }
122
- var inputSchema = z.object({
123
- query: z.string().describe("The search query"),
124
- country: z.string().regex(/^[a-z]{2}$/i, "Country must be a 2-letter code").optional().describe('2-letter country code for geo-targeted results (e.g., "us", "gb")'),
125
- language: z.string().regex(/^[a-z]{2}$/i, "Language must be a 2-letter code").optional().describe('Language code for localized Google results (e.g., "en", "es", "fr")'),
126
- start: z.number().int().nonnegative().optional().describe("Result offset for pagination (e.g. 10 to get the second page of 10 results)")
90
+ //#endregion
91
+ //#region src/search.ts
92
+ const inputSchema$1 = z.object({
93
+ query: z.string().describe("The search query"),
94
+ country: z.string().regex(/^[a-z]{2}$/i, "Country must be a 2-letter code").optional().describe("2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")"),
95
+ language: z.string().regex(/^[a-z]{2}$/i, "Language must be a 2-letter code").optional().describe("Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")"),
96
+ start: z.number().int().nonnegative().optional().describe("Result offset for pagination (e.g. 10 to get the second page of 10 results)")
127
97
  });
128
- var outputSchema = z.object({
129
- query: z.string(),
130
- results: z.array(
131
- z.object({
132
- link: z.string(),
133
- title: z.string(),
134
- description: z.string()
135
- })
136
- ),
137
- currentPage: z.number()
98
+ const outputSchema$1 = z.object({
99
+ query: z.string(),
100
+ results: z.array(z.object({
101
+ link: z.string(),
102
+ title: z.string(),
103
+ description: z.string()
104
+ })),
105
+ currentPage: z.number()
138
106
  });
139
107
  function createBrightDataSearchTool(config) {
140
- return createTool({
141
- id: "brightdata-search",
142
- description: "Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.",
143
- inputSchema,
144
- outputSchema,
145
- execute: async (input) => {
146
- const client = getBrightDataClient(config);
147
- try {
148
- const rawResponse = await client.search.google(input.query, {
149
- country: input.country,
150
- language: input.language,
151
- start: input.start
152
- });
153
- const response = typeof rawResponse === "string" ? JSON.parse(rawResponse) : rawResponse;
154
- const organic = Array.isArray(response.organic) ? response.organic : [];
155
- const results = organic.map((entry) => {
156
- if (!entry || typeof entry !== "object") return null;
157
- const e = entry;
158
- const link = typeof e.link === "string" ? e.link.trim() : "";
159
- const title = typeof e.title === "string" ? e.title.trim() : "";
160
- const description = typeof e.description === "string" ? e.description.trim() : "";
161
- if (!link || !title) return null;
162
- return { link, title, description };
163
- }).filter((r) => r !== null);
164
- const parsedPage = Number(response.current_page);
165
- const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;
166
- return {
167
- query: input.query,
168
- results,
169
- currentPage
170
- };
171
- } finally {
172
- await closeClient(client);
173
- }
174
- }
175
- });
108
+ return createTool({
109
+ id: "brightdata-search",
110
+ description: "Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.",
111
+ inputSchema: inputSchema$1,
112
+ outputSchema: outputSchema$1,
113
+ execute: async (input) => {
114
+ const client = getBrightDataClient(config);
115
+ try {
116
+ const rawResponse = await client.search.google(input.query, {
117
+ country: input.country,
118
+ language: input.language,
119
+ start: input.start
120
+ });
121
+ const response = typeof rawResponse === "string" ? JSON.parse(rawResponse) : rawResponse;
122
+ const results = (Array.isArray(response.organic) ? response.organic : []).map((entry) => {
123
+ if (!entry || typeof entry !== "object") return null;
124
+ const e = entry;
125
+ const link = typeof e.link === "string" ? e.link.trim() : "";
126
+ const title = typeof e.title === "string" ? e.title.trim() : "";
127
+ const description = typeof e.description === "string" ? e.description.trim() : "";
128
+ if (!link || !title) return null;
129
+ return {
130
+ link,
131
+ title,
132
+ description
133
+ };
134
+ }).filter((r) => r !== null);
135
+ const parsedPage = Number(response.current_page);
136
+ const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;
137
+ return {
138
+ query: input.query,
139
+ results,
140
+ currentPage
141
+ };
142
+ } finally {
143
+ await closeClient(client);
144
+ }
145
+ }
146
+ });
176
147
  }
177
- var inputSchema2 = z.object({
178
- url: z.string().url().describe("The URL to fetch")
179
- });
180
- var outputSchema2 = z.object({
181
- url: z.string(),
182
- content: z.string().describe("Page content as Markdown")
148
+ //#endregion
149
+ //#region src/fetch.ts
150
+ const inputSchema = z.object({ url: z.string().url().describe("The URL to fetch") });
151
+ const outputSchema = z.object({
152
+ url: z.string(),
153
+ content: z.string().describe("Page content as Markdown")
183
154
  });
184
155
  function createBrightDataFetchTool(config) {
185
- return createTool({
186
- id: "brightdata-fetch",
187
- description: "Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.",
188
- inputSchema: inputSchema2,
189
- outputSchema: outputSchema2,
190
- execute: async (input) => {
191
- const client = getBrightDataClient(config);
192
- try {
193
- const content = await client.scrapeUrl(input.url, {
194
- dataFormat: "markdown"
195
- });
196
- return {
197
- url: input.url,
198
- content
199
- };
200
- } finally {
201
- await closeClient(client);
202
- }
203
- }
204
- });
156
+ return createTool({
157
+ id: "brightdata-fetch",
158
+ description: "Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.",
159
+ inputSchema,
160
+ outputSchema,
161
+ execute: async (input) => {
162
+ const client = getBrightDataClient(config);
163
+ try {
164
+ const content = await client.scrapeUrl(input.url, { dataFormat: "markdown" });
165
+ return {
166
+ url: input.url,
167
+ content
168
+ };
169
+ } finally {
170
+ await closeClient(client);
171
+ }
172
+ }
173
+ });
205
174
  }
206
-
207
- // src/tools.ts
175
+ //#endregion
176
+ //#region src/tools.ts
208
177
  function createBrightDataTools(config) {
209
- return {
210
- webSearch: createBrightDataSearchTool(config),
211
- webFetch: createBrightDataFetchTool(config)
212
- };
178
+ return {
179
+ webSearch: createBrightDataSearchTool(config),
180
+ webFetch: createBrightDataFetchTool(config)
181
+ };
213
182
  }
214
-
183
+ //#endregion
215
184
  export { createBrightDataFetchTool, createBrightDataSearchTool, createBrightDataTools, getBrightDataClient };
216
- //# sourceMappingURL=index.js.map
185
+
217
186
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/search.ts","../src/fetch.ts","../src/tools.ts"],"names":["inputSchema","z","outputSchema","createTool"],"mappings":"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","file":"index.js","sourcesContent":["const REQUEST_ENDPOINT = 'https://api.brightdata.com/request';\nconst DEFAULT_SERP_ZONE = 'sdk_serp';\nconst DEFAULT_WEB_UNLOCKER_ZONE = 'sdk_unlocker';\nconst DEFAULT_TIMEOUT = 120_000;\n\ntype RequestFormat = 'raw' | 'json';\ntype DataFormat = 'html' | 'markdown' | 'screenshot';\n\nexport interface BrightDataClientOptions {\n [key: string]: unknown;\n apiKey?: string;\n timeout?: number;\n webUnlockerZone?: string;\n serpZone?: string;\n}\n\ninterface RequestOptions {\n country?: string;\n dataFormat?: DataFormat;\n format?: RequestFormat;\n method?: string;\n timeout?: number;\n zone?: string;\n}\n\ninterface SearchOptions extends RequestOptions {\n language?: string;\n start?: number;\n}\n\ninterface BrightDataRequestBody {\n country?: string;\n data_format?: Exclude<DataFormat, 'html'>;\n format: RequestFormat;\n method: string;\n url: string;\n zone: string;\n}\n\nexport interface BrightDataClient {\n search: {\n google: (query: string, options?: SearchOptions) => Promise<unknown>;\n };\n scrapeUrl: (url: string, options?: RequestOptions) => Promise<string>;\n close: () => Promise<void>;\n}\n\nasync function requestBrightData(\n apiKey: string,\n body: BrightDataRequestBody,\n timeout = DEFAULT_TIMEOUT,\n): Promise<unknown> {\n const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const response = await fetch(REQUEST_ENDPOINT, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n signal: controller.signal,\n });\n\n const responseText = await response.text();\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n throw new Error('invalid API key or insufficient permissions');\n }\n\n if (response.status === 400) {\n throw new Error(`bad request: ${responseText}`);\n }\n\n throw new Error(`request failed with status ${response.status}: ${responseText}`);\n }\n\n if (body.format === 'json') {\n return responseText ? JSON.parse(responseText) : {};\n }\n\n return responseText;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timed out after ${effectiveTimeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nfunction buildGoogleSearchUrl(query: string, options: SearchOptions = {}) {\n const url = new URL('https://www.google.com/search');\n url.searchParams.set('q', query.trim());\n if ((options.format ?? 'json') === 'json') {\n url.searchParams.set('brd_json', '1');\n }\n url.searchParams.set('hl', options.language ?? 'en');\n\n if (options.country) {\n url.searchParams.set('gl', options.country);\n }\n\n if (options.start !== undefined) {\n url.searchParams.set('start', String(options.start));\n }\n\n return url.toString();\n}\n\nfunction toRequestBody(url: string, zone: string, options: RequestOptions = {}): BrightDataRequestBody {\n const body: BrightDataRequestBody = {\n format: options.format ?? 'raw',\n method: options.method ?? 'GET',\n url,\n zone,\n };\n\n if (options.country) {\n body.country = options.country;\n }\n\n if (options.dataFormat && options.dataFormat !== 'html') {\n body.data_format = options.dataFormat;\n }\n\n return body;\n}\n\nexport function getBrightDataClient(config?: BrightDataClientOptions): BrightDataClient {\n const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;\n if (!apiKey) {\n throw new Error('Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.');\n }\n\n const timeout = config?.timeout;\n const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;\n const webUnlockerZone =\n config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;\n\n return {\n search: {\n google: async (query: string, options: SearchOptions = {}) => {\n if (options.language && !/^[a-z]{2}$/i.test(options.language)) {\n throw new Error('language must be a two-letter code (e.g. \"en\", \"es\")');\n }\n\n const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;\n\n const url = buildGoogleSearchUrl(query, normalizedOptions);\n return requestBrightData(\n apiKey,\n toRequestBody(url, normalizedOptions.zone ?? serpZone, {\n ...normalizedOptions,\n format: normalizedOptions.format ?? 'json',\n method: 'GET',\n }),\n normalizedOptions.timeout ?? timeout,\n );\n },\n },\n scrapeUrl: async (url: string, options: RequestOptions = {}) => {\n const response = await requestBrightData(\n apiKey,\n toRequestBody(url, options.zone ?? webUnlockerZone, options),\n options.timeout ?? timeout,\n );\n\n return typeof response === 'string' ? response : JSON.stringify(response);\n },\n close: async () => {},\n };\n}\n\nexport async function closeClient(client: BrightDataClient): Promise<void> {\n const close = client.close;\n try {\n await close.call(client);\n } catch {\n // best-effort cleanup; never mask the primary tool error from the finally block\n }\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n query: z.string().describe('The search query'),\n country: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Country must be a 2-letter code')\n .optional()\n .describe('2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")'),\n language: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Language must be a 2-letter code')\n .optional()\n .describe('Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")'),\n start: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe('Result offset for pagination (e.g. 10 to get the second page of 10 results)'),\n});\n\nconst outputSchema = z.object({\n query: z.string(),\n results: z.array(\n z.object({\n link: z.string(),\n title: z.string(),\n description: z.string(),\n }),\n ),\n currentPage: z.number(),\n});\n\nexport function createBrightDataSearchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-search',\n description:\n \"Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const rawResponse = await client.search.google(input.query, {\n country: input.country,\n language: input.language,\n start: input.start,\n });\n\n const response: { organic?: unknown; current_page?: unknown } =\n typeof rawResponse === 'string' ? JSON.parse(rawResponse) : rawResponse;\n\n const organic = Array.isArray(response.organic) ? response.organic : [];\n const results = organic\n .map((entry: unknown) => {\n if (!entry || typeof entry !== 'object') return null;\n const e = entry as Record<string, unknown>;\n const link = typeof e.link === 'string' ? e.link.trim() : '';\n const title = typeof e.title === 'string' ? e.title.trim() : '';\n const description = typeof e.description === 'string' ? e.description.trim() : '';\n if (!link || !title) return null;\n return { link, title, description };\n })\n .filter((r): r is { link: string; title: string; description: string } => r !== null);\n\n const parsedPage = Number(response.current_page);\n const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;\n\n return {\n query: input.query,\n results,\n currentPage,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n url: z.string().url().describe('The URL to fetch'),\n});\n\nconst outputSchema = z.object({\n url: z.string(),\n content: z.string().describe('Page content as Markdown'),\n});\n\nexport function createBrightDataFetchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-fetch',\n description:\n \"Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const content = await client.scrapeUrl(input.url, {\n dataFormat: 'markdown',\n });\n\n return {\n url: input.url,\n content,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import type { BrightDataClientOptions } from './client.js';\nimport { createBrightDataFetchTool } from './fetch.js';\nimport { createBrightDataSearchTool } from './search.js';\n\nexport function createBrightDataTools(config?: BrightDataClientOptions) {\n return {\n webSearch: createBrightDataSearchTool(config),\n webFetch: createBrightDataFetchTool(config),\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","names":["inputSchema","outputSchema"],"sources":["../src/client.ts","../src/search.ts","../src/fetch.ts","../src/tools.ts"],"sourcesContent":["const REQUEST_ENDPOINT = 'https://api.brightdata.com/request';\nconst DEFAULT_SERP_ZONE = 'sdk_serp';\nconst DEFAULT_WEB_UNLOCKER_ZONE = 'sdk_unlocker';\nconst DEFAULT_TIMEOUT = 120_000;\n\ntype RequestFormat = 'raw' | 'json';\ntype DataFormat = 'html' | 'markdown' | 'screenshot';\n\nexport interface BrightDataClientOptions {\n [key: string]: unknown;\n apiKey?: string;\n timeout?: number;\n webUnlockerZone?: string;\n serpZone?: string;\n}\n\ninterface RequestOptions {\n country?: string;\n dataFormat?: DataFormat;\n format?: RequestFormat;\n method?: string;\n timeout?: number;\n zone?: string;\n}\n\ninterface SearchOptions extends RequestOptions {\n language?: string;\n start?: number;\n}\n\ninterface BrightDataRequestBody {\n country?: string;\n data_format?: Exclude<DataFormat, 'html'>;\n format: RequestFormat;\n method: string;\n url: string;\n zone: string;\n}\n\nexport interface BrightDataClient {\n search: {\n google: (query: string, options?: SearchOptions) => Promise<unknown>;\n };\n scrapeUrl: (url: string, options?: RequestOptions) => Promise<string>;\n close: () => Promise<void>;\n}\n\nasync function requestBrightData(\n apiKey: string,\n body: BrightDataRequestBody,\n timeout = DEFAULT_TIMEOUT,\n): Promise<unknown> {\n const effectiveTimeout = Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_TIMEOUT;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);\n\n try {\n const response = await fetch(REQUEST_ENDPOINT, {\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n signal: controller.signal,\n });\n\n const responseText = await response.text();\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n throw new Error('invalid API key or insufficient permissions');\n }\n\n if (response.status === 400) {\n throw new Error(`bad request: ${responseText}`);\n }\n\n throw new Error(`request failed with status ${response.status}: ${responseText}`);\n }\n\n if (body.format === 'json') {\n return responseText ? JSON.parse(responseText) : {};\n }\n\n return responseText;\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request timed out after ${effectiveTimeout}ms`);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nfunction buildGoogleSearchUrl(query: string, options: SearchOptions = {}) {\n const url = new URL('https://www.google.com/search');\n url.searchParams.set('q', query.trim());\n if ((options.format ?? 'json') === 'json') {\n url.searchParams.set('brd_json', '1');\n }\n url.searchParams.set('hl', options.language ?? 'en');\n\n if (options.country) {\n url.searchParams.set('gl', options.country);\n }\n\n if (options.start !== undefined) {\n url.searchParams.set('start', String(options.start));\n }\n\n return url.toString();\n}\n\nfunction toRequestBody(url: string, zone: string, options: RequestOptions = {}): BrightDataRequestBody {\n const body: BrightDataRequestBody = {\n format: options.format ?? 'raw',\n method: options.method ?? 'GET',\n url,\n zone,\n };\n\n if (options.country) {\n body.country = options.country;\n }\n\n if (options.dataFormat && options.dataFormat !== 'html') {\n body.data_format = options.dataFormat;\n }\n\n return body;\n}\n\nexport function getBrightDataClient(config?: BrightDataClientOptions): BrightDataClient {\n const apiKey = config?.apiKey ?? process.env.BRIGHTDATA_API_TOKEN;\n if (!apiKey) {\n throw new Error('Bright Data API token is required. Pass { apiKey } or set BRIGHTDATA_API_TOKEN env var.');\n }\n\n const timeout = config?.timeout;\n const serpZone = config?.serpZone ?? process.env.BRIGHTDATA_SERP_ZONE ?? DEFAULT_SERP_ZONE;\n const webUnlockerZone =\n config?.webUnlockerZone ?? process.env.BRIGHTDATA_WEB_UNLOCKER_ZONE ?? DEFAULT_WEB_UNLOCKER_ZONE;\n\n return {\n search: {\n google: async (query: string, options: SearchOptions = {}) => {\n if (options.language && !/^[a-z]{2}$/i.test(options.language)) {\n throw new Error('language must be a two-letter code (e.g. \"en\", \"es\")');\n }\n\n const normalizedOptions = options.language ? { ...options, language: options.language.toLowerCase() } : options;\n\n const url = buildGoogleSearchUrl(query, normalizedOptions);\n return requestBrightData(\n apiKey,\n toRequestBody(url, normalizedOptions.zone ?? serpZone, {\n ...normalizedOptions,\n format: normalizedOptions.format ?? 'json',\n method: 'GET',\n }),\n normalizedOptions.timeout ?? timeout,\n );\n },\n },\n scrapeUrl: async (url: string, options: RequestOptions = {}) => {\n const response = await requestBrightData(\n apiKey,\n toRequestBody(url, options.zone ?? webUnlockerZone, options),\n options.timeout ?? timeout,\n );\n\n return typeof response === 'string' ? response : JSON.stringify(response);\n },\n close: async () => {},\n };\n}\n\nexport async function closeClient(client: BrightDataClient): Promise<void> {\n const close = client.close;\n try {\n await close.call(client);\n } catch {\n // best-effort cleanup; never mask the primary tool error from the finally block\n }\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n query: z.string().describe('The search query'),\n country: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Country must be a 2-letter code')\n .optional()\n .describe('2-letter country code for geo-targeted results (e.g., \"us\", \"gb\")'),\n language: z\n .string()\n .regex(/^[a-z]{2}$/i, 'Language must be a 2-letter code')\n .optional()\n .describe('Language code for localized Google results (e.g., \"en\", \"es\", \"fr\")'),\n start: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe('Result offset for pagination (e.g. 10 to get the second page of 10 results)'),\n});\n\nconst outputSchema = z.object({\n query: z.string(),\n results: z.array(\n z.object({\n link: z.string(),\n title: z.string(),\n description: z.string(),\n }),\n ),\n currentPage: z.number(),\n});\n\nexport function createBrightDataSearchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-search',\n description:\n \"Search Google and get back parsed organic results (link, title, description). Uses Bright Data's SERP API which bypasses bot detection. Supports country and language targeting, plus pagination via result offset.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const rawResponse = await client.search.google(input.query, {\n country: input.country,\n language: input.language,\n start: input.start,\n });\n\n const response: { organic?: unknown; current_page?: unknown } =\n typeof rawResponse === 'string' ? JSON.parse(rawResponse) : rawResponse;\n\n const organic = Array.isArray(response.organic) ? response.organic : [];\n const results = organic\n .map((entry: unknown) => {\n if (!entry || typeof entry !== 'object') return null;\n const e = entry as Record<string, unknown>;\n const link = typeof e.link === 'string' ? e.link.trim() : '';\n const title = typeof e.title === 'string' ? e.title.trim() : '';\n const description = typeof e.description === 'string' ? e.description.trim() : '';\n if (!link || !title) return null;\n return { link, title, description };\n })\n .filter((r): r is { link: string; title: string; description: string } => r !== null);\n\n const parsedPage = Number(response.current_page);\n const currentPage = Number.isFinite(parsedPage) && parsedPage > 0 ? parsedPage : 1;\n\n return {\n query: input.query,\n results,\n currentPage,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { closeClient, getBrightDataClient } from './client.js';\nimport type { BrightDataClientOptions } from './client.js';\n\nconst inputSchema = z.object({\n url: z.string().url().describe('The URL to fetch'),\n});\n\nconst outputSchema = z.object({\n url: z.string(),\n content: z.string().describe('Page content as Markdown'),\n});\n\nexport function createBrightDataFetchTool(config?: BrightDataClientOptions) {\n return createTool({\n id: 'brightdata-fetch',\n description:\n \"Fetch a webpage and return its content as Markdown. Uses Bright Data's Web Unlocker which bypasses bot detection and CAPTCHAs. Pass any URL, including pages that block normal scrapers.\",\n inputSchema,\n outputSchema,\n execute: async input => {\n const client = getBrightDataClient(config);\n try {\n const content = await client.scrapeUrl(input.url, {\n dataFormat: 'markdown',\n });\n\n return {\n url: input.url,\n content,\n };\n } finally {\n await closeClient(client);\n }\n },\n });\n}\n","import type { BrightDataClientOptions } from './client.js';\nimport { createBrightDataFetchTool } from './fetch.js';\nimport { createBrightDataSearchTool } from './search.js';\n\nexport function createBrightDataTools(config?: BrightDataClientOptions) {\n return {\n webSearch: createBrightDataSearchTool(config),\n webFetch: createBrightDataFetchTool(config),\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAI3D,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,uBAAuB;;;;;;;;;;;;;;;;;;;;;EAKrE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAI3D,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,uBAAuB;IAElE,SAAS;;;;;;;;;;;;;;IACT,QAAQ;;;;;;EAEX"}
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@mastra/brightdata",
3
- "version": "0.3.0",
3
+ "version": "0.3.1-alpha.0",
4
4
  "description": "Bright Data web search and web fetch tools for Mastra agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "files": [
9
- "dist",
10
- "CHANGELOG.md"
9
+ "dist"
11
10
  ],
12
11
  "exports": {
13
12
  ".": {
@@ -48,18 +47,19 @@
48
47
  "zod": ">=3.0.0"
49
48
  },
50
49
  "devDependencies": {
51
- "tsup": "^8.5.1",
52
- "typescript": "^6.0.3",
53
- "vitest": "4.1.8",
50
+ "tsdown": "0.22.9",
51
+ "typescript": "^7.0.2",
52
+ "vitest": "4.1.10",
54
53
  "zod": "^4.4.3",
55
- "@internal/lint": "0.0.107",
56
- "@internal/types-builder": "0.0.82",
57
- "@mastra/core": "1.45.0"
54
+ "@internal/lint": "0.0.129",
55
+ "@internal/types-builder": "0.0.104",
56
+ "@mastra/core": "1.64.0-alpha.2"
58
57
  },
59
58
  "scripts": {
60
- "build:lib": "tsup --silent --config tsup.config.ts",
59
+ "build:lib": "tsdown --silent --config tsdown.config.ts",
61
60
  "build:watch": "pnpm build:lib --watch",
62
- "lint": "eslint .",
61
+ "lint": "oxlint . && eslint .",
62
+ "lint:fix": "oxlint --fix . && eslint --fix .",
63
63
  "test": "vitest run"
64
64
  }
65
65
  }
package/CHANGELOG.md DELETED
@@ -1,115 +0,0 @@
1
- # @mastra/brightdata
2
-
3
- ## 0.3.0
4
-
5
- ### Minor Changes
6
-
7
- - Random bump ([#18178](https://github.com/mastra-ai/mastra/pull/18178))
8
-
9
- ### Patch Changes
10
-
11
- - Updated dependencies [[`7c0d868`](https://github.com/mastra-ai/mastra/commit/7c0d868d97d0fdbc04c14d0166dbf44d4c5a4a62), [`d9d2273`](https://github.com/mastra-ai/mastra/commit/d9d2273c702690c9a26eab2aebea879701d4355a), [`b04369d`](https://github.com/mastra-ai/mastra/commit/b04369d6b167c698ef103981171a8bf92808e756), [`8f3c262`](https://github.com/mastra-ai/mastra/commit/8f3c262587b335588a02d96b17fd6aca34c885b3)]:
12
- - @mastra/core@1.45.0
13
-
14
- ## 0.3.0-alpha.0
15
-
16
- ### Minor Changes
17
-
18
- - Random bump ([#18178](https://github.com/mastra-ai/mastra/pull/18178))
19
-
20
- ### Patch Changes
21
-
22
- - Updated dependencies [[`7c0d868`](https://github.com/mastra-ai/mastra/commit/7c0d868d97d0fdbc04c14d0166dbf44d4c5a4a62), [`d9d2273`](https://github.com/mastra-ai/mastra/commit/d9d2273c702690c9a26eab2aebea879701d4355a), [`b04369d`](https://github.com/mastra-ai/mastra/commit/b04369d6b167c698ef103981171a8bf92808e756), [`8f3c262`](https://github.com/mastra-ai/mastra/commit/8f3c262587b335588a02d96b17fd6aca34c885b3)]:
23
- - @mastra/core@1.45.0-alpha.0
24
-
25
- ## 0.2.4
26
-
27
- ### Patch Changes
28
-
29
- - Security remediation for the 2026-06-17 "easy-day-js" supply-chain incident. Patch bump to publish clean versions and move the `latest` dist-tag forward, superseding the compromised versions that declared the malicious `easy-day-js` dependency. ([#18056](https://github.com/mastra-ai/mastra/pull/18056))
30
-
31
- - Updated dependencies [[`339c57c`](https://github.com/mastra-ai/mastra/commit/339c57c5b2c6dbe75a125e138228e0556528976f), [`1dd4117`](https://github.com/mastra-ai/mastra/commit/1dd4117dcbd8e031ede9f0489436bfbc6f0315b8), [`2b11d1f`](https://github.com/mastra-ai/mastra/commit/2b11d1f6ac7024c5dd2b2dd12a48a956ac9d63bd), [`77a2351`](https://github.com/mastra-ai/mastra/commit/77a2351ee79296e360bce822cb3391f7cfd6489d), [`b7dff0a`](https://github.com/mastra-ai/mastra/commit/b7dff0a3d1022eb6868f48dc40a2b1febd5c277f), [`02087e1`](https://github.com/mastra-ai/mastra/commit/02087e1fbc54aa07f3071f7a200df1bf5be601a8), [`49af8df`](https://github.com/mastra-ai/mastra/commit/49af8df589c4ff71a5015a4553b377b32704b691), [`30ce559`](https://github.com/mastra-ai/mastra/commit/30ce55902ecf819b8ab8697398dd68b108228063), [`c241b92`](https://github.com/mastra-ai/mastra/commit/c241b929dc8c8d6a7b7219c99ed13ac1f3124a77), [`7d6ff70`](https://github.com/mastra-ai/mastra/commit/7d6ff708727297a0526ca0e26e93eeb5bbaaa187), [`ab975d4`](https://github.com/mastra-ai/mastra/commit/ab975d4dd9488752f05bda7afa03166d207e3e2a), [`9d6aa1b`](https://github.com/mastra-ai/mastra/commit/9d6aa1bae407e2afa6a089abc2a6accbbcb287b8)]:
32
- - @mastra/core@1.44.0
33
-
34
- ## 0.2.4-alpha.0
35
-
36
- ### Patch Changes
37
-
38
- - Security remediation for the 2026-06-17 "easy-day-js" supply-chain incident. Patch bump to publish clean versions and move the `latest` dist-tag forward, superseding the compromised versions that declared the malicious `easy-day-js` dependency. ([#18056](https://github.com/mastra-ai/mastra/pull/18056))
39
-
40
- - Updated dependencies [[`77a2351`](https://github.com/mastra-ai/mastra/commit/77a2351ee79296e360bce822cb3391f7cfd6489d)]:
41
- - @mastra/core@1.43.1-alpha.0
42
-
43
- ## 0.2.1
44
-
45
- ### Patch Changes
46
-
47
- - Fix Bright Data tools under Bun by replacing the SDK runtime client with fetch-based REST calls. ([#16630](https://github.com/mastra-ai/mastra/pull/16630))
48
-
49
- - Harden Bright Data search input handling. Country and language codes are now validated as alphabetic two-letter codes, the `getBrightDataClient().search.google()` client validates and lowercase-normalizes `language` before the request, and structured JSON (`brd_json=1`) is only requested when the search `format` is `json` so callers can obtain a true raw SERP response. ([#17341](https://github.com/mastra-ai/mastra/pull/17341))
50
-
51
- - Updated dependencies [[`fa63872`](https://github.com/mastra-ai/mastra/commit/fa6387280954e6b667bec5714b55ba082bc627ff), [`d779de3`](https://github.com/mastra-ai/mastra/commit/d779de3cd9d2e7ed8110547190e2f15e786a0e41), [`1750c97`](https://github.com/mastra-ai/mastra/commit/1750c975d6179fbf6db2813b15229d4f8f23fc55), [`9283971`](https://github.com/mastra-ai/mastra/commit/928397157009b4aef4d5fdf3a0a273cb371beb55), [`f07b646`](https://github.com/mastra-ai/mastra/commit/f07b64604ab7d25391179790b7fd4823df9e2dff), [`d8838ae`](https://github.com/mastra-ai/mastra/commit/d8838ae80b69780361693d27098f7f6684af12fe), [`40f9297`](https://github.com/mastra-ai/mastra/commit/40f9297003b921c62373d3e8d3a4bda76c9f6de3), [`19a8658`](https://github.com/mastra-ai/mastra/commit/19a86589c788ef48bb6c1b0612cc82a201857379), [`850af77`](https://github.com/mastra-ai/mastra/commit/850af7779cb87c350804488734544a5b1843de25), [`0f0d1ba`](https://github.com/mastra-ai/mastra/commit/0f0d1ba67bfcb2204e571401662f1eceefc03357), [`a18775a`](https://github.com/mastra-ai/mastra/commit/a18775a693172546ee2378d39b67d4e32895b251), [`1baf2d1`](https://github.com/mastra-ai/mastra/commit/1baf2d152c6881338ff8f114633d5316fe13dd15), [`8c31bcd`](https://github.com/mastra-ai/mastra/commit/8c31bcdb00e597880d5939b1b7d7566fbe5dacae), [`0e32507`](https://github.com/mastra-ai/mastra/commit/0e32507962cdfa5569b7bda5bc6fb3dd34e40b03), [`95b14cd`](https://github.com/mastra-ai/mastra/commit/95b14cdd820e86d97ac05fe568424c513a252e31), [`07c3de7`](https://github.com/mastra-ai/mastra/commit/07c3de7f7bc418beccaea3b5e6b7f7cdda79d492), [`0bf2d93`](https://github.com/mastra-ai/mastra/commit/0bf2d932d20e2936f2d9abb8c0a86e24fbc97ec6), [`7b0d34c`](https://github.com/mastra-ai/mastra/commit/7b0d34cfe4a2fce22ac86ae17404685ff67a2ddb), [`a659a77`](https://github.com/mastra-ai/mastra/commit/a659a779bdebe3a52a518c56d2260592d0240fe0), [`aa36be2`](https://github.com/mastra-ai/mastra/commit/aa36be23aa513b7dc53cb8ca16b7fab8f20e43ad), [`3332be9`](https://github.com/mastra-ai/mastra/commit/3332be9701ecd77aba840959d9a1d1ce7aef02d3), [`212c635`](https://github.com/mastra-ai/mastra/commit/212c635203e61d036ab41db8ff86c3893dc795b3), [`d8838ae`](https://github.com/mastra-ai/mastra/commit/d8838ae80b69780361693d27098f7f6684af12fe), [`9aa5a73`](https://github.com/mastra-ai/mastra/commit/9aa5a73e7e110f6e9365eec69364a33d5f03bb56), [`f73c789`](https://github.com/mastra-ai/mastra/commit/f73c789e8ef21561580395d2c410119cab5848c8), [`8bd16da`](https://github.com/mastra-ai/mastra/commit/8bd16da73a4cb874d739373643dbd6a6e7f88684), [`c8630f8`](https://github.com/mastra-ai/mastra/commit/c8630f80d4f40cb5d22e60ab162b618b1907167a), [`94dfef6`](https://github.com/mastra-ai/mastra/commit/94dfef6e2bf19a88467ea3940afcbce88a433f0f), [`47f71dc`](https://github.com/mastra-ai/mastra/commit/47f71dc6fbcbd12d71e21a979e676e20a02bd77d), [`50ceae2`](https://github.com/mastra-ai/mastra/commit/50ceae270878e2f8fb2b2c6c2faab09df0007c8a), [`a122f79`](https://github.com/mastra-ai/mastra/commit/a122f79427ae225ec79c7b2ed46278da48d04b17), [`8cdde58`](https://github.com/mastra-ai/mastra/commit/8cdde5875bbba6702d9df226f2b20232b8d75d6c), [`3a081c1`](https://github.com/mastra-ai/mastra/commit/3a081c1255c5ae8c99f6dad91cc612934ef6f2bd), [`49f8abc`](https://github.com/mastra-ai/mastra/commit/49f8abce8258e4f2f87bd326acfbdb641264a47c), [`847ff1e`](https://github.com/mastra-ai/mastra/commit/847ff1e0d94368d94b2e173e4e0908e115568ef3), [`0c1ed1d`](https://github.com/mastra-ai/mastra/commit/0c1ed1d00c7d87b5ac99ca95896211a2fa9189fa), [`259d409`](https://github.com/mastra-ai/mastra/commit/259d409a514174299dbde1ff5e1121209b3ba850), [`9e16c68`](https://github.com/mastra-ai/mastra/commit/9e16c6818b6485ccb43df28aba6f3a2219d28662), [`cefca33`](https://github.com/mastra-ai/mastra/commit/cefca33ae666e69810c935fedf95a929c173d1d7), [`d00e8c5`](https://github.com/mastra-ai/mastra/commit/d00e8c50daebe5bce5bf2f48bde39c86fc3d2fe4), [`36fa7e2`](https://github.com/mastra-ai/mastra/commit/36fa7e24d14e58a1eb46147097b32f583e5b8775), [`87e9774`](https://github.com/mastra-ai/mastra/commit/87e97741c1e493cd6d62f478eb810b49bda4d57c), [`65a72e7`](https://github.com/mastra-ai/mastra/commit/65a72e70c25eedea8ff985a6624b96be2850236b), [`fe9eacd`](https://github.com/mastra-ai/mastra/commit/fe9eacd9545a0a9d64aad31c9fa90294a425289e), [`4c02027`](https://github.com/mastra-ai/mastra/commit/4c020277235eaa6b1dc957c90ad0639eef213992), [`0f77241`](https://github.com/mastra-ai/mastra/commit/0f7724108806703799a8ba80ad0f09414afd5066), [`849efb9`](https://github.com/mastra-ai/mastra/commit/849efb9fca6dc976589c1f90a303fea618769109), [`92ff509`](https://github.com/mastra-ai/mastra/commit/92ff5098ef8a990438ca038077021a5f7541ec1d), [`3fce5e7`](https://github.com/mastra-ai/mastra/commit/3fce5e70d011d289043e75003ef3336ed4aa43c3), [`a763592`](https://github.com/mastra-ai/mastra/commit/a763592c3db46963ef1011cfe16fe372816e775e), [`db79c86`](https://github.com/mastra-ai/mastra/commit/db79c86c60723d57e02f9636ca2611bd4515f194), [`6855012`](https://github.com/mastra-ai/mastra/commit/685501247cc4717506f3e89beed03509d63a5370), [`80c7737`](https://github.com/mastra-ai/mastra/commit/80c7737e32d7917b5f356957d67c169d01744fd3), [`7fef31c`](https://github.com/mastra-ai/mastra/commit/7fef31c0d2a6d362a43a647a8a4f6ab893758a23), [`7fef31c`](https://github.com/mastra-ai/mastra/commit/7fef31c0d2a6d362a43a647a8a4f6ab893758a23), [`3f1cf47`](https://github.com/mastra-ai/mastra/commit/3f1cf476f74c1e4cc2df908837e05853a5347e31)]:
52
- - @mastra/core@1.38.0
53
-
54
- ## 0.2.1-alpha.0
55
-
56
- ### Patch Changes
57
-
58
- - Fix Bright Data tools under Bun by replacing the SDK runtime client with fetch-based REST calls. ([#16630](https://github.com/mastra-ai/mastra/pull/16630))
59
-
60
- - Harden Bright Data search input handling. Country and language codes are now validated as alphabetic two-letter codes, the `getBrightDataClient().search.google()` client validates and lowercase-normalizes `language` before the request, and structured JSON (`brd_json=1`) is only requested when the search `format` is `json` so callers can obtain a true raw SERP response. ([#17341](https://github.com/mastra-ai/mastra/pull/17341))
61
-
62
- - Updated dependencies [[`8ace89d`](https://github.com/mastra-ai/mastra/commit/8ace89df77f762e622d3b9f7f65ad7524350d050), [`fa63872`](https://github.com/mastra-ai/mastra/commit/fa6387280954e6b667bec5714b55ba082bc627ff), [`f07b646`](https://github.com/mastra-ai/mastra/commit/f07b64604ab7d25391179790b7fd4823df9e2dff), [`d8838ae`](https://github.com/mastra-ai/mastra/commit/d8838ae80b69780361693d27098f7f6684af12fe), [`40f9297`](https://github.com/mastra-ai/mastra/commit/40f9297003b921c62373d3e8d3a4bda76c9f6de3), [`0f0d1ba`](https://github.com/mastra-ai/mastra/commit/0f0d1ba67bfcb2204e571401662f1eceefc03357), [`8c31bcd`](https://github.com/mastra-ai/mastra/commit/8c31bcdb00e597880d5939b1b7d7566fbe5dacae), [`95b14cd`](https://github.com/mastra-ai/mastra/commit/95b14cdd820e86d97ac05fe568424c513a252e31), [`aa36be2`](https://github.com/mastra-ai/mastra/commit/aa36be23aa513b7dc53cb8ca16b7fab8f20e43ad), [`212c635`](https://github.com/mastra-ai/mastra/commit/212c635203e61d036ab41db8ff86c3893dc795b3), [`d8838ae`](https://github.com/mastra-ai/mastra/commit/d8838ae80b69780361693d27098f7f6684af12fe), [`9aa5a73`](https://github.com/mastra-ai/mastra/commit/9aa5a73e7e110f6e9365eec69364a33d5f03bb56), [`f73c789`](https://github.com/mastra-ai/mastra/commit/f73c789e8ef21561580395d2c410119cab5848c8), [`8bd16da`](https://github.com/mastra-ai/mastra/commit/8bd16da73a4cb874d739373643dbd6a6e7f88684), [`c8630f8`](https://github.com/mastra-ai/mastra/commit/c8630f80d4f40cb5d22e60ab162b618b1907167a), [`47f71dc`](https://github.com/mastra-ai/mastra/commit/47f71dc6fbcbd12d71e21a979e676e20a02bd77d), [`50ceae2`](https://github.com/mastra-ai/mastra/commit/50ceae270878e2f8fb2b2c6c2faab09df0007c8a), [`8cdde58`](https://github.com/mastra-ai/mastra/commit/8cdde5875bbba6702d9df226f2b20232b8d75d6c), [`847ff1e`](https://github.com/mastra-ai/mastra/commit/847ff1e0d94368d94b2e173e4e0908e115568ef3), [`259d409`](https://github.com/mastra-ai/mastra/commit/259d409a514174299dbde1ff5e1121209b3ba850), [`9e16c68`](https://github.com/mastra-ai/mastra/commit/9e16c6818b6485ccb43df28aba6f3a2219d28662), [`cefca33`](https://github.com/mastra-ai/mastra/commit/cefca33ae666e69810c935fedf95a929c173d1d7), [`d00e8c5`](https://github.com/mastra-ai/mastra/commit/d00e8c50daebe5bce5bf2f48bde39c86fc3d2fe4), [`36fa7e2`](https://github.com/mastra-ai/mastra/commit/36fa7e24d14e58a1eb46147097b32f583e5b8775), [`87e9774`](https://github.com/mastra-ai/mastra/commit/87e97741c1e493cd6d62f478eb810b49bda4d57c), [`65a72e7`](https://github.com/mastra-ai/mastra/commit/65a72e70c25eedea8ff985a6624b96be2850236b), [`0f77241`](https://github.com/mastra-ai/mastra/commit/0f7724108806703799a8ba80ad0f09414afd5066), [`92ff509`](https://github.com/mastra-ai/mastra/commit/92ff5098ef8a990438ca038077021a5f7541ec1d), [`3fce5e7`](https://github.com/mastra-ai/mastra/commit/3fce5e70d011d289043e75003ef3336ed4aa43c3), [`a763592`](https://github.com/mastra-ai/mastra/commit/a763592c3db46963ef1011cfe16fe372816e775e), [`80c7737`](https://github.com/mastra-ai/mastra/commit/80c7737e32d7917b5f356957d67c169d01744fd3), [`3f1cf47`](https://github.com/mastra-ai/mastra/commit/3f1cf476f74c1e4cc2df908837e05853a5347e31)]:
63
- - @mastra/core@1.38.0-alpha.3
64
-
65
- ## 0.2.0
66
-
67
- ### Minor Changes
68
-
69
- - Added `@mastra/brightdata` integration with `brightdata-search` and `brightdata-fetch` tools backed by Bright Data's SERP API and Web Unlocker. The tools bypass bot detection and CAPTCHAs out of the box. ([#16392](https://github.com/mastra-ai/mastra/pull/16392))
70
-
71
- ```typescript
72
- import { Agent } from '@mastra/core/agent';
73
- import { createBrightDataTools } from '@mastra/brightdata';
74
-
75
- const agent = new Agent({
76
- id: 'research-agent',
77
- name: 'Research Agent',
78
- model: 'anthropic/claude-sonnet-4-6',
79
- instructions: 'Use brightdata-search to find pages and brightdata-fetch to read them.',
80
- tools: createBrightDataTools(),
81
- });
82
- ```
83
-
84
- Set `BRIGHTDATA_API_TOKEN` in your environment, or pass `{ apiKey }` explicitly.
85
-
86
- ### Patch Changes
87
-
88
- - Updated dependencies [[`9f17410`](https://github.com/mastra-ai/mastra/commit/9f1741080def23d42ee50b39887a385ae316a3c6), [`7ad5585`](https://github.com/mastra-ai/mastra/commit/7ad55856406f1de398dc713f6a9eaa78b2784bb6), [`ac47842`](https://github.com/mastra-ai/mastra/commit/ac478427aa7a5f5fdaed633a911218689b438c60), [`cc189cc`](https://github.com/mastra-ai/mastra/commit/cc189cc0128eb7af233476b5e421ec6888bffde7), [`d1fdbd0`](https://github.com/mastra-ai/mastra/commit/d1fdbd012add5623cb7e6b7f882b605ab358bbb4), [`210ea7a`](https://github.com/mastra-ai/mastra/commit/210ea7af559791b73a44fc9c12179908aaa3183f), [`7c275a8`](https://github.com/mastra-ai/mastra/commit/7c275a810595e1a6c41ccc39720531ab65734700), [`bae019e`](https://github.com/mastra-ai/mastra/commit/bae019ecb6694da96909f7ec7b9eb3a0a33aa887), [`890b24c`](https://github.com/mastra-ai/mastra/commit/890b24cc7d32ed6aa4dfe253e54dc6bf4099f690), [`f984b4d`](https://github.com/mastra-ai/mastra/commit/f984b4d6c60bf2ae2a9b156f0e8c35a66fe96c91), [`6742347`](https://github.com/mastra-ai/mastra/commit/6742347d71955d7639adc9ddf6ff8282de7ee3ba), [`b59316f`](https://github.com/mastra-ai/mastra/commit/b59316ffa0f7688165b0f9c81ccdf85da461e5b2), [`0f48ebf`](https://github.com/mastra-ai/mastra/commit/0f48ebfc7ac7897b2092a189f45751924cf56d1c), [`37c0dc5`](https://github.com/mastra-ai/mastra/commit/37c0dc5697d343db98628bf867bf71ce6deec6d7), [`087e413`](https://github.com/mastra-ai/mastra/commit/087e4133e5d6efa36619e9556c16750e4179c047), [`83218c8`](https://github.com/mastra-ai/mastra/commit/83218c88b37773c9424fbe733b37be556e55e94d), [`ef6b584`](https://github.com/mastra-ai/mastra/commit/ef6b5847ac33c0a7e80af3a86e8801e2933dd3ee), [`c6eb39e`](https://github.com/mastra-ai/mastra/commit/c6eb39ea6dca381c6563cb240237fbe608e02f93), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`d91ebe2`](https://github.com/mastra-ai/mastra/commit/d91ebe28ee065d8f2ed6df741c3c07f58d359529), [`62666c3`](https://github.com/mastra-ai/mastra/commit/62666c367eaeac3941ead454b1d38810cc855721), [`33f5061`](https://github.com/mastra-ai/mastra/commit/33f5061cd1c0335020c3faae61ce96de822854fa), [`4af2160`](https://github.com/mastra-ai/mastra/commit/4af2160322f4718cac421930cce85641e9512389), [`087e413`](https://github.com/mastra-ai/mastra/commit/087e4133e5d6efa36619e9556c16750e4179c047), [`265ec9f`](https://github.com/mastra-ai/mastra/commit/265ec9f887b5c81255c873a76ff7796f16e4f99b), [`ce01024`](https://github.com/mastra-ai/mastra/commit/ce010242eee9bdfc09e4c26725b9d37998679a8d), [`6ce80bf`](https://github.com/mastra-ai/mastra/commit/6ce80bf4872a891e0bddf8b80561a80584efb14b), [`f984b4d`](https://github.com/mastra-ai/mastra/commit/f984b4d6c60bf2ae2a9b156f0e8c35a66fe96c91), [`136c959`](https://github.com/mastra-ai/mastra/commit/136c9592fb0eeb0cd212f28629d8a29b7557a2fc), [`9268531`](https://github.com/mastra-ai/mastra/commit/9268531e7ec4be98beeba3b3ae8be0a7ea380662), [`13ead79`](https://github.com/mastra-ai/mastra/commit/13ead79149486b88144db7e11e6ff551caef5be1), [`dccd8f1`](https://github.com/mastra-ai/mastra/commit/dccd8f1f8b8f1ad203b77556207e5529567c616d), [`4df7cc7`](https://github.com/mastra-ai/mastra/commit/4df7cc79342fd065fe7fdeef93c094db14b12bcd), [`f180e49`](https://github.com/mastra-ai/mastra/commit/f180e4990e71b04c9a475b523584071712f0048f), [`9260e01`](https://github.com/mastra-ai/mastra/commit/9260e015276fb1b500f7878ee452b47476bf1583), [`2f6c54e`](https://github.com/mastra-ai/mastra/commit/2f6c54e17c041cac1def54baaa6b771647836414), [`aca3121`](https://github.com/mastra-ai/mastra/commit/aca31211233dac25459f140ea4fcfb3a5af64c18), [`e06a159`](https://github.com/mastra-ai/mastra/commit/e06a1598ca07a6c3778aefc2a2d288363c6294ff), [`4dd900d`](https://github.com/mastra-ai/mastra/commit/4dd900d75dfe9be89f8c15188b368a8622aa1e18), [`b560d6f`](https://github.com/mastra-ai/mastra/commit/b560d6f88b9b904b15c10f75c949eb145bc27684), [`99869ec`](https://github.com/mastra-ai/mastra/commit/99869ecb1f2aa6dfcc44fa4e843e5ee0344efa64), [`900d086`](https://github.com/mastra-ai/mastra/commit/900d086bb737b9cf2fcf68f11b0389b801a2738c), [`4c0e286`](https://github.com/mastra-ai/mastra/commit/4c0e28637c9cfb4f416549b55e97ebfa13319dfc), [`55f1e2d`](https://github.com/mastra-ai/mastra/commit/55f1e2d65425b95a49ae788053b266f256e38c96), [`4ff5bdf`](https://github.com/mastra-ai/mastra/commit/4ff5bdfe170cba6dfb5260c6af0f4ba668430772), [`9cdf38e`](https://github.com/mastra-ai/mastra/commit/9cdf38e58506e1109c8b38f97cd7770978a4218e), [`087e413`](https://github.com/mastra-ai/mastra/commit/087e4133e5d6efa36619e9556c16750e4179c047), [`db34bc6`](https://github.com/mastra-ai/mastra/commit/db34bc6fb36cf125bda0c46be4d3fdc774b70cc4), [`990851e`](https://github.com/mastra-ai/mastra/commit/990851edcb0e30be5c2c18b6532f1a876cc2d335), [`bbcd93c`](https://github.com/mastra-ai/mastra/commit/bbcd93cf7d8aa1007d6d84bfd033b8015c912087), [`8373ff4`](https://github.com/mastra-ai/mastra/commit/8373ff46745d77af79f183c4470f80fa2727a6b2), [`d48a705`](https://github.com/mastra-ai/mastra/commit/d48a705ff3dfbdc7a996e07ecd8293b5effd9a2a), [`308bd07`](https://github.com/mastra-ai/mastra/commit/308bd074f35cef0c75d82fc1eb19382fe04ecf6f), [`6068a6c`](https://github.com/mastra-ai/mastra/commit/6068a6c42950fad3ebfc92346417896ba60803d2), [`36b3bbf`](https://github.com/mastra-ai/mastra/commit/36b3bbf5a8d59f7e23d47e29340e76c681b4929c), [`d86f031`](https://github.com/mastra-ai/mastra/commit/d86f031eb6b0b2570145afafea664e59bf688962), [`b275631`](https://github.com/mastra-ai/mastra/commit/b275631dc10541a482b2e2d4a3e3cfa843bd5fa1), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`bd36d8e`](https://github.com/mastra-ai/mastra/commit/bd36d8eb6de8c9a0310352649dbd4b06703c2299), [`11c1528`](https://github.com/mastra-ai/mastra/commit/11c152848c5d0ef227184853b5040f5b41ee7b1e), [`4999667`](https://github.com/mastra-ai/mastra/commit/49996678b68356cad7f088430009690406c50fbd), [`e2a079c`](https://github.com/mastra-ai/mastra/commit/e2a079cc3755b1895f7bd5dc36e9be81b11c7c22), [`8ac9141`](https://github.com/mastra-ai/mastra/commit/8ac9141439caa8fdd674944c4d84f29b3c730296), [`25184ff`](https://github.com/mastra-ai/mastra/commit/25184ffaf1293ec95119426eb1a1f8d38831b96c), [`534a456`](https://github.com/mastra-ai/mastra/commit/534a456a25e4df1e5407e7e632f4cb3b1fa14f9d), [`105e454`](https://github.com/mastra-ai/mastra/commit/105e454c95af06a7c741c15969d8f9b0f02463a7), [`aebde9c`](https://github.com/mastra-ai/mastra/commit/aebde9cfacf56592c6b6350cae721740fe090b8a), [`36bae07`](https://github.com/mastra-ai/mastra/commit/36bae07c0e70b1b3006f2fd20830e8883dcbd066), [`5688881`](https://github.com/mastra-ai/mastra/commit/5688881669c7ed157f31ac77f6fc5f8d95ceea32)]:
89
- - @mastra/core@1.33.0
90
-
91
- ## 0.2.0-alpha.0
92
-
93
- ### Minor Changes
94
-
95
- - Added `@mastra/brightdata` integration with `brightdata-search` and `brightdata-fetch` tools backed by Bright Data's SERP API and Web Unlocker. The tools bypass bot detection and CAPTCHAs out of the box. ([#16392](https://github.com/mastra-ai/mastra/pull/16392))
96
-
97
- ```typescript
98
- import { Agent } from '@mastra/core/agent';
99
- import { createBrightDataTools } from '@mastra/brightdata';
100
-
101
- const agent = new Agent({
102
- id: 'research-agent',
103
- name: 'Research Agent',
104
- model: 'anthropic/claude-sonnet-4-6',
105
- instructions: 'Use brightdata-search to find pages and brightdata-fetch to read them.',
106
- tools: createBrightDataTools(),
107
- });
108
- ```
109
-
110
- Set `BRIGHTDATA_API_TOKEN` in your environment, or pass `{ apiKey }` explicitly.
111
-
112
- ### Patch Changes
113
-
114
- - Updated dependencies [[`b59316f`](https://github.com/mastra-ai/mastra/commit/b59316ffa0f7688165b0f9c81ccdf85da461e5b2), [`55f1e2d`](https://github.com/mastra-ai/mastra/commit/55f1e2d65425b95a49ae788053b266f256e38c96), [`d48a705`](https://github.com/mastra-ai/mastra/commit/d48a705ff3dfbdc7a996e07ecd8293b5effd9a2a)]:
115
- - @mastra/core@1.33.0-alpha.12