@@ -5,10 +5,12 @@ TypeScript client library for [Diffbot](https://www.diffbot.com) APIs. This is a
55## Installation
66
77``` bash
8- pnpm add diffbot- typescript
8+ pnpm add @ diffbot/ typescript
99```
1010
11- Requires Node.js 18+ (native ` fetch ` ).
11+ Requires Node.js 18+ (native ` fetch ` ) to build and install. The main entry point itself
12+ runs anywhere ` fetch ` exists, including Cloudflare Workers with no compatibility flags —
13+ see [ Cloudflare Workers] ( #cloudflare-workers ) below.
1214
1315## Usage
1416
@@ -19,23 +21,71 @@ Create a client once, then pass it to the API functions you need. Import only th
1921### Authentication
2022
2123``` typescript
22- import { DiffbotClient , extract , resolveToken } from " diffbot- typescript" ;
24+ import { DiffbotClient , extract , resolveTokenFromEnv } from " @ diffbot/ typescript" ;
2325
24- const db = new DiffbotClient ({ token: resolveToken () });
26+ const db = new DiffbotClient ({ token: resolveTokenFromEnv () });
2527const data = await extract (db , " https://www.example.com" );
2628await db .close ();
2729```
2830
2931Token resolution order:
3032
31- 1 . Explicit argument to ` resolveToken(token) `
32- 2 . ` DIFFBOT_API_TOKEN ` environment variable
33- 3 . ` DIFFBOT_API_TOKEN=... ` line in ` ~/.diffbot/credentials `
33+ 1 . Explicit argument to ` resolveTokenFromEnv(token) `
34+ 2 . An ` env ` -style object passed as the second argument — the Workers convention: ` resolveTokenFromEnv(undefined, env) `
35+ 3 . ` DIFFBOT_API_TOKEN ` environment variable (` process.env ` )
36+
37+ Node users who want a ` ~/.diffbot/credentials ` file as a final fallback should import
38+ ` resolveToken ` from ` @diffbot/typescript/node ` instead — same first three steps, plus the
39+ file. See [ Runtime support] ( #runtime-support-node-vs-everywhere-else ) .
40+
41+ ### Client configuration
42+
43+ ` DiffbotClient ` is the single place to configure the SDK — every API function takes its
44+ settings from the client you hand it.
45+
46+ | Option | Default | Used by |
47+ | --------| ---------| ---------|
48+ | ` token ` | — (required) | all |
49+ | ` timeout ` | ` 30000 ` (ms) | all |
50+ | ` fetch ` | global ` fetch ` | all |
51+ | ` analyzeUrl ` | ` https://api.diffbot.com/v3 ` | ` extract ` |
52+ | ` crawlerUrl ` | ` https://api.diffbot.com/v3/crawl ` | ` crawl ` , ` crawlListJobs ` , ` crawlGetJob ` , ` crawlDeleteJob ` |
53+ | ` llmUrl ` | ` https://llm.diffbot.com/rag/v1/chat/completions ` | ` ask ` |
54+ | ` webSearchUrl ` | ` https://llm.diffbot.com/api/v1/web_search ` | ` webSearch ` |
55+ | ` nlpUrl ` | ` https://nl.diffbot.com/v1/ ` | ` entities ` |
56+ | ` dqlUrl ` | ` https://kg.diffbot.com/kg/v3/dql ` | ` dql ` , ` dqlParallel ` |
57+ | ` ontologyUrl ` | ` https://kg.diffbot.com/kg/ontology ` | ` dqlFetchOntology ` , ` dqlFetchOntologyText ` , ` OntologyStore ` |
58+
59+ ``` typescript
60+ import { DiffbotClient } from " @diffbot/typescript" ;
61+
62+ const db = new DiffbotClient ({
63+ token: " YOUR_TOKEN" ,
64+ timeout: 60_000 ,
65+ dqlUrl: " http://localhost:8080/kg/v3/dql" ,
66+ });
67+ ```
68+
69+ ` analyzeUrl ` and ` crawlerUrl ` are bases that the SDK appends to (` /${api} ` and ` /data `
70+ respectively); the rest are complete endpoints, used as given.
71+
72+ Passing ` fetch ` replaces the transport, which is the hook for retries, logging, extra
73+ headers, or mocking in tests:
74+
75+ ``` typescript
76+ const db = new DiffbotClient ({
77+ token: " YOUR_TOKEN" ,
78+ fetch : async (input , init ) => {
79+ console .log (" →" , input ); // the SDK always calls fetch with a URL string
80+ return fetch (input , init );
81+ },
82+ });
83+ ```
3484
3585### Extract structured content
3686
3787``` typescript
38- import { DiffbotClient , extract } from " diffbot- typescript" ;
88+ import { DiffbotClient , extract } from " @ diffbot/ typescript" ;
3989
4090const db = new DiffbotClient ({ token: " YOUR_TOKEN" });
4191const data = await extract (db , " https://www.example.com" );
@@ -44,7 +94,7 @@ const data = await extract(db, "https://www.example.com");
4494### Ask Diffbot LLM
4595
4696``` typescript
47- import { ask } from " diffbot- typescript" ;
97+ import { ask } from " @ diffbot/ typescript" ;
4898
4999for await (const chunk of ask (db , [{ role: " user" , content: " What's the capital of France?" }])) {
50100 process .stdout .write (chunk );
@@ -54,7 +104,7 @@ for await (const chunk of ask(db, [{ role: "user", content: "What's the capital
54104### Crawl a site
55105
56106``` typescript
57- import { crawl } from " diffbot- typescript" ;
107+ import { crawl } from " @ diffbot/ typescript" ;
58108
59109for await (const event of crawl (db , " https://www.example.com" , { hops: 1 })) {
60110 console .log (event );
@@ -64,26 +114,50 @@ for await (const event of crawl(db, "https://www.example.com", { hops: 1 })) {
64114### Query the Knowledge Graph
65115
66116``` typescript
67- import { dql } from " diffbot- typescript" ;
117+ import { dql } from " @ diffbot/ typescript" ;
68118
69119const results = await dql (db , ' type:Organization name:"Diffbot"' );
70120```
71121
72122### Web Search
73123
74124``` typescript
75- import { webSearch } from " diffbot- typescript" ;
125+ import { webSearch } from " @ diffbot/ typescript" ;
76126
77127const results = await webSearch (db , " diffbot knowledge graph" );
78128for (const r of results .search_results as Array <Record <string , unknown >>) {
79129 console .log (r .score , r .title , r .pageUrl );
80130}
81131```
82132
133+ ### Caching the Knowledge Graph ontology
134+
135+ ` dqlFetchOntology ` fetches on every call. For anything that calls it more than once,
136+ ` OntologyStore ` caches the parsed ` Ontology ` , dedupes concurrent fetches into one request,
137+ and clears its memo on a rejection so a failed fetch doesn't get stuck:
138+
139+ ``` typescript
140+ import { DiffbotClient , OntologyStore } from " @diffbot/typescript" ;
141+
142+ const db = new DiffbotClient ({ token: " YOUR_TOKEN" });
143+ const store = new OntologyStore (db );
144+
145+ const ontology = await store .load ();
146+ console .log (ontology .types ());
147+
148+ // Force a refetch, e.g. after `dqlRefreshOntology`'s old role:
149+ await store .load ({ refresh: true });
150+ ```
151+
152+ The base ` OntologyStore ` caches only in memory, for the life of the instance.
153+ ` KVOntologyStore ` (below) persists across instances via Cloudflare KV; Node users
154+ wanting a filesystem-backed cache should use ` FileOntologyStore ` from
155+ ` @diffbot/typescript/node ` — see [ Runtime support] ( #runtime-support-node-vs-everywhere-else ) .
156+
83157### Entities (NLP)
84158
85159``` typescript
86- import { entities } from " diffbot- typescript" ;
160+ import { entities } from " @ diffbot/ typescript" ;
87161
88162const result = await entities (db , " Apple CEO Tim Cook announced record quarterly earnings." );
89163```
@@ -93,23 +167,72 @@ const result = await entities(db, "Apple CEO Tim Cook announced record quarterly
93167` DiffbotClient ` supports explicit resource management for automatic cleanup:
94168
95169``` typescript
96- import { DiffbotClient , extract } from " diffbot- typescript" ;
170+ import { DiffbotClient , extract } from " @ diffbot/ typescript" ;
97171
98172await using db = new DiffbotClient ({ token: " YOUR_TOKEN" });
99173const data = await extract (db , " https://www.example.com" );
100174```
101175
176+ ## Runtime support: Node vs. everywhere else
177+
178+ The main entry point (` @diffbot/typescript ` ) imports no Node builtins and has no
179+ import-time side effects — it runs in Node, browsers, and edge runtimes including
180+ Cloudflare Workers, with ** no compatibility flags required** . It is enforced, not just
181+ tested: the build target is ` platform: "neutral" ` , so an accidental ` node:fs ` import
182+ anywhere in the main entry fails the build, and a post-build script scans the emitted
183+ bundle for node builtins as a second check.
184+
185+ Two things genuinely need a filesystem and live in a separate ` @diffbot/typescript/node `
186+ entry point instead:
187+
188+ ``` typescript
189+ import { resolveToken , FileOntologyStore } from " @diffbot/typescript/node" ;
190+
191+ const token = resolveToken (); // env, then ~/.diffbot/credentials
192+ const store = new FileOntologyStore (db , " /path/to/ontology.json" );
193+ ```
194+
195+ | | Main entry (` @diffbot/typescript ` ) | Node entry (` @diffbot/typescript/node ` ) |
196+ | ---| ---| ---|
197+ | Token resolution | ` resolveTokenFromEnv(token?, env?) ` — arg, ` env ` , ` process.env ` | ` resolveToken(token?, env?) ` — same, plus ` ~/.diffbot/credentials ` |
198+ | Ontology cache | ` OntologyStore ` (memory), ` KVOntologyStore ` (Cloudflare KV) | ` FileOntologyStore ` (filesystem) |
199+
200+ ## Cloudflare Workers
201+
202+ ``` typescript
203+ import { DiffbotClient , dql , resolveTokenFromEnv , KVOntologyStore } from " @diffbot/typescript" ;
204+
205+ export default {
206+ async fetch(request : Request , env : { DIFFBOT_API_TOKEN: string ; ONTOLOGY: KVNamespace }) {
207+ const db = new DiffbotClient ({ token: resolveTokenFromEnv (undefined , env ) });
208+ const ontology = await new KVOntologyStore (db , env .ONTOLOGY ).load ();
209+ const results = await dql (db , ' type:Organization name:"Diffbot"' );
210+ return Response .json ({ results , types: ontology .types () });
211+ },
212+ };
213+ ```
214+
215+ No ` compatibility_flags ` entry is needed for this package. Tokens come from ` env ` , not a
216+ credentials file — there is no filesystem in a Worker, so ` resolveToken ` (the Node-only,
217+ file-backed version) is not importable here; use ` resolveTokenFromEnv ` . For the ontology
218+ cache, pass a ` KVNamespace ` binding straight to ` KVOntologyStore ` — it satisfies the
219+ store's ` KVLike ` interface directly, with a lock against concurrent refresh stampedes and
220+ optional stale-while-revalidate via ` staleAfterSeconds ` + ` waitUntil ` .
221+
222+ ` fixtures/worker/ ` in this repo is a working Worker exercising exactly this path, verified
223+ in CI against workerd with ` compatibility_flags: [] ` .
224+
102225## Python ↔ TypeScript API mapping
103226
104227| Python | TypeScript |
105228| --------| ------------|
106- | ` resolve_token() ` | ` resolveToken() ` |
229+ | ` resolve_token() ` | ` resolveTokenFromEnv() ` (or ` resolveToken() ` from ` @diffbot/typescript/node ` ) |
107230| ` crawl_list_jobs() ` | ` crawlListJobs() ` |
108231| ` crawl_get_job() ` | ` crawlGetJob() ` |
109232| ` crawl_delete_job() ` | ` crawlDeleteJob() ` |
110233| ` dql_parallel() ` | ` dqlParallel() ` |
111234| ` dql_fetch_ontology() ` | ` dqlFetchOntology() ` |
112- | ` dql_refresh_ontology() ` | ` dqlRefreshOntology() ` |
235+ | ` dql_refresh_ontology() ` | ` new OntologyStore(db).load({ refresh: true }) ` (or ` FileOntologyStore ` from ` @diffbot/typescript/node ` ) |
113236| ` web_search() ` | ` webSearch() ` |
114237
115238## Development
@@ -126,6 +249,17 @@ Live integration tests (requires `DIFFBOT_API_TOKEN`):
126249pnpm test:live
127250```
128251
252+ Cloudflare Worker fixture (proves the main entry needs no compat flags — see
253+ ` fixtures/worker/ ` ):
254+
255+ ``` bash
256+ pnpm build # fixture resolves the package through dist/
257+ cd fixtures/worker
258+ pnpm install
259+ pnpm exec wrangler deploy --dry-run # bundle check, no Cloudflare credentials needed
260+ pnpm exec vitest run # runs in workerd via @cloudflare/vitest-pool-workers
261+ ```
262+
129263## License
130264
131265MIT
0 commit comments