@unfenced-ai/sdk 0.1.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 +30 -0
- package/README.md +171 -0
- package/dist/client.d.ts +385 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +349 -0
- package/dist/client.js.map +1 -0
- package/dist/credentials.d.ts +14 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +17 -0
- package/dist/credentials.js.map +1 -0
- package/dist/fetch.d.ts +16 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +387 -0
- package/dist/fetch.js.map +1 -0
- package/dist/http.d.ts +76 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +250 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/library.d.ts +17 -0
- package/dist/library.d.ts.map +1 -0
- package/dist/library.js +25 -0
- package/dist/library.js.map +1 -0
- package/dist/memory.d.ts +13 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +45 -0
- package/dist/memory.js.map +1 -0
- package/dist/permissions.d.ts +29 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +69 -0
- package/dist/permissions.js.map +1 -0
- package/dist/protocol.d.ts +296 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +89 -0
- package/dist/protocol.js.map +1 -0
- package/dist/session.d.ts +97 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +88 -0
- package/dist/session.js.map +1 -0
- package/dist/sessions.d.ts +131 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +197 -0
- package/dist/sessions.js.map +1 -0
- package/dist/token-usage.d.ts +11 -0
- package/dist/token-usage.d.ts.map +1 -0
- package/dist/token-usage.js +34 -0
- package/dist/token-usage.js.map +1 -0
- package/dist/types.d.ts +1409 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/url-identity.d.ts +8 -0
- package/dist/url-identity.d.ts.map +1 -0
- package/dist/url-identity.js +18 -0
- package/dist/url-identity.js.map +1 -0
- package/package.json +44 -0
package/dist/fetch.js
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fetch tier of the client: one URL, a batch, and a batch on a deadline.
|
|
3
|
+
*
|
|
4
|
+
* These are the bodies of `Unfenced.fetch`/`batch`/`batchWithin`, moved out
|
|
5
|
+
* verbatim and re-shaped from methods to functions that take a `Transport`.
|
|
6
|
+
* `this.request` became `http.request`, `this.awaitJob` and `this.fetch` became
|
|
7
|
+
* the module-local `awaitJob` and `fetch` below; nothing else changed. The error
|
|
8
|
+
* helpers (`errorCodeOf`, `targetRejection`, `toFetchFailure`) live here because
|
|
9
|
+
* fetch is their only caller. URL identity is shared with the worker.
|
|
10
|
+
*/
|
|
11
|
+
import { UnfencedError, parseErrorBody, validateDuration } from "./http.js";
|
|
12
|
+
import { urlIdentity } from "./url-identity.js";
|
|
13
|
+
/** A batch bounds work in flight, not just the size of its final answer. */
|
|
14
|
+
async function mapBatch(urls, options, run) {
|
|
15
|
+
// The production queue gives one tenant three waiting positions. Keep the
|
|
16
|
+
// default inside that share; callers with a larger deployment can opt up.
|
|
17
|
+
const concurrency = options.concurrency ?? 3;
|
|
18
|
+
if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 32) {
|
|
19
|
+
throw new RangeError("batch concurrency must be an integer from 1 to 32");
|
|
20
|
+
}
|
|
21
|
+
const results = new Array(urls.length);
|
|
22
|
+
let next = 0;
|
|
23
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, urls.length) }, async () => {
|
|
24
|
+
for (;;) {
|
|
25
|
+
const index = next++;
|
|
26
|
+
if (index >= urls.length)
|
|
27
|
+
return;
|
|
28
|
+
results[index] = await run(urls[index], index);
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
/** Keep a caller's base key unique per submitted URL, within the server bound. */
|
|
34
|
+
function batchIdempotencyKey(base, index) {
|
|
35
|
+
if (base === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
const suffix = `:${index}`;
|
|
38
|
+
return `${base.slice(0, Math.max(1, 128 - suffix.length))}${suffix}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A 400 rejection of the target itself, as a structured failure — or null when
|
|
42
|
+
* the error is about something else (auth, the service, the network).
|
|
43
|
+
*
|
|
44
|
+
* The server answers `{ "error": "blocked-target", "detail": "host did not
|
|
45
|
+
* resolve" }` with a 400; `request` surfaces that body as the thrown error's
|
|
46
|
+
* detail, so parse it back into the shape callers already handle.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* The server's own code for this failure, however the error carries it.
|
|
50
|
+
*
|
|
51
|
+
* `UnfencedError.code` is now filled at the throw site, from the body parsed
|
|
52
|
+
* before truncation. Both readers below used to re-parse `detail` as JSON
|
|
53
|
+
* instead — which worked only while `detail` WAS the raw body, and silently
|
|
54
|
+
* stopped the moment it became the parsed message. That is the whole regression
|
|
55
|
+
* this helper exists to prevent recurring: one place decides, and the fallback
|
|
56
|
+
* to re-parsing stays for an error constructed the old way.
|
|
57
|
+
*/
|
|
58
|
+
function errorCodeOf(error) {
|
|
59
|
+
if (error.code)
|
|
60
|
+
return { code: error.code, detail: error.detail };
|
|
61
|
+
const body = parseErrorBody(error.detail);
|
|
62
|
+
return {
|
|
63
|
+
...(body?.error ? { code: body.error } : {}),
|
|
64
|
+
...(body?.detail ? { detail: body.detail } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function targetRejection(error) {
|
|
68
|
+
if (!(error instanceof UnfencedError) || error.status !== 400)
|
|
69
|
+
return null;
|
|
70
|
+
const { code, detail } = errorCodeOf(error);
|
|
71
|
+
if (code) {
|
|
72
|
+
return {
|
|
73
|
+
outcome: "failed",
|
|
74
|
+
error: code,
|
|
75
|
+
...(detail ? { detail } : {}),
|
|
76
|
+
...(error.remedy ? { remedy: error.remedy } : {}),
|
|
77
|
+
...(error.retryAfterMs !== undefined ? { retryAfterMs: error.retryAfterMs } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { outcome: "failed", error: "bad-request", detail: error.detail || error.message };
|
|
81
|
+
}
|
|
82
|
+
/** Any thrown error as a structured failure — used to keep a batch intact. */
|
|
83
|
+
function toFetchFailure(error) {
|
|
84
|
+
const rejection = targetRejection(error);
|
|
85
|
+
if (rejection)
|
|
86
|
+
return rejection;
|
|
87
|
+
if (error instanceof UnfencedError) {
|
|
88
|
+
const { code, detail } = errorCodeOf(error);
|
|
89
|
+
return {
|
|
90
|
+
outcome: "failed",
|
|
91
|
+
error: code ?? `http-${error.status}`,
|
|
92
|
+
detail: detail ?? error.detail ?? error.message,
|
|
93
|
+
...(error.remedy ? { remedy: error.remedy } : {}),
|
|
94
|
+
...(error.retryAfterMs !== undefined ? { retryAfterMs: error.retryAfterMs } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
outcome: "failed",
|
|
99
|
+
error: "request-failed",
|
|
100
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Same page? Ignores a fragment that is only an anchor.
|
|
105
|
+
*
|
|
106
|
+
* The fragment used to be blanked unconditionally, on the stated ground that it
|
|
107
|
+
* "never varies content". That is true of `#section-3` and false of hash
|
|
108
|
+
* ROUTING, where the fragment IS the page: `https://app.example/#/orders` and
|
|
109
|
+
* `#/invoices` are two different screens of every dashboard and admin console
|
|
110
|
+
* built that way. A batch across several routes of one SPA returned the FIRST
|
|
111
|
+
* route's content under every other route's URL, marked `cached: true` and
|
|
112
|
+
* nothing else. A silent wrong answer, which the agent then reasons and acts on.
|
|
113
|
+
*
|
|
114
|
+
* A route is what a router would read: a fragment beginning `/`, `!` or `?`.
|
|
115
|
+
* An ordinary anchor still dedups, which is the case the collapse was for.
|
|
116
|
+
* A non-root trailing slash stays significant: HTTP servers may route
|
|
117
|
+
* `/resource` and `/resource/` to different representations.
|
|
118
|
+
*
|
|
119
|
+
* The worker cache and live-session reuse now import the same predicate from
|
|
120
|
+
* `url-identity.ts`, so a correction in one cannot leave the others behind.
|
|
121
|
+
*/
|
|
122
|
+
function sleep(ms) {
|
|
123
|
+
return new Promise((resolve) => {
|
|
124
|
+
const timer = setTimeout(resolve, ms);
|
|
125
|
+
// A poll that nobody is waiting on must not hold a process open. A batch
|
|
126
|
+
// abandons its stragglers, and an un-unref'd 500ms timer in each of them
|
|
127
|
+
// kept a script or a serverless invocation alive long after it had answered.
|
|
128
|
+
timer.unref?.();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/** A bounded opaque key for replaying a submission whose response was lost. */
|
|
132
|
+
function generatedIdempotencyKey() {
|
|
133
|
+
const uuid = globalThis.crypto?.randomUUID?.();
|
|
134
|
+
if (uuid)
|
|
135
|
+
return uuid;
|
|
136
|
+
return `unfenced-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Poll a job to its end, inside a deadline that bounds the wall clock.
|
|
140
|
+
*
|
|
141
|
+
* `deadline` is an absolute instant rather than a duration, and every request
|
|
142
|
+
* is handed what is LEFT of it. Before, the check ran only after a request came
|
|
143
|
+
* back, so a hung poll never reached it — the loop simply stopped, holding the
|
|
144
|
+
* caller for as long as the socket did.
|
|
145
|
+
*/
|
|
146
|
+
async function awaitJob(http, id, deadline) {
|
|
147
|
+
for (;;) {
|
|
148
|
+
const left = deadline - Date.now();
|
|
149
|
+
if (left <= 0) {
|
|
150
|
+
return { outcome: "failed", error: "timeout", detail: `job ${id} did not finish in time` };
|
|
151
|
+
}
|
|
152
|
+
let job;
|
|
153
|
+
try {
|
|
154
|
+
job = await http.request("GET", `/jobs/${id}`, undefined, left);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
// A deadline reached mid-poll is this call's own timeout, not a fault of
|
|
158
|
+
// the job, and it must read as one rather than as a transport error the
|
|
159
|
+
// caller has no branch for.
|
|
160
|
+
if (error instanceof UnfencedError && error.code === "timeout") {
|
|
161
|
+
// A poll can lose its response after the job was accepted. Re-reading
|
|
162
|
+
// the same immutable job id is safe, unlike replaying POST /jobs, and
|
|
163
|
+
// lets a brief socket reset recover without asking the caller to guess
|
|
164
|
+
// whether a fetch already ran. A request that consumed the deadline
|
|
165
|
+
// still falls through to the bounded timeout result below.
|
|
166
|
+
if (error.status === 0 && Date.now() < deadline) {
|
|
167
|
+
await sleep(Math.min(100, Math.max(0, deadline - Date.now())));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
return { outcome: "failed", error: "timeout", detail: `job ${id} did not finish in time` };
|
|
171
|
+
}
|
|
172
|
+
if (error instanceof UnfencedError &&
|
|
173
|
+
error.status === 0 &&
|
|
174
|
+
(error.code === "unreachable" || error.code === "timeout") &&
|
|
175
|
+
Date.now() < deadline) {
|
|
176
|
+
// The job id is the recovery key. Never repeat the creation request;
|
|
177
|
+
// only retry the read, and only while the caller's original deadline
|
|
178
|
+
// still has time left.
|
|
179
|
+
await sleep(Math.min(100, Math.max(0, deadline - Date.now())));
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
if (job.status === "archived" || job.archived === true) {
|
|
185
|
+
if (job.entry)
|
|
186
|
+
return { outcome: "archived", url: job.entry.url, entry: job.entry };
|
|
187
|
+
return { outcome: "failed", error: "no-result", detail: "archived job has no history entry" };
|
|
188
|
+
}
|
|
189
|
+
if (job.status === "done" || job.status === "error") {
|
|
190
|
+
if (job.result)
|
|
191
|
+
return job.result;
|
|
192
|
+
return { outcome: "failed", error: "no-result", detail: "job finished without a result" };
|
|
193
|
+
}
|
|
194
|
+
if (Date.now() >= deadline) {
|
|
195
|
+
return { outcome: "failed", error: "timeout", detail: `job ${id} did not finish in time` };
|
|
196
|
+
}
|
|
197
|
+
await sleep(Math.min(500, Math.max(0, deadline - Date.now())));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function fetch(http, url, options = {}, retryBusy = false, cancelOnTimeout = false) {
|
|
201
|
+
// One deadline for the whole call, taken before anything is sent, so the
|
|
202
|
+
// submit and every poll after it share the budget the caller asked for.
|
|
203
|
+
const timeoutMs = options.timeoutMs ?? 120_000;
|
|
204
|
+
validateDuration(timeoutMs, "timeoutMs");
|
|
205
|
+
if (timeoutMs === 0)
|
|
206
|
+
return {
|
|
207
|
+
outcome: "failed",
|
|
208
|
+
error: "timeout",
|
|
209
|
+
detail: "fetch budget expired before submission",
|
|
210
|
+
};
|
|
211
|
+
const deadline = Date.now() + timeoutMs;
|
|
212
|
+
let jobId;
|
|
213
|
+
const idempotencyKey = options.idempotencyKey ?? generatedIdempotencyKey();
|
|
214
|
+
const body = {
|
|
215
|
+
url,
|
|
216
|
+
expiresAt: deadline,
|
|
217
|
+
format: options.format ?? "markdown",
|
|
218
|
+
...(options.forceRender ? { forceRender: true } : {}),
|
|
219
|
+
...(options.force ? { force: true } : {}),
|
|
220
|
+
...(options.identify ? { identify: options.identify } : {}),
|
|
221
|
+
...(options.robots ? { robots: options.robots } : {}),
|
|
222
|
+
...(options.maxWords ? { maxWords: options.maxWords } : {}),
|
|
223
|
+
...(options.locale ? { locale: options.locale } : {}),
|
|
224
|
+
...(options.wholePageLinks ? { wholePageLinks: true } : {}),
|
|
225
|
+
...(options.proxy ? { proxy: options.proxy } : {}),
|
|
226
|
+
};
|
|
227
|
+
let submissionRetried = false;
|
|
228
|
+
try {
|
|
229
|
+
for (;;) {
|
|
230
|
+
try {
|
|
231
|
+
({ jobId } = await http.request("POST", "/jobs", body, deadline - Date.now(), { "idempotency-key": idempotencyKey }));
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (retryBusy &&
|
|
236
|
+
error instanceof UnfencedError &&
|
|
237
|
+
error.code === "server-busy" &&
|
|
238
|
+
Date.now() < deadline) {
|
|
239
|
+
const remaining = deadline - Date.now();
|
|
240
|
+
// The server's retry hint is a worst-case slot estimate (30 seconds
|
|
241
|
+
// at one slot), not a promise that the queue stays full that long.
|
|
242
|
+
// A batch with a shorter deadline must probe for a newly free slot;
|
|
243
|
+
// at most four probes per second keeps that retry bounded.
|
|
244
|
+
await sleep(Math.min(Math.max(25, error.retryAfterMs ?? 250), 250, remaining));
|
|
245
|
+
if (Date.now() < deadline)
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const canReplay = !submissionRetried &&
|
|
249
|
+
error instanceof UnfencedError &&
|
|
250
|
+
error.status === 0 &&
|
|
251
|
+
(error.code === "timeout" || error.code === "unreachable") &&
|
|
252
|
+
Date.now() < deadline;
|
|
253
|
+
if (!canReplay)
|
|
254
|
+
throw error;
|
|
255
|
+
submissionRetried = true;
|
|
256
|
+
await sleep(Math.min(25, Math.max(0, deadline - Date.now())));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
// The server rejects an unfetchable target (unresolvable host, private
|
|
262
|
+
// address, non-http scheme) with a 400 before any job exists. That is a
|
|
263
|
+
// fact about this URL, not an exceptional condition — so return it in the
|
|
264
|
+
// same structured shape as any other fetch failure rather than throwing.
|
|
265
|
+
// Auth, 5xx, and network problems still throw: they are about the client
|
|
266
|
+
// or the service, not the target.
|
|
267
|
+
const rejection = targetRejection(error);
|
|
268
|
+
if (rejection)
|
|
269
|
+
return rejection;
|
|
270
|
+
// A submit that never answered is this call's timeout, in the same shape as
|
|
271
|
+
// one that timed out waiting for the job.
|
|
272
|
+
if (error instanceof UnfencedError && error.code === "timeout") {
|
|
273
|
+
return {
|
|
274
|
+
outcome: "failed",
|
|
275
|
+
error: "timeout",
|
|
276
|
+
detail: `no complete submission response arrived inside ${options.timeoutMs ?? 120_000}ms; the job may have been accepted, so check its state before retrying`,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
const result = await awaitJob(http, jobId, deadline);
|
|
282
|
+
if (cancelOnTimeout && result.outcome === "failed" && result.error === "timeout") {
|
|
283
|
+
// The caller's answer is already fixed. Send a bounded cancellation without
|
|
284
|
+
// making the batch wait for a second network round trip past its deadline.
|
|
285
|
+
void http.request("DELETE", `/jobs/${jobId}`, undefined, 2_000).catch(() => { });
|
|
286
|
+
}
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
export async function batch(http, urls, options = {}) {
|
|
290
|
+
if (options.timeoutMs !== undefined)
|
|
291
|
+
validateDuration(options.timeoutMs, "timeoutMs");
|
|
292
|
+
// Fetch each distinct URL once. A repeated URL in a batch used to be
|
|
293
|
+
// fetched again from scratch — two full browser renders of the same page,
|
|
294
|
+
// seconds apart — and the caller is billed and made to wait for both.
|
|
295
|
+
// Every position still gets its entry, so the contract is unchanged.
|
|
296
|
+
const byUrl = new Map();
|
|
297
|
+
return mapBatch(urls, options, async (u, index) => {
|
|
298
|
+
const key = urlIdentity(u) ?? u;
|
|
299
|
+
const pending = byUrl.get(key);
|
|
300
|
+
if (pending) {
|
|
301
|
+
// Say so on the repeat. The server marks its own cache hits, but a
|
|
302
|
+
// duplicate inside one batch never reaches the server at all — so
|
|
303
|
+
// without this the only evidence of dedup was two identical
|
|
304
|
+
// durations, which is exactly the inference a caller should not have
|
|
305
|
+
// to make.
|
|
306
|
+
const first = await pending;
|
|
307
|
+
return first.outcome === "delivered"
|
|
308
|
+
? { ...first, meta: { ...first.meta, cached: true } }
|
|
309
|
+
: first;
|
|
310
|
+
}
|
|
311
|
+
const started = fetch(http, u, {
|
|
312
|
+
...options,
|
|
313
|
+
...(options.idempotencyKey !== undefined
|
|
314
|
+
? { idempotencyKey: batchIdempotencyKey(options.idempotencyKey, index) }
|
|
315
|
+
: {}),
|
|
316
|
+
}, true).catch(toFetchFailure);
|
|
317
|
+
byUrl.set(key, started);
|
|
318
|
+
return started;
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
export async function batchWithin(http, urls, deadlineMs, options = {}) {
|
|
322
|
+
validateDuration(deadlineMs, "deadlineMs");
|
|
323
|
+
if (options.timeoutMs !== undefined)
|
|
324
|
+
validateDuration(options.timeoutMs, "timeoutMs");
|
|
325
|
+
const expiresAt = Date.now() + deadlineMs;
|
|
326
|
+
let timer;
|
|
327
|
+
const deadline = new Promise((resolve) => {
|
|
328
|
+
timer = setTimeout(() => resolve(null), deadlineMs);
|
|
329
|
+
// Never hold the process open for a deadline nobody is waiting on.
|
|
330
|
+
timer.unref?.();
|
|
331
|
+
});
|
|
332
|
+
const timeout = (url) => ({
|
|
333
|
+
outcome: "failed",
|
|
334
|
+
error: "timeout",
|
|
335
|
+
url,
|
|
336
|
+
detail: `the batch deadline of ${Math.round(deadlineMs / 1000)}s passed before this URL answered`,
|
|
337
|
+
});
|
|
338
|
+
const byUrl = new Map();
|
|
339
|
+
try {
|
|
340
|
+
return await mapBatch(urls, options, async (u, index) => {
|
|
341
|
+
const key = urlIdentity(u) ?? u;
|
|
342
|
+
let started = byUrl.get(key);
|
|
343
|
+
const duplicate = started !== undefined;
|
|
344
|
+
if (!started) {
|
|
345
|
+
const remaining = expiresAt - Date.now();
|
|
346
|
+
if (remaining <= 0)
|
|
347
|
+
return timeout(u);
|
|
348
|
+
// Bounded by the SHARED deadline, not by the 120s default. A URL that
|
|
349
|
+
// loses the race is already reported as `timeout` and its answer can
|
|
350
|
+
// never be delivered, yet its poll loop went on issuing ~150 more
|
|
351
|
+
// requests over the following 75 seconds — a held browser slot on the
|
|
352
|
+
// single worker and a bill for a read the caller was told it did not
|
|
353
|
+
// get. There is no cancel route to call, so the honest bound is the one
|
|
354
|
+
// instant everything here shares.
|
|
355
|
+
//
|
|
356
|
+
// `Math.min`, not `??`. `options.timeoutMs ?? deadlineMs` bounded only
|
|
357
|
+
// the caller who passed nothing, and the signature invites the other
|
|
358
|
+
// case: `batchWithin(urls, 30_000, { timeoutMs: 120_000 })` is a
|
|
359
|
+
// perfectly ordinary call — the caller's own per-fetch budget, plus a
|
|
360
|
+
// tighter deadline for this batch — and it put the straggler right back
|
|
361
|
+
// where it started, polling a worker for 90 seconds after its answer
|
|
362
|
+
// was reported as `timeout` and became undeliverable. Nothing here can
|
|
363
|
+
// deliver an answer past the deadline, so nothing here may outlive it.
|
|
364
|
+
started = fetch(http, u, {
|
|
365
|
+
...options,
|
|
366
|
+
timeoutMs: Math.min(options.timeoutMs ?? deadlineMs, remaining),
|
|
367
|
+
...(options.idempotencyKey !== undefined
|
|
368
|
+
? { idempotencyKey: batchIdempotencyKey(options.idempotencyKey, index) }
|
|
369
|
+
: {}),
|
|
370
|
+
}, true, true).catch(toFetchFailure);
|
|
371
|
+
byUrl.set(key, started);
|
|
372
|
+
}
|
|
373
|
+
// The deadline is shared, so a straggler cannot extend the answer.
|
|
374
|
+
const settled = await Promise.race([started, deadline]);
|
|
375
|
+
if (!settled) {
|
|
376
|
+
return timeout(u);
|
|
377
|
+
}
|
|
378
|
+
return duplicate && settled.outcome === "delivered"
|
|
379
|
+
? { ...settled, meta: { ...settled.meta, cached: true } }
|
|
380
|
+
: settled;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
finally {
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transport and error plumbing shared by every client method.
|
|
3
|
+
*
|
|
4
|
+
* `Transport` owns the four things a request needs — the base URL, the token,
|
|
5
|
+
* the fetch implementation, and the extra headers — and the one method that
|
|
6
|
+
* turns them into a request; the domain modules take a `Transport` and stay
|
|
7
|
+
* ignorant of how a call is made. `UnfencedError` and `parseErrorBody` sit here
|
|
8
|
+
* because the transport raises the first using the second, and the memory and
|
|
9
|
+
* fetch modules read a thrown status back off it. All moved verbatim from the
|
|
10
|
+
* former single-file client.
|
|
11
|
+
*/
|
|
12
|
+
import type { UnfencedOptions } from "./types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Raised for any non-2xx response, carrying the server's status and detail.
|
|
15
|
+
*
|
|
16
|
+
* `code` and `remedy` exist because the server's refusals are structured and the
|
|
17
|
+
* actionable half was being thrown away. The body arrives as
|
|
18
|
+
* `{error, detail, remedy}`; this used to store the raw text truncated to 300
|
|
19
|
+
* characters, which cut a longer refusal mid-string — so the JSON no longer
|
|
20
|
+
* parsed downstream, the caller got a blob of half-JSON as its "detail", and the
|
|
21
|
+
* `remedy` that says how to proceed was simply gone. A refusal an agent cannot
|
|
22
|
+
* read its way out of is an infinite loop, which is the failure the act-guard in
|
|
23
|
+
* core already paid for once.
|
|
24
|
+
*/
|
|
25
|
+
export declare class UnfencedError extends Error {
|
|
26
|
+
readonly status: number;
|
|
27
|
+
readonly detail: string;
|
|
28
|
+
/** The server's error code, e.g. `use-fetch`, when the body carried one. */
|
|
29
|
+
readonly code: string | undefined;
|
|
30
|
+
/** What the server said to do instead. The half worth keeping. */
|
|
31
|
+
readonly remedy: string | undefined;
|
|
32
|
+
/** Validated server delay in milliseconds; does not authorize retrying a write. */
|
|
33
|
+
readonly retryAfterMs: number | undefined;
|
|
34
|
+
/** Original HTTP Retry-After value (delay-seconds or HTTP-date), when present. */
|
|
35
|
+
readonly retryAfter: string | undefined;
|
|
36
|
+
constructor(status: number, detail: string, parts?: {
|
|
37
|
+
code?: string | undefined;
|
|
38
|
+
remedy?: string | undefined;
|
|
39
|
+
retryAfterMs?: number | undefined;
|
|
40
|
+
retryAfter?: string | undefined;
|
|
41
|
+
cause?: unknown;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export declare function parseErrorBody(text: string): {
|
|
45
|
+
error?: string;
|
|
46
|
+
detail?: string;
|
|
47
|
+
remedy?: string;
|
|
48
|
+
retryAfterMs?: number;
|
|
49
|
+
} | null;
|
|
50
|
+
/** Keep durations inside the timer range shared by supported runtimes. */
|
|
51
|
+
export declare function validateDuration(value: number, name: string): void;
|
|
52
|
+
/** Sends requests; identity headers remain live by reference until submission. */
|
|
53
|
+
export declare class Transport {
|
|
54
|
+
private readonly baseUrl;
|
|
55
|
+
private readonly apiKey;
|
|
56
|
+
/** Narrowed to what this client calls: a string URL and an init object. */
|
|
57
|
+
private readonly doFetch;
|
|
58
|
+
private readonly extraHeaders;
|
|
59
|
+
/** A caller's cancel for the whole client, combined with each call's budget. */
|
|
60
|
+
private readonly clientSignal;
|
|
61
|
+
constructor(options?: UnfencedOptions);
|
|
62
|
+
/**
|
|
63
|
+
* Make a request, bounded.
|
|
64
|
+
*
|
|
65
|
+
* `budgetMs` is what is LEFT of the caller's `timeoutMs`, not a per-request
|
|
66
|
+
* allowance: `fetch()` computes a deadline once and hands each request the
|
|
67
|
+
* remainder, so ten polls cannot each take the whole budget. Nothing on this
|
|
68
|
+
* path carried a signal at all before — `grep -n AbortSignal packages/sdk`
|
|
69
|
+
* returned nothing — so `timeoutMs` bounded only the check between polls and
|
|
70
|
+
* a stalled connection wedged the call until the OS gave up.
|
|
71
|
+
*/
|
|
72
|
+
request<T>(method: string, path: string, body?: unknown, budgetMs?: number, requestHeaders?: Record<string, string>): Promise<T>;
|
|
73
|
+
/** The request itself, so the listener teardown above is one `finally`. */
|
|
74
|
+
private send;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD;;;;;;;;;;;GAWG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAWpB,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,MAAM;IAXhC,4EAA4E;IAC5E,SAAgB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,kEAAkE;IAClE,SAAgB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,mFAAmF;IACnF,SAAgB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,kFAAkF;IAClF,SAAgB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;gBAG7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EAC9B,KAAK,GAAE;QACL,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAClC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,KAAK,CAAC,EAAE,OAAO,CAAC;KACZ;CAWT;AAkDD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkBpF;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIlE;AAED,kFAAkF;AAClF,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyD;IACjF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyB;IACtD,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;gBAE3C,OAAO,GAAE,eAAoB;IAazC;;;;;;;;;OASG;IACG,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,OAAO,CAAC,CAAC,CAAC;IA+Bb,2EAA2E;YAC7D,IAAI;CAkFnB"}
|