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.
- package/README.md +93 -77
- package/dist/adapters.cjs +6 -0
- package/dist/adapters.d.cts +2 -0
- package/dist/adapters.d.ts +2 -0
- package/dist/adapters.js +3 -0
- package/dist/blogrolls/defaults.cjs +53 -0
- package/dist/blogrolls/defaults.d.cts +17 -0
- package/dist/blogrolls/defaults.d.ts +17 -0
- package/dist/blogrolls/defaults.js +44 -0
- package/dist/blogrolls/extractors.cjs +24 -0
- package/dist/blogrolls/extractors.d.cts +7 -0
- package/dist/blogrolls/extractors.d.ts +7 -0
- package/dist/blogrolls/extractors.js +24 -0
- package/dist/blogrolls/index.cjs +22 -0
- package/dist/blogrolls/index.d.cts +7 -0
- package/dist/blogrolls/index.d.ts +7 -0
- package/dist/blogrolls/index.js +22 -0
- package/dist/blogrolls/types.d.cts +6 -0
- package/dist/blogrolls/types.d.ts +6 -0
- package/dist/blogrolls.cjs +13 -0
- package/dist/blogrolls.d.cts +4 -0
- package/dist/blogrolls.d.ts +4 -0
- package/dist/blogrolls.js +4 -0
- package/dist/common/discover/adapters.cjs +76 -0
- package/dist/common/discover/adapters.d.cts +10 -0
- package/dist/common/discover/adapters.d.ts +10 -0
- package/dist/common/discover/adapters.js +72 -0
- package/dist/common/discover/index.cjs +54 -0
- package/dist/common/discover/index.js +54 -0
- package/dist/common/discover/utils.cjs +63 -0
- package/dist/common/discover/utils.js +62 -0
- package/dist/common/locales.cjs +15 -0
- package/dist/common/locales.js +9 -0
- package/dist/common/types.d.cts +93 -2
- package/dist/common/types.d.ts +93 -2
- package/dist/common/uris/guess/index.cjs +10 -0
- package/dist/common/uris/guess/index.d.cts +6 -0
- package/dist/common/uris/guess/index.d.ts +6 -0
- package/dist/common/uris/guess/index.js +10 -0
- package/dist/common/uris/guess/types.d.cts +29 -0
- package/dist/common/uris/guess/types.d.ts +29 -0
- package/dist/common/uris/guess/utils.cjs +89 -0
- package/dist/common/uris/guess/utils.d.cts +57 -0
- package/dist/common/uris/guess/utils.d.ts +57 -0
- package/dist/common/uris/guess/utils.js +86 -0
- package/dist/common/uris/headers/index.cjs +24 -0
- package/dist/common/uris/headers/index.d.cts +6 -0
- package/dist/common/uris/headers/index.d.ts +6 -0
- package/dist/common/uris/headers/index.js +24 -0
- package/dist/common/uris/headers/types.d.cts +9 -0
- package/dist/common/uris/headers/types.d.ts +9 -0
- package/dist/common/uris/html/handlers.cjs +47 -0
- package/dist/{utils-BVlxsJfJ.js → common/uris/html/handlers.js} +10 -12
- package/dist/common/uris/html/index.cjs +21 -0
- package/dist/common/uris/html/index.d.cts +6 -0
- package/dist/common/uris/html/index.d.ts +6 -0
- package/dist/common/uris/html/index.js +21 -0
- package/dist/common/uris/html/types.d.cts +12 -0
- package/dist/common/uris/html/types.d.ts +12 -0
- package/dist/common/uris/index.cjs +15 -0
- package/dist/common/uris/index.js +15 -0
- package/dist/common/utils.cjs +56 -6
- package/dist/common/utils.js +51 -2
- package/dist/feeds/defaults.cjs +89 -0
- package/dist/feeds/defaults.d.cts +18 -0
- package/dist/feeds/defaults.d.ts +18 -0
- package/dist/feeds/defaults.js +79 -0
- package/dist/feeds/extractors.cjs +46 -0
- package/dist/feeds/extractors.d.cts +7 -0
- package/dist/feeds/extractors.d.ts +7 -0
- package/dist/feeds/extractors.js +46 -0
- package/dist/feeds/index.cjs +22 -0
- package/dist/feeds/index.d.cts +7 -0
- package/dist/feeds/index.d.ts +7 -0
- package/dist/feeds/index.js +22 -0
- package/dist/feeds/types.d.cts +10 -0
- package/dist/feeds/types.d.ts +10 -0
- package/dist/feeds.cjs +14 -0
- package/dist/feeds.d.cts +4 -0
- package/dist/feeds.d.ts +4 -0
- package/dist/feeds.js +4 -0
- package/dist/hubs/discover/index.cjs +32 -0
- package/dist/hubs/discover/index.d.cts +7 -0
- package/dist/hubs/discover/index.d.ts +7 -0
- package/dist/hubs/discover/index.js +32 -0
- package/dist/hubs/discover/types.d.cts +14 -0
- package/dist/hubs/discover/types.d.ts +14 -0
- package/dist/hubs/discover/utils.cjs +20 -0
- package/dist/hubs/discover/utils.js +19 -0
- package/dist/hubs/feed/index.cjs +32 -0
- package/dist/hubs/feed/index.js +32 -0
- package/dist/hubs/headers/index.cjs +19 -0
- package/dist/hubs/headers/index.js +19 -0
- package/dist/hubs/html/index.cjs +30 -0
- package/dist/hubs/html/index.js +30 -0
- package/dist/hubs.d.cts +2 -0
- package/dist/hubs.d.ts +2 -0
- package/dist/index.cjs +6 -44
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4 -20
- package/dist/methods.cjs +11 -0
- package/dist/methods.d.cts +5 -0
- package/dist/methods.d.ts +5 -0
- package/dist/methods.js +6 -0
- package/package.json +52 -16
- package/dist/common/utils.d.cts +0 -13
- package/dist/common/utils.d.ts +0 -13
- package/dist/types-B0jVPx9s.d.ts +0 -17
- package/dist/types-BZOn_2Ua.d.cts +0 -17
- package/dist/utils-DsxN2_bI.cjs +0 -79
- /package/dist/{common/types.cjs → hubs.cjs} +0 -0
- /package/dist/{common/types.js → hubs.js} +0 -0
package/README.md
CHANGED
|
@@ -4,110 +4,126 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/feedscout)
|
|
5
5
|
[](https://github.com/macieklamberski/feedscout/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Advanced feed autodiscovery for JavaScript. Collect feeds from webpages using multiple discovery methods.
|
|
8
8
|
|
|
9
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
32
|
+
### Guess Method
|
|
23
33
|
|
|
24
|
-
|
|
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
|
-
|
|
42
|
+
### Basic Usage
|
|
31
43
|
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
+
Feedscout discovers and extracts feeds data:
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
```typescript
|
|
60
|
+
import { discoverFeeds } from 'feedscout'
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
const feeds = await discoverFeeds(
|
|
63
|
+
{ url: 'https://example.com', content: html },
|
|
64
|
+
{ methods: ['html', 'guess'] },
|
|
65
|
+
)
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
// [{ url: 'https://example.com/feed.xml', isValid: true, format: 'rss', title: '...' }]
|
|
68
|
+
```
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
By default, native `fetch()` is used. For projects using other HTTP libraries, adapters are available:
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
| `options` | `DiscoverFeedUrisOptions` | Yes | Discovery configuration |
|
|
72
|
+
```typescript
|
|
73
|
+
import axios from 'axios'
|
|
74
|
+
import { createAxiosAdapter } from 'feedscout/adapters'
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
const feeds = await discoverFeeds(input, {
|
|
77
|
+
methods: ['html', 'guess'],
|
|
78
|
+
fetchFn: createAxiosAdapter(axios),
|
|
79
|
+
})
|
|
80
|
+
```
|
|
72
81
|
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
88
|
-
|
|
89
|
-
'
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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;
|
package/dist/adapters.js
ADDED
|
@@ -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,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 };
|