@builtwith/sdk 1.1.0 → 1.2.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/README.md +2 -0
- package/package.json +1 -1
- package/src/index.js +91 -2
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@ if (result.ok) {
|
|
|
59
59
|
| `trust({ lookup })` | Root domain | Trust scoring |
|
|
60
60
|
| `financial({ lookup })` | Root domain | Financial data |
|
|
61
61
|
| `social({ lookup })` | Root domain | Social profile related domains |
|
|
62
|
+
| `vector_search({ query, limit? })` | Search query | Semantic technology/category search |
|
|
62
63
|
|
|
63
64
|
### Response Format
|
|
64
65
|
|
|
@@ -124,6 +125,7 @@ All methods accept a `CancellationToken` as an optional last parameter.
|
|
|
124
125
|
| `trust(lookup)` | `string` | Trust scoring |
|
|
125
126
|
| `financial(lookup)` | `string` | Financial data |
|
|
126
127
|
| `social(lookup)` | `string` | Social profile related domains |
|
|
128
|
+
| `vector_search(query, limit?)` | `string`, `int?` | Semantic technology/category search |
|
|
127
129
|
|
|
128
130
|
### Response Format
|
|
129
131
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const https = require('https');
|
|
4
|
+
const http = require('http');
|
|
4
5
|
const { URL } = require('url');
|
|
5
6
|
|
|
6
7
|
// ── Constants ──────────────────────────────────────────────────────────────────
|
|
7
8
|
|
|
8
9
|
const MCP_ENDPOINT = 'https://api.builtwith.com/mcp';
|
|
10
|
+
const PAYMENTS_ENDPOINT = 'https://payments.builtwith.com';
|
|
9
11
|
const MAX_RETRIES = 3;
|
|
10
12
|
const INITIAL_BACKOFF_MS = 1000;
|
|
11
13
|
const DOMAIN_RE = /^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)(\.[a-zA-Z]{2,})+$/;
|
|
@@ -100,10 +102,11 @@ function _parse_sse_body(raw_body) {
|
|
|
100
102
|
function _http_post(url_str, body, headers, timeout_ms) {
|
|
101
103
|
return new Promise((resolve, reject) => {
|
|
102
104
|
const parsed = new URL(url_str);
|
|
105
|
+
const transport = parsed.protocol === 'http:' ? http : https;
|
|
103
106
|
const payload = JSON.stringify(body);
|
|
104
107
|
const opts = {
|
|
105
108
|
hostname: parsed.hostname,
|
|
106
|
-
port: parsed.port || 443,
|
|
109
|
+
port: parsed.port || (parsed.protocol === 'http:' ? 80 : 443),
|
|
107
110
|
path: parsed.pathname + parsed.search,
|
|
108
111
|
method: 'POST',
|
|
109
112
|
headers: {
|
|
@@ -115,7 +118,7 @@ function _http_post(url_str, body, headers, timeout_ms) {
|
|
|
115
118
|
timeout: timeout_ms,
|
|
116
119
|
};
|
|
117
120
|
|
|
118
|
-
const req =
|
|
121
|
+
const req = transport.request(opts, (res) => {
|
|
119
122
|
const chunks = [];
|
|
120
123
|
res.on('data', chunk => chunks.push(chunk));
|
|
121
124
|
res.on('end', () => {
|
|
@@ -131,6 +134,37 @@ function _http_post(url_str, body, headers, timeout_ms) {
|
|
|
131
134
|
});
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
function _http_get(url_str, headers, timeout_ms) {
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const parsed = new URL(url_str);
|
|
140
|
+
const transport = parsed.protocol === 'http:' ? http : https;
|
|
141
|
+
const opts = {
|
|
142
|
+
hostname: parsed.hostname,
|
|
143
|
+
port: parsed.port || (parsed.protocol === 'http:' ? 80 : 443),
|
|
144
|
+
path: parsed.pathname + parsed.search,
|
|
145
|
+
method: 'GET',
|
|
146
|
+
headers: {
|
|
147
|
+
...headers,
|
|
148
|
+
'Accept': 'application/json',
|
|
149
|
+
},
|
|
150
|
+
timeout: timeout_ms,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const req = transport.request(opts, (res) => {
|
|
154
|
+
const chunks = [];
|
|
155
|
+
res.on('data', chunk => chunks.push(chunk));
|
|
156
|
+
res.on('end', () => {
|
|
157
|
+
const raw_body = Buffer.concat(chunks).toString('utf-8');
|
|
158
|
+
resolve({ status: res.statusCode, headers: res.headers, body: raw_body });
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
req.on('error', reject);
|
|
163
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timed out')); });
|
|
164
|
+
req.end();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
134
168
|
// ── Client ─────────────────────────────────────────────────────────────────────
|
|
135
169
|
|
|
136
170
|
class BuiltWithClient {
|
|
@@ -140,6 +174,7 @@ class BuiltWithClient {
|
|
|
140
174
|
}
|
|
141
175
|
this._api_key = api_key;
|
|
142
176
|
this._endpoint = options.endpoint || MCP_ENDPOINT;
|
|
177
|
+
this._payments_endpoint = options.payments_endpoint || PAYMENTS_ENDPOINT;
|
|
143
178
|
this._max_retries = options.max_retries != null ? options.max_retries : MAX_RETRIES;
|
|
144
179
|
this._timeout_ms = options.timeout_ms || 30000;
|
|
145
180
|
}
|
|
@@ -236,6 +271,38 @@ class BuiltWithClient {
|
|
|
236
271
|
return _err(last_error || new BuiltWithError('UNKNOWN_ERROR', 'Request failed', 0), mcp_tool);
|
|
237
272
|
}
|
|
238
273
|
|
|
274
|
+
// ── Payment API ────────────────────────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
async _payment_request(method, path, body = null) {
|
|
277
|
+
const url = this._payments_endpoint + path;
|
|
278
|
+
const headers = { Authorization: `Bearer ${this._api_key}` };
|
|
279
|
+
try {
|
|
280
|
+
const res = method === 'GET'
|
|
281
|
+
? await _http_get(url, headers, this._timeout_ms)
|
|
282
|
+
: await _http_post(url, body, headers, this._timeout_ms);
|
|
283
|
+
|
|
284
|
+
const status = res.status;
|
|
285
|
+
|
|
286
|
+
if (status === 400) return _err(new BuiltWithError('VALIDATION_ERROR', `HTTP 400: ${res.body.substring(0, 200)}`, status, null, 'Check request parameters.'), path);
|
|
287
|
+
if (status === 401 || status === 403) return _err(new BuiltWithError('AUTH_ERROR', 'Authentication failed. Check your API key.', status, null, 'Verify your BuiltWith API key is correct and active.'), path);
|
|
288
|
+
if (status === 402) return _err(new BuiltWithError('PAYMENT_FAILED', `HTTP 402: ${res.body.substring(0, 200)}`, status, null, 'Payment could not be processed. Check your billing details at payments.builtwith.com/agent-payment-api-config.'), path);
|
|
289
|
+
if (status === 405) return _err(new BuiltWithError('METHOD_NOT_ALLOWED', `HTTP 405: wrong HTTP method.`, status), path);
|
|
290
|
+
if (status >= 500) return _err(new BuiltWithError('SERVER_ERROR', `HTTP ${status}: ${res.body.substring(0, 200)}`, status, null, 'The server encountered an error. Try again later.'), path);
|
|
291
|
+
if (status < 200 || status >= 300) return _err(new BuiltWithError('HTTP_ERROR', `HTTP ${status}: ${res.body.substring(0, 200)}`, status), path);
|
|
292
|
+
|
|
293
|
+
let parsed;
|
|
294
|
+
try {
|
|
295
|
+
parsed = JSON.parse(res.body);
|
|
296
|
+
} catch (_) {
|
|
297
|
+
return _err(new BuiltWithError('PARSE_ERROR', 'Failed to parse response JSON.', status), path);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return _ok(parsed, parsed, path);
|
|
301
|
+
} catch (err) {
|
|
302
|
+
return _err(new BuiltWithError('NETWORK_ERROR', err.message, 0, null, 'Check network connectivity.'), path);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
239
306
|
// ── Public SDK methods ─────────────────────────────────────────────────────
|
|
240
307
|
|
|
241
308
|
async domain_lookup_live(params) {
|
|
@@ -328,6 +395,28 @@ class BuiltWithClient {
|
|
|
328
395
|
return this._request('vector-search', { query, ...(limit != null ? { limit } : {}) });
|
|
329
396
|
}
|
|
330
397
|
|
|
398
|
+
async payment_discovery() {
|
|
399
|
+
return this._payment_request('GET', '/v1/billing/api-discovery');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async payment_configuration() {
|
|
403
|
+
return this._payment_request('GET', '/v1/billing/api-configuration');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async payment_purchase(params) {
|
|
407
|
+
const { credits } = params || {};
|
|
408
|
+
if (credits === undefined || credits === null) {
|
|
409
|
+
throw new BuiltWithError('VALIDATION_ERROR', 'credits is required.', 0, null, 'Provide a credits value (minimum 2000).');
|
|
410
|
+
}
|
|
411
|
+
if (typeof credits !== 'number' || !Number.isInteger(credits)) {
|
|
412
|
+
throw new BuiltWithError('VALIDATION_ERROR', 'credits must be an integer.', 0, null, 'Provide a whole number of credits.');
|
|
413
|
+
}
|
|
414
|
+
if (credits < 2000) {
|
|
415
|
+
throw new BuiltWithError('VALIDATION_ERROR', 'credits must be at least 2000.', 0, null, 'Minimum purchase is 2000 credits.');
|
|
416
|
+
}
|
|
417
|
+
return this._payment_request('POST', '/v1/billing/api-purchase', { credits });
|
|
418
|
+
}
|
|
419
|
+
|
|
331
420
|
// ── Prompt helpers ─────────────────────────────────────────────────────────
|
|
332
421
|
|
|
333
422
|
prompt_analyze_tech_stack(params) {
|