webforai 2.1.1 → 4.0.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.
Files changed (203) hide show
  1. package/README.md +86 -4
  2. package/dist/adapters/index.js +58 -0
  3. package/dist/adapters/registry.js +149 -0
  4. package/dist/adapters/sites/declarative.js +178 -0
  5. package/dist/adapters/sites/hackernews.js +94 -0
  6. package/dist/adapters/sites/youtube.js +165 -0
  7. package/dist/adapters/types.js +0 -0
  8. package/dist/bin.js +4142 -549
  9. package/dist/cjs/adapters/index.js +86 -0
  10. package/dist/cjs/adapters/registry.js +178 -0
  11. package/dist/cjs/adapters/sites/declarative.js +202 -0
  12. package/dist/cjs/adapters/sites/hackernews.js +117 -0
  13. package/dist/cjs/adapters/sites/youtube.js +191 -0
  14. package/dist/cjs/adapters/types.js +16 -0
  15. package/dist/cjs/constants.js +2 -2
  16. package/dist/cjs/detect-client-shell.js +78 -0
  17. package/dist/cjs/extract-meta-refresh.js +71 -0
  18. package/dist/cjs/extractors/index.js +5 -0
  19. package/dist/cjs/extractors/lib/constants.js +186 -0
  20. package/dist/cjs/extractors/lib/sanitize.js +429 -0
  21. package/dist/cjs/extractors/lib/score.js +264 -0
  22. package/dist/cjs/extractors/lib/terminators.js +131 -0
  23. package/dist/cjs/extractors/lib/ui-chrome.js +119 -0
  24. package/dist/cjs/extractors/pipeExtractors.js +12 -9
  25. package/dist/cjs/extractors/presets/auto.js +44 -0
  26. package/dist/cjs/extractors/presets/minimal-filter.js +27 -48
  27. package/dist/cjs/extractors/presets/takumi.js +84 -122
  28. package/dist/cjs/html-to-markdown.js +44 -7
  29. package/dist/cjs/html-to-mdast.js +10 -1
  30. package/dist/cjs/index.js +43 -2
  31. package/dist/cjs/link-replacer.js +19 -13
  32. package/dist/cjs/loaders/cf-puppeteer.js +14 -7
  33. package/dist/cjs/loaders/fetch.js +14 -2
  34. package/dist/cjs/loaders/playwright.js +32 -30
  35. package/dist/cjs/loaders/puppeteer.js +14 -7
  36. package/dist/cjs/md-splitter.js +24 -11
  37. package/dist/cjs/mdast-handlers/custom-a-handler.js +25 -9
  38. package/dist/cjs/mdast-handlers/custom-code-handler.js +18 -7
  39. package/dist/cjs/mdast-handlers/custom-div-handler.js +12 -33
  40. package/dist/cjs/mdast-handlers/custom-img-handler.js +23 -1
  41. package/dist/cjs/mdast-handlers/custom-table-handler.js +16 -0
  42. package/dist/cjs/mdast-handlers/definition-list-handler.js +110 -0
  43. package/dist/cjs/mdast-handlers/math-handler.js +12 -3
  44. package/dist/cjs/mdast-handlers/sup-sub-handler.js +39 -0
  45. package/dist/cjs/mdast-to-markdown.js +2 -5
  46. package/dist/cjs/metadata/index.js +223 -0
  47. package/dist/cjs/normalize/index.js +177 -0
  48. package/dist/cjs/platform/client.js +204 -0
  49. package/dist/cjs/platform/error.js +36 -0
  50. package/dist/cjs/platform/fetch.js +37 -0
  51. package/dist/cjs/platform/index.js +44 -0
  52. package/dist/cjs/platform/types.js +40 -0
  53. package/dist/cjs/utils/hast-fast.js +284 -0
  54. package/dist/constants.js +2 -2
  55. package/dist/detect-client-shell.js +53 -0
  56. package/dist/extract-meta-refresh.js +47 -0
  57. package/dist/extractors/index.js +3 -0
  58. package/dist/extractors/lib/constants.js +150 -0
  59. package/dist/extractors/lib/sanitize.js +419 -0
  60. package/dist/extractors/lib/score.js +242 -0
  61. package/dist/extractors/lib/terminators.js +107 -0
  62. package/dist/extractors/lib/ui-chrome.js +96 -0
  63. package/dist/extractors/pipeExtractors.js +12 -9
  64. package/dist/extractors/presets/auto.js +20 -0
  65. package/dist/extractors/presets/minimal-filter.js +35 -47
  66. package/dist/extractors/presets/takumi.js +91 -122
  67. package/dist/html-to-markdown.js +42 -6
  68. package/dist/html-to-mdast.js +10 -1
  69. package/dist/index.js +45 -2
  70. package/dist/link-replacer.js +19 -13
  71. package/dist/loaders/cf-puppeteer.js +15 -8
  72. package/dist/loaders/fetch.js +14 -2
  73. package/dist/loaders/playwright.js +32 -30
  74. package/dist/loaders/puppeteer.js +15 -8
  75. package/dist/md-splitter.js +24 -11
  76. package/dist/mdast-handlers/custom-a-handler.js +25 -9
  77. package/dist/mdast-handlers/custom-code-handler.js +17 -7
  78. package/dist/mdast-handlers/custom-div-handler.js +12 -33
  79. package/dist/mdast-handlers/custom-img-handler.js +23 -1
  80. package/dist/mdast-handlers/custom-table-handler.js +16 -0
  81. package/dist/mdast-handlers/definition-list-handler.js +87 -0
  82. package/dist/mdast-handlers/math-handler.js +12 -3
  83. package/dist/mdast-handlers/sup-sub-handler.js +16 -0
  84. package/dist/mdast-to-markdown.js +2 -5
  85. package/dist/metadata/index.js +198 -0
  86. package/dist/normalize/index.js +159 -0
  87. package/dist/platform/client.js +182 -0
  88. package/dist/platform/error.js +13 -0
  89. package/dist/platform/fetch.js +14 -0
  90. package/dist/platform/index.js +23 -0
  91. package/dist/platform/types.js +13 -0
  92. package/dist/types/adapters/index.d.ts +24 -0
  93. package/dist/types/adapters/index.js.map +1 -0
  94. package/dist/types/adapters/registry.d.ts +35 -0
  95. package/dist/types/adapters/registry.js.map +1 -0
  96. package/dist/types/adapters/sites/declarative.d.ts +13 -0
  97. package/dist/types/adapters/sites/declarative.js.map +1 -0
  98. package/dist/types/adapters/sites/hackernews.d.ts +13 -0
  99. package/dist/types/adapters/sites/hackernews.js.map +1 -0
  100. package/dist/types/adapters/sites/youtube.d.ts +31 -0
  101. package/dist/types/adapters/sites/youtube.js.map +1 -0
  102. package/dist/types/adapters/types.d.ts +99 -0
  103. package/dist/types/adapters/types.js.map +1 -0
  104. package/dist/types/cli/bin.js.map +1 -1
  105. package/dist/types/cli/commands/jobs/files.d.ts +28 -0
  106. package/dist/types/cli/commands/jobs/files.js.map +1 -0
  107. package/dist/types/cli/commands/jobs/llms-txt.d.ts +33 -0
  108. package/dist/types/cli/commands/jobs/llms-txt.js.map +1 -0
  109. package/dist/types/cli/commands/jobs/options.d.ts +58 -0
  110. package/dist/types/cli/commands/jobs/options.js.map +1 -0
  111. package/dist/types/cli/commands/jobs/run.d.ts +44 -0
  112. package/dist/types/cli/commands/jobs/run.js.map +1 -0
  113. package/dist/types/cli/commands/skill/content.d.ts +9 -0
  114. package/dist/types/cli/commands/skill/content.js.map +1 -0
  115. package/dist/types/cli/commands/skill/index.d.ts +19 -0
  116. package/dist/types/cli/commands/skill/index.js.map +1 -0
  117. package/dist/types/cli/commands/webforai/interactive.d.ts +7 -0
  118. package/dist/types/cli/commands/webforai/interactive.js.map +1 -0
  119. package/dist/types/cli/commands/webforai/loadHtml.js.map +1 -1
  120. package/dist/types/cli/commands/webforai/options.d.ts +62 -0
  121. package/dist/types/cli/commands/webforai/options.js.map +1 -0
  122. package/dist/types/cli/commands/webforai/run.d.ts +10 -0
  123. package/dist/types/cli/commands/webforai/run.js.map +1 -0
  124. package/dist/types/cli/constants.d.ts +14 -4
  125. package/dist/types/cli/constants.js.map +1 -1
  126. package/dist/types/cli/helpers/selectExtractMode.js.map +1 -1
  127. package/dist/types/cli/helpers/selectLoader.js.map +1 -1
  128. package/dist/types/cli/utils.d.ts +8 -1
  129. package/dist/types/cli/utils.js.map +1 -1
  130. package/dist/types/constants.d.ts +7 -1
  131. package/dist/types/constants.js.map +1 -1
  132. package/dist/types/detect-client-shell.d.ts +24 -0
  133. package/dist/types/detect-client-shell.js.map +1 -0
  134. package/dist/types/extract-meta-refresh.d.ts +29 -0
  135. package/dist/types/extract-meta-refresh.js.map +1 -0
  136. package/dist/types/extractors/index.d.ts +1 -0
  137. package/dist/types/extractors/index.js.map +1 -1
  138. package/dist/types/extractors/lib/constants.d.ts +81 -0
  139. package/dist/types/extractors/lib/constants.js.map +1 -0
  140. package/dist/types/extractors/lib/sanitize.d.ts +66 -0
  141. package/dist/types/extractors/lib/sanitize.js.map +1 -0
  142. package/dist/types/extractors/lib/score.d.ts +85 -0
  143. package/dist/types/extractors/lib/score.js.map +1 -0
  144. package/dist/types/extractors/lib/terminators.d.ts +26 -0
  145. package/dist/types/extractors/lib/terminators.js.map +1 -0
  146. package/dist/types/extractors/lib/ui-chrome.d.ts +18 -0
  147. package/dist/types/extractors/lib/ui-chrome.js.map +1 -0
  148. package/dist/types/extractors/pipeExtractors.d.ts +5 -0
  149. package/dist/types/extractors/pipeExtractors.js.map +1 -1
  150. package/dist/types/extractors/presets/auto.d.ts +30 -0
  151. package/dist/types/extractors/presets/auto.js.map +1 -0
  152. package/dist/types/extractors/presets/minimal-filter.d.ts +10 -2
  153. package/dist/types/extractors/presets/minimal-filter.js.map +1 -1
  154. package/dist/types/extractors/presets/takumi.d.ts +19 -3
  155. package/dist/types/extractors/presets/takumi.js.map +1 -1
  156. package/dist/types/extractors/types.d.ts +8 -0
  157. package/dist/types/html-to-markdown.d.ts +38 -0
  158. package/dist/types/html-to-markdown.js.map +1 -1
  159. package/dist/types/html-to-mdast.d.ts +11 -0
  160. package/dist/types/html-to-mdast.js.map +1 -1
  161. package/dist/types/index.d.ts +8 -3
  162. package/dist/types/index.js.map +1 -1
  163. package/dist/types/link-replacer.d.ts +3 -1
  164. package/dist/types/link-replacer.js.map +1 -1
  165. package/dist/types/loaders/cf-puppeteer.js.map +1 -1
  166. package/dist/types/loaders/fetch.d.ts +4 -0
  167. package/dist/types/loaders/fetch.js.map +1 -1
  168. package/dist/types/loaders/playwright.js.map +1 -1
  169. package/dist/types/loaders/puppeteer.js.map +1 -1
  170. package/dist/types/md-splitter.d.ts +1 -1
  171. package/dist/types/md-splitter.js.map +1 -1
  172. package/dist/types/mdast-handlers/custom-a-handler.js.map +1 -1
  173. package/dist/types/mdast-handlers/custom-code-handler.d.ts +2 -0
  174. package/dist/types/mdast-handlers/custom-code-handler.js.map +1 -1
  175. package/dist/types/mdast-handlers/custom-div-handler.js.map +1 -1
  176. package/dist/types/mdast-handlers/custom-img-handler.js.map +1 -1
  177. package/dist/types/mdast-handlers/custom-table-handler.js.map +1 -1
  178. package/dist/types/mdast-handlers/definition-list-handler.d.ts +2 -0
  179. package/dist/types/mdast-handlers/definition-list-handler.js.map +1 -0
  180. package/dist/types/mdast-handlers/math-handler.js.map +1 -1
  181. package/dist/types/mdast-handlers/sup-sub-handler.d.ts +10 -0
  182. package/dist/types/mdast-handlers/sup-sub-handler.js.map +1 -0
  183. package/dist/types/mdast-to-markdown.js.map +1 -1
  184. package/dist/types/metadata/index.d.ts +47 -0
  185. package/dist/types/metadata/index.js.map +1 -0
  186. package/dist/types/normalize/index.d.ts +53 -0
  187. package/dist/types/normalize/index.js.map +1 -0
  188. package/dist/types/platform/client.d.ts +55 -0
  189. package/dist/types/platform/client.js.map +1 -0
  190. package/dist/types/platform/error.d.ts +22 -0
  191. package/dist/types/platform/error.js.map +1 -0
  192. package/dist/types/platform/fetch.d.ts +36 -0
  193. package/dist/types/platform/fetch.js.map +1 -0
  194. package/dist/types/platform/index.d.ts +4 -0
  195. package/dist/types/platform/index.js.map +1 -0
  196. package/dist/types/platform/types.d.ts +164 -0
  197. package/dist/types/platform/types.js.map +1 -0
  198. package/dist/types/utils/hast-fast.d.ts +101 -0
  199. package/dist/types/utils/hast-fast.js.map +1 -0
  200. package/dist/utils/hast-fast.js +246 -0
  201. package/package.json +25 -7
  202. package/dist/types/cli/commands/webforai/index.d.ts +0 -6
  203. package/dist/types/cli/commands/webforai/index.js.map +0 -1
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var youtube_exports = {};
20
+ __export(youtube_exports, {
21
+ extractAssignedJson: () => extractAssignedJson,
22
+ isYoutubeElement: () => isYoutubeElement,
23
+ youtubeAdapter: () => youtubeAdapter,
24
+ youtubeCaptionTracks: () => youtubeCaptionTracks
25
+ });
26
+ module.exports = __toCommonJS(youtube_exports);
27
+ var import_hast_fast = require("../../utils/hast-fast");
28
+ const findObjectEnd = (source, start) => {
29
+ let depth = 0;
30
+ let inString = false;
31
+ let escaped = false;
32
+ for (let index = start; index < source.length; index++) {
33
+ const character = source[index];
34
+ if (escaped) {
35
+ escaped = false;
36
+ } else if (character === "\\") {
37
+ escaped = true;
38
+ } else if (character === '"') {
39
+ inString = !inString;
40
+ } else if (!inString) {
41
+ if (character === "{") {
42
+ depth += 1;
43
+ } else if (character === "}" && --depth === 0) {
44
+ return index + 1;
45
+ }
46
+ }
47
+ }
48
+ return -1;
49
+ };
50
+ const extractAssignedJson = (source, name) => {
51
+ const markerIndex = source.indexOf(`${name} =`);
52
+ if (markerIndex === -1) {
53
+ return void 0;
54
+ }
55
+ const start = source.indexOf("{", markerIndex);
56
+ if (start === -1) {
57
+ return void 0;
58
+ }
59
+ const end = findObjectEnd(source, start);
60
+ if (end === -1) {
61
+ return void 0;
62
+ }
63
+ try {
64
+ return JSON.parse(source.slice(start, end));
65
+ } catch {
66
+ return void 0;
67
+ }
68
+ };
69
+ const scriptText = (root) => (0, import_hast_fast.collectElements)(root, (element2) => element2.tagName === "script").map(
70
+ (script) => script.children.map((child) => child.type === "text" ? child.value : "").join("")
71
+ );
72
+ const findPlayerResponse = (root) => {
73
+ for (const source of scriptText(root)) {
74
+ if (!source.includes("ytInitialPlayerResponse")) {
75
+ continue;
76
+ }
77
+ const parsed = extractAssignedJson(source, "ytInitialPlayerResponse");
78
+ if (parsed && typeof parsed === "object") {
79
+ return parsed;
80
+ }
81
+ }
82
+ return void 0;
83
+ };
84
+ const youtubeCaptionTracks = (root) => {
85
+ const player = findPlayerResponse(root);
86
+ const renderer = player?.captions?.playerCaptionsTracklistRenderer;
87
+ const tracks = renderer?.captionTracks;
88
+ if (!Array.isArray(tracks)) {
89
+ return [];
90
+ }
91
+ return tracks.flatMap((track) => {
92
+ const url = typeof track.baseUrl === "string" ? track.baseUrl : void 0;
93
+ const languageCode = typeof track.languageCode === "string" ? track.languageCode : void 0;
94
+ if (!(url && languageCode)) {
95
+ return [];
96
+ }
97
+ const name = track.name?.simpleText;
98
+ return [
99
+ {
100
+ url,
101
+ languageCode,
102
+ name: typeof name === "string" ? name : void 0,
103
+ isAutomatic: track.kind === "asr"
104
+ }
105
+ ];
106
+ });
107
+ };
108
+ const text = (value) => ({ type: "text", value });
109
+ const element = (tagName, children) => ({
110
+ type: "element",
111
+ tagName,
112
+ properties: {},
113
+ children
114
+ });
115
+ const heading = (depth, value) => element(`h${depth}`, [text(value)]);
116
+ const paragraph = (value) => element("p", [text(value)]);
117
+ const descriptionNodes = (description) => description.split(/\n{2,}/).map((block) => block.trim()).filter((block) => block.length > 0).map(
118
+ (block) => element(
119
+ "p",
120
+ block.split("\n").flatMap((line, index) => index === 0 ? [text(line)] : [element("br", []), text(line)])
121
+ )
122
+ );
123
+ const formatDuration = (seconds) => {
124
+ const hours = Math.floor(seconds / 3600);
125
+ const minutes = Math.floor(seconds % 3600 / 60);
126
+ const remainder = seconds % 60;
127
+ const pad = (value) => String(value).padStart(2, "0");
128
+ return hours > 0 ? `${hours}:${pad(minutes)}:${pad(remainder)}` : `${minutes}:${pad(remainder)}`;
129
+ };
130
+ const metadataList = (details) => {
131
+ const items = [];
132
+ if (details.author) {
133
+ items.push(element("li", [text(`Channel: ${details.author}`)]));
134
+ }
135
+ const seconds = Number(details.lengthSeconds);
136
+ if (Number.isFinite(seconds) && seconds > 0) {
137
+ items.push(element("li", [text(`Duration: ${formatDuration(seconds)}`)]));
138
+ }
139
+ const views = Number(details.viewCount);
140
+ if (Number.isFinite(views) && views > 0) {
141
+ items.push(element("li", [text(`Views: ${views.toLocaleString("en-US")}`)]));
142
+ }
143
+ return items.length > 0 ? element("ul", items) : void 0;
144
+ };
145
+ const youtubeAdapter = {
146
+ id: "youtube",
147
+ matches: ({ url }) => {
148
+ if (!url) {
149
+ return false;
150
+ }
151
+ try {
152
+ return /(^|\.)(youtube\.com|youtu\.be|youtube-nocookie\.com)$/.test(new URL(url).hostname);
153
+ } catch {
154
+ return false;
155
+ }
156
+ },
157
+ // Scanning every script body for the JSON blob would cost a full traversal on every page, so
158
+ // the fallback keys off markers the signature already collected.
159
+ matchesFingerprint: ({ signature }) => Boolean(signature?.ids.has("movie_player") || signature?.classes.has("ytd-app")),
160
+ extract: ({ hast }) => {
161
+ const player = findPlayerResponse(hast);
162
+ const details = player?.videoDetails;
163
+ if (!details?.title) {
164
+ return void 0;
165
+ }
166
+ const children = [heading(1, details.title)];
167
+ const metadata = metadataList(details);
168
+ if (metadata) {
169
+ children.push(metadata);
170
+ }
171
+ const description = details.shortDescription?.trim();
172
+ if (description) {
173
+ children.push(heading(2, "Description"));
174
+ children.push(...descriptionNodes(description));
175
+ }
176
+ const tracks = youtubeCaptionTracks(hast);
177
+ if (tracks.length > 0) {
178
+ const languages = [...new Set(tracks.map((track) => track.languageCode))].sort();
179
+ children.push(paragraph(`Captions available: ${languages.join(", ")}`));
180
+ }
181
+ return { type: "root", children };
182
+ }
183
+ };
184
+ const isYoutubeElement = import_hast_fast.isElement;
185
+ // Annotate the CommonJS export names for ESM import in node:
186
+ 0 && (module.exports = {
187
+ extractAssignedJson,
188
+ isYoutubeElement,
189
+ youtubeAdapter,
190
+ youtubeCaptionTracks
191
+ });
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
@@ -21,8 +21,8 @@ __export(constants_exports, {
21
21
  DEFAULT_EXTRACTORS: () => DEFAULT_EXTRACTORS
22
22
  });
23
23
  module.exports = __toCommonJS(constants_exports);
24
- var import_takumi = require("./extractors/presets/takumi");
25
- const DEFAULT_EXTRACTORS = [import_takumi.takumiExtractor];
24
+ var import_auto = require("./extractors/presets/auto");
25
+ const DEFAULT_EXTRACTORS = [import_auto.autoExtractor];
26
26
  // Annotate the CommonJS export names for ESM import in node:
27
27
  0 && (module.exports = {
28
28
  DEFAULT_EXTRACTORS
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var detect_client_shell_exports = {};
20
+ __export(detect_client_shell_exports, {
21
+ SHELL_EMPTY_THRESHOLD: () => SHELL_EMPTY_THRESHOLD,
22
+ SHELL_SUSPICION_THRESHOLD: () => SHELL_SUSPICION_THRESHOLD,
23
+ detectClientShell: () => detectClientShell
24
+ });
25
+ module.exports = __toCommonJS(detect_client_shell_exports);
26
+ const SHELL_SUSPICION_THRESHOLD = 300;
27
+ const SHELL_EMPTY_THRESHOLD = 50;
28
+ const BODY_PATTERN = /<body[^>]*>([\s\S]*?)<\/body>/i;
29
+ const HEAD_PATTERN = /<head[^>]*>[\s\S]*?<\/head>/gi;
30
+ const NOSCRIPT_PATTERN = /<noscript[^>]*>([\s\S]*?)<\/noscript>/gi;
31
+ const INVISIBLE_ELEMENT_PATTERN = /<(script|style|template|svg|noscript)[^>]*>[\s\S]*?<\/\1>/gi;
32
+ const COMMENT_PATTERN = /<!--[\s\S]*?-->/g;
33
+ const TAG_PATTERN = /<[^>]+>/g;
34
+ const MOUNT_POINT_PATTERN = /<[a-z][^>]*\sid=["'](?:root|app|__next|___gatsby|__nuxt|q-app|svelte|react-root)["']|<app-root[\s>]|\sdata-reactroot[\s>=]/i;
35
+ const CHALLENGE_PATTERN = /cf-chl|challenge-platform|cf_chl_opt|just a moment|attention required|checking your browser|_incapsula_|px-captcha|datadome/i;
36
+ const ENTITIES = {
37
+ "&nbsp;": " ",
38
+ "&amp;": "&",
39
+ "&lt;": "<",
40
+ "&gt;": ">",
41
+ "&quot;": '"',
42
+ "&#39;": "'"
43
+ };
44
+ const visibleTextOf = (markup) => markup.replace(COMMENT_PATTERN, " ").replace(INVISIBLE_ELEMENT_PATTERN, " ").replace(TAG_PATTERN, " ").replace(/&(?:nbsp|amp|lt|gt|quot|#39);/g, (entity) => ENTITIES[entity] ?? " ").replace(/\s+/g, " ").trim();
45
+ const noscriptMentionsJavascript = (html) => {
46
+ for (const match of html.matchAll(NOSCRIPT_PATTERN)) {
47
+ if (/javascript/i.test(match[1] ?? "")) {
48
+ return true;
49
+ }
50
+ }
51
+ return false;
52
+ };
53
+ const detectClientShell = (html) => {
54
+ const body = BODY_PATTERN.exec(html)?.[1] ?? html.replace(HEAD_PATTERN, " ");
55
+ const visibleTextLength = visibleTextOf(body).length;
56
+ if (visibleTextLength >= SHELL_SUSPICION_THRESHOLD) {
57
+ return { isShell: false, visibleTextLength };
58
+ }
59
+ if (CHALLENGE_PATTERN.test(html)) {
60
+ return { isShell: true, reason: "anti-bot-challenge", visibleTextLength };
61
+ }
62
+ if (MOUNT_POINT_PATTERN.test(body)) {
63
+ return { isShell: true, reason: "spa-shell", visibleTextLength };
64
+ }
65
+ if (noscriptMentionsJavascript(html)) {
66
+ return { isShell: true, reason: "noscript-only", visibleTextLength };
67
+ }
68
+ if (visibleTextLength < SHELL_EMPTY_THRESHOLD) {
69
+ return { isShell: true, reason: "empty-body", visibleTextLength };
70
+ }
71
+ return { isShell: false, visibleTextLength };
72
+ };
73
+ // Annotate the CommonJS export names for ESM import in node:
74
+ 0 && (module.exports = {
75
+ SHELL_EMPTY_THRESHOLD,
76
+ SHELL_SUSPICION_THRESHOLD,
77
+ detectClientShell
78
+ });
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var extract_meta_refresh_exports = {};
20
+ __export(extract_meta_refresh_exports, {
21
+ MAX_META_REFRESH_DELAY_SECONDS: () => MAX_META_REFRESH_DELAY_SECONDS,
22
+ extractMetaRefresh: () => extractMetaRefresh
23
+ });
24
+ module.exports = __toCommonJS(extract_meta_refresh_exports);
25
+ const MAX_META_REFRESH_DELAY_SECONDS = 10;
26
+ const META_TAG_PATTERN = /<meta\b[^>]*>/gi;
27
+ const HTTP_EQUIV_REFRESH_PATTERN = /\bhttp-equiv\s*=\s*("\s*refresh\s*"|'\s*refresh\s*'|refresh\b)/i;
28
+ const CONTENT_ATTR_PATTERN = /\bcontent\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i;
29
+ const CONTENT_VALUE_PATTERN = /^\s*(\d+(?:\.\d+)?)\s*[;,]\s*url\s*=\s*(?:"([^"]*)"|'([^']*)'|(.+?))\s*$/i;
30
+ const resolveTarget = (raw, baseUrl) => {
31
+ try {
32
+ return baseUrl === void 0 ? new URL(raw) : new URL(raw, baseUrl);
33
+ } catch {
34
+ return void 0;
35
+ }
36
+ };
37
+ const extractMetaRefresh = (html, baseUrl) => {
38
+ for (const [tag] of html.matchAll(META_TAG_PATTERN)) {
39
+ if (!HTTP_EQUIV_REFRESH_PATTERN.test(tag)) {
40
+ continue;
41
+ }
42
+ const contentMatch = CONTENT_ATTR_PATTERN.exec(tag);
43
+ const content = contentMatch?.[1] ?? contentMatch?.[2] ?? contentMatch?.[3];
44
+ if (!content) {
45
+ continue;
46
+ }
47
+ const value = CONTENT_VALUE_PATTERN.exec(content);
48
+ if (!value) {
49
+ continue;
50
+ }
51
+ const delaySeconds = Number.parseFloat(value[1] ?? "");
52
+ const raw = (value[2] ?? value[3] ?? value[4] ?? "").trim();
53
+ if (!raw || delaySeconds > MAX_META_REFRESH_DELAY_SECONDS) {
54
+ continue;
55
+ }
56
+ const target = resolveTarget(raw, baseUrl);
57
+ if (!target || target.protocol !== "http:" && target.protocol !== "https:") {
58
+ continue;
59
+ }
60
+ if (baseUrl !== void 0 && resolveTarget(baseUrl, void 0)?.href === target.href) {
61
+ continue;
62
+ }
63
+ return { url: target.href, delaySeconds };
64
+ }
65
+ return void 0;
66
+ };
67
+ // Annotate the CommonJS export names for ESM import in node:
68
+ 0 && (module.exports = {
69
+ MAX_META_REFRESH_DELAY_SECONDS,
70
+ extractMetaRefresh
71
+ });
@@ -18,6 +18,8 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var extractors_exports = {};
20
20
  __export(extractors_exports, {
21
+ autoExtractor: () => import_auto.autoExtractor,
22
+ createAutoExtractor: () => import_auto.createAutoExtractor,
21
23
  minimalFilter: () => import_minimal_filter.minimalFilter,
22
24
  pipeExtractors: () => import_pipeExtractors.pipeExtractors,
23
25
  takumiExtractor: () => import_takumi.takumiExtractor
@@ -26,8 +28,11 @@ module.exports = __toCommonJS(extractors_exports);
26
28
  var import_pipeExtractors = require("./pipeExtractors");
27
29
  var import_takumi = require("./presets/takumi");
28
30
  var import_minimal_filter = require("./presets/minimal-filter");
31
+ var import_auto = require("./presets/auto");
29
32
  // Annotate the CommonJS export names for ESM import in node:
30
33
  0 && (module.exports = {
34
+ autoExtractor,
35
+ createAutoExtractor,
31
36
  minimalFilter,
32
37
  pipeExtractors,
33
38
  takumiExtractor
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var constants_exports = {};
20
+ __export(constants_exports, {
21
+ CANDIDATE_TAGS: () => CANDIDATE_TAGS,
22
+ CHROME_TAGS: () => CHROME_TAGS,
23
+ CONTENT_ROLES: () => CONTENT_ROLES,
24
+ CONTEXTUAL_LANDMARK_TAGS: () => CONTEXTUAL_LANDMARK_TAGS,
25
+ DROP_WHEN_EMPTY_TAGS: () => DROP_WHEN_EMPTY_TAGS,
26
+ EMBEDDED_CONTENT_TAGS: () => EMBEDDED_CONTENT_TAGS,
27
+ HIDDEN_CLASS_NAMES: () => HIDDEN_CLASS_NAMES,
28
+ MIN_CONTENT_LENGTH: () => MIN_CONTENT_LENGTH,
29
+ NON_CONTENT_TAGS: () => NON_CONTENT_TAGS,
30
+ REGEXPS: () => REGEXPS,
31
+ RESPONSIVE_DISPLAY_OVERRIDE: () => RESPONSIVE_DISPLAY_OVERRIDE,
32
+ SCOREABLE_TAGS: () => SCOREABLE_TAGS,
33
+ UNLIKELY_ROLES: () => UNLIKELY_ROLES,
34
+ minContentLength: () => minContentLength
35
+ });
36
+ module.exports = __toCommonJS(constants_exports);
37
+ const REGEXPS = {
38
+ /**
39
+ * Containers that almost never hold the article body.
40
+ *
41
+ * Note the words that are deliberately *absent*. `header` and `footer` match the heading
42
+ * anchors and article furniture that documentation generators emit (`<a class="header">`,
43
+ * `class="post-header"`), so matching them here deletes the page's headings. The landmark
44
+ * versions of those elements are handled structurally instead.
45
+ */
46
+ unlikelyCandidates: /-ad-|ai2html|banner|breadcrumb|combx|comment(?!ary)|community|cover-wrap|disqus|gdpr|legends|menu|related|remark|replies|rss|shoutbox|sidebar|site-index|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore|avatar|subscribe|newsletter|paywall|consent|cookie|toolbar|masthead|promo|share|sharing|widget|tooltip|dropdown|modal|overlay|backdrop|carousel|announcement|notification|toast|skip-link|screen-reader|visually-hidden|sr-only/i,
47
+ /** Rescues containers whose class merely happens to contain an unlikely substring. */
48
+ okMaybeItsaCandidate: /and|article|body|column|content|main|shadow|code|post|entry|story|markdown|prose|doc/i,
49
+ /** Very high-confidence boilerplate, not rescued by the clause above. */
50
+ stronglyUnlikely: /^(nav|navbar|breadcrumbs?|cookie-?(banner|consent|notice)|consent-?(banner|manager)|skip-?link|site-?header|site-?footer|global-?(header|footer)|social-?(share|links?)|share-?(bar|buttons?)|related-?(posts?|articles?)|newsletter-?(signup|form)|comment-?(form|list)|toc-?sidebar)$/i,
51
+ /** Class/id fragments that mark real article content. */
52
+ positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story|markdown|prose|documentation|doc-?content|readme/i,
53
+ /** Class/id fragments that mark furniture. */
54
+ negative: /-ad-|hidden|^hid$| hid$|^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|widget|toolbar|nav|menu|cookie|consent|subscribe|newsletter|popup|modal|overlay|breadcrumb|pagination|social/i,
55
+ /** Placeholder imagery that should never reach the output. */
56
+ hidden: /fallback-image/i,
57
+ byline: /byline|author|dateline|writtenby|p-author|c-author|post-meta|entry-meta/i,
58
+ /** Wiki/CMS chrome that generic scoring alone tends to keep. */
59
+ specialUnlikelyCandidates: /frb-|uls-menu|language-link|mw-editsection|noprint|navbox|metadata|catlinks|printfooter/i
60
+ };
61
+ const NON_CONTENT_TAGS = /* @__PURE__ */ new Set([
62
+ "script",
63
+ "style",
64
+ "link",
65
+ "meta",
66
+ "noscript",
67
+ "template",
68
+ "base",
69
+ "param",
70
+ "source",
71
+ "track",
72
+ "title"
73
+ ]);
74
+ const CHROME_TAGS = /* @__PURE__ */ new Set(["nav", "aside", "dialog", "menu"]);
75
+ const CONTEXTUAL_LANDMARK_TAGS = /* @__PURE__ */ new Set(["header", "footer"]);
76
+ const HIDDEN_CLASS_NAMES = /* @__PURE__ */ new Set([
77
+ "hidden",
78
+ "invisible",
79
+ "is-hidden",
80
+ "d-none",
81
+ "display-none",
82
+ "hide",
83
+ "is-invisible"
84
+ ]);
85
+ const RESPONSIVE_DISPLAY_OVERRIDE = /^(sm|md|lg|xl|2xl|print):(block|flex|grid|inline|inline-block|inline-flex|table|contents|list-item)$/;
86
+ const UNLIKELY_ROLES = /* @__PURE__ */ new Set([
87
+ "menu",
88
+ "menubar",
89
+ "menuitem",
90
+ "complementary",
91
+ "navigation",
92
+ "alert",
93
+ "alertdialog",
94
+ "dialog",
95
+ "banner",
96
+ "contentinfo",
97
+ "search",
98
+ "searchbox",
99
+ "toolbar",
100
+ "tablist",
101
+ "tooltip"
102
+ // `presentation` is deliberately absent. It marks an element as decorative *structure* — a
103
+ // layout table, a wrapper — while the content inside it is usually real. Treating it as
104
+ // chrome deletes article text.
105
+ ]);
106
+ const CONTENT_ROLES = /* @__PURE__ */ new Set(["main", "article", "document"]);
107
+ const SCOREABLE_TAGS = /* @__PURE__ */ new Set(["p", "td", "pre", "blockquote", "dd", "li", "figure", "section", "div"]);
108
+ const CANDIDATE_TAGS = /* @__PURE__ */ new Set([
109
+ "div",
110
+ "section",
111
+ "article",
112
+ "main",
113
+ "td",
114
+ "pre",
115
+ "blockquote",
116
+ "form",
117
+ "ul",
118
+ "ol",
119
+ "dl"
120
+ ]);
121
+ const EMBEDDED_CONTENT_TAGS = /* @__PURE__ */ new Set([
122
+ "img",
123
+ "picture",
124
+ "video",
125
+ "audio",
126
+ "iframe",
127
+ "embed",
128
+ "object",
129
+ "svg",
130
+ // Formulae hold no text of their own, so an empty-wrapper rule would otherwise delete them.
131
+ "math",
132
+ "mjx-container",
133
+ "canvas"
134
+ ]);
135
+ const DROP_WHEN_EMPTY_TAGS = /* @__PURE__ */ new Set([
136
+ "p",
137
+ "h1",
138
+ "h2",
139
+ "h3",
140
+ "h4",
141
+ "h5",
142
+ "h6",
143
+ "li",
144
+ "td",
145
+ "th",
146
+ "blockquote",
147
+ "figcaption",
148
+ "dd",
149
+ "dt",
150
+ "a",
151
+ "span",
152
+ "div",
153
+ "section",
154
+ "article"
155
+ ]);
156
+ const MIN_CONTENT_LENGTH = {
157
+ ja: 140,
158
+ zh: 140,
159
+ ko: 160,
160
+ th: 160,
161
+ default: 400
162
+ };
163
+ const minContentLength = (lang) => {
164
+ if (!lang) {
165
+ return MIN_CONTENT_LENGTH.default;
166
+ }
167
+ const primary = lang.toLowerCase().split("-")[0];
168
+ return MIN_CONTENT_LENGTH[primary] ?? MIN_CONTENT_LENGTH.default;
169
+ };
170
+ // Annotate the CommonJS export names for ESM import in node:
171
+ 0 && (module.exports = {
172
+ CANDIDATE_TAGS,
173
+ CHROME_TAGS,
174
+ CONTENT_ROLES,
175
+ CONTEXTUAL_LANDMARK_TAGS,
176
+ DROP_WHEN_EMPTY_TAGS,
177
+ EMBEDDED_CONTENT_TAGS,
178
+ HIDDEN_CLASS_NAMES,
179
+ MIN_CONTENT_LENGTH,
180
+ NON_CONTENT_TAGS,
181
+ REGEXPS,
182
+ RESPONSIVE_DISPLAY_OVERRIDE,
183
+ SCOREABLE_TAGS,
184
+ UNLIKELY_ROLES,
185
+ minContentLength
186
+ });