@diffbot/typescript 0.1.0 → 0.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 +142 -8
- package/dist/index.cjs +141 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -6
- package/dist/index.d.ts +111 -6
- package/dist/index.js +141 -45
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +93 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +27 -0
- package/dist/node/index.d.ts +27 -0
- package/dist/node/index.js +63 -0
- package/dist/node/index.js.map +1 -0
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -8,7 +8,9 @@ TypeScript client library for [Diffbot](https://www.diffbot.com) APIs. This is a
|
|
|
8
8
|
pnpm add @diffbot/typescript
|
|
9
9
|
```
|
|
10
10
|
|
|
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.
|
|
12
14
|
|
|
13
15
|
## Usage
|
|
14
16
|
|
|
@@ -19,18 +21,66 @@ Create a client once, then pass it to the API functions you need. Import only th
|
|
|
19
21
|
### Authentication
|
|
20
22
|
|
|
21
23
|
```typescript
|
|
22
|
-
import { DiffbotClient, extract,
|
|
24
|
+
import { DiffbotClient, extract, resolveTokenFromEnv } from "@diffbot/typescript";
|
|
23
25
|
|
|
24
|
-
const db = new DiffbotClient({ token:
|
|
26
|
+
const db = new DiffbotClient({ token: resolveTokenFromEnv() });
|
|
25
27
|
const data = await extract(db, "https://www.example.com");
|
|
26
28
|
await db.close();
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
Token resolution order:
|
|
30
32
|
|
|
31
|
-
1. Explicit argument to `
|
|
32
|
-
2. `
|
|
33
|
-
3. `DIFFBOT_API_TOKEN
|
|
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
|
+
```
|
|
34
84
|
|
|
35
85
|
### Extract structured content
|
|
36
86
|
|
|
@@ -80,6 +130,30 @@ for (const r of results.search_results as Array<Record<string, unknown>>) {
|
|
|
80
130
|
}
|
|
81
131
|
```
|
|
82
132
|
|
|
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
|
+
|
|
83
157
|
### Entities (NLP)
|
|
84
158
|
|
|
85
159
|
```typescript
|
|
@@ -99,17 +173,66 @@ await using db = new DiffbotClient({ token: "YOUR_TOKEN" });
|
|
|
99
173
|
const data = await extract(db, "https://www.example.com");
|
|
100
174
|
```
|
|
101
175
|
|
|
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
|
+
|
|
102
225
|
## Python ↔ TypeScript API mapping
|
|
103
226
|
|
|
104
227
|
| Python | TypeScript |
|
|
105
228
|
|--------|------------|
|
|
106
|
-
| `resolve_token()` | `resolveToken()` |
|
|
229
|
+
| `resolve_token()` | `resolveTokenFromEnv()` (or `resolveToken()` from `@diffbot/typescript/node`) |
|
|
107
230
|
| `crawl_list_jobs()` | `crawlListJobs()` |
|
|
108
231
|
| `crawl_get_job()` | `crawlGetJob()` |
|
|
109
232
|
| `crawl_delete_job()` | `crawlDeleteJob()` |
|
|
110
233
|
| `dql_parallel()` | `dqlParallel()` |
|
|
111
234
|
| `dql_fetch_ontology()` | `dqlFetchOntology()` |
|
|
112
|
-
| `dql_refresh_ontology()` | `
|
|
235
|
+
| `dql_refresh_ontology()` | `new OntologyStore(db).load({ refresh: true })` (or `FileOntologyStore` from `@diffbot/typescript/node`) |
|
|
113
236
|
| `web_search()` | `webSearch()` |
|
|
114
237
|
|
|
115
238
|
## Development
|
|
@@ -126,6 +249,17 @@ Live integration tests (requires `DIFFBOT_API_TOKEN`):
|
|
|
126
249
|
pnpm test:live
|
|
127
250
|
```
|
|
128
251
|
|
|
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
|
+
|
|
129
263
|
## License
|
|
130
264
|
|
|
131
265
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,9 @@ __export(index_exports, {
|
|
|
26
26
|
DiffbotClient: () => DiffbotClient,
|
|
27
27
|
DiffbotError: () => DiffbotError,
|
|
28
28
|
ExtractionError: () => ExtractionError,
|
|
29
|
+
KVOntologyStore: () => KVOntologyStore,
|
|
29
30
|
Ontology: () => Ontology,
|
|
31
|
+
OntologyStore: () => OntologyStore,
|
|
30
32
|
RateLimitError: () => RateLimitError,
|
|
31
33
|
VERSION: () => VERSION,
|
|
32
34
|
ValidationError: () => ValidationError,
|
|
@@ -37,17 +39,17 @@ __export(index_exports, {
|
|
|
37
39
|
crawlListJobs: () => crawlListJobs,
|
|
38
40
|
dql: () => dql,
|
|
39
41
|
dqlFetchOntology: () => dqlFetchOntology,
|
|
42
|
+
dqlFetchOntologyText: () => dqlFetchOntologyText,
|
|
40
43
|
dqlParallel: () => dqlParallel,
|
|
41
|
-
dqlRefreshOntology: () => dqlRefreshOntology,
|
|
42
44
|
entities: () => entities,
|
|
43
45
|
extract: () => extract,
|
|
44
|
-
|
|
46
|
+
resolveTokenFromEnv: () => resolveTokenFromEnv,
|
|
45
47
|
webSearch: () => webSearch
|
|
46
48
|
});
|
|
47
49
|
module.exports = __toCommonJS(index_exports);
|
|
48
50
|
|
|
49
51
|
// src/constants.ts
|
|
50
|
-
var VERSION = "0.
|
|
52
|
+
var VERSION = "0.2.0";
|
|
51
53
|
var DEFAULT_TIMEOUT = 3e4;
|
|
52
54
|
var EXTRACT_BASE = "https://api.diffbot.com/v3";
|
|
53
55
|
var CRAWL_BASE = "https://api.diffbot.com/v3/crawl";
|
|
@@ -188,6 +190,8 @@ var DiffbotClient = class {
|
|
|
188
190
|
crawlerUrl;
|
|
189
191
|
webSearchUrl;
|
|
190
192
|
nlpUrl;
|
|
193
|
+
dqlUrl;
|
|
194
|
+
ontologyUrl;
|
|
191
195
|
http;
|
|
192
196
|
constructor(options) {
|
|
193
197
|
if (!options.token) {
|
|
@@ -199,6 +203,8 @@ var DiffbotClient = class {
|
|
|
199
203
|
this.crawlerUrl = options.crawlerUrl ?? CRAWL_BASE;
|
|
200
204
|
this.webSearchUrl = options.webSearchUrl ?? WEB_SEARCH_BASE;
|
|
201
205
|
this.nlpUrl = options.nlpUrl ?? NLP_BASE;
|
|
206
|
+
this.dqlUrl = options.dqlUrl ?? KG_DQL_ENDPOINT;
|
|
207
|
+
this.ontologyUrl = options.ontologyUrl ?? KG_ONTOLOGY_ENDPOINT;
|
|
202
208
|
this.http = new HttpClient(
|
|
203
209
|
options.fetch ?? fetch,
|
|
204
210
|
options.timeout ?? DEFAULT_TIMEOUT,
|
|
@@ -214,34 +220,20 @@ var DiffbotClient = class {
|
|
|
214
220
|
};
|
|
215
221
|
|
|
216
222
|
// src/auth.ts
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return "";
|
|
226
|
-
}
|
|
227
|
-
const text = (0, import_node_fs.readFileSync)(path, "utf8");
|
|
228
|
-
for (const line of text.split("\n")) {
|
|
229
|
-
const trimmed = line.trim();
|
|
230
|
-
if (trimmed.startsWith(`${TOKEN_ENV_VAR}=`)) {
|
|
231
|
-
return trimmed.slice(TOKEN_ENV_VAR.length + 1).trim();
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return "";
|
|
223
|
+
function envToken(env) {
|
|
224
|
+
const fromEnv = env?.[TOKEN_ENV_VAR];
|
|
225
|
+
if (typeof fromEnv === "string" && fromEnv.trim()) {
|
|
226
|
+
return fromEnv.trim();
|
|
227
|
+
}
|
|
228
|
+
const proc = globalThis.process;
|
|
229
|
+
const fromProcess = proc?.env?.[TOKEN_ENV_VAR];
|
|
230
|
+
return fromProcess?.trim() ?? "";
|
|
235
231
|
}
|
|
236
|
-
function
|
|
232
|
+
function resolveTokenFromEnv(token, env) {
|
|
237
233
|
if (token?.trim()) {
|
|
238
234
|
return token.trim();
|
|
239
235
|
}
|
|
240
|
-
|
|
241
|
-
if (envToken) {
|
|
242
|
-
return envToken;
|
|
243
|
-
}
|
|
244
|
-
return readCredentialsFile();
|
|
236
|
+
return envToken(env);
|
|
245
237
|
}
|
|
246
238
|
|
|
247
239
|
// src/extract.ts
|
|
@@ -470,12 +462,7 @@ async function crawlDeleteJob(client, jobName) {
|
|
|
470
462
|
raiseForStatus(response, body);
|
|
471
463
|
}
|
|
472
464
|
|
|
473
|
-
// src/kg.ts
|
|
474
|
-
var import_promises2 = require("fs/promises");
|
|
475
|
-
var import_node_path2 = require("path");
|
|
476
|
-
|
|
477
465
|
// src/ontology.ts
|
|
478
|
-
var import_promises = require("fs/promises");
|
|
479
466
|
var Ontology = class _Ontology {
|
|
480
467
|
data;
|
|
481
468
|
constructor(data) {
|
|
@@ -485,10 +472,6 @@ var Ontology = class _Ontology {
|
|
|
485
472
|
const text = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
|
|
486
473
|
return new _Ontology(JSON.parse(text));
|
|
487
474
|
}
|
|
488
|
-
static async fromPath(path) {
|
|
489
|
-
const text = await (0, import_promises.readFile)(path, "utf8");
|
|
490
|
-
return _Ontology.fromJson(text);
|
|
491
|
-
}
|
|
492
475
|
types() {
|
|
493
476
|
const types = this.data.types;
|
|
494
477
|
return Object.keys(types ?? {}).sort();
|
|
@@ -601,7 +584,7 @@ function buildDqlParams(client, query, options) {
|
|
|
601
584
|
}
|
|
602
585
|
async function dql(client, query, options = {}) {
|
|
603
586
|
const params = buildDqlParams(client, query, options);
|
|
604
|
-
const response = await client.http.get(
|
|
587
|
+
const response = await client.http.get(client.dqlUrl, { params });
|
|
605
588
|
const body = await readBodyText(response);
|
|
606
589
|
raiseForStatus(response, body);
|
|
607
590
|
if (options.raw) {
|
|
@@ -625,18 +608,14 @@ async function dqlParallel(client, queries, workers = 8) {
|
|
|
625
608
|
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
626
609
|
return results;
|
|
627
610
|
}
|
|
628
|
-
async function
|
|
629
|
-
const response = await client.http.get(
|
|
611
|
+
async function dqlFetchOntologyText(client) {
|
|
612
|
+
const response = await client.http.get(client.ontologyUrl);
|
|
630
613
|
const body = await readBodyText(response);
|
|
631
614
|
raiseForStatus(response, body);
|
|
632
|
-
|
|
633
|
-
await (0, import_promises2.writeFile)(dest, body);
|
|
615
|
+
return body;
|
|
634
616
|
}
|
|
635
617
|
async function dqlFetchOntology(client) {
|
|
636
|
-
|
|
637
|
-
const body = await readBodyText(response);
|
|
638
|
-
raiseForStatus(response, body);
|
|
639
|
-
return Ontology.fromJson(body);
|
|
618
|
+
return Ontology.fromJson(await dqlFetchOntologyText(client));
|
|
640
619
|
}
|
|
641
620
|
|
|
642
621
|
// src/nlp.ts
|
|
@@ -651,6 +630,123 @@ async function entities(client, text, lang = "auto") {
|
|
|
651
630
|
return Array.isArray(data) ? data[0] ?? {} : data;
|
|
652
631
|
}
|
|
653
632
|
|
|
633
|
+
// src/ontology-store.ts
|
|
634
|
+
var OntologyStore = class {
|
|
635
|
+
client;
|
|
636
|
+
ttlSeconds;
|
|
637
|
+
inFlight = null;
|
|
638
|
+
constructor(client, options = {}) {
|
|
639
|
+
this.client = client;
|
|
640
|
+
this.ttlSeconds = options.ttlSeconds ?? 86400;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Resolve the ontology, from cache when possible. Concurrent calls share
|
|
644
|
+
* one in-flight fetch rather than issuing duplicate requests; a rejected
|
|
645
|
+
* fetch clears the in-flight memo so the next call retries instead of
|
|
646
|
+
* replaying the same failure forever.
|
|
647
|
+
*/
|
|
648
|
+
load(options = {}) {
|
|
649
|
+
if (options.refresh) {
|
|
650
|
+
this.inFlight = null;
|
|
651
|
+
}
|
|
652
|
+
if (!this.inFlight) {
|
|
653
|
+
this.inFlight = this.resolve(options.refresh ?? false).catch((error) => {
|
|
654
|
+
this.inFlight = null;
|
|
655
|
+
throw error;
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return this.inFlight;
|
|
659
|
+
}
|
|
660
|
+
async resolve(refresh) {
|
|
661
|
+
if (!refresh) {
|
|
662
|
+
const cached = await this.read();
|
|
663
|
+
if (cached !== void 0) {
|
|
664
|
+
try {
|
|
665
|
+
return Ontology.fromJson(cached);
|
|
666
|
+
} catch {
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const text = await dqlFetchOntologyText(this.client);
|
|
671
|
+
await this.write(text);
|
|
672
|
+
return Ontology.fromJson(text);
|
|
673
|
+
}
|
|
674
|
+
/** Read the cached ontology text, or `undefined` on a miss. Memory-only by default. */
|
|
675
|
+
read() {
|
|
676
|
+
return Promise.resolve(void 0);
|
|
677
|
+
}
|
|
678
|
+
/** Persist ontology text after a fetch. No-op by default. */
|
|
679
|
+
write(_text) {
|
|
680
|
+
return Promise.resolve();
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
var KVOntologyStore = class extends OntologyStore {
|
|
684
|
+
kv;
|
|
685
|
+
key;
|
|
686
|
+
refreshedAtKey;
|
|
687
|
+
lockKey;
|
|
688
|
+
staleAfterSeconds;
|
|
689
|
+
lockTtlSeconds;
|
|
690
|
+
waitUntil;
|
|
691
|
+
constructor(client, kv, options = {}) {
|
|
692
|
+
super(client, options);
|
|
693
|
+
this.kv = kv;
|
|
694
|
+
this.key = options.key ?? "diffbot:ontology:v1";
|
|
695
|
+
this.refreshedAtKey = `${this.key}:refreshed_at`;
|
|
696
|
+
this.lockKey = `${this.key}:lock`;
|
|
697
|
+
this.staleAfterSeconds = options.staleAfterSeconds ?? 0;
|
|
698
|
+
this.lockTtlSeconds = options.lockTtlSeconds ?? 60;
|
|
699
|
+
this.waitUntil = options.waitUntil;
|
|
700
|
+
}
|
|
701
|
+
load(options = {}) {
|
|
702
|
+
if (!options.refresh && this.staleAfterSeconds > 0) {
|
|
703
|
+
return this.loadWithStaleWhileRevalidate();
|
|
704
|
+
}
|
|
705
|
+
return super.load(options);
|
|
706
|
+
}
|
|
707
|
+
async loadWithStaleWhileRevalidate() {
|
|
708
|
+
const [cached, refreshedAt] = await Promise.all([
|
|
709
|
+
this.kv.get(this.key),
|
|
710
|
+
this.kv.get(this.refreshedAtKey)
|
|
711
|
+
]);
|
|
712
|
+
if (cached === null) {
|
|
713
|
+
return super.load();
|
|
714
|
+
}
|
|
715
|
+
const age = refreshedAt ? (Date.now() - Number(refreshedAt)) / 1e3 : Infinity;
|
|
716
|
+
const isStale = age > this.staleAfterSeconds;
|
|
717
|
+
const ontology = Ontology.fromJson(cached);
|
|
718
|
+
if (isStale) {
|
|
719
|
+
const refresh = super.load({ refresh: true }).catch(() => {
|
|
720
|
+
});
|
|
721
|
+
if (this.waitUntil) {
|
|
722
|
+
this.waitUntil(refresh);
|
|
723
|
+
} else {
|
|
724
|
+
await refresh;
|
|
725
|
+
return super.load();
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return ontology;
|
|
729
|
+
}
|
|
730
|
+
async read() {
|
|
731
|
+
const cached = await this.kv.get(this.key);
|
|
732
|
+
return cached ?? void 0;
|
|
733
|
+
}
|
|
734
|
+
async write(text) {
|
|
735
|
+
if (await this.kv.get(this.lockKey)) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
await this.kv.put(this.lockKey, "1", { expirationTtl: this.lockTtlSeconds });
|
|
739
|
+
try {
|
|
740
|
+
await this.kv.put(this.key, text, { expirationTtl: this.ttlSeconds });
|
|
741
|
+
await this.kv.put(this.refreshedAtKey, String(Date.now()), {
|
|
742
|
+
expirationTtl: this.ttlSeconds
|
|
743
|
+
});
|
|
744
|
+
} finally {
|
|
745
|
+
await this.kv.delete(this.lockKey);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
|
|
654
750
|
// src/web-search.ts
|
|
655
751
|
async function webSearch(client, text, options = {}) {
|
|
656
752
|
const headers = { Authorization: `Bearer ${client.token}` };
|
|
@@ -662,30 +758,4 @@ async function webSearch(client, text, options = {}) {
|
|
|
662
758
|
raiseForStatus(response, body);
|
|
663
759
|
return JSON.parse(body);
|
|
664
760
|
}
|
|
665
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
666
|
-
0 && (module.exports = {
|
|
667
|
-
APIError,
|
|
668
|
-
AuthError,
|
|
669
|
-
CrawlEventType,
|
|
670
|
-
DiffbotClient,
|
|
671
|
-
DiffbotError,
|
|
672
|
-
ExtractionError,
|
|
673
|
-
Ontology,
|
|
674
|
-
RateLimitError,
|
|
675
|
-
VERSION,
|
|
676
|
-
ValidationError,
|
|
677
|
-
ask,
|
|
678
|
-
crawl,
|
|
679
|
-
crawlDeleteJob,
|
|
680
|
-
crawlGetJob,
|
|
681
|
-
crawlListJobs,
|
|
682
|
-
dql,
|
|
683
|
-
dqlFetchOntology,
|
|
684
|
-
dqlParallel,
|
|
685
|
-
dqlRefreshOntology,
|
|
686
|
-
entities,
|
|
687
|
-
extract,
|
|
688
|
-
resolveToken,
|
|
689
|
-
webSearch
|
|
690
|
-
});
|
|
691
761
|
//# sourceMappingURL=index.cjs.map
|