@vibe-agent-toolkit/resources 0.1.39-rc.8 → 0.1.39
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/dist/content-cache.d.ts +67 -0
- package/dist/content-cache.d.ts.map +1 -0
- package/dist/content-cache.js +160 -0
- package/dist/content-cache.js.map +1 -0
- package/dist/external-link-cache.d.ts +16 -2
- package/dist/external-link-cache.d.ts.map +1 -1
- package/dist/external-link-cache.js +43 -13
- package/dist/external-link-cache.js.map +1 -1
- package/dist/external-link-validator.d.ts +75 -2
- package/dist/external-link-validator.d.ts.map +1 -1
- package/dist/external-link-validator.js +184 -4
- package/dist/external-link-validator.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/link-auth-classify.d.ts +34 -0
- package/dist/link-auth-classify.d.ts.map +1 -0
- package/dist/link-auth-classify.js +42 -0
- package/dist/link-auth-classify.js.map +1 -0
- package/dist/link-auth-config-build.d.ts +47 -0
- package/dist/link-auth-config-build.d.ts.map +1 -0
- package/dist/link-auth-config-build.js +86 -0
- package/dist/link-auth-config-build.js.map +1 -0
- package/dist/link-auth-content-fetch.d.ts +75 -0
- package/dist/link-auth-content-fetch.d.ts.map +1 -0
- package/dist/link-auth-content-fetch.js +101 -0
- package/dist/link-auth-content-fetch.js.map +1 -0
- package/dist/link-auth-deps-memo.d.ts +40 -0
- package/dist/link-auth-deps-memo.d.ts.map +1 -0
- package/dist/link-auth-deps-memo.js +47 -0
- package/dist/link-auth-deps-memo.js.map +1 -0
- package/dist/link-auth-transport.d.ts +44 -0
- package/dist/link-auth-transport.d.ts.map +1 -0
- package/dist/link-auth-transport.js +151 -0
- package/dist/link-auth-transport.js.map +1 -0
- package/dist/link-parser.d.ts.map +1 -1
- package/dist/link-parser.js +8 -1
- package/dist/link-parser.js.map +1 -1
- package/dist/link-validator.d.ts +8 -8
- package/dist/link-validator.d.ts.map +1 -1
- package/dist/link-validator.js +51 -18
- package/dist/link-validator.js.map +1 -1
- package/dist/resource-registry.d.ts +2 -0
- package/dist/resource-registry.d.ts.map +1 -1
- package/dist/resource-registry.js +19 -4
- package/dist/resource-registry.js.map +1 -1
- package/dist/schemas/link-auth.d.ts +1049 -303
- package/dist/schemas/link-auth.d.ts.map +1 -1
- package/dist/schemas/link-auth.js +39 -20
- package/dist/schemas/link-auth.js.map +1 -1
- package/dist/schemas/project-config.d.ts +2942 -759
- package/dist/schemas/project-config.d.ts.map +1 -1
- package/dist/schemas/project-config.js +27 -1
- package/dist/schemas/project-config.js.map +1 -1
- package/dist/schemas/resource-metadata.d.ts +10 -9
- package/dist/schemas/resource-metadata.d.ts.map +1 -1
- package/dist/schemas/resource-metadata.js +2 -0
- package/dist/schemas/resource-metadata.js.map +1 -1
- package/package.json +4 -4
- package/src/content-cache.ts +190 -0
- package/src/external-link-cache.ts +50 -13
- package/src/external-link-validator.ts +268 -5
- package/src/index.ts +23 -0
- package/src/link-auth-classify.ts +61 -0
- package/src/link-auth-config-build.ts +130 -0
- package/src/link-auth-content-fetch.ts +146 -0
- package/src/link-auth-deps-memo.ts +56 -0
- package/src/link-auth-transport.ts +179 -0
- package/src/link-parser.ts +8 -1
- package/src/link-validator.ts +65 -17
- package/src/resource-registry.ts +25 -5
- package/src/schemas/link-auth.ts +47 -21
- package/src/schemas/project-config.ts +31 -1
- package/src/schemas/resource-metadata.ts +2 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public content-fetch primitive for the linkAuth feature (design issue #113 §6.2).
|
|
3
|
+
*
|
|
4
|
+
* Ships as a standalone primitive — no consumer wiring (asset-references,
|
|
5
|
+
* bundling) lands in this slice. The shape and security disciplines are
|
|
6
|
+
* designed so future callers can adopt it without reworking the contract.
|
|
7
|
+
*
|
|
8
|
+
* Responsibility split:
|
|
9
|
+
* - `resolveAuthenticatedUrl` (engine): pick provider, rewrite URL, resolve
|
|
10
|
+
* token, expand auth.headers AND fetch.headers against the same context.
|
|
11
|
+
* - `ContentCache`: persist `(bytes, metadata)` keyed by rewritten URL with
|
|
12
|
+
* 30-min default TTL; whitelists fields so tokens cannot be persisted.
|
|
13
|
+
* - `authTransport`: cross-origin auth strip, 429/Retry-After handling.
|
|
14
|
+
* - **This primitive**: wire them together, decide cache vs fetch, build
|
|
15
|
+
* metadata, return a typed result.
|
|
16
|
+
*
|
|
17
|
+
* Behavior matrix:
|
|
18
|
+
* - Engine returns `unsupported` → return as-is, no fetch, no cache touch.
|
|
19
|
+
* - Engine returns `unverified` → return as-is, no fetch, **no cache touch**
|
|
20
|
+
* even if a cache was supplied (§6.3: result flips when a token appears,
|
|
21
|
+
* so caching the no-token answer would poison future runs).
|
|
22
|
+
* - Engine returns success + cache present + not forceRefresh + cache hit →
|
|
23
|
+
* return `{ bytes, metadata, cached: true }`, no fetch.
|
|
24
|
+
* - Engine returns success otherwise → fetch via `authTransport` (using
|
|
25
|
+
* `fetch.headers` merged over `auth.headers` when present), write to
|
|
26
|
+
* cache if supplied, return `{ bytes, metadata, cached: false }`.
|
|
27
|
+
*
|
|
28
|
+
* **Throws** on network-level failures from the transport: DNS resolution
|
|
29
|
+
* failure, TLS handshake failure, connection refused, `AbortError` from the
|
|
30
|
+
* caller's `signal`, or any underlying `fetchImpl` rejection. The cache is
|
|
31
|
+
* only touched after the response body is fully read, so a transport failure
|
|
32
|
+
* cannot land a partial entry on disk. Consumers that need degradation
|
|
33
|
+
* semantics (validators, batch tools) should wrap calls in a try/catch.
|
|
34
|
+
*
|
|
35
|
+
* **Token never persisted.** Tokens are interpolated into headers in-memory;
|
|
36
|
+
* the metadata interface excludes header fields. The cache additionally
|
|
37
|
+
* whitelists the metadata fields it accepts. See cycle-6 token-persistence
|
|
38
|
+
* test for the on-disk assertion.
|
|
39
|
+
*
|
|
40
|
+
* **High-volume callers**: token resolution can be expensive (`gh auth token`
|
|
41
|
+
* spawns a subprocess). Callers iterating many URLs should wrap their `deps`
|
|
42
|
+
* once with `wrapLinkAuthDepsWithMemo` from `./link-auth-deps-memo.js` and
|
|
43
|
+
* pass the wrapped object to every invocation, so the same argv resolves at
|
|
44
|
+
* most once across the iteration.
|
|
45
|
+
*/
|
|
46
|
+
import { resolveAuthenticatedUrl } from '@vibe-agent-toolkit/utils';
|
|
47
|
+
import { authTransport } from './link-auth-transport.js';
|
|
48
|
+
export async function fetchAuthenticated(url, config, options = {}) {
|
|
49
|
+
const plan = resolveAuthenticatedUrl(url, config, options.deps);
|
|
50
|
+
// Discriminate via Object.hasOwn (not `'fetchUrl' in plan`) so a prototype-
|
|
51
|
+
// injected `fetchUrl` field cannot reroute a non-success outcome onto the
|
|
52
|
+
// cache/fetch path. The engine controls plan shape — defending in depth.
|
|
53
|
+
if (!Object.hasOwn(plan, 'fetchUrl')) {
|
|
54
|
+
// unsupported / unverified — both short-circuit without fetch or cache.
|
|
55
|
+
const failure = plan;
|
|
56
|
+
return failure.outcome === 'unverified'
|
|
57
|
+
? { outcome: 'unverified', reason: failure.reason }
|
|
58
|
+
: { outcome: 'unsupported' };
|
|
59
|
+
}
|
|
60
|
+
const success = plan;
|
|
61
|
+
const cache = options.cache;
|
|
62
|
+
if (cache !== undefined && options.forceRefresh !== true) {
|
|
63
|
+
const hit = await cache.get(success.fetchUrl);
|
|
64
|
+
if (hit !== null) {
|
|
65
|
+
return { bytes: hit.bytes, metadata: hit.metadata, cached: true };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Merge headers: start from auth (covers Authorization + check-mode Accept),
|
|
69
|
+
// layer fetch.headers on top (overrides on conflict — e.g. swap the GitHub
|
|
70
|
+
// Accept from +json to .raw). Both header objects come from the engine, so
|
|
71
|
+
// both have the resolved token baked in (§6.2 dual-expand).
|
|
72
|
+
const requestHeaders = {
|
|
73
|
+
...success.headers,
|
|
74
|
+
...(success.fetchHeaders ?? {}),
|
|
75
|
+
};
|
|
76
|
+
const transportOptions = {
|
|
77
|
+
...(options.transportOptions ?? {}),
|
|
78
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
79
|
+
};
|
|
80
|
+
const response = await authTransport(success.fetchUrl, requestHeaders, options.fetchImpl ?? globalThis.fetch, transportOptions);
|
|
81
|
+
// Read full body as bytes. We use arrayBuffer (binary-clean) and wrap into a
|
|
82
|
+
// fresh Uint8Array so the caller doesn't hold a view onto fetch's internal
|
|
83
|
+
// buffer.
|
|
84
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
85
|
+
const bytes = new Uint8Array(arrayBuffer);
|
|
86
|
+
const metadata = {
|
|
87
|
+
status: response.status,
|
|
88
|
+
contentType: response.headers.get('content-type'),
|
|
89
|
+
etag: response.headers.get('etag'),
|
|
90
|
+
lastModified: response.headers.get('last-modified'),
|
|
91
|
+
fetchedAt: Date.now(),
|
|
92
|
+
rewrittenUrl: success.fetchUrl,
|
|
93
|
+
};
|
|
94
|
+
// Write-through. The ContentCache whitelists fields and fails soft on IO,
|
|
95
|
+
// so a write failure does not propagate.
|
|
96
|
+
if (cache !== undefined) {
|
|
97
|
+
await cache.set(success.fetchUrl, bytes, metadata);
|
|
98
|
+
}
|
|
99
|
+
return { bytes, metadata, cached: false };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=link-auth-content-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-auth-content-fetch.js","sourceRoot":"","sources":["../src/link-auth-content-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memoization wrapper for linkAuth `runCommand`-shaped token resolvers.
|
|
3
|
+
*
|
|
4
|
+
* Token resolution can be expensive — `gh auth token` spawns a subprocess on
|
|
5
|
+
* every call, env-source reads are cheap but consistent treatment is simpler
|
|
6
|
+
* to reason about — so the validator and the content-fetch primitive both
|
|
7
|
+
* wrap their `runCommand` once per session. Identical argv tuples return the
|
|
8
|
+
* cached result; distinct argv tuples are run independently.
|
|
9
|
+
*
|
|
10
|
+
* Lifetime of the memo is the lifetime of the returned `LinkAuthDeps` —
|
|
11
|
+
* one-per-session, never module-global. Callers that want a fresh resolve
|
|
12
|
+
* (e.g. token rotation between runs) construct a fresh validator / primitive
|
|
13
|
+
* call and get a fresh memo.
|
|
14
|
+
*
|
|
15
|
+
* Lifted out of `external-link-validator.ts` (where it shipped first in #125)
|
|
16
|
+
* so the slice-3 content-fetch primitive shares the same implementation —
|
|
17
|
+
* see CLAUDE.md "code duplication policy" (jscpd would flag a clone).
|
|
18
|
+
*
|
|
19
|
+
* Per design issue #113 review on PR #125 (memoize all token sources, not
|
|
20
|
+
* just `command` sources).
|
|
21
|
+
*/
|
|
22
|
+
import { type resolveAuthenticatedUrl } from '@vibe-agent-toolkit/utils';
|
|
23
|
+
/**
|
|
24
|
+
* Re-exposed deps type — the third argument to `resolveAuthenticatedUrl`.
|
|
25
|
+
* Mirrors the engine's `Partial<TokenResolutionDeps>` without importing the
|
|
26
|
+
* private type name.
|
|
27
|
+
*/
|
|
28
|
+
export type LinkAuthDeps = Parameters<typeof resolveAuthenticatedUrl>[2];
|
|
29
|
+
/**
|
|
30
|
+
* Wrap a `LinkAuthDeps` so its `runCommand` (used by the engine's
|
|
31
|
+
* `resolveToken`) caches results per unique argv. Without this, validating N
|
|
32
|
+
* URLs from the same host re-runs the token command N times.
|
|
33
|
+
*
|
|
34
|
+
* Caches by JSON-stringified argv so semantically-identical invocations
|
|
35
|
+
* share. The cache is per-call-site (one Map per wrapper); callers that share
|
|
36
|
+
* across multiple `resolveAuthenticatedUrl` invocations should call this
|
|
37
|
+
* once and reuse the wrapped object.
|
|
38
|
+
*/
|
|
39
|
+
export declare function wrapLinkAuthDepsWithMemo(deps: LinkAuthDeps): NonNullable<LinkAuthDeps>;
|
|
40
|
+
//# sourceMappingURL=link-auth-deps-memo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-auth-deps-memo.d.ts","sourceRoot":"","sources":["../src/link-auth-deps-memo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAE5F;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzE;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC,CActF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memoization wrapper for linkAuth `runCommand`-shaped token resolvers.
|
|
3
|
+
*
|
|
4
|
+
* Token resolution can be expensive — `gh auth token` spawns a subprocess on
|
|
5
|
+
* every call, env-source reads are cheap but consistent treatment is simpler
|
|
6
|
+
* to reason about — so the validator and the content-fetch primitive both
|
|
7
|
+
* wrap their `runCommand` once per session. Identical argv tuples return the
|
|
8
|
+
* cached result; distinct argv tuples are run independently.
|
|
9
|
+
*
|
|
10
|
+
* Lifetime of the memo is the lifetime of the returned `LinkAuthDeps` —
|
|
11
|
+
* one-per-session, never module-global. Callers that want a fresh resolve
|
|
12
|
+
* (e.g. token rotation between runs) construct a fresh validator / primitive
|
|
13
|
+
* call and get a fresh memo.
|
|
14
|
+
*
|
|
15
|
+
* Lifted out of `external-link-validator.ts` (where it shipped first in #125)
|
|
16
|
+
* so the slice-3 content-fetch primitive shares the same implementation —
|
|
17
|
+
* see CLAUDE.md "code duplication policy" (jscpd would flag a clone).
|
|
18
|
+
*
|
|
19
|
+
* Per design issue #113 review on PR #125 (memoize all token sources, not
|
|
20
|
+
* just `command` sources).
|
|
21
|
+
*/
|
|
22
|
+
import { defaultRunCommand } from '@vibe-agent-toolkit/utils';
|
|
23
|
+
/**
|
|
24
|
+
* Wrap a `LinkAuthDeps` so its `runCommand` (used by the engine's
|
|
25
|
+
* `resolveToken`) caches results per unique argv. Without this, validating N
|
|
26
|
+
* URLs from the same host re-runs the token command N times.
|
|
27
|
+
*
|
|
28
|
+
* Caches by JSON-stringified argv so semantically-identical invocations
|
|
29
|
+
* share. The cache is per-call-site (one Map per wrapper); callers that share
|
|
30
|
+
* across multiple `resolveAuthenticatedUrl` invocations should call this
|
|
31
|
+
* once and reuse the wrapped object.
|
|
32
|
+
*/
|
|
33
|
+
export function wrapLinkAuthDepsWithMemo(deps) {
|
|
34
|
+
const memo = new Map();
|
|
35
|
+
const baseRunCommand = deps?.runCommand ?? defaultRunCommand;
|
|
36
|
+
const runCommand = (argv) => {
|
|
37
|
+
const key = JSON.stringify(argv);
|
|
38
|
+
const cached = memo.get(key);
|
|
39
|
+
if (cached !== undefined)
|
|
40
|
+
return cached;
|
|
41
|
+
const fresh = baseRunCommand(argv);
|
|
42
|
+
memo.set(key, fresh);
|
|
43
|
+
return fresh;
|
|
44
|
+
};
|
|
45
|
+
return { ...(deps ?? {}), runCommand };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=link-auth-deps-memo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-auth-deps-memo.js","sourceRoot":"","sources":["../src/link-auth-deps-memo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAgC,MAAM,2BAA2B,CAAC;AAS5F;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAkB;IAGzD,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4B,CAAC;IACjD,MAAM,cAAc,GAAiB,IAAI,EAAE,UAAU,IAAI,iBAAiB,CAAC;IAC3E,MAAM,UAAU,GAAiB,CAAC,IAAI,EAAE,EAAE;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-safe HTTP transport for the linkAuth feature (design issue #113 §5.2, §8).
|
|
3
|
+
*
|
|
4
|
+
* Lower-level than the public `fetchAuthenticated` primitive — this transport
|
|
5
|
+
* does not know about providers, token resolution, or caching. It takes a URL
|
|
6
|
+
* + already-built headers and adds two behaviors required by the design:
|
|
7
|
+
*
|
|
8
|
+
* §8 (cross-origin token leak defense) — `redirect: 'manual'`, then a
|
|
9
|
+
* bounded loop that follows Location headers. On any redirect to a
|
|
10
|
+
* different origin the `Authorization` header is stripped and stays
|
|
11
|
+
* stripped for subsequent hops (defeats token-laundering via a cross-origin
|
|
12
|
+
* bounce back to the original host).
|
|
13
|
+
*
|
|
14
|
+
* §5.2 (rate-limit handling) — on HTTP 429, parse `Retry-After` (seconds or
|
|
15
|
+
* HTTP-date), wait, retry. Bounded by `maxRetries` so a stuck host cannot
|
|
16
|
+
* hang validation; bounded by `maxRetryAfterMs` so a hostile or buggy host
|
|
17
|
+
* cannot pin a validation run for an hour with `Retry-After: 86400`.
|
|
18
|
+
*
|
|
19
|
+
* Pure-ish: `fetchImpl` and `sleep` are dependency-injected so tests do not
|
|
20
|
+
* touch the network or wall-clock. Production callers pass `globalThis.fetch`.
|
|
21
|
+
*/
|
|
22
|
+
export interface AuthTransportOptions {
|
|
23
|
+
/** Maximum redirect hops to follow before returning the last 3xx response (default: 5). */
|
|
24
|
+
readonly maxRedirects?: number;
|
|
25
|
+
/** Maximum 429 retries before returning the final 429 response (default: 2). */
|
|
26
|
+
readonly maxRetries?: number;
|
|
27
|
+
/** Cap on Retry-After in ms; defends against hostile/buggy long values (default: 60_000). */
|
|
28
|
+
readonly maxRetryAfterMs?: number;
|
|
29
|
+
/** Abort signal propagated to every fetchImpl call (validator's per-request timeout budget). */
|
|
30
|
+
readonly signal?: AbortSignal;
|
|
31
|
+
/** Test-only sleep injection. Production callers omit. */
|
|
32
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse a `Retry-After` header value into milliseconds-to-wait.
|
|
36
|
+
*
|
|
37
|
+
* Returns `null` when the value is missing, empty, negative, or unparseable —
|
|
38
|
+
* callers treat `null` as "don't retry" (we can't pick a delay without a hint).
|
|
39
|
+
* HTTP-date values in the past return `0` (the server's hint is "you can retry
|
|
40
|
+
* now"). RFC 7231 §7.1.3.
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseRetryAfter(value: string | null): number | null;
|
|
43
|
+
export declare function authTransport(url: string, headers: Record<string, string>, fetchImpl: typeof fetch, options?: AuthTransportOptions): Promise<Response>;
|
|
44
|
+
//# sourceMappingURL=link-auth-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-auth-transport.d.ts","sourceRoot":"","sources":["../src/link-auth-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,oBAAoB;IACnC,2FAA2F;IAC3F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gGAAgG;IAChG,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAmBD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAkBnE;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,EAAE,OAAO,KAAK,EACvB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,QAAQ,CAAC,CA8CnB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-safe HTTP transport for the linkAuth feature (design issue #113 §5.2, §8).
|
|
3
|
+
*
|
|
4
|
+
* Lower-level than the public `fetchAuthenticated` primitive — this transport
|
|
5
|
+
* does not know about providers, token resolution, or caching. It takes a URL
|
|
6
|
+
* + already-built headers and adds two behaviors required by the design:
|
|
7
|
+
*
|
|
8
|
+
* §8 (cross-origin token leak defense) — `redirect: 'manual'`, then a
|
|
9
|
+
* bounded loop that follows Location headers. On any redirect to a
|
|
10
|
+
* different origin the `Authorization` header is stripped and stays
|
|
11
|
+
* stripped for subsequent hops (defeats token-laundering via a cross-origin
|
|
12
|
+
* bounce back to the original host).
|
|
13
|
+
*
|
|
14
|
+
* §5.2 (rate-limit handling) — on HTTP 429, parse `Retry-After` (seconds or
|
|
15
|
+
* HTTP-date), wait, retry. Bounded by `maxRetries` so a stuck host cannot
|
|
16
|
+
* hang validation; bounded by `maxRetryAfterMs` so a hostile or buggy host
|
|
17
|
+
* cannot pin a validation run for an hour with `Retry-After: 86400`.
|
|
18
|
+
*
|
|
19
|
+
* Pure-ish: `fetchImpl` and `sleep` are dependency-injected so tests do not
|
|
20
|
+
* touch the network or wall-clock. Production callers pass `globalThis.fetch`.
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_MAX_REDIRECTS = 5;
|
|
23
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
24
|
+
const DEFAULT_MAX_RETRY_AFTER_MS = 60_000;
|
|
25
|
+
/**
|
|
26
|
+
* Minimum delay between 429 retries. A hostile host can send `Retry-After: 0`
|
|
27
|
+
* (or an HTTP-date in the past, parsing to 0); without a floor, we'd retry
|
|
28
|
+
* immediately, which is worse-than-useless for the host's rate-limiting and
|
|
29
|
+
* makes us a poor neighbor. Bounded by `maxRetries` regardless, but the floor
|
|
30
|
+
* gives the host's window a chance to slide.
|
|
31
|
+
*/
|
|
32
|
+
const MIN_RETRY_AFTER_MS = 250;
|
|
33
|
+
const defaultSleep = (ms) => new Promise((resolve) => {
|
|
34
|
+
setTimeout(resolve, ms);
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Parse a `Retry-After` header value into milliseconds-to-wait.
|
|
38
|
+
*
|
|
39
|
+
* Returns `null` when the value is missing, empty, negative, or unparseable —
|
|
40
|
+
* callers treat `null` as "don't retry" (we can't pick a delay without a hint).
|
|
41
|
+
* HTTP-date values in the past return `0` (the server's hint is "you can retry
|
|
42
|
+
* now"). RFC 7231 §7.1.3.
|
|
43
|
+
*/
|
|
44
|
+
export function parseRetryAfter(value) {
|
|
45
|
+
if (value === null)
|
|
46
|
+
return null;
|
|
47
|
+
const trimmed = value.trim();
|
|
48
|
+
if (trimmed === '')
|
|
49
|
+
return null;
|
|
50
|
+
// delta-seconds form: positive integer count of seconds.
|
|
51
|
+
if (/^\d+$/.test(trimmed)) {
|
|
52
|
+
return Number(trimmed) * 1000;
|
|
53
|
+
}
|
|
54
|
+
// HTTP-date form per RFC 7231 §7.1.1.1 — always contains weekday and month
|
|
55
|
+
// names. Guard with /[A-Za-z]/ because Date.parse() is permissive: '-5'
|
|
56
|
+
// parses as year-5 BC, '0' as 1 BC, etc. Requiring at least one letter
|
|
57
|
+
// restricts us to real HTTP-date strings.
|
|
58
|
+
if (!/[A-Za-z]/.test(trimmed))
|
|
59
|
+
return null;
|
|
60
|
+
const parsedMs = Date.parse(trimmed);
|
|
61
|
+
if (!Number.isFinite(parsedMs))
|
|
62
|
+
return null;
|
|
63
|
+
return Math.max(0, parsedMs - Date.now());
|
|
64
|
+
}
|
|
65
|
+
export async function authTransport(url, headers, fetchImpl, options = {}) {
|
|
66
|
+
const maxRedirects = options.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
67
|
+
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
68
|
+
const maxRetryAfterMs = options.maxRetryAfterMs ?? DEFAULT_MAX_RETRY_AFTER_MS;
|
|
69
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
70
|
+
let currentUrl = url;
|
|
71
|
+
let currentHeaders = { ...headers };
|
|
72
|
+
let redirects = 0;
|
|
73
|
+
let retries = 0;
|
|
74
|
+
// Bounded loop: every iteration either returns or strictly advances one of
|
|
75
|
+
// (retries, redirects), both capped, so termination is guaranteed within
|
|
76
|
+
// `maxRetries + maxRedirects + 1` fetchImpl calls.
|
|
77
|
+
while (redirects + retries < maxRedirects + maxRetries + 1) {
|
|
78
|
+
const init = {
|
|
79
|
+
headers: currentHeaders,
|
|
80
|
+
redirect: 'manual',
|
|
81
|
+
};
|
|
82
|
+
if (options.signal !== undefined)
|
|
83
|
+
init.signal = options.signal;
|
|
84
|
+
const response = await fetchImpl(currentUrl, init);
|
|
85
|
+
const retryDelay = retries < maxRetries ? computeRetryDelay(response, maxRetryAfterMs) : null;
|
|
86
|
+
if (retryDelay !== null) {
|
|
87
|
+
await sleep(retryDelay);
|
|
88
|
+
retries++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (redirects < maxRedirects) {
|
|
92
|
+
const next = computeRedirect(response, currentUrl, currentHeaders);
|
|
93
|
+
if (next !== null) {
|
|
94
|
+
currentUrl = next.url;
|
|
95
|
+
currentHeaders = next.headers;
|
|
96
|
+
redirects++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return response;
|
|
101
|
+
}
|
|
102
|
+
// Unreachable: the loop returns or continues on every iteration, and the
|
|
103
|
+
// loop condition strictly bounds total iterations.
|
|
104
|
+
throw new Error('authTransport: unreachable iteration cap exceeded');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Decide the wait-time for a 429 response, or `null` if the response is not
|
|
108
|
+
* a 429 OR has no parseable Retry-After hint (no hint → caller returns the 429
|
|
109
|
+
* rather than retrying blindly).
|
|
110
|
+
*/
|
|
111
|
+
function computeRetryDelay(response, maxRetryAfterMs) {
|
|
112
|
+
if (response.status !== 429)
|
|
113
|
+
return null;
|
|
114
|
+
const retryAfter = parseRetryAfter(response.headers.get('retry-after'));
|
|
115
|
+
if (retryAfter === null)
|
|
116
|
+
return null;
|
|
117
|
+
// Two-sided clamp: never longer than the DoS cap, never shorter than the
|
|
118
|
+
// good-neighbor floor (defends against `Retry-After: 0` busy-loops).
|
|
119
|
+
return Math.min(Math.max(retryAfter, MIN_RETRY_AFTER_MS), maxRetryAfterMs);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Decide the next hop for a 3xx redirect, or `null` if the response is not a
|
|
123
|
+
* redirect / has no Location. Strips Authorization on cross-origin per §8.
|
|
124
|
+
*/
|
|
125
|
+
function computeRedirect(response, currentUrl, currentHeaders) {
|
|
126
|
+
if (response.status < 300 || response.status >= 400)
|
|
127
|
+
return null;
|
|
128
|
+
const location = response.headers.get('location');
|
|
129
|
+
if (location === null)
|
|
130
|
+
return null;
|
|
131
|
+
const nextUrl = new URL(location, currentUrl).toString();
|
|
132
|
+
const sameOrigin = new URL(nextUrl).origin === new URL(currentUrl).origin;
|
|
133
|
+
return {
|
|
134
|
+
url: nextUrl,
|
|
135
|
+
headers: sameOrigin ? currentHeaders : stripAuthorization(currentHeaders),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Remove any header whose name is `Authorization` (case-insensitive). Returns
|
|
140
|
+
* a new object — does not mutate the input.
|
|
141
|
+
*/
|
|
142
|
+
function stripAuthorization(headers) {
|
|
143
|
+
const result = {};
|
|
144
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
145
|
+
if (name.toLowerCase() === 'authorization')
|
|
146
|
+
continue;
|
|
147
|
+
result[name] = value;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=link-auth-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-auth-transport.js","sourceRoot":"","sources":["../src/link-auth-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-parser.d.ts","sourceRoot":"","sources":["../src/link-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAwC1E;AA+ED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"link-parser.d.ts","sourceRoot":"","sources":["../src/link-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAwC1E;AA+ED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAkEnD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEvD"}
|
package/dist/link-parser.js
CHANGED
|
@@ -172,8 +172,15 @@ export function classifyLink(href) {
|
|
|
172
172
|
if (href.startsWith('#')) {
|
|
173
173
|
return 'anchor';
|
|
174
174
|
}
|
|
175
|
+
// Self-contained inline resources: a data: URI embeds its payload and a blob:
|
|
176
|
+
// URL references an in-memory object. Neither has a target to fetch or an
|
|
177
|
+
// anchor to resolve, so they are valid-but-nothing-to-validate (skipped), not
|
|
178
|
+
// "unknown". Common in HTML (inline SVG/PNG/GIF logos).
|
|
179
|
+
if (href.startsWith('data:') || href.startsWith('blob:')) {
|
|
180
|
+
return 'embedded';
|
|
181
|
+
}
|
|
175
182
|
// Any remaining href containing ':' is a protocol-like pattern we don't recognise
|
|
176
|
-
// (e.g., javascript:, tel:,
|
|
183
|
+
// (e.g., javascript:, tel:, ftp:) — classify as unknown rather than local file
|
|
177
184
|
if (href.includes(':')) {
|
|
178
185
|
return 'unknown';
|
|
179
186
|
}
|
package/dist/link-parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-parser.js","sourceRoot":"","sources":["../src/link-parser.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"link-parser.js","sourceRoot":"","sources":["../src/link-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,OAAO,iBAAiB,MAAM,oBAAoB,CAAC;AACnD,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAsB7B;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,8BAA8B;IAC9B,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzC,+GAA+G;QAC/G,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,+GAA+G;QAC/G,IAAI,CAAC,QAAQ,CAAC;KACf,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC;IAC7B,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE1D,qCAAqC;IACrC,MAAM,SAAS,GAAG,OAAO,EAAE;SACxB,GAAG,CAAC,WAAW,CAAC;SAChB,GAAG,CAAC,SAAS,CAAC;SACd,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAE1B,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAS,CAAC;IAE9C,gBAAgB;IAChB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEjC,uCAAuC;IACvC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAEvC,sBAAsB;IACtB,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAE1E,oFAAoF;IACpF,wCAAwC;IACxC,OAAO;QACL,KAAK;QACL,QAAQ;QACR,GAAG,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,CAAC;QACjD,GAAG,CAAC,gBAAgB,KAAK,SAAS,IAAI,EAAE,gBAAgB,EAAE,CAAC;QAC3D,OAAO;QACP,SAAS;QACT,mBAAmB;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,YAAY,CAAC,IAAU;IAC9B,MAAM,KAAK,GAAmB,EAAE,CAAC;IAEjC,8DAA8D;IAC9D,0EAA0E;IAC1E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,IAAgB,EAAE,EAAE;QAC7C,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,iDAAiD;IACjD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAU,EAAE,EAAE;QACjC,MAAM,IAAI,GAAiB;YACzB,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;YAC3B,IAAI,EAAE,IAAI,CAAC,GAAG;YACd,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI;YAC/B,QAAQ,EAAE,MAAM;SACjB,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,oDAAoD;IACpD,sGAAsG;IACtG,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC,IAAmB,EAAE,EAAE;QACnD,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,iFAAiF;YACjF,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAiB;YACzB,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;YAC3B,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,YAAY,CAAC,WAAW,CAAC;YAC/B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI;YAC/B,QAAQ,EAAE,eAAe;SAC1B,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,wDAAwD;IACxD,KAAK,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,IAAgB,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAiB;YACzB,IAAI,EAAE,IAAI,CAAC,UAAU;YACrB,IAAI,EAAE,IAAI,CAAC,GAAG;YACd,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI;YAC/B,QAAQ,EAAE,YAAY;SACvB,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAA0B;IACjD,OAAO,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9D,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,8EAA8E;IAC9E,0EAA0E;IAC1E,8EAA8E;IAC9E,wDAAwD;IACxD,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,kFAAkF;IAClF,+EAA+E;IAC/E,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,mEAAmE;IACnE,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAChD,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,gDAAgD;IAChD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,mCAAmC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,mFAAmF;IACnF,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5E,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,kEAAkE;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,GAAG,SAAS,EAAE,CAAC;QAC1C,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,mEAAmE;IACnE,uFAAuF;IACvF,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,6DAA6D;IAC7D,2DAA2D;IAC3D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,8CAA8C;IAChD,CAAC;IACD,2EAA2E;IAC3E,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,iBAAiB,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,SAAS,eAAe,CAAC,IAAU;IACjC,MAAM,YAAY,GAAkB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IAEpC,qDAAqD;IACrD,kFAAkF;IAClF,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAa,EAAE,EAAE;QACvC,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,OAAO,GAAgB;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI;SAChC,CAAC;QACF,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,kDAAkD;IAClD,OAAO,gBAAgB,CAAC,YAAY,CAAC,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,IAAa;IACvC,OAAO,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAaD;;;;;;;;;;;;GAYG;AACH,SAAS,uBAAuB,CAAC,QAAkC;IACjE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,sEAAsE;QACtE,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC,KAAK,CAAC;QACrB,CAAC;QACD,uEAAuE;QACvE,yCAAyC;QACzC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAGD;;;;;;;;;;GAUG;AACH,SAAS,gBAAgB,CAAC,YAA2B;IACnD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,4BAA4B;QAC5B,MAAM,mBAAmB,GAAgB;YACvC,GAAG,OAAO;YACV,QAAQ,EAAE,EAAE;SACb,CAAC;QAEF,kEAAkE;QAClE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACvE,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,+BAA+B;YAC/B,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,mCAAmC;YACnC,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC;gBACvB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAClC,CAAC;IAED,wDAAwD;IACxD,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAE5B,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,QAAuB;IACnD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC/B,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3D,oBAAoB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,IAAU;IAIpC,IAAI,eAAoD,CAAC;IACzD,IAAI,YAAgC,CAAC;IAErC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,IAAuB,EAAE,EAAE;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC7B,0BAA0B;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5E,eAAe,GAAG,MAAiC,CAAC;YACtD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,sDAAsD;YACtD,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,OAAO;QACL,GAAG,CAAC,eAAe,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;QACtE,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
|
package/dist/link-validator.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ export interface ValidateLinkOptions {
|
|
|
28
28
|
skipGitIgnoreCheck?: boolean;
|
|
29
29
|
/** Git tracker for efficient git-ignore checking (optional, improves performance) */
|
|
30
30
|
gitTracker?: GitTracker;
|
|
31
|
+
/** Strictly resolve HTML fragment anchors against element ids/names (default: false). HTML fragments are often runtime-defined by JS, so a static miss is not proof of breakage. */
|
|
32
|
+
checkHtmlAnchors?: boolean;
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
33
35
|
* Validate a single link in a markdown resource.
|
|
@@ -105,17 +107,15 @@ export declare function fragmentIndex(entries?: Iterable<readonly [string, Set<s
|
|
|
105
107
|
*
|
|
106
108
|
* - `'skip'` — target file is not indexed; we cannot prove the anchor is
|
|
107
109
|
* broken, so callers must not emit an issue.
|
|
108
|
-
* -
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* - For HTML targets the empty fragment (`#`) and `top` (ASCII
|
|
112
|
-
* case-insensitive) are always valid: per the HTML fragment-navigation
|
|
113
|
-
* algorithm both scroll to the top of the document regardless of whether a
|
|
114
|
-
* matching element exists, so `href="#"` / `href="#top"` are not broken.
|
|
110
|
+
* - HTML targets are delegated to {@link checkHtmlAnchor} (top-navigation
|
|
111
|
+
* rule, structural non-anchors, and the `checkHtmlAnchors` opt-in gate).
|
|
112
|
+
* - Markdown targets resolve against the indexed heading slugs, case-folded.
|
|
115
113
|
*
|
|
116
114
|
* @param anchor - Fragment without the leading `#`.
|
|
117
115
|
* @param targetFilePath - Absolute path of the file the fragment lives in.
|
|
118
116
|
* @param fragmentsByFile - Fragment index carrying each file's matching policy.
|
|
117
|
+
* @param checkHtmlAnchors - Strictly resolve HTML fragments against indexed
|
|
118
|
+
* element ids/names (default: false — see {@link checkHtmlAnchor}).
|
|
119
119
|
*/
|
|
120
|
-
export declare function checkAnchor(anchor: string, targetFilePath: string, fragmentsByFile: FragmentIndex): AnchorCheck;
|
|
120
|
+
export declare function checkAnchor(anchor: string, targetFilePath: string, fragmentsByFile: FragmentIndex, checkHtmlAnchors?: boolean): AnchorCheck;
|
|
121
121
|
//# sourceMappingURL=link-validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-validator.d.ts","sourceRoot":"","sources":["../src/link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAkC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAuB9E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qFAAqF;IACrF,UAAU,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"link-validator.d.ts","sourceRoot":"","sources":["../src/link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAC7F,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAkC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAuB9E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qFAAqF;IACrF,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,oLAAoL;IACpL,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,YAAY,EAClB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,aAAa,EAC9B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmCjC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EAC7C,IAAI,EAAE,YAAY,EAClB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAyBxB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1E,IAAI,EAAE,YAAY,EAClB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,eAAe,GAAG,IAAI,CAsBxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACvC,eAAe,GAAG,IAAI,CA2BxB;AAsHD,+DAA+D;AAC/D,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,+FAA+F;IAC/F,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,4DAA4D;AAC5D,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,kBAAkB,CAE3G;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAM,GAAG,aAAa,CAMnG;AA0CD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,aAAa,EAC9B,gBAAgB,UAAQ,GACvB,WAAW,CAYb"}
|