@crawlbrulee/sdk 0.4.0 โ 0.7.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 +158 -59
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -29
- package/dist/index.d.ts +41 -29
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ๐ฎ crawlbrulee js/ts sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@crawlbrulee/sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@crawlbrulee/sdk)
|
|
5
|
+
[](./LICENSE)
|
|
4
6
|
|
|
5
|
-
-
|
|
7
|
+
the official js/ts sdk for the [crawlbrulee](https://crawlbrulee.com) web-scraping api โ published to npm as [`@crawlbrulee/sdk`](https://www.npmjs.com/package/@crawlbrulee/sdk). you
|
|
8
|
+
send a url, you get back markdown, cleaned html, links, images, metadata, or a screenshot.
|
|
9
|
+
|
|
10
|
+
- fully typed.
|
|
6
11
|
- ESM + CommonJS, ships its own `.d.ts`.
|
|
7
|
-
-
|
|
8
|
-
-
|
|
12
|
+
- zero runtime dependencies โ just `fetch`.
|
|
13
|
+
- works on Node.js 22+, modern Deno, Bun, and runtimes where `fetch` is available.
|
|
14
|
+
|
|
15
|
+
this readme covers the sdk itself โ the client, the types, and the js-side ergonomics. for how
|
|
16
|
+
the api behaves โ endpoints, parameters, and error semantics โ please see our
|
|
17
|
+
[api docs](https://crawlbrulee.com/docs).
|
|
18
|
+
|
|
19
|
+
> **status:** v0.7.0 (beta). the api surface is stabilizing โ expect minor breaking changes between 0.x releases.
|
|
9
20
|
|
|
10
|
-
|
|
21
|
+
**get a free api key** โ [dashboard.crawlbrulee.com](https://dashboard.crawlbrulee.com)
|
|
11
22
|
|
|
12
23
|
---
|
|
13
24
|
|
|
14
|
-
##
|
|
25
|
+
## install
|
|
15
26
|
|
|
16
27
|
```bash
|
|
17
28
|
pnpm add @crawlbrulee/sdk
|
|
@@ -21,12 +32,12 @@ npm install @crawlbrulee/sdk
|
|
|
21
32
|
yarn add @crawlbrulee/sdk
|
|
22
33
|
```
|
|
23
34
|
|
|
24
|
-
##
|
|
35
|
+
## quickstart
|
|
25
36
|
|
|
26
37
|
```ts
|
|
27
38
|
import { Crawlbrulee } from '@crawlbrulee/sdk'
|
|
28
39
|
|
|
29
|
-
const crawlbrulee = new Crawlbrulee({ apiKey: '
|
|
40
|
+
const crawlbrulee = new Crawlbrulee({ apiKey: 'cwbl_โฆ' })
|
|
30
41
|
// or read CRAWLBRULEE_API_KEY from the environment:
|
|
31
42
|
const crawlbrulee = Crawlbrulee.fromEnv()
|
|
32
43
|
|
|
@@ -41,22 +52,38 @@ console.log(page.metadata?.title) // structured <head> metadata
|
|
|
41
52
|
console.log(page.response_meta.usage.credits, 'credits charged') // usage accounting
|
|
42
53
|
```
|
|
43
54
|
|
|
44
|
-
###
|
|
55
|
+
### authentication
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
| ----------- | ---------------- | ------------------------------------------------------------------------------------------ |
|
|
48
|
-
| `apiKey` | โ | API key, sent as `Authorization: Bearer โฆ`. **Required** โ or use `Crawlbrulee.fromEnv()`. |
|
|
49
|
-
| `timeoutMs` | `0` (no timeout) | Per-request timeout (covers headers + body). A per-call `timeoutMs` overrides this. |
|
|
57
|
+
every request carries your api key as `Authorization: Bearer <key>`. give it to the sdk one of two ways:
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
```ts
|
|
60
|
+
// explicit โ pass the key directly
|
|
61
|
+
const crawlbrulee = new Crawlbrulee({ apiKey: 'cwbl_โฆ' })
|
|
62
|
+
|
|
63
|
+
// from the environment โ reads CRAWLBRULEE_API_KEY
|
|
64
|
+
const crawlbrulee = Crawlbrulee.fromEnv()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`Crawlbrulee.fromEnv(overrides?)` reads the key from `CRAWLBRULEE_API_KEY` and forwards any other option through
|
|
68
|
+
`overrides` (e.g. `Crawlbrulee.fromEnv({ timeoutMs: 30_000 })`). it throws if the variable is unset or empty. keys are
|
|
69
|
+
minted in the dashboard; see [authentication](https://crawlbrulee.com/docs/authentication) for how the api consumes them.
|
|
70
|
+
|
|
71
|
+
### configuration
|
|
72
|
+
|
|
73
|
+
| option | default | description |
|
|
74
|
+
| ----------- | ----------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `apiKey` | โ | api key, sent as `Authorization: Bearer โฆ`. **required** โ or use `Crawlbrulee.fromEnv()`. |
|
|
76
|
+
| `baseUrl` | `https://api.crawlbrulee.com` | override the target host (local dev / staging). trailing slashes are stripped. |
|
|
77
|
+
| `timeoutMs` | `0` (no timeout) | per-request timeout in milliseconds (covers headers + body). a per-call `timeoutMs` overrides this. |
|
|
52
78
|
|
|
53
79
|
---
|
|
54
80
|
|
|
55
|
-
##
|
|
81
|
+
## api reference
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
all methods return a `Promise` that resolves to the parsed json response, or rejects with a [`CrawlbruleeError`](#errors)
|
|
84
|
+
subclass.
|
|
58
85
|
|
|
59
|
-
|
|
86
|
+
every method accepts an optional second argument with per-call overrides:
|
|
60
87
|
|
|
61
88
|
```ts
|
|
62
89
|
crawlbrulee.scrape(request, {
|
|
@@ -65,11 +92,11 @@ crawlbrulee.scrape(request, {
|
|
|
65
92
|
})
|
|
66
93
|
```
|
|
67
94
|
|
|
68
|
-
###
|
|
95
|
+
### scraping
|
|
69
96
|
|
|
70
97
|
#### `crawlbrulee.scrape(request, options?)`
|
|
71
98
|
|
|
72
|
-
|
|
99
|
+
scrape a url synchronously. the request blocks until the server is done.
|
|
73
100
|
|
|
74
101
|
```ts
|
|
75
102
|
const page = await crawlbrulee.scrape({
|
|
@@ -93,37 +120,62 @@ const page = await crawlbrulee.scrape({
|
|
|
93
120
|
})
|
|
94
121
|
```
|
|
95
122
|
|
|
96
|
-
|
|
123
|
+
the response carries the extracted content alongside structured `metadata` (the parsed `<head>` tags โ `title`,
|
|
124
|
+
`description`, OG/Twitter fields, โฆ) and a `response_meta` envelope:
|
|
97
125
|
|
|
98
126
|
```ts
|
|
99
127
|
page.metadata?.title // structured <head> metadata (when extract.metadata, on by default)
|
|
100
128
|
|
|
101
129
|
page.response_meta.usage.credits // credits charged โ 0 on a cache hit
|
|
102
|
-
page.response_meta.usage.proxy // the resolved proxy tier actually used: '
|
|
130
|
+
page.response_meta.usage.proxy // the resolved proxy tier actually used: 'basic' | 'advanced' (never 'auto')
|
|
103
131
|
page.response_meta.usage.cache_hit // true when the result was served from cache
|
|
104
132
|
```
|
|
105
133
|
|
|
106
|
-
|
|
134
|
+
notes:
|
|
135
|
+
|
|
136
|
+
- **`proxy`**: defaults to `auto` when omitted โ it starts at the basic tier and escalates to advanced on failure,
|
|
137
|
+
billed at the delivered tier. pass `'basic'` or `'advanced'` to pin a tier. on the response,
|
|
138
|
+
`response_meta.usage.proxy` reports the tier we resolved and used โ never `'auto'`. see
|
|
139
|
+
[proxies & location](https://crawlbrulee.com/docs/proxies) for what each tier does.
|
|
140
|
+
- **`screenshot`**: custom `viewport.width`/`height` are integers in `[16, 10000]` and `device_scale_factor` is in
|
|
141
|
+
`[1, 4]`; out-of-range values are rejected with a `400`. full capture options:
|
|
142
|
+
[screenshots](https://crawlbrulee.com/docs/scrape/screenshots).
|
|
143
|
+
- **`extract.images`**: urls preserve their query string and resolve document-relative `src`s against the full page url
|
|
144
|
+
(browser parity) โ the same rules as `links`. every extract field is documented under
|
|
145
|
+
[extraction](https://crawlbrulee.com/docs/scrape/extraction).
|
|
146
|
+
- **`warnings`**: when we complete a scrape but something is worth flagging โ e.g. `screenshot_truncated` when a long
|
|
147
|
+
page exceeded the scrolling-screenshot height cap โ the codes land on `page.warnings`. they're stable, so you can switch
|
|
148
|
+
on them. fresh scrapes only; cache hits omit warnings.
|
|
149
|
+
- **`unsupported_fields`**: if you request an extract that doesn't apply to the content type (e.g. `markdown` of a pdf),
|
|
150
|
+
that field name comes back on `page.unsupported_fields` and the rest of your payload is still returned.
|
|
151
|
+
|
|
152
|
+
see [`ScrapeRequest`](src/types/scrape.ts) and [`ScrapeResponse`](src/types/scrape.ts) for every field, with inline
|
|
153
|
+
documentation โ and the [scrape endpoint](https://crawlbrulee.com/docs/scrape) reference for the api-side contract those
|
|
154
|
+
types mirror.
|
|
107
155
|
|
|
108
156
|
#### `crawlbrulee.scrapeAsync(request, options?)`
|
|
109
157
|
|
|
110
|
-
|
|
158
|
+
submit a scrape job in the background. returns immediately with a `job_id`.
|
|
111
159
|
|
|
112
160
|
```ts
|
|
113
161
|
const { job_id } = await crawlbrulee.scrapeAsync({ url: 'https://example.com' })
|
|
114
162
|
```
|
|
115
163
|
|
|
164
|
+
pass a `webhook` to be notified on completion instead of polling โ see [webhooks](#webhooks).
|
|
165
|
+
|
|
116
166
|
#### `crawlbrulee.getScrapeStatus(jobId, options?)`
|
|
117
167
|
|
|
118
|
-
|
|
168
|
+
look up the current state of an async job โ `pending`, `running`, `done`, or `failed`. the response carries `job_id` and
|
|
169
|
+
`created_at` (snake_case, straight off the wire). once the job is `done`, it also carries usage accounting on
|
|
170
|
+
`response_meta.usage` (`credits`, `proxy`, `cache_hit`).
|
|
119
171
|
|
|
120
172
|
#### `crawlbrulee.getScrapeResult(jobId, options?)`
|
|
121
173
|
|
|
122
|
-
|
|
174
|
+
fetch the result of a completed async job. throws if the job hasn't finished yet.
|
|
123
175
|
|
|
124
176
|
#### `crawlbrulee.waitForScrape(jobId, options?)`
|
|
125
177
|
|
|
126
|
-
|
|
178
|
+
poll an async job until it reaches a terminal state, then return the scrape result.
|
|
127
179
|
|
|
128
180
|
```ts
|
|
129
181
|
const { job_id } = await crawlbrulee.scrapeAsync({ url: 'https://example.com' })
|
|
@@ -134,13 +186,16 @@ const page = await crawlbrulee.waitForScrape(job_id, {
|
|
|
134
186
|
})
|
|
135
187
|
```
|
|
136
188
|
|
|
137
|
-
|
|
189
|
+
throws a `CrawlbruleeError` with `errorName: 'job_failed'` if the job ends in `failed`, or `errorName: 'request_timeout'`
|
|
190
|
+
if the wait expires. the job lifecycle itself โ states, retention, and when to prefer async over sync โ is documented
|
|
191
|
+
under [async scrape](https://crawlbrulee.com/docs/scrape/async).
|
|
138
192
|
|
|
139
|
-
###
|
|
193
|
+
### mapping
|
|
140
194
|
|
|
141
195
|
#### `crawlbrulee.map(request, options?)`
|
|
142
196
|
|
|
143
|
-
|
|
197
|
+
build (or return a cached) link map for a website. combines sitemap discovery with the freshest cached homepage scrape
|
|
198
|
+
when available.
|
|
144
199
|
|
|
145
200
|
```ts
|
|
146
201
|
const result = await crawlbrulee.map({
|
|
@@ -156,25 +211,41 @@ console.log(result.links.length, 'urls on page 1 of', result.response_meta.pagin
|
|
|
156
211
|
console.log(result.response_meta.usage.credits, 'credits charged') // usage accounting, alongside pagination + truncation
|
|
157
212
|
```
|
|
158
213
|
|
|
159
|
-
|
|
214
|
+
`result.response_meta` carries `usage` (credits / resolved `proxy` / `cache_hit`) alongside the map-specific `pagination`
|
|
215
|
+
and `truncation` blocks. see the [map endpoint](https://crawlbrulee.com/docs/map) for discovery rules and pagination
|
|
216
|
+
semantics.
|
|
217
|
+
|
|
218
|
+
### account
|
|
160
219
|
|
|
161
220
|
#### `crawlbrulee.usage(options?)`
|
|
162
221
|
|
|
163
|
-
|
|
222
|
+
return the current billing-cycle snapshot โ `total_credits`, `used_credits`, `available_credits`, `used_quota_percent`,
|
|
223
|
+
`max_concurrency`, and the `usage_reset` timestamp.
|
|
164
224
|
|
|
165
225
|
#### `crawlbrulee.whoami(options?)`
|
|
166
226
|
|
|
167
|
-
|
|
227
|
+
return the organization name and token identity behind the api key (`organization_name`, `token_name`, and a
|
|
228
|
+
safe-to-display `token_preview`). use it to confirm which key is in play before a destructive operation.
|
|
229
|
+
|
|
230
|
+
what a call costs, and how credits are counted, is documented under
|
|
231
|
+
[credits & pricing](https://crawlbrulee.com/docs/credits-and-pricing).
|
|
168
232
|
|
|
169
233
|
---
|
|
170
234
|
|
|
171
|
-
##
|
|
235
|
+
## webhooks
|
|
236
|
+
|
|
237
|
+
when an async scrape job finishes, crawlbrulee can `POST` a `scrape.complete` webhook to your configured endpoint. the
|
|
238
|
+
sdk ships two helpers for it.
|
|
172
239
|
|
|
173
|
-
|
|
240
|
+
the delivery contract and payload shape live under [webhooks](https://crawlbrulee.com/docs/scrape/webhooks); the
|
|
241
|
+
signature scheme is specified in [webhook verification](https://crawlbrulee.com/docs/webhook-verification). what follows
|
|
242
|
+
is how this sdk helps you consume them.
|
|
174
243
|
|
|
175
|
-
###
|
|
244
|
+
### triggering a webhook (`scrapeAsync`)
|
|
176
245
|
|
|
177
|
-
|
|
246
|
+
pass a `webhook` to `scrapeAsync` to have us deliver a single signed `scrape.complete` `POST` when the job reaches a
|
|
247
|
+
terminal state. this is **async-only** โ the synchronous `scrape()` response _is_ the notification, so it does not accept
|
|
248
|
+
a `webhook`.
|
|
178
249
|
|
|
179
250
|
```ts
|
|
180
251
|
const { job_id } = await crawlbrulee.scrapeAsync({
|
|
@@ -189,11 +260,16 @@ const { job_id } = await crawlbrulee.scrapeAsync({
|
|
|
189
260
|
})
|
|
190
261
|
```
|
|
191
262
|
|
|
192
|
-
|
|
263
|
+
configure the signing secret used for these deliveries in the dashboard (**account โ webhooks**). there is no per-request
|
|
264
|
+
secret - when the delivery arrives, verify it with [`verifyWebhookSignature`](#verifywebhooksignatureoptions) and read your `metadata` back from
|
|
265
|
+
`webhook.data.metadata`. the delivery also carries usage accounting on `webhook.data.response_meta.usage` (`credits`,
|
|
266
|
+
`proxy`, `cache_hit`). see [`AsyncScrapeWebhook`](src/types/scrape.ts) for the full field documentation.
|
|
193
267
|
|
|
194
268
|
### `verifyWebhookSignature(options)`
|
|
195
269
|
|
|
196
|
-
|
|
270
|
+
a standalone, network-free helper (built on Web Crypto, so it runs on Node.js 22+, browsers, Bun, Deno, and edge) that
|
|
271
|
+
verifies the `X-Cwbl-Signature` header. **it returns a result object rather than throwing** โ a failed verification is
|
|
272
|
+
normal control flow.
|
|
197
273
|
|
|
198
274
|
```ts
|
|
199
275
|
import { verifyWebhookSignature } from '@crawlbrulee/sdk'
|
|
@@ -212,11 +288,15 @@ if (result.verified) {
|
|
|
212
288
|
}
|
|
213
289
|
```
|
|
214
290
|
|
|
215
|
-
|
|
291
|
+
during a **signing-secret rotation grace window** we send a second `X-Cwbl-Signature-Rotated` header signed with the
|
|
292
|
+
previous secret. `verifyWebhookSignature` tries your `secret` against the primary header first, then the rotated one,
|
|
293
|
+
and reports which matched via `signedWith` โ so verification keeps working whether you still hold the old secret or have
|
|
294
|
+
already rotated to the new one.
|
|
216
295
|
|
|
217
296
|
### `crawlbrulee.fetchScrapeResultFromWebhook(webhook, options?)`
|
|
218
297
|
|
|
219
|
-
|
|
298
|
+
given a verified `scrape.complete` body, fetch the scrape result. returns `getScrapeResult(job_id)` for a `success` job;
|
|
299
|
+
throws a `CrawlbruleeError` for `failed` (carrying the failure message) or `cancelled` jobs.
|
|
220
300
|
|
|
221
301
|
```ts
|
|
222
302
|
import { Crawlbrulee, verifyWebhookSignature, type ScrapeCompleteWebhook } from '@crawlbrulee/sdk'
|
|
@@ -240,28 +320,30 @@ app.post('/webhooks/crawlbrulee', async (req, res) => {
|
|
|
240
320
|
})
|
|
241
321
|
```
|
|
242
322
|
|
|
243
|
-
|
|
323
|
+
always verify the signature **before** parsing or trusting the body. the `X-Cwbl-Event-Id` header (also
|
|
324
|
+
`webhook.event_id`) is a stable id you can use to de-duplicate deliveries.
|
|
244
325
|
|
|
245
326
|
---
|
|
246
327
|
|
|
247
|
-
##
|
|
328
|
+
## errors
|
|
248
329
|
|
|
249
|
-
|
|
330
|
+
every failure raised by the sdk extends [`CrawlbruleeError`](src/errors.ts). typed subclasses are exported for the most actionable
|
|
331
|
+
cases:
|
|
250
332
|
|
|
251
|
-
|
|
|
333
|
+
| class | when it's raised |
|
|
252
334
|
| ---------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
253
|
-
| `AuthenticationError` | 401 / 403 responses (missing, invalid, or unauthorized
|
|
254
|
-
| `RateLimitError` | 429 responses.
|
|
255
|
-
| `UsageAllocationError` |
|
|
335
|
+
| `AuthenticationError` | 401 / 403 responses (missing, invalid, or unauthorized api key). |
|
|
336
|
+
| `RateLimitError` | 429 responses. exposes `retryAfterMs` and `limitedBy` when the server provided them. |
|
|
337
|
+
| `UsageAllocationError` | the org's plan limit was hit. exposes `reason` (`credit_limit`, `concurrency_limit`, โฆ) and `usage`. |
|
|
256
338
|
| `ValidationError` | 4xx caused by a bad request (`invalid_url`, `url_too_long`, `blocked_url`, โฆ). |
|
|
257
339
|
| `NotFoundError` | 404 responses (e.g. unknown async `jobId`). |
|
|
258
|
-
| `TransportError` |
|
|
259
|
-
| `CrawlbruleeError` |
|
|
340
|
+
| `TransportError` | network failures, aborts, non-json responses, request body read failures. |
|
|
341
|
+
| `CrawlbruleeError` | base class โ used for any other api error. always has `status`, `errorName`, `message`. |
|
|
260
342
|
|
|
261
343
|
```ts
|
|
262
344
|
import { Crawlbrulee, RateLimitError, UsageAllocationError } from '@crawlbrulee/sdk'
|
|
263
345
|
|
|
264
|
-
const crawlbrulee = new Crawlbrulee({ apiKey: '
|
|
346
|
+
const crawlbrulee = new Crawlbrulee({ apiKey: 'cwbl_โฆ' })
|
|
265
347
|
try {
|
|
266
348
|
await crawlbrulee.scrape({ url: 'https://example.com' })
|
|
267
349
|
} catch (err) {
|
|
@@ -276,13 +358,13 @@ try {
|
|
|
276
358
|
}
|
|
277
359
|
```
|
|
278
360
|
|
|
279
|
-
|
|
361
|
+
for exhaustive branching, switch on `err.errorName` โ the literal-typed union is exported as `ApiErrorName`. the
|
|
362
|
+
`isCrawlbruleeError(err)` type guard narrows an `unknown` to the base error. the api docs carry the canonical
|
|
363
|
+
[error reference](https://crawlbrulee.com/docs/errors) โ every `errorName`, what causes it, and how to recover.
|
|
280
364
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
## Cancellation and timeouts
|
|
365
|
+
## cancellation and timeouts
|
|
284
366
|
|
|
285
|
-
|
|
367
|
+
every method accepts an `AbortSignal`:
|
|
286
368
|
|
|
287
369
|
```ts
|
|
288
370
|
const controller = new AbortController()
|
|
@@ -291,11 +373,12 @@ const page = crawlbrulee.scrape({ url: 'https://slow.example.com' }, { signal: c
|
|
|
291
373
|
setTimeout(() => controller.abort(), 5_000)
|
|
292
374
|
```
|
|
293
375
|
|
|
294
|
-
|
|
376
|
+
the per-call `timeoutMs` and the caller's signal are composed โ whichever fires first wins. a fired timeout surfaces as
|
|
377
|
+
a `TransportError` with `errorName: 'request_timeout'`; an aborted signal as `errorName: 'client_closed_request'`.
|
|
295
378
|
|
|
296
379
|
---
|
|
297
380
|
|
|
298
|
-
##
|
|
381
|
+
## development
|
|
299
382
|
|
|
300
383
|
```bash
|
|
301
384
|
pnpm install
|
|
@@ -305,4 +388,20 @@ pnpm lint # eslint
|
|
|
305
388
|
pnpm build # tsup โ dist/
|
|
306
389
|
```
|
|
307
390
|
|
|
308
|
-
|
|
391
|
+
the sdk has zero runtime dependencies on purpose. please keep it that way when contributing.
|
|
392
|
+
|
|
393
|
+
## part of the crawlbrulee toolkit
|
|
394
|
+
|
|
395
|
+
one api, many ways to call it:
|
|
396
|
+
|
|
397
|
+
- **[js/ts sdk](https://github.com/crawlbrulee/crawlbrulee-js)** โ `@crawlbrulee/sdk` (this one)
|
|
398
|
+
- **[python sdk](https://github.com/crawlbrulee/crawlbrulee-py)** โ `crawlbrulee` on pypi
|
|
399
|
+
- **[cli](https://github.com/crawlbrulee/crawlbrulee-cli)** โ `npx crawlbrulee`
|
|
400
|
+
- **[mcp server](https://github.com/crawlbrulee/crawlbrulee-mcp)** โ `@crawlbrulee/mcp`, for ai agents
|
|
401
|
+
- **[agent skills](https://github.com/crawlbrulee/crawlbrulee-skills)** โ for skills-aware coding agents
|
|
402
|
+
|
|
403
|
+
docs: [crawlbrulee.com/docs](https://crawlbrulee.com/docs) ยท dashboard: [dashboard.crawlbrulee.com](https://dashboard.crawlbrulee.com)
|
|
404
|
+
|
|
405
|
+
## license
|
|
406
|
+
|
|
407
|
+
[AGPL-3.0-only](./LICENSE)
|
package/dist/index.cjs
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/config.ts
|
|
4
4
|
var DEFAULT_BASE_URL = "https://api.crawlbrulee.com";
|
|
5
|
-
var DEFAULT_REQUEST_TIMEOUT_MS =
|
|
5
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 0;
|
|
6
6
|
var ENV_API_KEY = "CRAWLBRULEE_API_KEY";
|
|
7
|
-
var USER_AGENT = "@crawlbrulee/sdk/0.
|
|
7
|
+
var USER_AGENT = "@crawlbrulee/sdk/0.7.0 (node)";
|
|
8
8
|
|
|
9
9
|
// src/errors.ts
|
|
10
10
|
var CrawlbruleeError = class extends Error {
|
|
@@ -134,7 +134,7 @@ var CwblInstrumentation = {
|
|
|
134
134
|
const g = globalThis;
|
|
135
135
|
if (typeof g.fetch !== "function") {
|
|
136
136
|
throw new CrawlbruleeError(
|
|
137
|
-
"No global fetch is available in this runtime. crawlbrulee requires Node.js
|
|
137
|
+
"No global fetch is available in this runtime. crawlbrulee requires Node.js 22+, Bun, Deno, or a modern browser/edge runtime.",
|
|
138
138
|
{ status: 0, errorName: null }
|
|
139
139
|
);
|
|
140
140
|
}
|
|
@@ -159,7 +159,7 @@ var HttpClient = class {
|
|
|
159
159
|
this.baseUrl = stripTrailingSlash(options.baseUrl ?? CwblInstrumentation.getBaseUrl());
|
|
160
160
|
this.apiKey = options.apiKey;
|
|
161
161
|
this.fetch = CwblInstrumentation.getFetch();
|
|
162
|
-
this.timeoutMs = options.timeoutMs ??
|
|
162
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
163
163
|
}
|
|
164
164
|
/** Send a `GET` request and parse the response as `T`. */
|
|
165
165
|
get(path, options) {
|
|
@@ -679,7 +679,7 @@ function getSubtle() {
|
|
|
679
679
|
const subtle = globalThis.crypto?.subtle;
|
|
680
680
|
if (!subtle) {
|
|
681
681
|
throw new Error(
|
|
682
|
-
"Web Crypto (globalThis.crypto.subtle) is not available in this runtime. crawlbrulee webhook verification requires Node.js
|
|
682
|
+
"Web Crypto (globalThis.crypto.subtle) is not available in this runtime. crawlbrulee webhook verification requires Node.js 22+, Bun, Deno, or a modern browser/edge runtime."
|
|
683
683
|
);
|
|
684
684
|
}
|
|
685
685
|
return subtle;
|