feedscout 0.9.0 → 1.0.0-beta.2

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 (113) hide show
  1. package/README.md +93 -77
  2. package/dist/adapters.cjs +6 -0
  3. package/dist/adapters.d.cts +2 -0
  4. package/dist/adapters.d.ts +2 -0
  5. package/dist/adapters.js +3 -0
  6. package/dist/blogrolls/defaults.cjs +53 -0
  7. package/dist/blogrolls/defaults.d.cts +17 -0
  8. package/dist/blogrolls/defaults.d.ts +17 -0
  9. package/dist/blogrolls/defaults.js +44 -0
  10. package/dist/blogrolls/extractors.cjs +24 -0
  11. package/dist/blogrolls/extractors.d.cts +7 -0
  12. package/dist/blogrolls/extractors.d.ts +7 -0
  13. package/dist/blogrolls/extractors.js +24 -0
  14. package/dist/blogrolls/index.cjs +22 -0
  15. package/dist/blogrolls/index.d.cts +7 -0
  16. package/dist/blogrolls/index.d.ts +7 -0
  17. package/dist/blogrolls/index.js +22 -0
  18. package/dist/blogrolls/types.d.cts +6 -0
  19. package/dist/blogrolls/types.d.ts +6 -0
  20. package/dist/blogrolls.cjs +13 -0
  21. package/dist/blogrolls.d.cts +4 -0
  22. package/dist/blogrolls.d.ts +4 -0
  23. package/dist/blogrolls.js +4 -0
  24. package/dist/common/discover/adapters.cjs +76 -0
  25. package/dist/common/discover/adapters.d.cts +10 -0
  26. package/dist/common/discover/adapters.d.ts +10 -0
  27. package/dist/common/discover/adapters.js +72 -0
  28. package/dist/common/discover/index.cjs +54 -0
  29. package/dist/common/discover/index.js +54 -0
  30. package/dist/common/discover/utils.cjs +63 -0
  31. package/dist/common/discover/utils.js +62 -0
  32. package/dist/common/locales.cjs +15 -0
  33. package/dist/common/locales.js +9 -0
  34. package/dist/common/types.d.cts +93 -2
  35. package/dist/common/types.d.ts +93 -2
  36. package/dist/common/uris/guess/index.cjs +10 -0
  37. package/dist/common/uris/guess/index.d.cts +6 -0
  38. package/dist/common/uris/guess/index.d.ts +6 -0
  39. package/dist/common/uris/guess/index.js +10 -0
  40. package/dist/common/uris/guess/types.d.cts +29 -0
  41. package/dist/common/uris/guess/types.d.ts +29 -0
  42. package/dist/common/uris/guess/utils.cjs +89 -0
  43. package/dist/common/uris/guess/utils.d.cts +57 -0
  44. package/dist/common/uris/guess/utils.d.ts +57 -0
  45. package/dist/common/uris/guess/utils.js +86 -0
  46. package/dist/common/uris/headers/index.cjs +24 -0
  47. package/dist/common/uris/headers/index.d.cts +6 -0
  48. package/dist/common/uris/headers/index.d.ts +6 -0
  49. package/dist/common/uris/headers/index.js +24 -0
  50. package/dist/common/uris/headers/types.d.cts +9 -0
  51. package/dist/common/uris/headers/types.d.ts +9 -0
  52. package/dist/common/uris/html/handlers.cjs +47 -0
  53. package/dist/{utils-BVlxsJfJ.js → common/uris/html/handlers.js} +10 -12
  54. package/dist/common/uris/html/index.cjs +21 -0
  55. package/dist/common/uris/html/index.d.cts +6 -0
  56. package/dist/common/uris/html/index.d.ts +6 -0
  57. package/dist/common/uris/html/index.js +21 -0
  58. package/dist/common/uris/html/types.d.cts +12 -0
  59. package/dist/common/uris/html/types.d.ts +12 -0
  60. package/dist/common/uris/index.cjs +15 -0
  61. package/dist/common/uris/index.js +15 -0
  62. package/dist/common/utils.cjs +56 -6
  63. package/dist/common/utils.js +51 -2
  64. package/dist/feeds/defaults.cjs +89 -0
  65. package/dist/feeds/defaults.d.cts +18 -0
  66. package/dist/feeds/defaults.d.ts +18 -0
  67. package/dist/feeds/defaults.js +79 -0
  68. package/dist/feeds/extractors.cjs +46 -0
  69. package/dist/feeds/extractors.d.cts +7 -0
  70. package/dist/feeds/extractors.d.ts +7 -0
  71. package/dist/feeds/extractors.js +46 -0
  72. package/dist/feeds/index.cjs +22 -0
  73. package/dist/feeds/index.d.cts +7 -0
  74. package/dist/feeds/index.d.ts +7 -0
  75. package/dist/feeds/index.js +22 -0
  76. package/dist/feeds/types.d.cts +10 -0
  77. package/dist/feeds/types.d.ts +10 -0
  78. package/dist/feeds.cjs +14 -0
  79. package/dist/feeds.d.cts +4 -0
  80. package/dist/feeds.d.ts +4 -0
  81. package/dist/feeds.js +4 -0
  82. package/dist/hubs/discover/index.cjs +32 -0
  83. package/dist/hubs/discover/index.d.cts +7 -0
  84. package/dist/hubs/discover/index.d.ts +7 -0
  85. package/dist/hubs/discover/index.js +32 -0
  86. package/dist/hubs/discover/types.d.cts +14 -0
  87. package/dist/hubs/discover/types.d.ts +14 -0
  88. package/dist/hubs/discover/utils.cjs +20 -0
  89. package/dist/hubs/discover/utils.js +19 -0
  90. package/dist/hubs/feed/index.cjs +32 -0
  91. package/dist/hubs/feed/index.js +32 -0
  92. package/dist/hubs/headers/index.cjs +19 -0
  93. package/dist/hubs/headers/index.js +19 -0
  94. package/dist/hubs/html/index.cjs +30 -0
  95. package/dist/hubs/html/index.js +30 -0
  96. package/dist/hubs.d.cts +2 -0
  97. package/dist/hubs.d.ts +2 -0
  98. package/dist/index.cjs +6 -44
  99. package/dist/index.d.cts +6 -6
  100. package/dist/index.d.ts +6 -6
  101. package/dist/index.js +4 -20
  102. package/dist/methods.cjs +11 -0
  103. package/dist/methods.d.cts +5 -0
  104. package/dist/methods.d.ts +5 -0
  105. package/dist/methods.js +6 -0
  106. package/package.json +52 -16
  107. package/dist/common/utils.d.cts +0 -13
  108. package/dist/common/utils.d.ts +0 -13
  109. package/dist/types-B0jVPx9s.d.ts +0 -17
  110. package/dist/types-BZOn_2Ua.d.cts +0 -17
  111. package/dist/utils-DsxN2_bI.cjs +0 -79
  112. /package/dist/{common/types.cjs → hubs.cjs} +0 -0
  113. /package/dist/{common/types.js → hubs.js} +0 -0
package/README.md CHANGED
@@ -4,110 +4,126 @@
4
4
  [![npm version](https://img.shields.io/npm/v/feedscout.svg)](https://www.npmjs.com/package/feedscout)
5
5
  [![license](https://img.shields.io/npm/l/feedscout.svg)](https://github.com/macieklamberski/feedscout/blob/main/LICENSE)
6
6
 
7
- Lightweight feed autodiscovery for TypeScript. Extract RSS, Atom, and JSON feed URIs from HTML with configurable options.
7
+ Advanced feed autodiscovery for JavaScript. Collect feeds from webpages using multiple discovery methods.
8
8
 
9
- > **Work in Progress:** This library is under active development. The API may change before reaching v1.0.
9
+ **[Read full docs ↗](https://feedscout.dev)**
10
+   ·  
11
+ [Quick Start](#quick-start)
12
+
13
+ ---
10
14
 
11
15
  ## Overview
12
16
 
13
- Feedscout makes it easy to gather all feed URIs from a webpage. It implements multiple discovery strategies:
17
+ Feedscout makes it easy to discover feeds from webpages using multiple methods.
18
+
19
+ ### HTML Discovery
20
+
21
+ Extracts feed URIs from HTML content using multiple strategies:
22
+
23
+ - **Link elements** — `<link rel="alternate">` with feed MIME types and `<link rel="feed">` elements
24
+ - **Anchor elements** — `<a href="…">` matching `/feed`, `/rss.xml` or containing "RSS", "Subscribe", etc.
25
+
26
+ This method uses [htmlparser2](https://github.com/fb55/htmlparser2) for efficient parsing. Follows [RSS Board](https://www.rssboard.org/rss-autodiscovery) and [WHATWG](https://blog.whatwg.org/feed-autodiscovery) specs.
14
27
 
15
- - **Standard autodiscovery** — `<link rel="alternate">` with feed MIME types
16
- - **HTML5 feeds** — `<link rel="feed">` elements
17
- - **Anchor patterns** — Links matching `/feed`, `/rss.xml`, etc.
18
- - **Anchor text** — Links containing "RSS", "Subscribe", etc.
28
+ ### HTTP Headers Discovery
19
29
 
20
- The library uses [htmlparser2](https://github.com/fb55/htmlparser2) for efficient HTML parsing with low memory footprint (streaming support on the roadmap).
30
+ Parses HTTP `Link` headers for `rel="alternate"` with feed MIME types per [RFC 8288](https://www.rfc-editor.org/rfc/rfc8288). Useful when feeds are advertised via HTTP headers rather than HTML metadata.
21
31
 
22
- Implementation follows [RSS Board](https://www.rssboard.org/rss-autodiscovery), [WHATWG](https://blog.whatwg.org/feed-autodiscovery), and [historical best practices](https://web.archive.org/web/20100620085023/http://diveintomark.org/archives/2002/08/15/ultraliberal_rss_locator) for feed autodiscovery.
32
+ ### Guess Method
23
33
 
24
- ## Installation
34
+ Tests common feed paths (`/feed`, `/rss.xml`, `/atom.xml`, etc.) against the base URL. Useful as fallback when other methods fail.
35
+
36
+ ## Quick Start
25
37
 
26
38
  ```bash
27
39
  npm install feedscout
28
40
  ```
29
41
 
30
- ## Usage
42
+ ### Basic Usage
31
43
 
32
- ```typescript
33
- import { discoverFeedUris } from 'feedscout'
34
-
35
- const html = `
36
- <html>
37
- <head>
38
- <link rel="alternate" type="application/rss+xml" href="/feed.xml" />
39
- </head>
40
- <body>
41
- <a href="/rss">RSS Feed</a>
42
- </body>
43
- </html>
44
- `
45
-
46
- const uris = discoverFeedUris(html, {
47
- linkMimeTypes: ['application/rss+xml', 'application/atom+xml'],
48
- anchorUris: ['/feed', '/rss', '/rss.xml'],
49
- anchorIgnoredUris: ['wp-json/', 'comments'],
50
- anchorLabels: ['rss', 'feed', 'subscribe'],
51
- })
44
+ Given HTML content on https://example.com:
52
45
 
53
- console.log(uris) // ['/feed.xml', '/rss']
46
+ ```html
47
+ <html>
48
+ <head>
49
+ <link rel="alternate" type="application/rss+xml" href="/feed.xml" />
50
+ </head>
51
+ <body>
52
+ <a href="/rss">RSS Feed</a>
53
+ </body>
54
+ </html>
54
55
  ```
55
56
 
56
- Returned URIs may be relative. Resolve to absolute URLs using new URL(uri, baseUrl).
57
+ Feedscout discovers and extracts feeds data:
57
58
 
58
- Identical URIs are deduplicated, but variations like http:// vs https:// are preserved.
59
+ ```typescript
60
+ import { discoverFeeds } from 'feedscout'
59
61
 
60
- ## API Reference
62
+ const feeds = await discoverFeeds(
63
+ { url: 'https://example.com', content: html },
64
+ { methods: ['html', 'guess'] },
65
+ )
61
66
 
62
- ### `discoverFeedUris(html, options)`
67
+ // [{ url: 'https://example.com/feed.xml', isValid: true, format: 'rss', title: '...' }]
68
+ ```
63
69
 
64
- Discovers feed URIs from HTML content.
70
+ By default, native `fetch()` is used. For projects using other HTTP libraries, adapters are available:
65
71
 
66
- | Parameter | Type | Required | Description |
67
- |-----------|------|----------|-------------|
68
- | `html` | `string` | Yes | HTML content to parse |
69
- | `options` | `DiscoverFeedUrisOptions` | Yes | Discovery configuration |
72
+ ```typescript
73
+ import axios from 'axios'
74
+ import { createAxiosAdapter } from 'feedscout/adapters'
70
75
 
71
- **Returns:** `string[]` Array of discovered feed URIs (may be relative)
76
+ const feeds = await discoverFeeds(input, {
77
+ methods: ['html', 'guess'],
78
+ fetchFn: createAxiosAdapter(axios),
79
+ })
80
+ ```
72
81
 
73
- ### `DiscoverFeedUrisOptions`
82
+ | Adapter | Library |
83
+ |---------|---------|
84
+ | `createNativeFetchAdapter` | Native `fetch` (default) |
85
+ | `createAxiosAdapter` | [axios](https://axios-http.com) |
86
+ | `createGotAdapter` | [got](https://github.com/sindresorhus/got) |
87
+ | `createKyAdapter` | [ky](https://github.com/sindresorhus/ky) |
74
88
 
75
- All options are **required**. Configure each discovery strategy explicitly.
76
89
 
77
- | Property | Type | Description |
78
- |----------|------|-------------|
79
- | `linkMimeTypes` | `string[]` | MIME types to match in `<link type="...">` attributes |
80
- | `anchorUris` | `string[]` | URI patterns to match in anchor `href` attributes |
81
- | `anchorIgnoredUris` | `string[]` | URI patterns to exclude from anchor matching |
82
- | `anchorLabels` | `string[]` | Text patterns to match in anchor content (case-insensitive) |
90
+ ### Using Existing Response Data
83
91
 
84
- **Example configuration:**
92
+ If you already have the response, you can provide it directly instead of fetching the data again:
85
93
 
86
94
  ```typescript
87
- const options: DiscoverFeedUrisOptions = {
88
- linkMimeTypes: [
89
- 'application/rss+xml',
90
- 'application/atom+xml',
91
- 'application/json',
92
- 'application/feed+json',
93
- ],
94
- anchorUris: [
95
- '/feed',
96
- '/rss',
97
- '/rss.xml',
98
- '/atom.xml',
99
- '?feed=rss',
100
- ],
101
- anchorIgnoredUris: [
102
- 'wp-json/',
103
- 'comments',
104
- 'twitter.com',
105
- ],
106
- anchorLabels: [
107
- 'rss',
108
- 'feed',
109
- 'atom',
110
- 'subscribe',
111
- ],
112
- }
95
+ const feeds = await discoverFeeds(
96
+ {
97
+ url: 'https://example.com',
98
+ content: htmlContent,
99
+ headers: responseHeaders,
100
+ },
101
+ {
102
+ methods: ['html', 'headers', 'guess'],
103
+ },
104
+ )
113
105
  ```
106
+
107
+ ### Custom Options with Object Syntax
108
+
109
+ If you want more control over what types of links, anchors or labels are treated as feeds, use object syntax to customize method options:
110
+
111
+ ```typescript
112
+ const feeds = await discoverFeeds('https://example.com', {
113
+ methods: {
114
+ html: {
115
+ anchorLabels: ['rss', 'feed', 'subscribe'],
116
+ anchorUris: ['/feed', '/rss'],
117
+ },
118
+ headers: true, // Use defaults
119
+ guess: {
120
+ uris: ['/custom-feed', '/blog/rss'],
121
+ },
122
+ },
123
+ concurrency: 5,
124
+ stopOnFirst: true,
125
+ }
126
+ )
127
+ ```
128
+
129
+ For all available options, [visit the reference page in documentation ↗](https://feedscout.dev).
@@ -0,0 +1,6 @@
1
+ const require_adapters = require('./common/discover/adapters.cjs');
2
+
3
+ exports.createAxiosAdapter = require_adapters.createAxiosAdapter;
4
+ exports.createGotAdapter = require_adapters.createGotAdapter;
5
+ exports.createKyAdapter = require_adapters.createKyAdapter;
6
+ exports.createNativeFetchAdapter = require_adapters.createNativeFetchAdapter;
@@ -0,0 +1,2 @@
1
+ import { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter } from "./common/discover/adapters.cjs";
2
+ export { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter };
@@ -0,0 +1,2 @@
1
+ import { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter } from "./common/discover/adapters.js";
2
+ export { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter };
@@ -0,0 +1,3 @@
1
+ import { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter } from "./common/discover/adapters.js";
2
+
3
+ export { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter };
@@ -0,0 +1,53 @@
1
+
2
+ //#region src/blogrolls/defaults.ts
3
+ const opmlMimeTypes = [
4
+ "text/x-opml",
5
+ "application/xml",
6
+ "text/xml"
7
+ ];
8
+ const blogrollUrisMinimal = [
9
+ "/.well-known/recommendations.opml",
10
+ "/blogroll.opml",
11
+ "/opml.xml"
12
+ ];
13
+ const blogrollUrisBalanced = [
14
+ ...blogrollUrisMinimal,
15
+ "/blogroll.xml",
16
+ "/subscriptions.opml",
17
+ "/recommendations.opml"
18
+ ];
19
+ const blogrollUrisComprehensive = [
20
+ ...blogrollUrisBalanced,
21
+ "/links.opml",
22
+ "/feeds.opml",
23
+ "/subscriptions.xml"
24
+ ];
25
+ const anchorLabels = [
26
+ "blogroll",
27
+ "opml",
28
+ "subscriptions",
29
+ "reading list"
30
+ ];
31
+ const linkSelectors = [{ rel: "blogroll" }, {
32
+ rel: "outline",
33
+ types: opmlMimeTypes
34
+ }];
35
+ const defaultHtmlOptions = {
36
+ linkSelectors,
37
+ anchorUris: blogrollUrisComprehensive,
38
+ anchorIgnoredUris: [],
39
+ anchorLabels
40
+ };
41
+ const defaultHeadersOptions = { linkSelectors };
42
+ const defaultGuessOptions = { uris: blogrollUrisBalanced };
43
+
44
+ //#endregion
45
+ exports.anchorLabels = anchorLabels;
46
+ exports.blogrollUrisBalanced = blogrollUrisBalanced;
47
+ exports.blogrollUrisComprehensive = blogrollUrisComprehensive;
48
+ exports.blogrollUrisMinimal = blogrollUrisMinimal;
49
+ exports.defaultGuessOptions = defaultGuessOptions;
50
+ exports.defaultHeadersOptions = defaultHeadersOptions;
51
+ exports.defaultHtmlOptions = defaultHtmlOptions;
52
+ exports.linkSelectors = linkSelectors;
53
+ exports.opmlMimeTypes = opmlMimeTypes;
@@ -0,0 +1,17 @@
1
+ import { GuessMethodOptions } from "../common/uris/guess/types.cjs";
2
+ import { HeadersMethodOptions } from "../common/uris/headers/types.cjs";
3
+ import { HtmlMethodOptions } from "../common/uris/html/types.cjs";
4
+ import { LinkSelector } from "../common/types.cjs";
5
+
6
+ //#region src/blogrolls/defaults.d.ts
7
+ declare const opmlMimeTypes: string[];
8
+ declare const blogrollUrisMinimal: string[];
9
+ declare const blogrollUrisBalanced: string[];
10
+ declare const blogrollUrisComprehensive: string[];
11
+ declare const anchorLabels: string[];
12
+ declare const linkSelectors: Array<LinkSelector>;
13
+ declare const defaultHtmlOptions: Omit<HtmlMethodOptions, 'baseUrl'>;
14
+ declare const defaultHeadersOptions: Omit<HeadersMethodOptions, 'baseUrl'>;
15
+ declare const defaultGuessOptions: Omit<GuessMethodOptions, 'baseUrl'>;
16
+ //#endregion
17
+ export { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,17 @@
1
+ import { GuessMethodOptions } from "../common/uris/guess/types.js";
2
+ import { HeadersMethodOptions } from "../common/uris/headers/types.js";
3
+ import { HtmlMethodOptions } from "../common/uris/html/types.js";
4
+ import { LinkSelector } from "../common/types.js";
5
+
6
+ //#region src/blogrolls/defaults.d.ts
7
+ declare const opmlMimeTypes: string[];
8
+ declare const blogrollUrisMinimal: string[];
9
+ declare const blogrollUrisBalanced: string[];
10
+ declare const blogrollUrisComprehensive: string[];
11
+ declare const anchorLabels: string[];
12
+ declare const linkSelectors: Array<LinkSelector>;
13
+ declare const defaultHtmlOptions: Omit<HtmlMethodOptions, 'baseUrl'>;
14
+ declare const defaultHeadersOptions: Omit<HeadersMethodOptions, 'baseUrl'>;
15
+ declare const defaultGuessOptions: Omit<GuessMethodOptions, 'baseUrl'>;
16
+ //#endregion
17
+ export { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,44 @@
1
+ //#region src/blogrolls/defaults.ts
2
+ const opmlMimeTypes = [
3
+ "text/x-opml",
4
+ "application/xml",
5
+ "text/xml"
6
+ ];
7
+ const blogrollUrisMinimal = [
8
+ "/.well-known/recommendations.opml",
9
+ "/blogroll.opml",
10
+ "/opml.xml"
11
+ ];
12
+ const blogrollUrisBalanced = [
13
+ ...blogrollUrisMinimal,
14
+ "/blogroll.xml",
15
+ "/subscriptions.opml",
16
+ "/recommendations.opml"
17
+ ];
18
+ const blogrollUrisComprehensive = [
19
+ ...blogrollUrisBalanced,
20
+ "/links.opml",
21
+ "/feeds.opml",
22
+ "/subscriptions.xml"
23
+ ];
24
+ const anchorLabels = [
25
+ "blogroll",
26
+ "opml",
27
+ "subscriptions",
28
+ "reading list"
29
+ ];
30
+ const linkSelectors = [{ rel: "blogroll" }, {
31
+ rel: "outline",
32
+ types: opmlMimeTypes
33
+ }];
34
+ const defaultHtmlOptions = {
35
+ linkSelectors,
36
+ anchorUris: blogrollUrisComprehensive,
37
+ anchorIgnoredUris: [],
38
+ anchorLabels
39
+ };
40
+ const defaultHeadersOptions = { linkSelectors };
41
+ const defaultGuessOptions = { uris: blogrollUrisBalanced };
42
+
43
+ //#endregion
44
+ export { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,24 @@
1
+ let feedsmith = require("feedsmith");
2
+
3
+ //#region src/blogrolls/extractors.ts
4
+ const feedsmithExtractor = async ({ content, url }) => {
5
+ if (!content) return {
6
+ url,
7
+ isValid: false
8
+ };
9
+ try {
10
+ return {
11
+ url,
12
+ isValid: true,
13
+ title: (0, feedsmith.parseOpml)(content).head?.title
14
+ };
15
+ } catch {
16
+ return {
17
+ url,
18
+ isValid: false
19
+ };
20
+ }
21
+ };
22
+
23
+ //#endregion
24
+ exports.feedsmithExtractor = feedsmithExtractor;
@@ -0,0 +1,7 @@
1
+ import { DiscoverExtractFn } from "../common/types.cjs";
2
+ import { BlogrollResultValid } from "./types.cjs";
3
+
4
+ //#region src/blogrolls/extractors.d.ts
5
+ declare const feedsmithExtractor: DiscoverExtractFn<BlogrollResultValid>;
6
+ //#endregion
7
+ export { feedsmithExtractor };
@@ -0,0 +1,7 @@
1
+ import { DiscoverExtractFn } from "../common/types.js";
2
+ import { BlogrollResultValid } from "./types.js";
3
+
4
+ //#region src/blogrolls/extractors.d.ts
5
+ declare const feedsmithExtractor: DiscoverExtractFn<BlogrollResultValid>;
6
+ //#endregion
7
+ export { feedsmithExtractor };
@@ -0,0 +1,24 @@
1
+ import { parseOpml } from "feedsmith";
2
+
3
+ //#region src/blogrolls/extractors.ts
4
+ const feedsmithExtractor = async ({ content, url }) => {
5
+ if (!content) return {
6
+ url,
7
+ isValid: false
8
+ };
9
+ try {
10
+ return {
11
+ url,
12
+ isValid: true,
13
+ title: parseOpml(content).head?.title
14
+ };
15
+ } catch {
16
+ return {
17
+ url,
18
+ isValid: false
19
+ };
20
+ }
21
+ };
22
+
23
+ //#endregion
24
+ export { feedsmithExtractor };
@@ -0,0 +1,22 @@
1
+ const require_adapters = require('../common/discover/adapters.cjs');
2
+ const require_utils = require('../common/utils.cjs');
3
+ const require_index = require('../common/discover/index.cjs');
4
+ const require_defaults = require('./defaults.cjs');
5
+ const require_extractors = require('./extractors.cjs');
6
+
7
+ //#region src/blogrolls/index.ts
8
+ const discoverBlogrolls = async (input, options) => {
9
+ return require_index.discover(input, {
10
+ ...options,
11
+ fetchFn: options.fetchFn ?? require_adapters.createNativeFetchAdapter(),
12
+ extractFn: options.extractFn ?? require_extractors.feedsmithExtractor,
13
+ normalizeUrlFn: options.normalizeUrlFn ?? require_utils.normalizeUrl
14
+ }, {
15
+ html: require_defaults.defaultHtmlOptions,
16
+ headers: require_defaults.defaultHeadersOptions,
17
+ guess: require_defaults.defaultGuessOptions
18
+ });
19
+ };
20
+
21
+ //#endregion
22
+ exports.discoverBlogrolls = discoverBlogrolls;
@@ -0,0 +1,7 @@
1
+ import { DiscoverInput, DiscoverOptions, DiscoverResult } from "../common/types.cjs";
2
+ import { BlogrollResultValid } from "./types.cjs";
3
+
4
+ //#region src/blogrolls/index.d.ts
5
+ declare const discoverBlogrolls: <TValid extends BlogrollResultValid = BlogrollResultValid>(input: DiscoverInput, options: DiscoverOptions<TValid>) => Promise<Array<DiscoverResult<TValid>>>;
6
+ //#endregion
7
+ export { discoverBlogrolls };
@@ -0,0 +1,7 @@
1
+ import { DiscoverInput, DiscoverOptions, DiscoverResult } from "../common/types.js";
2
+ import { BlogrollResultValid } from "./types.js";
3
+
4
+ //#region src/blogrolls/index.d.ts
5
+ declare const discoverBlogrolls: <TValid extends BlogrollResultValid = BlogrollResultValid>(input: DiscoverInput, options: DiscoverOptions<TValid>) => Promise<Array<DiscoverResult<TValid>>>;
6
+ //#endregion
7
+ export { discoverBlogrolls };
@@ -0,0 +1,22 @@
1
+ import { createNativeFetchAdapter } from "../common/discover/adapters.js";
2
+ import { normalizeUrl } from "../common/utils.js";
3
+ import { discover } from "../common/discover/index.js";
4
+ import { defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions } from "./defaults.js";
5
+ import { feedsmithExtractor } from "./extractors.js";
6
+
7
+ //#region src/blogrolls/index.ts
8
+ const discoverBlogrolls = async (input, options) => {
9
+ return discover(input, {
10
+ ...options,
11
+ fetchFn: options.fetchFn ?? createNativeFetchAdapter(),
12
+ extractFn: options.extractFn ?? feedsmithExtractor,
13
+ normalizeUrlFn: options.normalizeUrlFn ?? normalizeUrl
14
+ }, {
15
+ html: defaultHtmlOptions,
16
+ headers: defaultHeadersOptions,
17
+ guess: defaultGuessOptions
18
+ });
19
+ };
20
+
21
+ //#endregion
22
+ export { discoverBlogrolls };
@@ -0,0 +1,6 @@
1
+ //#region src/blogrolls/types.d.ts
2
+ type BlogrollResultValid = {
3
+ title?: string;
4
+ };
5
+ //#endregion
6
+ export { BlogrollResultValid };
@@ -0,0 +1,6 @@
1
+ //#region src/blogrolls/types.d.ts
2
+ type BlogrollResultValid = {
3
+ title?: string;
4
+ };
5
+ //#endregion
6
+ export { BlogrollResultValid };
@@ -0,0 +1,13 @@
1
+ const require_defaults = require('./blogrolls/defaults.cjs');
2
+ const require_extractors = require('./blogrolls/extractors.cjs');
3
+
4
+ exports.anchorLabels = require_defaults.anchorLabels;
5
+ exports.blogrollUrisBalanced = require_defaults.blogrollUrisBalanced;
6
+ exports.blogrollUrisComprehensive = require_defaults.blogrollUrisComprehensive;
7
+ exports.blogrollUrisMinimal = require_defaults.blogrollUrisMinimal;
8
+ exports.defaultGuessOptions = require_defaults.defaultGuessOptions;
9
+ exports.defaultHeadersOptions = require_defaults.defaultHeadersOptions;
10
+ exports.defaultHtmlOptions = require_defaults.defaultHtmlOptions;
11
+ exports.feedsmithExtractor = require_extractors.feedsmithExtractor;
12
+ exports.linkSelectors = require_defaults.linkSelectors;
13
+ exports.opmlMimeTypes = require_defaults.opmlMimeTypes;
@@ -0,0 +1,4 @@
1
+ import { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes } from "./blogrolls/defaults.cjs";
2
+ import { BlogrollResultValid } from "./blogrolls/types.cjs";
3
+ import { feedsmithExtractor } from "./blogrolls/extractors.cjs";
4
+ export { BlogrollResultValid, anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, feedsmithExtractor, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,4 @@
1
+ import { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes } from "./blogrolls/defaults.js";
2
+ import { BlogrollResultValid } from "./blogrolls/types.js";
3
+ import { feedsmithExtractor } from "./blogrolls/extractors.js";
4
+ export { BlogrollResultValid, anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, feedsmithExtractor, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,4 @@
1
+ import { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, linkSelectors, opmlMimeTypes } from "./blogrolls/defaults.js";
2
+ import { feedsmithExtractor } from "./blogrolls/extractors.js";
3
+
4
+ export { anchorLabels, blogrollUrisBalanced, blogrollUrisComprehensive, blogrollUrisMinimal, defaultGuessOptions, defaultHeadersOptions, defaultHtmlOptions, feedsmithExtractor, linkSelectors, opmlMimeTypes };
@@ -0,0 +1,76 @@
1
+
2
+ //#region src/common/discover/adapters.ts
3
+ const createNativeFetchAdapter = (baseOptions) => {
4
+ return async (url, options) => {
5
+ const response = await fetch(url, {
6
+ ...baseOptions,
7
+ method: options?.method || "GET",
8
+ headers: {
9
+ ...baseOptions?.headers,
10
+ ...options?.headers
11
+ }
12
+ });
13
+ return {
14
+ headers: response.headers,
15
+ body: await response.text(),
16
+ url: response.url,
17
+ status: response.status,
18
+ statusText: response.statusText
19
+ };
20
+ };
21
+ };
22
+ const createGotAdapter = (gotInstance) => {
23
+ return async (url, options) => {
24
+ const response = await gotInstance(url, {
25
+ method: options?.method || "GET",
26
+ headers: options?.headers,
27
+ throwHttpErrors: false
28
+ });
29
+ return {
30
+ headers: new Headers(response.headers),
31
+ body: response.body,
32
+ url: response.url,
33
+ status: response.statusCode,
34
+ statusText: response.statusMessage
35
+ };
36
+ };
37
+ };
38
+ const createAxiosAdapter = (axiosInstance) => {
39
+ return async (url, options) => {
40
+ const response = await axiosInstance({
41
+ url,
42
+ method: options?.method || "GET",
43
+ headers: options?.headers,
44
+ validateStatus: () => true
45
+ });
46
+ return {
47
+ headers: new Headers(response.headers),
48
+ body: response.data,
49
+ url: response.request?.res?.responseUrl || url,
50
+ status: response.status,
51
+ statusText: response.statusText
52
+ };
53
+ };
54
+ };
55
+ const createKyAdapter = (kyInstance) => {
56
+ return async (url, options) => {
57
+ const response = await kyInstance(url, {
58
+ method: options?.method || "GET",
59
+ headers: options?.headers,
60
+ throwHttpErrors: false
61
+ });
62
+ return {
63
+ headers: response.headers,
64
+ body: await response.text(),
65
+ url: response.url,
66
+ status: response.status,
67
+ statusText: response.statusText
68
+ };
69
+ };
70
+ };
71
+
72
+ //#endregion
73
+ exports.createAxiosAdapter = createAxiosAdapter;
74
+ exports.createGotAdapter = createGotAdapter;
75
+ exports.createKyAdapter = createKyAdapter;
76
+ exports.createNativeFetchAdapter = createNativeFetchAdapter;
@@ -0,0 +1,10 @@
1
+ import { DiscoverFetchFn } from "../types.cjs";
2
+
3
+ //#region src/common/discover/adapters.d.ts
4
+ type AnyInstance = any;
5
+ declare const createNativeFetchAdapter: (baseOptions?: RequestInit) => DiscoverFetchFn;
6
+ declare const createGotAdapter: (gotInstance: AnyInstance) => DiscoverFetchFn;
7
+ declare const createAxiosAdapter: (axiosInstance: AnyInstance) => DiscoverFetchFn;
8
+ declare const createKyAdapter: (kyInstance: AnyInstance) => DiscoverFetchFn;
9
+ //#endregion
10
+ export { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter };
@@ -0,0 +1,10 @@
1
+ import { DiscoverFetchFn } from "../types.js";
2
+
3
+ //#region src/common/discover/adapters.d.ts
4
+ type AnyInstance = any;
5
+ declare const createNativeFetchAdapter: (baseOptions?: RequestInit) => DiscoverFetchFn;
6
+ declare const createGotAdapter: (gotInstance: AnyInstance) => DiscoverFetchFn;
7
+ declare const createAxiosAdapter: (axiosInstance: AnyInstance) => DiscoverFetchFn;
8
+ declare const createKyAdapter: (kyInstance: AnyInstance) => DiscoverFetchFn;
9
+ //#endregion
10
+ export { createAxiosAdapter, createGotAdapter, createKyAdapter, createNativeFetchAdapter };