@ozzylabs/feedradar 0.1.1 → 0.1.3

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.
Files changed (78) hide show
  1. package/README.ja.md +16 -5
  2. package/README.md +16 -5
  3. package/dist/agents/_boundary.d.ts +48 -1
  4. package/dist/agents/_boundary.d.ts.map +1 -1
  5. package/dist/agents/_boundary.js +65 -0
  6. package/dist/agents/_boundary.js.map +1 -1
  7. package/dist/agents/claude-code.js +3 -3
  8. package/dist/agents/claude-code.js.map +1 -1
  9. package/dist/agents/codex-cli.js +3 -3
  10. package/dist/agents/codex-cli.js.map +1 -1
  11. package/dist/agents/copilot.js +3 -3
  12. package/dist/agents/copilot.js.map +1 -1
  13. package/dist/agents/gemini-cli.js +3 -3
  14. package/dist/agents/gemini-cli.js.map +1 -1
  15. package/dist/cli/doctor.d.ts +83 -0
  16. package/dist/cli/doctor.d.ts.map +1 -0
  17. package/dist/cli/doctor.js +260 -0
  18. package/dist/cli/doctor.js.map +1 -0
  19. package/dist/cli/index.d.ts.map +1 -1
  20. package/dist/cli/index.js +2 -2
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/init.d.ts +14 -7
  23. package/dist/cli/init.d.ts.map +1 -1
  24. package/dist/cli/init.js +44 -2
  25. package/dist/cli/init.js.map +1 -1
  26. package/dist/cli/research.d.ts +10 -6
  27. package/dist/cli/research.d.ts.map +1 -1
  28. package/dist/cli/research.js +201 -35
  29. package/dist/cli/research.js.map +1 -1
  30. package/dist/cli/source.d.ts +25 -3
  31. package/dist/cli/source.d.ts.map +1 -1
  32. package/dist/cli/source.js +185 -8
  33. package/dist/cli/source.js.map +1 -1
  34. package/dist/cli/watch.d.ts +16 -0
  35. package/dist/cli/watch.d.ts.map +1 -1
  36. package/dist/cli/watch.js +3 -0
  37. package/dist/cli/watch.js.map +1 -1
  38. package/dist/core/feeds/_html-common.d.ts +30 -0
  39. package/dist/core/feeds/_html-common.d.ts.map +1 -0
  40. package/dist/core/feeds/_html-common.js +192 -0
  41. package/dist/core/feeds/_html-common.js.map +1 -0
  42. package/dist/core/feeds/html-js.d.ts +50 -0
  43. package/dist/core/feeds/html-js.d.ts.map +1 -0
  44. package/dist/core/feeds/html-js.js +135 -0
  45. package/dist/core/feeds/html-js.js.map +1 -0
  46. package/dist/core/feeds/html.d.ts +1 -7
  47. package/dist/core/feeds/html.d.ts.map +1 -1
  48. package/dist/core/feeds/html.js +25 -183
  49. package/dist/core/feeds/html.js.map +1 -1
  50. package/dist/core/feeds/index.d.ts.map +1 -1
  51. package/dist/core/feeds/index.js +2 -0
  52. package/dist/core/feeds/index.js.map +1 -1
  53. package/dist/core/feeds/rss.js +3 -3
  54. package/dist/core/feeds/rss.js.map +1 -1
  55. package/dist/core/playwright-check.d.ts +134 -0
  56. package/dist/core/playwright-check.d.ts.map +1 -0
  57. package/dist/core/playwright-check.js +98 -0
  58. package/dist/core/playwright-check.js.map +1 -0
  59. package/dist/core/templates.d.ts +10 -9
  60. package/dist/core/templates.d.ts.map +1 -1
  61. package/dist/core/templates.js +27 -12
  62. package/dist/core/templates.js.map +1 -1
  63. package/dist/core/watcher.d.ts +43 -0
  64. package/dist/core/watcher.d.ts.map +1 -1
  65. package/dist/core/watcher.js +84 -4
  66. package/dist/core/watcher.js.map +1 -1
  67. package/dist/schemas/source.d.ts +42 -0
  68. package/dist/schemas/source.d.ts.map +1 -1
  69. package/dist/schemas/source.js +42 -7
  70. package/dist/schemas/source.js.map +1 -1
  71. package/dist/schemas/state.d.ts +2 -0
  72. package/dist/schemas/state.d.ts.map +1 -1
  73. package/dist/schemas/state.js +4 -0
  74. package/dist/schemas/state.js.map +1 -1
  75. package/dist/templates/agents/AGENTS.md +4 -2
  76. package/dist/templates/digest.md +59 -0
  77. package/dist/templates/feedradar.md +4 -2
  78. package/package.json +11 -1
@@ -0,0 +1,50 @@
1
+ import type { SourceJsOptions } from "../../schemas/index.js";
2
+ import type { FeedAdapter, FeedAdapterOptions } from "./types.js";
3
+ /**
4
+ * Minimal subset of the Playwright surface this adapter uses. Defined
5
+ * structurally so the `chromium` argument passed by tests does not need to
6
+ * pull in the full Playwright type tree (which is itself an optional peer
7
+ * dep and therefore not guaranteed to be installed in dev).
8
+ */
9
+ export interface PlaywrightLike {
10
+ chromium: {
11
+ launch(options?: {
12
+ headless?: boolean;
13
+ }): Promise<PlaywrightBrowserLike>;
14
+ };
15
+ }
16
+ export interface PlaywrightBrowserLike {
17
+ newContext(options?: {
18
+ acceptDownloads?: boolean;
19
+ userAgent?: string;
20
+ }): Promise<PlaywrightContextLike>;
21
+ close(): Promise<void>;
22
+ }
23
+ export interface PlaywrightContextLike {
24
+ newPage(): Promise<PlaywrightPageLike>;
25
+ close(): Promise<void>;
26
+ }
27
+ export interface PlaywrightPageLike {
28
+ goto(url: string, options?: {
29
+ waitUntil?: SourceJsOptions["waitUntil"];
30
+ timeout?: number;
31
+ }): Promise<unknown>;
32
+ waitForSelector(selector: string, options?: {
33
+ timeout?: number;
34
+ }): Promise<unknown>;
35
+ content(): Promise<string>;
36
+ close(): Promise<void>;
37
+ }
38
+ /**
39
+ * Test-only extension to `FeedAdapterOptions` for the `html-js` adapter.
40
+ *
41
+ * Production callers leave `playwright` unset and the adapter dynamically
42
+ * imports it. Tests inject a fake module so they can exercise the adapter
43
+ * without spinning up real Chromium. The shape mirrors the subset above.
44
+ */
45
+ export interface HtmlJsAdapterOptions extends FeedAdapterOptions {
46
+ /** Injected Playwright module (tests only). Production uses dynamic import. */
47
+ playwright?: PlaywrightLike;
48
+ }
49
+ export declare const htmlJsAdapter: FeedAdapter;
50
+ //# sourceMappingURL=html-js.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-js.d.ts","sourceRoot":"","sources":["../../../src/core/feeds/html-js.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA+ClE;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE;QACR,MAAM,CAAC,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;KAC1E,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,OAAO,CAAC,EAAE;QACnB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CACF,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpF,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,+EAA+E;IAC/E,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAqBD,eAAO,MAAM,aAAa,EAAE,WAyE3B,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { contentHash, parseHtmlDocument } from "./_html-common.js";
2
+ /**
3
+ * `kind: html-js` adapter — Playwright-rendered HTML scraping (ADR-0010).
4
+ *
5
+ * Same selector contract as `kind: html` (delegates to `parseHtmlDocument`),
6
+ * but acquires the document by driving headless Chromium so SPA / CSR pages
7
+ * (Next.js, Notion embeds, Algolia DocSearch, etc.) that ship empty initial
8
+ * HTML can still be scraped.
9
+ *
10
+ * ## Hardening (ADR-0010 §D5 — hardcoded, NOT user-configurable)
11
+ *
12
+ * | Policy | Value | Rationale |
13
+ * |---------------------|----------------------|----------------------------------------------------------|
14
+ * | `headless` | `true` | UI mode is CI-incompatible and an operator-UI risk. |
15
+ * | `acceptDownloads` | `false` | Block drive-by downloads (page JS-triggered file saves). |
16
+ * | context reuse | none — fresh each fetch | Prevent SW / IndexedDB / localStorage injection persistence and cross-source state mixing. |
17
+ * | default `timeout` | 30000ms | Cap OOM / infinite loops on pathological pages. |
18
+ * | `page.close()` | in `finally` | Prevent page leak / memory accumulation. |
19
+ * | viewport | Playwright default | Avoid bloating DOM with oversized viewports. |
20
+ *
21
+ * The above are intentionally NOT exposed through `SourceJsOptions`. Users
22
+ * may tune `waitFor` / `waitUntil` / `timeout` / `userAgent`, but the threat
23
+ * model assumes the policy floor above always holds.
24
+ *
25
+ * ## Optional peer dep
26
+ *
27
+ * Playwright is declared as an *optional* peer dependency (ADR-0010 §D3) so
28
+ * users who only run `kind: rss` / `kind: html` are not forced to install
29
+ * Chromium. The import is therefore `await import("playwright")` and resolves
30
+ * lazily on the first `html-js` fetch; missing-module errors are translated
31
+ * into a user-friendly install hint.
32
+ */
33
+ /**
34
+ * Default per-step timeout in ms when `Source.js?.timeout` is omitted.
35
+ * Mirrors `SourceJsOptionsSchema`'s default so adapter-direct callers (not
36
+ * going through schema parse) still get the documented behavior.
37
+ */
38
+ const DEFAULT_TIMEOUT_MS = 30_000;
39
+ /**
40
+ * Default Playwright `page.goto()` waitUntil mode. `networkidle` is the
41
+ * safest default for SPA / CSR pages where item data arrives via XHR after
42
+ * the document has loaded.
43
+ */
44
+ const DEFAULT_WAIT_UNTIL = "networkidle";
45
+ /**
46
+ * Dynamically import Playwright. Translates the very common
47
+ * "package not installed" failure into the install hint from ADR-0010 §D3.
48
+ */
49
+ async function loadPlaywright() {
50
+ try {
51
+ // Bare specifier: resolves via the consumer project's node_modules. The
52
+ // type assertion narrows the dynamic import to the subset we use.
53
+ const mod = (await import("playwright"));
54
+ return mod;
55
+ }
56
+ catch (e) {
57
+ const message = e instanceof Error ? e.message : String(e);
58
+ throw new Error(`html-js adapter: failed to load Playwright (${message}). ` +
59
+ "Install it with: `npm i playwright && npx playwright install chromium`");
60
+ }
61
+ }
62
+ export const htmlJsAdapter = {
63
+ kind: "html-js",
64
+ fetch: async (source, options = {}) => {
65
+ if (!source.selectors) {
66
+ throw new Error(`html-js adapter: source '${source.id}' has no selectors`);
67
+ }
68
+ const selectors = source.selectors;
69
+ const js = source.js;
70
+ const timeout = js?.timeout ?? DEFAULT_TIMEOUT_MS;
71
+ const waitUntil = js?.waitUntil ?? DEFAULT_WAIT_UNTIL;
72
+ // When `waitFor` is omitted we wait for the item selector itself — the
73
+ // common "wait until the item list rendered" intent without extra config.
74
+ const waitFor = js?.waitFor ?? selectors.item;
75
+ const playwright = options.playwright ?? (await loadPlaywright());
76
+ const previous = options.state;
77
+ const fetchedAt = new Date().toISOString();
78
+ // Hardening: headless is forced true. Even if a future Playwright default
79
+ // changes, the adapter pins it explicitly here.
80
+ const browser = await playwright.chromium.launch({ headless: true });
81
+ let html;
82
+ try {
83
+ // Hardening: fresh context per fetch (no SW / IndexedDB / localStorage
84
+ // persistence across fetches or sources). `acceptDownloads: false`
85
+ // blocks drive-by download routes (page JS triggering file saves).
86
+ const context = await browser.newContext({
87
+ acceptDownloads: false,
88
+ ...(js?.userAgent ? { userAgent: js.userAgent } : {}),
89
+ });
90
+ try {
91
+ const page = await context.newPage();
92
+ try {
93
+ await page.goto(source.url, { waitUntil, timeout });
94
+ await page.waitForSelector(waitFor, { timeout });
95
+ html = await page.content();
96
+ }
97
+ finally {
98
+ // `finally` guarantees page close even on goto / waitFor timeout —
99
+ // prevents page leak / memory accumulation per ADR-0010 §D5.
100
+ await page.close();
101
+ }
102
+ }
103
+ finally {
104
+ await context.close();
105
+ }
106
+ }
107
+ finally {
108
+ await browser.close();
109
+ }
110
+ // Dedup via content hash stored in the `lastEtag` slot (same convention
111
+ // as `kind: html` — see `_html-common.ts`). Server-side ETags are not
112
+ // observable from `page.content()`, so the content hash is the only
113
+ // dedup signal available here.
114
+ const bodyHash = contentHash(html);
115
+ if (previous?.lastEtag === bodyHash) {
116
+ return {
117
+ items: [],
118
+ notModified: true,
119
+ state: {
120
+ lastFetchedAt: fetchedAt,
121
+ lastEtag: bodyHash,
122
+ },
123
+ };
124
+ }
125
+ const items = parseHtmlDocument(html, source, fetchedAt);
126
+ return {
127
+ items,
128
+ state: {
129
+ lastFetchedAt: fetchedAt,
130
+ lastEtag: bodyHash,
131
+ },
132
+ };
133
+ },
134
+ };
135
+ //# sourceMappingURL=html-js.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-js.js","sourceRoot":"","sources":["../../../src/core/feeds/html-js.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,4 @@
1
- import type { Item, Source } from "../../schemas/index.js";
2
1
  import type { FeedAdapter } from "./types.js";
3
- /**
4
- * Parse an HTML document into validated `Item[]` using the source's
5
- * `selectors`. Exported so tests can drive the parser directly without
6
- * needing a fake HTTP layer.
7
- */
8
- export declare function parseHtmlDocument(html: string, source: Source, fetchedAt: string): Item[];
2
+ export { parseHtmlDocument } from "./_html-common.js";
9
3
  export declare const htmlAdapter: FeedAdapter;
10
4
  //# sourceMappingURL=html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/core/feeds/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAmB,MAAM,wBAAwB,CAAC;AAG5E,OAAO,KAAK,EAAE,WAAW,EAAiC,MAAM,YAAY,CAAC;AA6J7E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,CAiBzF;AA+CD,eAAO,MAAM,WAAW,EAAE,WAuDzB,CAAC"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/core/feeds/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAiC,MAAM,YAAY,CAAC;AAK7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA8CtD,eAAO,MAAM,WAAW,EAAE,WAmEzB,CAAC"}
@@ -1,188 +1,15 @@
1
- import { createHash } from "node:crypto";
2
- import { parse as parseHtml } from "node-html-parser";
3
- import { ItemSchema } from "../../schemas/index.js";
4
- import { deriveItemId, deriveStableKey } from "./derive-id.js";
1
+ import { CONTENT_HASH_PREFIX, contentHash, parseHtmlDocument } from "./_html-common.js";
2
+ // Re-export shared primitives so existing imports (and tests) that pulled
3
+ // `parseHtmlDocument` from this module keep working after the
4
+ // `_html-common.ts` split (ADR-0010 §D1, no behavior change).
5
+ export { parseHtmlDocument } from "./_html-common.js";
5
6
  const USER_AGENT = "feedradar/0.0.0 (+https://github.com/ozzy-labs/feedradar)";
6
- /**
7
- * Prefix that flags an `lastEtag` slot as carrying a content hash rather than
8
- * an actual HTTP ETag. We reuse the `lastEtag` field so this Phase does not
9
- * have to migrate `SourceState` (see `docs/design/source-html.md`).
10
- */
11
- const CONTENT_HASH_PREFIX = "sha256:";
12
- /** Attributes the adapter checks before falling back to text content. */
13
- const DATETIME_ATTRS = ["datetime", "content", "value"];
14
- /**
15
- * Convert an `HTMLElement | null` to its trimmed text, or `undefined` when
16
- * the selector did not match. We always trim because raw scrapes routinely
17
- * carry surrounding whitespace from formatted markup.
18
- */
19
- function textOf(el) {
20
- if (!el)
21
- return undefined;
22
- const text = el.text?.trim();
23
- return text ? text : undefined;
24
- }
25
- /**
26
- * Apply a CSS selector relative to `root` and return the first match.
27
- * `node-html-parser` returns `null` instead of throwing for invalid input,
28
- * which matches what callers want here (a missing field, not a hard error).
29
- */
30
- function queryFirst(root, selector) {
31
- return root.querySelector(selector);
32
- }
33
- /**
34
- * Resolve the `link` selector to an `href` (or text fallback).
35
- *
36
- * Anchor tags expose the URL via `href` so we prefer the attribute. When the
37
- * selector points at a non-anchor (e.g. a `<div data-link>` wrapper used by
38
- * some changelog layouts), we fall back to text content so the adapter can
39
- * still operate, deferring URL validation to `ItemSchema`.
40
- */
41
- function pickLink(el) {
42
- if (!el)
43
- return undefined;
44
- const href = el.getAttribute("href");
45
- if (href && href.trim())
46
- return href.trim();
47
- return textOf(el);
48
- }
49
- /**
50
- * Resolve `publishedAt` to a candidate string for `new Date()`.
51
- *
52
- * `<time datetime="2026-05-12">` and `<meta content="..."/>` markup hide the
53
- * canonical timestamp in attributes; the visible text is often a
54
- * localized "May 12, 2026" that is harder to parse reliably. We probe the
55
- * known attributes first, then fall back to element text.
56
- */
57
- function pickDatetime(el) {
58
- if (!el)
59
- return undefined;
60
- for (const attr of DATETIME_ATTRS) {
61
- const value = el.getAttribute(attr);
62
- if (value && value.trim())
63
- return value.trim();
64
- }
65
- return textOf(el);
66
- }
67
- /**
68
- * Try to parse a candidate timestamp into ISO 8601. Returns `undefined` for
69
- * unparseable inputs so the item can still be emitted (RSS adapter parity).
70
- */
71
- function toIsoDate(value) {
72
- if (!value)
73
- return undefined;
74
- const date = new Date(value);
75
- if (Number.isNaN(date.getTime()))
76
- return undefined;
77
- return date.toISOString();
78
- }
79
- /** Collect the trimmed text of every match for `selector`. */
80
- function collectTags(root, selector) {
81
- if (!selector)
82
- return undefined;
83
- const tags = root
84
- .querySelectorAll(selector)
85
- .map((el) => el.text?.trim())
86
- .filter((t) => !!t && t.length > 0);
87
- return tags.length > 0 ? tags : undefined;
88
- }
89
- /**
90
- * Resolve a relative `link` against the source URL.
91
- *
92
- * Many sites publish `<a href="/changelog/foo">` rather than absolute URLs;
93
- * without resolution `ItemSchema`'s `z.string().url()` would drop them. We
94
- * intentionally swallow `URL` constructor errors so a malformed `link`
95
- * surfaces as a normal validation drop later instead of breaking the whole
96
- * fetch.
97
- */
98
- function resolveUrl(raw, base) {
99
- try {
100
- return new URL(raw, base).toString();
101
- }
102
- catch {
103
- return raw;
104
- }
105
- }
106
- /** Normalize one matched element into an Item, or `null` to drop it. */
107
- function parseItem(itemEl, selectors, source, fetchedAt) {
108
- const title = textOf(queryFirst(itemEl, selectors.title));
109
- const linkRaw = pickLink(queryFirst(itemEl, selectors.link));
110
- if (!title || !linkRaw)
111
- return null;
112
- const url = resolveUrl(linkRaw, source.url);
113
- const summary = selectors.summary ? textOf(queryFirst(itemEl, selectors.summary)) : undefined;
114
- const body = selectors.body ? textOf(queryFirst(itemEl, selectors.body)) : undefined;
115
- const publishedAt = selectors.publishedAt
116
- ? toIsoDate(pickDatetime(queryFirst(itemEl, selectors.publishedAt)))
117
- : undefined;
118
- const tags = collectTags(itemEl, selectors.tags);
119
- const stableKey = deriveStableKey({
120
- url,
121
- fallbackHashInputs: [title, publishedAt],
122
- });
123
- const id = deriveItemId(title, stableKey);
124
- // Preserve a structured snapshot of the raw scrape rather than the
125
- // `HTMLElement` instance itself — the watcher serializes `raw` to YAML and
126
- // we want the on-disk payload to be diff-friendly.
127
- const raw = { title, link: linkRaw };
128
- if (summary !== undefined)
129
- raw.summary = summary;
130
- if (body !== undefined)
131
- raw.body = body;
132
- if (publishedAt !== undefined)
133
- raw.publishedAt = publishedAt;
134
- if (tags !== undefined)
135
- raw.tags = tags;
136
- return validateItem({
137
- id,
138
- sourceId: source.id,
139
- title,
140
- url,
141
- summary,
142
- publishedAt,
143
- fetchedAt,
144
- raw,
145
- });
146
- }
147
- function validateItem(candidate) {
148
- const result = ItemSchema.safeParse(candidate);
149
- // Items that fail validation (e.g. unresolvable URL) are dropped silently —
150
- // see rss.ts for the same fail-soft rationale.
151
- return result.success ? result.data : null;
152
- }
153
- /**
154
- * Parse an HTML document into validated `Item[]` using the source's
155
- * `selectors`. Exported so tests can drive the parser directly without
156
- * needing a fake HTTP layer.
157
- */
158
- export function parseHtmlDocument(html, source, fetchedAt) {
159
- if (!source.selectors) {
160
- throw new Error(`html adapter: source '${source.id}' has no selectors`);
161
- }
162
- const selectors = source.selectors;
163
- let root;
164
- try {
165
- root = parseHtml(html);
166
- }
167
- catch (e) {
168
- throw new Error(`html adapter: failed to parse HTML: ${e instanceof Error ? e.message : String(e)}`);
169
- }
170
- const itemEls = root.querySelectorAll(selectors.item);
171
- return itemEls
172
- .map((el) => parseItem(el, selectors, source, fetchedAt))
173
- .filter((i) => i !== null);
174
- }
175
- /**
176
- * Compute the sha256 of the raw response body, prefixed so callers can tell
177
- * it apart from a real ETag inside `SourceState.lastEtag`.
178
- */
179
- function contentHash(body) {
180
- return `${CONTENT_HASH_PREFIX}${createHash("sha256").update(body).digest("hex")}`;
181
- }
182
7
  /**
183
8
  * Issue an HTTP GET with conditional headers. The previous `lastEtag` slot
184
9
  * may contain either an actual ETag (mirror RSS behavior) or a `sha256:`
185
- * content hash; we only forward real ETags as `If-None-Match`.
10
+ * content hash; we only forward real ETags as `If-None-Match`. A stored
11
+ * `lastModified` (RFC 1123 string from the server) is echoed back as
12
+ * `If-Modified-Since` so well-behaved static sites can reply 304.
186
13
  */
187
14
  async function fetchHtml(url, fetchImpl, options = {}) {
188
15
  const headers = {
@@ -195,16 +22,19 @@ async function fetchHtml(url, fetchImpl, options = {}) {
195
22
  if (options.etag && !options.etag.startsWith(CONTENT_HASH_PREFIX)) {
196
23
  headers["if-none-match"] = options.etag;
197
24
  }
25
+ if (options.lastModified)
26
+ headers["if-modified-since"] = options.lastModified;
198
27
  const response = await fetchImpl(url, { headers, signal: options.signal });
199
28
  const etag = response.headers.get("etag");
29
+ const lastModified = response.headers.get("last-modified");
200
30
  if (response.status === 304) {
201
- return { status: 304, body: "", etag };
31
+ return { status: 304, body: "", etag, lastModified };
202
32
  }
203
33
  if (response.status < 200 || response.status >= 300) {
204
34
  throw new Error(`html adapter: HTTP ${response.status} from ${url}`);
205
35
  }
206
36
  const body = await response.text();
207
- return { status: response.status, body, etag };
37
+ return { status: response.status, body, etag, lastModified };
208
38
  }
209
39
  export const htmlAdapter = {
210
40
  kind: "html",
@@ -220,6 +50,7 @@ export const htmlAdapter = {
220
50
  const fetchedAt = new Date().toISOString();
221
51
  const response = await fetchHtml(source.url, fetchImpl, {
222
52
  etag: previous?.lastEtag,
53
+ lastModified: previous?.lastModified,
223
54
  });
224
55
  if (response.status === 304) {
225
56
  return {
@@ -230,6 +61,9 @@ export const htmlAdapter = {
230
61
  // Preserve whatever marker we had — server may not echo the ETag
231
62
  // back on 304, in which case we keep the previous content hash too.
232
63
  lastEtag: response.etag ?? previous?.lastEtag,
64
+ // Last-Modified is typically NOT re-sent on 304, so fall back to the
65
+ // previously stored value so the next request can still echo it.
66
+ lastModified: response.lastModified ?? previous?.lastModified,
233
67
  },
234
68
  };
235
69
  }
@@ -245,6 +79,10 @@ export const htmlAdapter = {
245
79
  state: {
246
80
  lastFetchedAt: fetchedAt,
247
81
  lastEtag: bodyHash,
82
+ // Refresh `lastModified` when the server provided one this time,
83
+ // otherwise keep the previous value so future requests still send
84
+ // a meaningful `If-Modified-Since`.
85
+ lastModified: response.lastModified ?? previous?.lastModified,
248
86
  },
249
87
  };
250
88
  }
@@ -256,6 +94,10 @@ export const htmlAdapter = {
256
94
  // Prefer the real ETag when the server provides one; otherwise stash
257
95
  // the content hash in the same slot for next-run dedup.
258
96
  lastEtag: response.etag ?? bodyHash,
97
+ // Persist the server's `Last-Modified` (RFC 1123 string, opaque) so
98
+ // we can echo it back as `If-Modified-Since` on the next run. Keep
99
+ // the previous value when the server omitted the header.
100
+ lastModified: response.lastModified ?? previous?.lastModified,
259
101
  },
260
102
  };
261
103
  },
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/core/feeds/html.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/core/feeds/html.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/feeds/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAKrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,WAAW,CAMhE;AAED,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/feeds/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAMrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAU9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,WAAW,CAMhE;AAED,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -1,10 +1,12 @@
1
1
  import { githubReleasesAdapter } from "./github-releases.js";
2
2
  import { htmlAdapter } from "./html.js";
3
+ import { htmlJsAdapter } from "./html-js.js";
3
4
  import { npmRegistryAdapter } from "./npm-registry.js";
4
5
  import { rssAdapter } from "./rss.js";
5
6
  const adapters = new Map([
6
7
  [rssAdapter.kind, rssAdapter],
7
8
  [htmlAdapter.kind, htmlAdapter],
9
+ [htmlJsAdapter.kind, htmlJsAdapter],
8
10
  [githubReleasesAdapter.kind, githubReleasesAdapter],
9
11
  [npmRegistryAdapter.kind, npmRegistryAdapter],
10
12
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/feeds/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAA8B;IACpD,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC;IAC7B,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;IAC/B,CAAC,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACnD,CAAC,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,CAAC;CAC9C,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/feeds/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAA8B;IACpD,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC;IAC7B,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;IAC/B,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC;IACnC,CAAC,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACnD,CAAC,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,CAAC;CAC9C,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -195,9 +195,7 @@ export const rssAdapter = {
195
195
  const fetchedAt = new Date().toISOString();
196
196
  const response = await fetchFeed(source.url, fetchImpl, {
197
197
  etag: previous?.lastEtag,
198
- // We do not currently persist Last-Modified separately; ETag suffices
199
- // for the well-behaved feed publishers we target. If a publisher only
200
- // exposes Last-Modified we will revisit (issue #13 follow-up).
198
+ lastModified: previous?.lastModified,
201
199
  });
202
200
  if (response.status === 304) {
203
201
  return {
@@ -206,6 +204,7 @@ export const rssAdapter = {
206
204
  state: {
207
205
  lastFetchedAt: fetchedAt,
208
206
  lastEtag: response.etag ?? previous?.lastEtag,
207
+ lastModified: response.lastModified ?? previous?.lastModified,
209
208
  },
210
209
  };
211
210
  }
@@ -215,6 +214,7 @@ export const rssAdapter = {
215
214
  state: {
216
215
  lastFetchedAt: fetchedAt,
217
216
  lastEtag: response.etag ?? previous?.lastEtag,
217
+ lastModified: response.lastModified ?? previous?.lastModified,
218
218
  },
219
219
  };
220
220
  },
@@ -1 +1 @@
1
- {"version":3,"file":"rss.js","sourceRoot":"","sources":["../../../src/core/feeds/rss.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rss.js","sourceRoot":"","sources":["../../../src/core/feeds/rss.ts"],"names":[],"mappings":"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"}