@sdxc/outbound 2026.10.24 → 2026.10.25
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 +4 -0
- package/dist/error.d.ts +4 -4
- package/dist/follow.d.ts +6 -0
- package/dist/follow.js +17 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -102,6 +102,9 @@ Answers the final response whatever its status. Beside every `checkUrl` option:
|
|
|
102
102
|
- `maxRedirects`: default `5`.
|
|
103
103
|
- `resolve`: when `true`, resolves every hop's name with `resolveHost` and refuses it unless every
|
|
104
104
|
address is public. Default `false`; skipped with `hosts: "any"`.
|
|
105
|
+
- `sign`: `(request) => Promise<Result<Request, Error>>`, run on each hop's request before it is
|
|
106
|
+
sent, such as `webBotAuthSigner` from `@sdxc/http-signatures/web-bot-auth`. A failure stops the
|
|
107
|
+
walk as `signing-failed`.
|
|
105
108
|
|
|
106
109
|
### `resolveHost(url: URL, options?: { signal?: AbortSignal }): Promise<Result<string[], OutboundError>>`
|
|
107
110
|
|
|
@@ -145,6 +148,7 @@ for `invalid-url`, or `""` for a body with no URL), and `retryable`.
|
|
|
145
148
|
| `refused-host` | No | A reserved name, a single label, or no address |
|
|
146
149
|
| `refused-address` | No | A non-public literal, or a non-public DNS answer |
|
|
147
150
|
| `too-many-redirects` | No | The chain ran past `maxRedirects` |
|
|
151
|
+
| `signing-failed` | No | The `sign` option answered a failure |
|
|
148
152
|
| `too-large` | No | The body passed `maxBytes` |
|
|
149
153
|
| `timeout` | Yes | The deadline passed |
|
|
150
154
|
| `network` | Yes | `fetch` rejected, a body broke off, or DNS failed |
|
package/dist/error.d.ts
CHANGED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* @copyright Sergio Xalambrí 2026
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
|
-
* Why an outbound request was refused or failed. Each `refused-*` code
|
|
11
|
-
* before a request leaves; `timeout` and `network` are the
|
|
12
|
-
* change.
|
|
10
|
+
* Why an outbound request was refused or failed. Each `refused-*` code, and
|
|
11
|
+
* `signing-failed`, is decided before a request leaves; `timeout` and `network` are the
|
|
12
|
+
* only outcomes a retry can change.
|
|
13
13
|
*/
|
|
14
|
-
export type OutboundErrorCode = "invalid-url" | "refused-scheme" | "refused-credentials" | "refused-port" | "refused-host" | "refused-address" | "too-many-redirects" | "too-large" | "timeout" | "network";
|
|
14
|
+
export type OutboundErrorCode = "invalid-url" | "refused-scheme" | "refused-credentials" | "refused-port" | "refused-host" | "refused-address" | "too-many-redirects" | "signing-failed" | "too-large" | "timeout" | "network";
|
|
15
15
|
/** Returned inside a `Failure` by every function in this package, never thrown. */
|
|
16
16
|
export declare class OutboundError extends Error {
|
|
17
17
|
name: string;
|
package/dist/follow.d.ts
CHANGED
|
@@ -30,6 +30,12 @@ export interface FollowOptions extends CheckOptions {
|
|
|
30
30
|
resolve?: boolean;
|
|
31
31
|
/** The caller's own abort, combined with `timeout`. */
|
|
32
32
|
signal?: AbortSignal;
|
|
33
|
+
/**
|
|
34
|
+
* Signs each hop's request before it is sent, such as with a Web Bot Auth signature, so
|
|
35
|
+
* every origin in the chain receives a signature over its own authority. A failure
|
|
36
|
+
* stops the walk as `signing-failed`.
|
|
37
|
+
*/
|
|
38
|
+
sign?: (request: Request) => Promise<Result<Request, Error>>;
|
|
33
39
|
}
|
|
34
40
|
/** The last response of a chain, where it came from, and how many hops it took. */
|
|
35
41
|
export interface Followed {
|
package/dist/follow.js
CHANGED
|
@@ -40,15 +40,25 @@ export async function follow(input, options = {}) {
|
|
|
40
40
|
if (isFailure(resolved))
|
|
41
41
|
return resolved;
|
|
42
42
|
}
|
|
43
|
+
let request = new Request(url, {
|
|
44
|
+
method: options.method ?? "GET",
|
|
45
|
+
headers,
|
|
46
|
+
signal,
|
|
47
|
+
redirect: "manual",
|
|
48
|
+
credentials: "omit",
|
|
49
|
+
});
|
|
50
|
+
if (options.sign) {
|
|
51
|
+
let signed = await options.sign(request);
|
|
52
|
+
if (isFailure(signed)) {
|
|
53
|
+
return failure(new OutboundError("signing-failed", url.href, `Could not sign ${url.href}`, {
|
|
54
|
+
cause: signed.error,
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
request = signed.data;
|
|
58
|
+
}
|
|
43
59
|
let response;
|
|
44
60
|
try {
|
|
45
|
-
response = await fetch(
|
|
46
|
-
method: options.method ?? "GET",
|
|
47
|
-
headers,
|
|
48
|
-
signal,
|
|
49
|
-
redirect: "manual",
|
|
50
|
-
credentials: "omit",
|
|
51
|
-
});
|
|
61
|
+
response = await fetch(request);
|
|
52
62
|
}
|
|
53
63
|
catch (error) {
|
|
54
64
|
return failure(failedWith(url.href, error));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdxc/outbound",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.25",
|
|
4
4
|
"description": "Check, follow and read URLs a stranger chose: public hosts on every redirect, one deadline, bounded bodies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
".": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@sdxc/doh": "2026.10.
|
|
11
|
+
"@sdxc/doh": "2026.10.25",
|
|
12
12
|
"@sdxc/duration": "2026.10.13",
|
|
13
13
|
"@sdxc/ip": "2026.10.13",
|
|
14
14
|
"@sdxc/result": "2026.10.13"
|
|
15
15
|
},
|
|
16
|
-
"gitHead": "
|
|
16
|
+
"gitHead": "1440b969c0a3e3808dfcee3f17d2ef43915f32a8",
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|