lens-content-processor 0.9.0 → 0.10.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/dist/cli.d.ts +2 -0
- package/dist/cli.js +57 -7
- package/dist/cli.js.map +1 -1
- package/dist/validator/url-cache.d.ts +29 -0
- package/dist/validator/url-cache.js +73 -0
- package/dist/validator/url-cache.js.map +1 -0
- package/dist/validator/url-reachability.d.ts +14 -1
- package/dist/validator/url-reachability.js +89 -42
- package/dist/validator/url-reachability.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// src/cli.ts
|
|
3
3
|
import { readVaultFiles } from "./fs/read-vault.js";
|
|
4
|
-
import { processContent } from "./index.js";
|
|
5
|
-
import { validateUrls } from "./validator/url-reachability.js";
|
|
4
|
+
import { processContent, } from "./index.js";
|
|
5
|
+
import { validateUrls, materializeUrlIssue, } from "./validator/url-reachability.js";
|
|
6
|
+
import { UrlCache } from "./validator/url-cache.js";
|
|
6
7
|
import { buildFileToCourses } from "./reference-graph.js";
|
|
7
8
|
import { dedupeErrors } from "./dedupe-errors.js";
|
|
8
9
|
import { writeFile } from "fs/promises";
|
|
@@ -11,6 +12,8 @@ export function parseArgs(argv) {
|
|
|
11
12
|
let vaultPath = null;
|
|
12
13
|
let outputPath = null;
|
|
13
14
|
let stdin = false;
|
|
15
|
+
let deferUrls = false;
|
|
16
|
+
let checkUrlsOnly = false;
|
|
14
17
|
for (let i = 0; i < args.length; i++) {
|
|
15
18
|
if (args[i] === "--output" || args[i] === "-o") {
|
|
16
19
|
outputPath = args[i + 1] || null;
|
|
@@ -19,11 +22,17 @@ export function parseArgs(argv) {
|
|
|
19
22
|
else if (args[i] === "--stdin") {
|
|
20
23
|
stdin = true;
|
|
21
24
|
}
|
|
25
|
+
else if (args[i] === "--defer-urls") {
|
|
26
|
+
deferUrls = true;
|
|
27
|
+
}
|
|
28
|
+
else if (args[i] === "--check-urls-only") {
|
|
29
|
+
checkUrlsOnly = true;
|
|
30
|
+
}
|
|
22
31
|
else if (!args[i].startsWith("-")) {
|
|
23
32
|
vaultPath = args[i];
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
|
-
return { vaultPath, outputPath, stdin };
|
|
35
|
+
return { vaultPath, outputPath, stdin, deferUrls, checkUrlsOnly };
|
|
27
36
|
}
|
|
28
37
|
async function readStdin() {
|
|
29
38
|
const chunks = [];
|
|
@@ -63,6 +72,22 @@ export async function run(options) {
|
|
|
63
72
|
}
|
|
64
73
|
async function main() {
|
|
65
74
|
const options = parseArgs(process.argv);
|
|
75
|
+
if (options.deferUrls && options.checkUrlsOnly) {
|
|
76
|
+
console.error("--defer-urls and --check-urls-only are mutually exclusive");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
if (options.checkUrlsOnly) {
|
|
80
|
+
try {
|
|
81
|
+
const urls = JSON.parse(await readStdin());
|
|
82
|
+
const issues = await validateUrls(urls, UrlCache.load());
|
|
83
|
+
console.log(JSON.stringify(dedupeErrors(issues), null, 2));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
66
91
|
if (!options.vaultPath && !options.stdin) {
|
|
67
92
|
console.error("Usage: npx tsx src/cli.ts <vault-path> [--output <file>]");
|
|
68
93
|
console.error(" npx tsx src/cli.ts --stdin [--output <file>]");
|
|
@@ -70,14 +95,39 @@ async function main() {
|
|
|
70
95
|
}
|
|
71
96
|
try {
|
|
72
97
|
const result = await run(options);
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
|
|
98
|
+
let output = result;
|
|
99
|
+
if (options.deferUrls) {
|
|
100
|
+
// Zero network: materialize issues from still-fresh cache entries and
|
|
101
|
+
// report how many unique URLs would need a live check. The consumer
|
|
102
|
+
// (backend) runs those later via --check-urls-only and replaces
|
|
103
|
+
// urlIssues wholesale — hence issues stay OUT of `errors` here.
|
|
104
|
+
const cache = UrlCache.load();
|
|
105
|
+
const cachedIssues = [];
|
|
106
|
+
for (const entry of result.urlsToValidate) {
|
|
107
|
+
const outcome = cache.getFresh(entry.url);
|
|
108
|
+
if (!outcome)
|
|
109
|
+
continue;
|
|
110
|
+
const issue = materializeUrlIssue(entry, outcome);
|
|
111
|
+
if (issue)
|
|
112
|
+
cachedIssues.push(issue);
|
|
113
|
+
}
|
|
114
|
+
// Dedupe against content errors exactly like the default mode's combined
|
|
115
|
+
// dedupe, then keep only the URL tail (errors are already deduped, so
|
|
116
|
+
// the slice boundary is exact).
|
|
117
|
+
const urlIssues = dedupeErrors([...result.errors, ...cachedIssues]).slice(result.errors.length);
|
|
118
|
+
output = {
|
|
119
|
+
...result,
|
|
120
|
+
urlIssues,
|
|
121
|
+
staleUrlCount: cache.staleCount(result.urlsToValidate),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else if (result.urlsToValidate.length > 0) {
|
|
125
|
+
const urlWarnings = await validateUrls(result.urlsToValidate, UrlCache.load());
|
|
76
126
|
// Re-dedupe: urlWarnings are appended after processContent already
|
|
77
127
|
// deduped, and can themselves repeat (same unreachable URL twice).
|
|
78
128
|
result.errors = dedupeErrors([...result.errors, ...urlWarnings]);
|
|
79
129
|
}
|
|
80
|
-
const json = JSON.stringify(
|
|
130
|
+
const json = JSON.stringify(output, null, 2);
|
|
81
131
|
if (options.outputPath) {
|
|
82
132
|
await writeFile(options.outputPath, json, "utf-8");
|
|
83
133
|
console.error(`Written to ${options.outputPath}`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type UrlOutcome = {
|
|
2
|
+
kind: "ok";
|
|
3
|
+
} | {
|
|
4
|
+
kind: "not_found";
|
|
5
|
+
status: number;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "unconfirmed";
|
|
8
|
+
status: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "timeout";
|
|
11
|
+
} | {
|
|
12
|
+
kind: "network_error";
|
|
13
|
+
};
|
|
14
|
+
export declare function defaultUrlCachePath(): string;
|
|
15
|
+
export declare class UrlCache {
|
|
16
|
+
private readonly path;
|
|
17
|
+
private entries;
|
|
18
|
+
private constructor();
|
|
19
|
+
/** Missing/corrupt/version-mismatched file ⇒ empty cache (degradable). */
|
|
20
|
+
static load(path?: string): UrlCache;
|
|
21
|
+
getFresh(url: string, nowMs?: number): UrlOutcome | null;
|
|
22
|
+
set(url: string, outcome: UrlOutcome, nowMs?: number): void;
|
|
23
|
+
/** Unique URLs in `urls` with no fresh cache entry. */
|
|
24
|
+
staleCount(urls: {
|
|
25
|
+
url: string;
|
|
26
|
+
}[], nowMs?: number): number;
|
|
27
|
+
/** Temp-file + rename so concurrent runs are last-writer-wins, never corrupt. */
|
|
28
|
+
persist(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/validator/url-cache.ts
|
|
2
|
+
// Persistent per-URL reachability cache (24h TTL). Shared by all CLI modes.
|
|
3
|
+
// See docs/plans/2026-07-07-url-cache-nonblocking-design.md §1.
|
|
4
|
+
import { readFileSync, writeFileSync, renameSync } from "fs";
|
|
5
|
+
import { tmpdir } from "os";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
const CACHE_VERSION = 1;
|
|
8
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
9
|
+
export function defaultUrlCachePath() {
|
|
10
|
+
return (process.env.LENS_URL_CACHE_PATH ??
|
|
11
|
+
join(tmpdir(), "lens-content-processor-url-cache.json"));
|
|
12
|
+
}
|
|
13
|
+
export class UrlCache {
|
|
14
|
+
path;
|
|
15
|
+
entries;
|
|
16
|
+
constructor(path, entries) {
|
|
17
|
+
this.path = path;
|
|
18
|
+
this.entries = entries;
|
|
19
|
+
}
|
|
20
|
+
/** Missing/corrupt/version-mismatched file ⇒ empty cache (degradable). */
|
|
21
|
+
static load(path = defaultUrlCachePath()) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
24
|
+
if (parsed.version === CACHE_VERSION && parsed.entries) {
|
|
25
|
+
return new UrlCache(path, parsed.entries);
|
|
26
|
+
}
|
|
27
|
+
console.error(`url-cache: discarding ${path} (version mismatch)`);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
// A missing file is the normal cold-start case — stay quiet. Anything
|
|
31
|
+
// else (corrupt JSON, permission error) is worth a stderr note.
|
|
32
|
+
if (error.code !== "ENOENT") {
|
|
33
|
+
console.error(`url-cache: treating ${path} as empty:`, error instanceof Error ? error.message : error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return new UrlCache(path, {});
|
|
37
|
+
}
|
|
38
|
+
getFresh(url, nowMs = Date.now()) {
|
|
39
|
+
const entry = this.entries[url];
|
|
40
|
+
if (!entry)
|
|
41
|
+
return null;
|
|
42
|
+
const age = nowMs - Date.parse(entry.checkedAt);
|
|
43
|
+
if (!(age >= 0 && age < TTL_MS))
|
|
44
|
+
return null;
|
|
45
|
+
return entry.outcome;
|
|
46
|
+
}
|
|
47
|
+
set(url, outcome, nowMs = Date.now()) {
|
|
48
|
+
this.entries[url] = { checkedAt: new Date(nowMs).toISOString(), outcome };
|
|
49
|
+
}
|
|
50
|
+
/** Unique URLs in `urls` with no fresh cache entry. */
|
|
51
|
+
staleCount(urls, nowMs = Date.now()) {
|
|
52
|
+
const stale = new Set();
|
|
53
|
+
for (const { url } of urls) {
|
|
54
|
+
if (this.getFresh(url, nowMs) === null)
|
|
55
|
+
stale.add(url);
|
|
56
|
+
}
|
|
57
|
+
return stale.size;
|
|
58
|
+
}
|
|
59
|
+
/** Temp-file + rename so concurrent runs are last-writer-wins, never corrupt. */
|
|
60
|
+
persist() {
|
|
61
|
+
const file = { version: CACHE_VERSION, entries: this.entries };
|
|
62
|
+
const tmpPath = `${this.path}.${process.pid}.tmp`;
|
|
63
|
+
try {
|
|
64
|
+
writeFileSync(tmpPath, JSON.stringify(file), "utf-8");
|
|
65
|
+
renameSync(tmpPath, this.path);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// Degradable: an unwritable cache must never break validation.
|
|
69
|
+
console.error(`url-cache: failed to persist ${this.path}:`, error instanceof Error ? error.message : error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=url-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-cache.js","sourceRoot":"","sources":["../../src/validator/url-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ContentError } from "../index.js";
|
|
2
|
+
import type { UrlOutcome, UrlCache } from "./url-cache.js";
|
|
2
3
|
export interface UrlToValidate {
|
|
3
4
|
url: string;
|
|
4
5
|
file: string;
|
|
@@ -6,4 +7,16 @@ export interface UrlToValidate {
|
|
|
6
7
|
label: string;
|
|
7
8
|
allowUnreachable?: boolean;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Classification → warning/error for one urlsToValidate entry. Preserves the
|
|
12
|
+
* old checkUrl output BYTE-FOR-BYTE: the two original branches built their
|
|
13
|
+
* objects with different key orders, and JSON.stringify preserves insertion
|
|
14
|
+
* order, so each branch below must keep its exact key order.
|
|
15
|
+
*
|
|
16
|
+
* 404/410 are definitively dead: an error, never overridable. Any other
|
|
17
|
+
* non-ok outcome means we could not confirm reachability (a 403 bot/WAF
|
|
18
|
+
* block, a 5xx, a timeout, a DNS hiccup); those warnings can be vouched for
|
|
19
|
+
* by hand via allowUnreachable.
|
|
20
|
+
*/
|
|
21
|
+
export declare function materializeUrlIssue(entry: UrlToValidate, outcome: UrlOutcome): ContentError | null;
|
|
22
|
+
export declare function validateUrls(urls: UrlToValidate[], cache?: UrlCache): Promise<ContentError[]>;
|
|
@@ -17,9 +17,10 @@ async function fetchWithTimeout(url, method) {
|
|
|
17
17
|
clearTimeout(timeout);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
/** Network → classification. Must match the old checkUrl decision tree exactly. */
|
|
21
|
+
async function classifyUrl(url) {
|
|
21
22
|
try {
|
|
22
|
-
let response = await fetchWithTimeout(
|
|
23
|
+
let response = await fetchWithTimeout(url, "HEAD");
|
|
23
24
|
// A HEAD that isn't a definitive answer (not OK, not a known 404/410 or
|
|
24
25
|
// rate-limit) may just mean the server rejects the HEAD method: some do so
|
|
25
26
|
// with 405, others unconventionally with 403. Retry with GET to get the true
|
|
@@ -27,56 +28,102 @@ async function checkUrl(entry) {
|
|
|
27
28
|
if (!response.ok &&
|
|
28
29
|
!NOT_FOUND_STATUSES.has(response.status) &&
|
|
29
30
|
!REACHABLE_STATUSES.has(response.status)) {
|
|
30
|
-
response = await fetchWithTimeout(
|
|
31
|
+
response = await fetchWithTimeout(url, "GET");
|
|
31
32
|
}
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
if (response.ok || REACHABLE_STATUSES.has(response.status)) {
|
|
34
|
+
return { kind: "ok" };
|
|
35
|
+
}
|
|
36
|
+
if (NOT_FOUND_STATUSES.has(response.status)) {
|
|
37
|
+
return { kind: "not_found", status: response.status };
|
|
38
|
+
}
|
|
39
|
+
return { kind: "unconfirmed", status: response.status };
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const aborted = error instanceof DOMException && error.name === "AbortError";
|
|
43
|
+
return aborted ? { kind: "timeout" } : { kind: "network_error" };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classification → warning/error for one urlsToValidate entry. Preserves the
|
|
48
|
+
* old checkUrl output BYTE-FOR-BYTE: the two original branches built their
|
|
49
|
+
* objects with different key orders, and JSON.stringify preserves insertion
|
|
50
|
+
* order, so each branch below must keep its exact key order.
|
|
51
|
+
*
|
|
52
|
+
* 404/410 are definitively dead: an error, never overridable. Any other
|
|
53
|
+
* non-ok outcome means we could not confirm reachability (a 403 bot/WAF
|
|
54
|
+
* block, a 5xx, a timeout, a DNS hiccup); those warnings can be vouched for
|
|
55
|
+
* by hand via allowUnreachable.
|
|
56
|
+
*/
|
|
57
|
+
export function materializeUrlIssue(entry, outcome) {
|
|
58
|
+
switch (outcome.kind) {
|
|
59
|
+
case "ok":
|
|
60
|
+
return null;
|
|
61
|
+
case "not_found":
|
|
62
|
+
return {
|
|
63
|
+
file: entry.file,
|
|
64
|
+
line: entry.line,
|
|
65
|
+
message: `${entry.label} returned HTTP ${outcome.status}: ${entry.url}`,
|
|
66
|
+
severity: "error",
|
|
67
|
+
};
|
|
68
|
+
case "unconfirmed":
|
|
69
|
+
if (entry.allowUnreachable)
|
|
38
70
|
return null;
|
|
39
71
|
return {
|
|
40
72
|
file: entry.file,
|
|
41
73
|
line: entry.line,
|
|
42
|
-
message: `${entry.label} returned HTTP ${
|
|
43
|
-
severity:
|
|
44
|
-
|
|
74
|
+
message: `${entry.label} returned HTTP ${outcome.status}: ${entry.url}`,
|
|
75
|
+
severity: "warning",
|
|
76
|
+
suggestion: OVERRIDE_HINT,
|
|
77
|
+
};
|
|
78
|
+
case "timeout":
|
|
79
|
+
case "network_error":
|
|
80
|
+
if (entry.allowUnreachable)
|
|
81
|
+
return null;
|
|
82
|
+
return {
|
|
83
|
+
file: entry.file,
|
|
84
|
+
line: entry.line,
|
|
85
|
+
message: outcome.kind === "timeout"
|
|
86
|
+
? `${entry.label} timed out: ${entry.url}`
|
|
87
|
+
: `${entry.label} unreachable: ${entry.url}`,
|
|
88
|
+
suggestion: OVERRIDE_HINT,
|
|
89
|
+
severity: "warning",
|
|
45
90
|
};
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
// A timeout or network failure is "could not confirm" too (our own network, a
|
|
51
|
-
// transient DNS hiccup, or a flaky host), not a definitive 404/410, so it is
|
|
52
|
-
// overridable as well.
|
|
53
|
-
if (entry.allowUnreachable)
|
|
54
|
-
return null;
|
|
55
|
-
const aborted = error instanceof DOMException && error.name === "AbortError";
|
|
56
|
-
return {
|
|
57
|
-
file: entry.file,
|
|
58
|
-
line: entry.line,
|
|
59
|
-
message: aborted
|
|
60
|
-
? `${entry.label} timed out: ${entry.url}`
|
|
61
|
-
: `${entry.label} unreachable: ${entry.url}`,
|
|
62
|
-
suggestion: OVERRIDE_HINT,
|
|
63
|
-
severity: "warning",
|
|
64
|
-
};
|
|
65
91
|
}
|
|
66
92
|
}
|
|
67
|
-
export async function validateUrls(urls) {
|
|
93
|
+
export async function validateUrls(urls, cache) {
|
|
68
94
|
if (urls.length === 0)
|
|
69
95
|
return [];
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
// Resolve one outcome per unique URL: from fresh cache where possible,
|
|
97
|
+
// otherwise over the network (batched, then written back to the cache).
|
|
98
|
+
const outcomes = new Map();
|
|
99
|
+
const toCheck = [];
|
|
100
|
+
for (const { url } of urls) {
|
|
101
|
+
if (outcomes.has(url) || toCheck.includes(url))
|
|
102
|
+
continue;
|
|
103
|
+
const cached = cache?.getFresh(url) ?? null;
|
|
104
|
+
if (cached)
|
|
105
|
+
outcomes.set(url, cached);
|
|
106
|
+
else
|
|
107
|
+
toCheck.push(url);
|
|
108
|
+
}
|
|
109
|
+
// Process in batches to avoid overwhelming servers/network. Persist after
|
|
110
|
+
// each batch so an interrupted sweep still makes durable progress.
|
|
111
|
+
for (let i = 0; i < toCheck.length; i += CONCURRENCY) {
|
|
112
|
+
const batch = toCheck.slice(i, i + CONCURRENCY);
|
|
113
|
+
const results = await Promise.all(batch.map(classifyUrl));
|
|
114
|
+
batch.forEach((url, j) => {
|
|
115
|
+
outcomes.set(url, results[j]);
|
|
116
|
+
cache?.set(url, results[j]);
|
|
117
|
+
});
|
|
118
|
+
cache?.persist();
|
|
119
|
+
}
|
|
120
|
+
// One issue per entry, in urlsToValidate entry order (output parity).
|
|
121
|
+
const issues = [];
|
|
122
|
+
for (const entry of urls) {
|
|
123
|
+
const issue = materializeUrlIssue(entry, outcomes.get(entry.url));
|
|
124
|
+
if (issue)
|
|
125
|
+
issues.push(issue);
|
|
79
126
|
}
|
|
80
|
-
return
|
|
127
|
+
return issues;
|
|
81
128
|
}
|
|
82
129
|
//# sourceMappingURL=url-reachability.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-reachability.js","sourceRoot":"","sources":["../../src/validator/url-reachability.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url-reachability.js","sourceRoot":"","sources":["../../src/validator/url-reachability.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED