@wenathlan/saddle 1.8.2 → 1.8.5

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 (257) hide show
  1. package/README.md +9 -9
  2. package/browser/playwright.js +22 -0
  3. package/docs/.gitkeep +0 -0
  4. package/docs/gapmatrix.md +3 -3
  5. package/docs/libraryapi.md +1 -0
  6. package/docs/logs/.gitkeep +0 -0
  7. package/docs/packageaudit185.md +23 -0
  8. package/docs/plans/00.index.md +50 -0
  9. package/docs/plans/01.architecture.md +86 -0
  10. package/docs/plans/02.research.computer.use.md +58 -0
  11. package/docs/plans/03.research.captcha.bypass.md +68 -0
  12. package/docs/plans/04.research.sandbox.ai.md +52 -0
  13. package/docs/plans/05.capture.platform.md +57 -0
  14. package/docs/plans/06.dependencies.md +97 -0
  15. package/docs/plans/07.captcha.test.page.md +41 -0
  16. package/docs/plans/08.production.infra.md +70 -0
  17. package/docs/plans/09.database.schema.md +121 -0
  18. package/docs/plans/10.cloudinary.storage.md +57 -0
  19. package/docs/plans/11.movement.logs.json.md +72 -0
  20. package/docs/plans/12.research.atlas.agent.browser.md +79 -0
  21. package/docs/plans/13.research.anti.detection.md +898 -0
  22. package/docs/plans/14.research.proxy.md +1495 -0
  23. package/docs/plans/15.research.retry.rate.limit.md +1958 -0
  24. package/docs/plans/16.research.crawling.md +1417 -0
  25. package/docs/plans/17.research.caching.md +1610 -0
  26. package/docs/plans/18.research.content.extraction.md +1952 -0
  27. package/docs/plans/19.research.errors.events.md +1523 -0
  28. package/docs/plans/20.research.zod.validation.md +1350 -0
  29. package/docs/plans/21.research.batch.concurrency.md +1888 -0
  30. package/docs/plans/22.research.universal.runtime.md +944 -0
  31. package/docs/plans/23.research.ai.integration.md +1465 -0
  32. package/docs/plans/24.research.memory.persistence.md +1979 -0
  33. package/docs/plans/25.research.server.api.md +342 -0
  34. package/docs/plans/26.research.compilation.md +249 -0
  35. package/docs/plans/27.research.html.parsing.md +251 -0
  36. package/docs/plans/28.action.plan.md +50 -0
  37. package/docs/plans/29.api.reference.md +174 -0
  38. package/docs/plans/30.architecture.plan.md +94 -0
  39. package/docs/plans/31.auditoria.dados.md +163 -0
  40. package/docs/plans/32.bots.automacao.computacional.md +214 -0
  41. package/docs/plans/33.bots.codigo.revisao.md +220 -0
  42. package/docs/plans/34.bots.seguranca.cicd.md +366 -0
  43. package/docs/plans/35.comparativo.concorrencia.md +464 -0
  44. package/docs/plans/36.computational.memory.md +340 -0
  45. package/docs/plans/37.deploystrategy.md +394 -0
  46. package/docs/plans/38.flow.md +155 -0
  47. package/docs/plans/39.multi.platform.bot.md +252 -0
  48. package/docs/plans/40.npm.publish.md +250 -0
  49. package/docs/plans/41.o.que.falta.md +407 -0
  50. package/docs/plans/42.pesquisa.concorrencia.md +721 -0
  51. package/docs/plans/43.plan.universal.architecture.md +496 -0
  52. package/docs/plans/44.reference.md +100 -0
  53. package/docs/plans/45.robotarchitecture.md +237 -0
  54. package/docs/plans/46.scdnintegration.md +284 -0
  55. package/docs/plans/47.multiforge.readme.md +129 -0
  56. package/docs/plans/48.theory.v4.repo.os.md +152 -0
  57. package/docs/plans/49.third.party.infra.md +12 -0
  58. package/docs/plans/50.file.as.compute.md +39 -0
  59. package/docs/plans/51.architecture.virtual.processor.md +80 -0
  60. package/docs/plans/52.manifesto.v8.md +11 -0
  61. package/docs/plans/58.cdn.list.md +23 -0
  62. package/docs/plans/59.sql.frameworks.md +33 -0
  63. package/docs/plans/60.sql.thirdparty.md +26 -0
  64. package/docs/plans/61.objective.multiforge.md +63 -0
  65. package/docs/plans/62.huggingface.upload.md +26 -0
  66. package/docs/plans/63.kaggle.upload.md +24 -0
  67. package/docs/plans/64.npm.storage.md +30 -0
  68. package/docs/plans/65.rclone.terabox.md +32 -0
  69. package/docs/plans/66.buckets.and.models.todo.md +14 -0
  70. package/docs/plans/67.database.todo.md +13 -0
  71. package/docs/plans/68.deploy.packages.todo.md +12 -0
  72. package/docs/plans/69.report.human.operator.md +133 -0
  73. package/docs/plans/70.report.brain2qwerty.ems.md +135 -0
  74. package/docs/plans/71.report.hd.infinito.vram.md +155 -0
  75. package/docs/plans/72.plan.hd.infinito.node.md +146 -0
  76. package/docs/plans/73.plan.scifi.repos.md +125 -0
  77. package/docs/plans/74.000.manifesto.v8.flat.2..md +11 -0
  78. package/docs/plans/README.md +489 -0
  79. package/docs/plans/aggregate_platforms.mjs +146 -0
  80. package/docs/plans/examplesession.json +36 -0
  81. package/docs/plans/missing-facts.md +192 -0
  82. package/docs/plans/models.md +64 -0
  83. package/docs/plans/organize.cjs +270 -0
  84. package/docs/plans/platforms.md +2887 -0
  85. package/docs/plans/sites.md +31322 -0
  86. package/docs/platformpipelineaudit.md +18 -0
  87. package/docs/platformpipelines.md +13 -0
  88. package/docs/registryresearch.md +4 -0
  89. package/docs/release.md +4 -4
  90. package/docs/release182notes.md +2 -0
  91. package/docs/release184notes.md +7 -0
  92. package/docs/release185notes.md +7 -0
  93. package/docs/sources/farm.py +117 -0
  94. package/docs/sources/html/saddle1.html +132 -0
  95. package/docs/sources/html/saddle2.html +157 -0
  96. package/docs/sources/html/saddle3.html +119 -0
  97. package/docs/sources/html/saddle4.html +144 -0
  98. package/docs/sources/html/saddle5.html +72 -0
  99. package/docs/sources/html/saddle6.html +171 -0
  100. package/docs/sources/html/saddle7.html +236 -0
  101. package/docs/sources/saddle.ts +74 -0
  102. package/docs/sources/schema.prisma +88 -0
  103. package/docs/sources/script.sh +64 -0
  104. package/docs/sources/workflows.yml +458 -0
  105. package/docs/talks1/_body.txt +14 -0
  106. package/docs/talks1/_index.md +15 -0
  107. package/docs/talks1/_screenshot.png +0 -0
  108. package/docs/talks1/assistant-01.md +5 -0
  109. package/docs/talks1/assistant-02.md +5 -0
  110. package/docs/talks1/assistant-03.md +531 -0
  111. package/docs/talks1/assistant-04.md +26 -0
  112. package/docs/talks1/assistant-05.md +774 -0
  113. package/docs/talks1/assistant-06.md +1718 -0
  114. package/docs/talks1/scrape-share.cjs +185 -0
  115. package/docs/talks1/scrape-share.ts +183 -0
  116. package/docs/talks1/user-01.md +3 -0
  117. package/docs/talks1/user-02.md +3 -0
  118. package/docs/talks1/user-03.md +88 -0
  119. package/docs/talks1/user-04.md +3 -0
  120. package/docs/talks1/user-05.md +3 -0
  121. package/docs/talks1/user-06.md +88 -0
  122. package/docs/talks1/user-07.md +88 -0
  123. package/docs/talks2/_body.txt +14 -0
  124. package/docs/talks2/_index.md +16 -0
  125. package/docs/talks2/_screenshot.png +0 -0
  126. package/docs/talks2/assistant-01.md +5 -0
  127. package/docs/talks2/assistant-02.md +5 -0
  128. package/docs/talks2/assistant-03.md +424 -0
  129. package/docs/talks2/assistant-04.md +598 -0
  130. package/docs/talks2/assistant-05.md +1280 -0
  131. package/docs/talks2/assistant-06.md +1227 -0
  132. package/docs/talks2/assistant-07.md +1252 -0
  133. package/docs/talks2/user-01.md +3 -0
  134. package/docs/talks2/user-02.md +3 -0
  135. package/docs/talks2/user-03.md +88 -0
  136. package/docs/talks2/user-04.md +88 -0
  137. package/docs/talks2/user-05.md +88 -0
  138. package/docs/talks2/user-06.md +88 -0
  139. package/docs/talks2/user-07.md +3 -0
  140. package/docs/talks3/_body.txt +467 -0
  141. package/docs/talks3/_index.md +10 -0
  142. package/docs/talks3/_screenshot.png +0 -0
  143. package/docs/talks3/assistant-01.md +417 -0
  144. package/docs/talks3/assistant-02.md +417 -0
  145. package/docs/talks3/assistant-03.md +29 -0
  146. package/docs/talks3/assistant-04.md +727 -0
  147. package/docs/talks3/user-01.md +88 -0
  148. package/docs/talks3/user-02.md +88 -0
  149. package/docs/talks3/user-03.md +3 -0
  150. package/docs/talks3/user-04.md +3 -0
  151. package/docs/talks4/_body.txt +14 -0
  152. package/docs/talks4/_index.md +12 -0
  153. package/docs/talks4/_screenshot.png +0 -0
  154. package/docs/talks4/assistant-01.md +5 -0
  155. package/docs/talks4/assistant-02.md +5 -0
  156. package/docs/talks4/assistant-03.md +35 -0
  157. package/docs/talks4/assistant-04.md +512 -0
  158. package/docs/talks4/assistant-05.md +599 -0
  159. package/docs/talks4/user-01.md +3 -0
  160. package/docs/talks4/user-02.md +3 -0
  161. package/docs/talks4/user-03.md +88 -0
  162. package/docs/talks4/user-04.md +88 -0
  163. package/docs/talks4/user-05.md +7 -0
  164. package/docs/talks5/_body.txt +14 -0
  165. package/docs/talks5/_index.md +13 -0
  166. package/docs/talks5/_screenshot.png +0 -0
  167. package/docs/talks5/assistant-01.md +5 -0
  168. package/docs/talks5/assistant-02.md +5 -0
  169. package/docs/talks5/assistant-03.md +690 -0
  170. package/docs/talks5/assistant-04.md +758 -0
  171. package/docs/talks5/assistant-05.md +974 -0
  172. package/docs/talks5/user-01.md +3 -0
  173. package/docs/talks5/user-02.md +3 -0
  174. package/docs/talks5/user-03.md +105 -0
  175. package/docs/talks5/user-04.md +105 -0
  176. package/docs/talks5/user-05.md +63 -0
  177. package/docs/talks5/user-06.md +105 -0
  178. package/docs/talks6/_body.txt +14 -0
  179. package/docs/talks6/_index.md +9 -0
  180. package/docs/talks6/_screenshot.png +0 -0
  181. package/docs/talks6/assistant-01.md +5 -0
  182. package/docs/talks6/assistant-02.md +5 -0
  183. package/docs/talks6/assistant-03.md +1499 -0
  184. package/docs/talks6/user-01.md +3 -0
  185. package/docs/talks6/user-02.md +3 -0
  186. package/docs/talks6/user-03.md +88 -0
  187. package/docs/talks6/user-04.md +88 -0
  188. package/docs/talks7/_body.txt +14 -0
  189. package/docs/talks7/_index.md +10 -0
  190. package/docs/talks7/_screenshot.png +0 -0
  191. package/docs/talks7/assistant-01.md +5 -0
  192. package/docs/talks7/assistant-02.md +5 -0
  193. package/docs/talks7/assistant-03.md +523 -0
  194. package/docs/talks7/assistant-04.md +617 -0
  195. package/docs/talks7/user-01.md +3 -0
  196. package/docs/talks7/user-02.md +3 -0
  197. package/docs/talks7/user-03.md +105 -0
  198. package/docs/talks7/user-04.md +67 -0
  199. package/docs/talks8/conversa1.txt +1322 -0
  200. package/docs/talks8/conversa2.txt +237 -0
  201. package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +174 -0
  202. package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +59 -0
  203. package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +91 -0
  204. package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +116 -0
  205. package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +128 -0
  206. package/docs/talks9/README (2).md +489 -0
  207. package/docs/talks9/README.md +198 -0
  208. package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +80 -0
  209. package/docs/talks9/conversa.txt +544 -0
  210. package/docs/talks9/other (2).md +39 -0
  211. package/docs/talks9/other.md +57 -0
  212. package/docs/talks9/outro.txt +24 -0
  213. package/extension/README.md +3 -3
  214. package/extension/serviceworker.js +63 -4
  215. package/extension/worker.js +3 -1
  216. package/package.json +12 -2
  217. package/packager/manifest.js +1 -1
  218. package/scrape/agent.ts +122 -0
  219. package/scrape/batch.ts +79 -0
  220. package/scrape/biome.json +76 -0
  221. package/scrape/browser.ts +222 -0
  222. package/scrape/cache.ts +84 -0
  223. package/scrape/chunking.ts +193 -0
  224. package/scrape/cli.ts +105 -0
  225. package/scrape/crawler.ts +115 -0
  226. package/scrape/dev-server.ts +94 -0
  227. package/scrape/errors.ts +132 -0
  228. package/scrape/events.ts +26 -0
  229. package/scrape/extract.ts +165 -0
  230. package/scrape/fetch.ts +105 -0
  231. package/scrape/formats.ts +85 -0
  232. package/scrape/headers.ts +71 -0
  233. package/scrape/index.ts +92 -0
  234. package/scrape/jsdom.d.ts +6 -0
  235. package/scrape/llms-txt.ts +84 -0
  236. package/scrape/middleware.ts +90 -0
  237. package/scrape/package-lock.json +9397 -0
  238. package/scrape/package.json +1420 -0
  239. package/scrape/pool.ts +95 -0
  240. package/scrape/port.ts +18 -0
  241. package/scrape/proxy.ts +103 -0
  242. package/scrape/rate-limiter.ts +95 -0
  243. package/scrape/renderer.ts +194 -0
  244. package/scrape/retry.ts +64 -0
  245. package/scrape/robots.ts +137 -0
  246. package/scrape/scrape.ts +123 -0
  247. package/scrape/serialize.ts +310 -0
  248. package/scrape/server.ts +137 -0
  249. package/scrape/session.ts +109 -0
  250. package/scrape/sitemap.ts +131 -0
  251. package/scrape/tokens.ts +45 -0
  252. package/scrape/tsconfig.json +28 -0
  253. package/scrape/types.ts +214 -0
  254. package/scrape/utils.ts +77 -0
  255. package/scrape/vite.config.ts +55 -0
  256. package/scrape/vitest.config.ts +17 -0
  257. package/workflow/templates.js +4 -4
@@ -0,0 +1,251 @@
1
+ # Pesquisa: HTML Parsing e Extração (2026)
2
+
3
+ ## 1. Parser Comparison
4
+
5
+ | Feature | **Cheerio** | **jsdom** | **node-html-parser** | **parse5** |
6
+ |---------|-------------|-----------|---------------------|------------|
7
+ | Weekly downloads | ~10M | ~8M | ~300K+ | ~235M (indirect) |
8
+ | Memory per page | ~1MB | ~50MB | ~1MB | <1MB |
9
+ | Startup time | Instant | Fast (~100ms) | Instant | Instant |
10
+ | API style | jQuery-like `$()` | Standard DOM `querySelector` | Simple DOM traversal | AST methods |
11
+ | Script execution | No | Yes (limited) | No | No |
12
+ | CSS selector support | Yes (css-select) | Yes (nwsapi) | Yes (basic) | No (AST only) |
13
+ | HTML5 spec compliance | Good | Good | Basic | Full |
14
+ | Malformed HTML | Good | Good | Basic | Excellent |
15
+ | Best for | Web scraping, HTML transform | Testing, DOM APIs | High-throughput | Build tools |
16
+
17
+ ### Decision Tree
18
+
19
+ ```
20
+ Is the content rendered by JavaScript (SPA/React/Vue)?
21
+ Yes → Use Playwright (not here)
22
+ No (static HTML):
23
+ Do you need DOM APIs (addEventListener, classList)?
24
+ Yes → jsdom
25
+ No → Do you need max throughput?
26
+ Yes → node-html-parser or parse5
27
+ No → Cheerio (best developer experience)
28
+ ```
29
+
30
+ ## 2. HTML Entities
31
+
32
+ | Library | Weekly Downloads | Performance (ops/s) | Standards |
33
+ |---------|-----------------|---------------------|-----------|
34
+ | **entities** | ~235M | 5,838,416 (fastest) | XML, HTML4, HTML5 |
35
+ | **html-entities** | ~31M | 2,919,637 | XML, HTML4, HTML5 |
36
+ | **he** | ~15M | 2,318,438 | HTML5 only |
37
+
38
+ ```typescript
39
+ import * as entities from "entities";
40
+ entities.decodeHTML("asdf &amp; ÿ ü '"); // "asdf & ÿ ü '"
41
+ ```
42
+
43
+ ## 3. CSS Selector Engine: css-select
44
+
45
+ **Version:** 7.0.0 (March 2026)
46
+
47
+ ```typescript
48
+ import CSSselect from "css-select";
49
+ const results = CSSselect.selectAll('.article > h2:first-child', elements);
50
+ ```
51
+
52
+ Supports: `:scope`, `:is()`, `:where()`, `:has()`, attribute selectors, sibling combinators.
53
+
54
+ ## 4. Structured Data Extraction
55
+
56
+ ### Cheerio `$.extract()` (Declarative)
57
+
58
+ ```typescript
59
+ const $ = await cheerio.fromURL('https://example.com');
60
+ const data = $.extract({
61
+ title: 'title',
62
+ posts: [{
63
+ selector: '.post',
64
+ value: {
65
+ title: '.post-title',
66
+ link: { selector: 'a', value: 'href' },
67
+ date: { selector: 'time', value: 'datetime' },
68
+ tags: ['.tag'],
69
+ }
70
+ }]
71
+ });
72
+ ```
73
+
74
+ ### Extraction Priority Order
75
+
76
+ 1. **JSON-LD** — `<script type="application/ld+json">`
77
+ 2. **Microdata** — `itemscope`, `itemprop` attributes
78
+ 3. **OpenGraph** — `og:` meta tags
79
+ 4. **data-* attributes** — developer hooks
80
+ 5. **CSS selectors** — last resort
81
+
82
+ ```typescript
83
+ // JSON-LD extraction
84
+ $('script[type="application/ld+json"]').each((_, el) => {
85
+ try {
86
+ const data = JSON.parse($(el).html());
87
+ if (data['@type'] === 'Product') {
88
+ console.log(data.name, data.offers?.price);
89
+ }
90
+ } catch {}
91
+ });
92
+ ```
93
+
94
+ ## 5. Malformed HTML Handling
95
+
96
+ ### htmlparser2 (Forgiving)
97
+
98
+ ```typescript
99
+ import htmlparser2 from "htmlparser2";
100
+ const parser = new htmlparser2.Parser({
101
+ onopentag(name, attribs) { /* ... */ },
102
+ ontext(text) { /* ... */ },
103
+ onclosetag(tagname) { /* ... */ },
104
+ }, {
105
+ decodeEntities: true,
106
+ xmlMode: false, // HTML mode (forgiving)
107
+ });
108
+ ```
109
+
110
+ ### tag-soup (Lightweight, 20KB gzipped)
111
+
112
+ ```typescript
113
+ import { createDOMParser } from "tag-soup";
114
+ const parser = createDOMParser({
115
+ areUnbalancedEndTagsIgnored: true,
116
+ areUnbalancedStartTagsImplicitlyClosed: true,
117
+ });
118
+ ```
119
+
120
+ ## 6. HTML Sanitization
121
+
122
+ ### sanitize-html (Server-side, ~8.6M weekly downloads)
123
+
124
+ ```typescript
125
+ import sanitizeHtml from "sanitize-html";
126
+ const clean = sanitizeHtml(dirty, {
127
+ allowedTags: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'ol', 'li'],
128
+ allowedAttributes: { 'a': ['href', 'title'] },
129
+ transformTags: {
130
+ 'a': sanitizeHtml.simpleTransform('a', { rel: 'noopener noreferrer' })
131
+ }
132
+ });
133
+ ```
134
+
135
+ ### DOMPurify (Browser-side, ~40M weekly downloads)
136
+
137
+ ```typescript
138
+ import DOMPurify from "dompurify";
139
+ const clean = DOMPurify.sanitize('<b>hello</b><script>alert(1)</script>');
140
+ // Result: '<b>hello</b>'
141
+ ```
142
+
143
+ **Recommendation:** sanitize-html for server, DOMPurify for browser.
144
+
145
+ ## 7. Text Extraction with Formatting
146
+
147
+ ### Formatting-Preserving Walk
148
+
149
+ ```typescript
150
+ function extractFormattedText($: cheerio.CheerioAPI, element: cheerio.Element): string {
151
+ let result = '';
152
+ $(element).contents().each((_, node) => {
153
+ if (node.type === 'text') {
154
+ result += node.data;
155
+ } else if (node.type === 'tag') {
156
+ switch (node.name) {
157
+ case 'br': result += '\n'; break;
158
+ case 'p': result += extractFormattedText($, node) + '\n\n'; break;
159
+ case 'strong': case 'b': result += `**${extractFormattedText($, node)}**`; break;
160
+ case 'em': case 'i': result += `*${extractFormattedText($, node)}*`; break;
161
+ case 'h1': result += `# ${extractFormattedText($, node)}\n\n`; break;
162
+ case 'h2': result += `## ${extractFormattedText($, node)}\n\n`; break;
163
+ case 'li': result += `- ${extractFormattedText($, node)}\n`; break;
164
+ default: result += extractFormattedText($, node);
165
+ }
166
+ }
167
+ });
168
+ return result;
169
+ }
170
+ ```
171
+
172
+ ## 8. HTML-to-Markdown
173
+
174
+ ### Performance Comparison (166KB Wikipedia page)
175
+
176
+ | Package | Time | Speed vs Turndown |
177
+ |---------|------|-------------------|
178
+ | **mdream** (Rust) | 0.34ms | 33x faster |
179
+ | **mdream** (JS) | 3.26ms | 3.5x faster |
180
+ | **Turndown** | 11.26ms | baseline |
181
+ | **node-html-markdown** | 14.31ms | 1.3x slower |
182
+
183
+ ### Turndown (Industry Standard, 4.8M weekly downloads)
184
+
185
+ ```typescript
186
+ import TurndownService from 'turndown';
187
+ import turndownPluginGfm from 'turndown-plugin-gfm';
188
+
189
+ const turndownService = new TurndownService({
190
+ headingStyle: 'atx',
191
+ codeBlockStyle: 'fenced',
192
+ bulletListMarker: '-',
193
+ });
194
+ turndownService.use(turndownPluginGfm.gfm);
195
+ const markdown = turndownService.turndown(html);
196
+ ```
197
+
198
+ ### html-to-text (Plain Text, v10.0.0)
199
+
200
+ ```typescript
201
+ import { convert } from 'html-to-text';
202
+ const text = convert(html, {
203
+ wordWrap: 80,
204
+ tables: true,
205
+ links: { hideLinkUrls: true },
206
+ });
207
+ ```
208
+
209
+ ## 9. Table Parsing
210
+
211
+ ### cheerio-tableparser (colspan/rowspan support)
212
+
213
+ ```typescript
214
+ import cheerioTableparser from "cheerio-tableparser";
215
+ cheerioTableparser($);
216
+ const data = $("table").parsetable(true, true, true);
217
+ // dupCols, dupRows, textMode
218
+ ```
219
+
220
+ ## 10. Custom Extraction Rules
221
+
222
+ ### Schema-Based Pattern
223
+
224
+ ```typescript
225
+ const schema = {
226
+ title: { selector: 'h1', type: 'text' },
227
+ price: {
228
+ selector: '.price',
229
+ type: 'text',
230
+ transform: (v: string) => parseFloat(v.replace(/[^0-9.]/g, ''))
231
+ },
232
+ tags: { selector: '.tag', type: 'text', multiple: true },
233
+ links: { selector: 'a', type: 'attribute', attribute: 'href', multiple: true },
234
+ };
235
+ ```
236
+
237
+ ### Recommended Stack (2026)
238
+
239
+ | Task | Package |
240
+ |------|---------|
241
+ | Static HTML parsing | **Cheerio** (default) |
242
+ | Full DOM APIs | **jsdom** |
243
+ | High-throughput parsing | **node-html-parser** |
244
+ | HTML entity encoding | **entities** (fastest) |
245
+ | HTML sanitization (server) | **sanitize-html** |
246
+ | HTML sanitization (browser) | **DOMPurify** |
247
+ | HTML to Markdown | **Turndown** (plugins) or **mdream** (speed) |
248
+ | HTML to plain text | **html-to-text** |
249
+ | Article extraction | **@mozilla/readability** |
250
+ | Malformed HTML | **htmlparser2** |
251
+ | Structured extraction | Cheerio `$.extract()` |
@@ -0,0 +1,50 @@
1
+ # Action Plan
2
+
3
+ ## Phase: planning + research done
4
+ - [x] Folder structure (mirrors `cli`/`debonair`): `docs/plans`, `docs/talks`, `docs/logs`, `tests/{examples,output,scripts}`, `web`, `.github/workflows`.
5
+ - [x] Config files: `package.json` (`@devthink/saddle`, 65 deps), `tsconfig.json`, `biome.json`, `vitest.config.ts`, `.github/workflows/saddle-tests.yml`, `.gitignore`, `.npmrc`, `.nvmrc`, `README.md`.
6
+ - [x] Research done (computer use, hcaptcha bypass, vercel sandbox, atlas agent browser).
7
+ - [x] Planning docs in `docs/plans/` (01 to 12 + index).
8
+ - [x] Applied skill arch: no `src/`, no vercel/netlify functions, mysql2, socket, no localhost, lowercase files, production = `web/`.
9
+
10
+ ## Next phase: implementation (waits for user approval)
11
+ The user stated: "when i give you the go ahead to build the platform". So no code is written now (`web/` logic, db, etc).
12
+
13
+ ### Step 1 — Capture platform (after approval)
14
+ - Root files in `web/`: `humancursor.js`, `trajectory.js`, `fingerprint.js`, `recorder.js`, `replay.js`, `runcapture.js`, `capture.js`, `index.html`.
15
+ - Export to `docs/logs/<session>.json` (format in `11-movement-logs-json.md`).
16
+
17
+ ### Step 2 — Captcha test page
18
+ - `tests/examples/hcaptchatest.html` (local) + real sites (cloudflare/google/hcaptcha).
19
+ - `tests/scripts/` with detect -> solve -> record -> assert.
20
+ - Evidence in `tests/output/`.
21
+
22
+ ### Step 3 — Production infra
23
+ - `web/` with open node server (hono/express): routes `sessions`, `events`, `replays`, `captcha`.
24
+ - Db: drizzle + mysql2 (and prisma schema). Migrations in deploy.
25
+ - Cloudinary for assets/replays.
26
+
27
+ ### Step 4 — Sandbox
28
+ - `@vercel/sandbox` for isolated agent execution.
29
+ - Agent https post/get requests to the deployed site.
30
+
31
+ ### Step 5 — Tests
32
+ - `tests/*.test.ts` (vitest) for trajectory, recorder, schema, cloudinary helper.
33
+ - Example already at `tests/capture.test.ts`.
34
+
35
+ ## Architecture constraints (skill arch)
36
+ - No `src/`. Root based in `web/`.
37
+ - No vercel functions. No netlify functions.
38
+ - Data: prisma, drizzle, mysql2, socket.
39
+ - No localhost. Host parametrized. Ports randomized then locked.
40
+ - Files lowercase. No underscore. No hyphen. English. Jsdoc.
41
+
42
+ ## Dependencies registered
43
+ See `06-dependencies.md` (65 packages). Install with `npm install` when implementation starts.
44
+
45
+ ## Acceptance criteria (defined by user)
46
+ - Capture movement (virtual mouse, virtual arrow, click, rotation, coordinates) in brave.
47
+ - Export json logs to `docs/logs/`.
48
+ - Open test page in brave and face hcaptcha/cloudflare/recaptcha.
49
+ - Production backend deployed (vercel/netlify) with db (drizzle/prisma/mysql2) + cloudinary.
50
+ - Agent https post/get requests to the deployed site.
@@ -0,0 +1,174 @@
1
+ # API Reference
2
+
3
+ ## Core Functions
4
+
5
+ ### `scrapeUrl(url, options?)`
6
+ Scrape a URL using Playwright.
7
+ ```ts
8
+ const result = await scrapeUrl('https://example.com', {
9
+ scroll: true, // Scroll to bottom before extracting
10
+ extractLinks: true, // Extract all links
11
+ extractImages: true, // Extract all images
12
+ extractTables: true, // Extract all tables
13
+ readable: false, // Use readable mode
14
+ screenshot: false, // Take a screenshot
15
+ headless: true, // Run browser headless
16
+ timeout: 30000, // Navigation timeout
17
+ });
18
+ ```
19
+
20
+ ### `scrapeHtml(html, options?)`
21
+ Scrape raw HTML string without a browser.
22
+ ```ts
23
+ const result = await scrapeHtml('<html>...</html>', { extractTables: true });
24
+ ```
25
+
26
+ ### `scrapeWithBrowser(browser, url, options?)`
27
+ Reuse an existing AgentBrowser instance.
28
+ ```ts
29
+ const browser = new AgentBrowser();
30
+ await browser.launch('chromium');
31
+ const result = await scrapeWithBrowser(browser, 'https://example.com');
32
+ ```
33
+
34
+ ### `extractContent(html, options?)`
35
+ Extract structured content from HTML.
36
+ ```ts
37
+ const content = await extractContent(html, {
38
+ extractLinks: true,
39
+ extractImages: true,
40
+ extractTables: true,
41
+ readable: false,
42
+ });
43
+ ```
44
+ Returns `ExtractedContent` with: `title`, `author`, `text`, `links[]`, `images[]`, `tables[]`, `metadata`.
45
+
46
+ ### `serializeResult(result, options)`
47
+ Serialize a ScrapeResult to target format.
48
+ ```ts
49
+ const output = serializeResult(result, { format: 'markdown' });
50
+ const json = serializeResult(result, { format: 'json', pretty: true });
51
+ ```
52
+ Returns `SerializedOutput` with: `content`, `format`, `extension`.
53
+
54
+ ### `serializeHtml(html, options)`
55
+ Serialize raw HTML directly to target format.
56
+ ```ts
57
+ const md = serializeHtml('<h1>Hello</h1>', { format: 'markdown' });
58
+ ```
59
+
60
+ ### `formatForAgent(result, options?)`
61
+ Format scraped content for AI agent consumption.
62
+ ```ts
63
+ const agent = formatForAgent(result, {
64
+ maxChunkSize: 4000, // Max tokens per chunk
65
+ includeSummary: true,
66
+ includeKeyPoints: true,
67
+ includeRelevantUrls: true,
68
+ includeMetadata: true,
69
+ });
70
+ ```
71
+ Returns `AgentOutput` with: `summary`, `keyPoints`, `content`, `relevantUrls`, `chunks[]`, `tokenCount`.
72
+
73
+ ## Classes
74
+
75
+ ### `AgentBrowser`
76
+ Playwright browser automation manager.
77
+
78
+ ```ts
79
+ const browser = new AgentBrowser({
80
+ headless: true,
81
+ stealth: true, // Enable stealth mode
82
+ adBlock: true, // Block ads and trackers
83
+ viewport: { width: 1280, height: 720 },
84
+ userAgent: 'custom', // Custom UA string
85
+ });
86
+
87
+ await browser.launch('chromium');
88
+ await browser.navigate(url, { waitUntil: 'networkidle' });
89
+ await browser.click(selector);
90
+ await browser.type(selector, text);
91
+ await browser.screenshot({ fullPage: true });
92
+ await browser.html(); // Get page HTML
93
+ await browser.text(); // Get page text
94
+ await browser.title(); // Get page title
95
+ await browser.evaluate(fn); // Run JS in page
96
+ await browser.scrollToBottom({ step: 500, delay: 100 });
97
+ await browser.executeCommands([ // Chain commands
98
+ { action: 'goto', args: { url } },
99
+ { action: 'extract' },
100
+ { action: 'screenshot' },
101
+ ]);
102
+ await browser.close();
103
+ ```
104
+
105
+ ### `PygameRenderer`
106
+ Bridge to Python/Pygame for rendering.
107
+
108
+ ```ts
109
+ const renderer = new PygameRenderer({ pythonPath: 'python3' });
110
+ await renderer.renderScreenshot(screenshotBuffer, 'output.png');
111
+ await renderer.renderDoom(frameBuffer, 'doom-frame.png');
112
+ renderer.close();
113
+ ```
114
+
115
+ ## CLI
116
+
117
+ ```
118
+ Usage: webscrape <url> [options]
119
+
120
+ Arguments:
121
+ url URL to scrape
122
+
123
+ Options:
124
+ -f, --format <fmt> Output format: markdown, json, xml, redis, text (default: markdown)
125
+ -o, --output <file> Output file
126
+ --pretty Pretty-print JSON/XML output
127
+ --scroll Scroll to bottom before extraction
128
+ --readable Use readable mode
129
+ --agent Format output for AI agent consumption
130
+ --screenshot Take a screenshot
131
+ -h, --help Show help
132
+ ```
133
+
134
+ ## Types
135
+
136
+ ```ts
137
+ interface ScrapeResult {
138
+ url: string;
139
+ title: string;
140
+ html: string;
141
+ text: string;
142
+ links: { href: string; text: string }[];
143
+ images: { src: string; alt: string }[];
144
+ tables: { headers: string[]; rows: string[][] }[];
145
+ metadata: Record<string, string>;
146
+ screenshot?: Buffer;
147
+ timestamp: number;
148
+ }
149
+
150
+ interface ExtractedContent {
151
+ title: string;
152
+ author: string;
153
+ text: string;
154
+ links: { href: string; text: string }[];
155
+ images: { src: string; alt: string }[];
156
+ tables: { headers: string[]; rows: string[][] }[];
157
+ metadata: Record<string, string>;
158
+ }
159
+
160
+ interface SerializedOutput {
161
+ content: string;
162
+ format: string;
163
+ extension: string;
164
+ }
165
+
166
+ interface AgentOutput {
167
+ summary: string;
168
+ keyPoints: string[];
169
+ content: string;
170
+ relevantUrls: { url: string; text: string }[];
171
+ chunks: { content: string; tokenCount: number }[];
172
+ tokenCount: number;
173
+ }
174
+ ```
@@ -0,0 +1,94 @@
1
+ # Architecture
2
+
3
+ ## Module Overview
4
+
5
+ ```
6
+ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐
7
+ │ AgentBrowser│────▶│ scrapeUrl / │────▶│ extractContent │
8
+ │ (browser.ts)│ │ scrapeHtml │ │ (extract.ts) │
9
+ └─────────────┘ └──────────────┘ └────────────────┘
10
+
11
+
12
+ ┌─────────────┐ ┌──────────────────┐ ┌────────────────┐
13
+ │ formatFor │◀────│ serializeResult │◀────│ ScrapeResult │
14
+ │ Agent │ │ (serialize.ts) │ │ │
15
+ │ (agent.ts) │ │ formats: md, xml,│ └────────────────┘
16
+ └─────────────┘ │ json, redis, txt │
17
+ └──────────────────┘
18
+
19
+
20
+ ┌──────────────┐
21
+ │ Pygame │
22
+ │ Renderer │
23
+ │ (renderer.ts)│
24
+ └──────────────┘
25
+ ```
26
+
27
+ ## Module Responsibilities
28
+
29
+ ### `browser.ts` — AgentBrowser
30
+ - Wraps Playwright `Browser`, `BrowserContext`, and `Page`
31
+ - Provides chainable command execution (`executeCommands`)
32
+ - Handles stealth mode, ad blocking, and browser lifecycle
33
+
34
+ ### `scrape.ts` — Scraping Engine
35
+ - `scrapeUrl(url, options?)` — Launches browser, navigates, extracts
36
+ - `scrapeHtml(html, options?)` — Works offline with raw HTML
37
+ - `scrapeWithBrowser(browser, url, options?)` — Reuses existing AgentBrowser
38
+
39
+ ### `extract.ts` — Content Extraction
40
+ - `extractContent(html, options?)` — Parses HTML via Cheerio
41
+ - Extracts: title, author, text, links, images, tables, metadata
42
+ - Returns structured `ExtractedContent`
43
+
44
+ ### `serialize.ts` — Multi-Format Serialization
45
+ - `serializeResult(result, options)` — Converts `ScrapeResult` to target format
46
+ - `serializeHtml(html, options)` — Direct HTML-to-format conversion
47
+ - Supports: Markdown, HTML, JSON, XML, Redis, Plaintext
48
+
49
+ ### `formats.ts` — Format Registry
50
+ - Maps format names to serializers
51
+ - Provides format detection (article, list, page)
52
+ - Extensions and MIME types
53
+
54
+ ### `agent.ts` — AI Agent Output
55
+ - `formatForAgent(result, options?)` — Structures content for LLM consumption
56
+ - Generates: summary, key points, relevant URLs, content chunks with token counts
57
+
58
+ ### `renderer.ts` — Pygame Bridge
59
+ - `PygameRenderer` — Renders screenshots and DOOM game frames via Python/Pygame
60
+ - Spawns Python subprocess for rendering
61
+
62
+ ### `cli.ts` — Command-Line Interface
63
+ - Commander-based CLI for scraping from terminal
64
+ - Accepts format, pretty-print, scroll, readable, and agent options
65
+
66
+ ### `utils.ts` — Utilities
67
+ - `slugify`, `truncate`, `tokenEstimate`, `chunkText`
68
+ - URL validation and classification (internal/external)
69
+
70
+ ### `dev-server.mjs` — Development Server
71
+ - Standalone Node.js HTTP server
72
+ - POST `/api/scrape` endpoint wrapping Playwright
73
+ - Used by Vite dev server via proxy
74
+
75
+ ## Package Organization
76
+
77
+ ```
78
+ webscrape/
79
+ ├── index.ts # Public API exports
80
+ ├── browser.ts # AgentBrowser (Playwright wrapper)
81
+ ├── scrape.ts # Scraping engine
82
+ ├── extract.ts # HTML content extraction
83
+ ├── serialize.ts # Multi-format serialization
84
+ ├── formats.ts # Format registry
85
+ ├── agent.ts # AI agent output
86
+ ├── renderer.ts # Pygame bridge
87
+ ├── cli.ts # CLI entry
88
+ ├── utils.ts # Utilities
89
+ ├── types.ts # TypeScript interfaces
90
+ ├── web/ # Web demo UI
91
+ ├── tests/ # Test suites
92
+ ├── docs/ # Documentation
93
+ └── dev-server.mjs # API server for dev mode
94
+ ```