@link-assistant/web-capture 1.12.0 → 2.0.1
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/CHANGELOG.md +17 -0
- package/README.md +2 -1
- package/bin/web-capture.js +5 -7
- package/package.json +32 -18
- package/src/archive.js +1 -2
- package/src/binary-download.js +13 -0
- package/src/docx.js +14 -11
- package/src/fetch.js +1 -2
- package/src/figures.js +2 -12
- package/src/gdocs-images.js +0 -1
- package/src/gdocs.js +0 -1
- package/src/github.js +0 -1
- package/src/lib.js +1 -2
- package/src/localize-images.js +2 -12
- package/src/markdown.js +0 -1
- package/src/shared-dialog.js +0 -1
- package/src/stream.js +0 -1
- package/src/transport.js +23 -5
- package/src/txt.js +0 -1
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.dockerignore +0 -6
- package/.jscpd.json +0 -19
- package/.lenv +0 -8
- package/.prettierignore +0 -8
- package/.prettierrc +0 -10
- package/Dockerfile +0 -52
- package/babel.config.cjs +0 -13
- package/docker-compose.yml +0 -11
- package/eslint.config.js +0 -112
- package/examples/js/capture_cache.js +0 -12
- package/examples/js/engine_comparison.js +0 -39
- package/examples/js/html_download.js +0 -23
- package/examples/js/image_download.js +0 -36
- package/examples/js/markdown_download.js +0 -23
- package/examples/js/playwright_example.js +0 -23
- package/examples/python/html_download.py +0 -15
- package/examples/python/image_download.py +0 -20
- package/examples/python/markdown_download.py +0 -15
- package/examples/python/playwright_example.py +0 -22
- package/jest.config.mjs +0 -20
- package/tests/ci/dependency-freshness.test.js +0 -74
- package/tests/ci/detect-code-changes.test.js +0 -174
- package/tests/ci/docker-install.test.js +0 -31
- package/tests/ci/rust-dockerfile.test.js +0 -54
- package/tests/ci/workflow-policy.test.js +0 -79
- package/tests/e2e/docker.test.js +0 -186
- package/tests/e2e/process.test.js +0 -215
- package/tests/fixtures/bold-coalesce-and-leakage.html +0 -27
- package/tests/fixtures/deepwiki/deepwiki-full-page.png +0 -0
- package/tests/fixtures/deepwiki/index.md +0 -1500
- package/tests/fixtures/deepwiki/part-1.md +0 -776
- package/tests/fixtures/habr-articles.js +0 -45
- package/tests/fixtures/heading-numbering.html +0 -19
- package/tests/fixtures/list-item-with-br.html +0 -8
- package/tests/fixtures/ol-continuous-numbering.html +0 -12
- package/tests/fixtures/paragraph-vs-line-break.html +0 -11
- package/tests/helpers/nock.js +0 -10
- package/tests/helpers/search-fixture.cjs +0 -17
- package/tests/helpers/temporary-directory.js +0 -12
- package/tests/integration/api-endpoints.test.js +0 -418
- package/tests/integration/archive-default-layout.test.js +0 -37
- package/tests/integration/browser-engines.test.js +0 -128
- package/tests/integration/browser-packaged-path.test.js +0 -45
- package/tests/integration/deepwiki-download.test.js +0 -144
- package/tests/integration/deepwiki-rendered-page.mock.test.js +0 -121
- package/tests/integration/formalai-contract.test.js +0 -214
- package/tests/integration/gdocs-public-doc.test.js +0 -315
- package/tests/integration/github-readme.test.js +0 -137
- package/tests/integration/google-drive-image.test.js +0 -246
- package/tests/integration/habr-article.test.js +0 -337
- package/tests/integration/search-endpoint.test.js +0 -88
- package/tests/integration/stackoverflow-download.test.js +0 -173
- package/tests/integration/wikipedia-download.test.js +0 -142
- package/tests/jest.setup.mjs +0 -7
- package/tests/mock/index.test.js +0 -225
- package/tests/unit/animation.test.js +0 -33
- package/tests/unit/batch.test.js +0 -114
- package/tests/unit/bold-coalesce-and-leakage.test.js +0 -54
- package/tests/unit/browser-launch-options.test.js +0 -42
- package/tests/unit/browser.test.js +0 -172
- package/tests/unit/cache.test.js +0 -182
- package/tests/unit/cli.test.js +0 -399
- package/tests/unit/convertGoogleDriveUrl.test.js +0 -89
- package/tests/unit/convertRelativeUrls.test.js +0 -34
- package/tests/unit/extract-images.test.js +0 -259
- package/tests/unit/fetch-html.test.js +0 -54
- package/tests/unit/figures.test.js +0 -74
- package/tests/unit/gdocs-export-headers.test.js +0 -28
- package/tests/unit/gdocs-preprocess.test.js +0 -36
- package/tests/unit/gdocs.test.js +0 -1490
- package/tests/unit/github.test.js +0 -156
- package/tests/unit/heading-image.test.js +0 -49
- package/tests/unit/heading-numbering.test.js +0 -28
- package/tests/unit/html2md-br-in-list-item.test.js +0 -23
- package/tests/unit/html2md-ol-numbering.test.js +0 -20
- package/tests/unit/html2md.test.js +0 -695
- package/tests/unit/image-mode-defaults.test.js +0 -54
- package/tests/unit/kreuzberg.test.js +0 -249
- package/tests/unit/latex.test.js +0 -123
- package/tests/unit/localize-images.test.js +0 -114
- package/tests/unit/markdown.test.js +0 -36
- package/tests/unit/metadata.test.js +0 -140
- package/tests/unit/package-runtime-dependencies.test.js +0 -74
- package/tests/unit/paragraph-vs-line-break.test.js +0 -56
- package/tests/unit/postprocess.test.js +0 -110
- package/tests/unit/proxy-headers.test.js +0 -100
- package/tests/unit/publish-verification.test.js +0 -57
- package/tests/unit/retry.test.js +0 -111
- package/tests/unit/search.test.js +0 -339
- package/tests/unit/shared-dialog.test.js +0 -173
- package/tests/unit/stackoverflow.test.js +0 -32
- package/tests/unit/stream.test.js +0 -85
- package/tests/unit/verify.test.js +0 -182
- package/tests/xpaste/xpaste-screenshot-markdown.mock.test.js +0 -375
- package/tests/xpaste/xpaste.e2e.test.js +0 -36
- package/tests/xpaste/xpaste.integration.test.js +0 -41
- package/tests/xpaste/xpaste.mock.test.js +0 -261
- package/tests/xpaste/xpaste.unit.test.js +0 -119
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @link-assistant/web-capture
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 724c1a9: Fix CI/CD false positives, false negatives, and warnings (#177):
|
|
8
|
+
|
|
9
|
+
- Restore the `browser-commander` 0.10.0 pin required by open blocker #160 and repair the npm lock so `npm ci` installs again after the Dependabot update.
|
|
10
|
+
- Use Node's built-in `fetch` instead of `node-fetch`, removing the deprecated `node-domexception` package from the install. Transport diagnostics now include the underlying network error (for example `fetch failed: connect ECONNREFUSED ...`) and no longer report server-side network failures as possible CORS blocks.
|
|
11
|
+
- Load the `docx` library only when a DOCX is generated. Its bundled browser polyfills read `globalThis.localStorage` on import, so on Node 25+ every process that imported the server printed "ExperimentalWarning: localStorage is not available because --localstorage-file was not provided".
|
|
12
|
+
- Publish only the runtime files (`bin/`, `src/`, `README.md`, `CHANGELOG.md`) instead of the tests and fixtures, normalize `bin` and `repository` so `npm publish` no longer auto-corrects them, and install the pre-commit hook from the repository root instead of printing ".git can't be found" on every install.
|
|
13
|
+
|
|
14
|
+
## 2.0.0
|
|
15
|
+
|
|
16
|
+
### Major Changes
|
|
17
|
+
|
|
18
|
+
- b055a30: Require Node.js 26.10 or newer and update Playwright to 1.64. Use current Trixie browser images, native Jest ESM and reproducibly locked release tooling. Add locked Python examples and weekly dependency/security maintenance across all ecosystems.
|
|
19
|
+
|
|
3
20
|
## 1.12.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -19,7 +19,8 @@ A CLI and microservice to fetch URLs and render them as:
|
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
22
|
-
Node.js
|
|
22
|
+
Node.js 26.10.0 or newer is required. CI uses 26.11.1 and the latest published
|
|
23
|
+
Node Docker image uses 26.10.0 on Debian Trixie. Use `npm ci`
|
|
23
24
|
for a locked repository install; Docker and CI share `package-lock.json` and its
|
|
24
25
|
security overrides.
|
|
25
26
|
|
package/bin/web-capture.js
CHANGED
|
@@ -1110,11 +1110,9 @@ async function captureUrl(url, options) {
|
|
|
1110
1110
|
await import('../src/lib.js');
|
|
1111
1111
|
const { retry } = await import('../src/retry.js');
|
|
1112
1112
|
const cheerio = await import('cheerio');
|
|
1113
|
-
const nodeFetch = await import('node-fetch');
|
|
1114
1113
|
|
|
1114
|
+
// retry() defaults: 3 retries from a 1000ms base delay.
|
|
1115
1115
|
const html = await retry(() => fetchHtml(absoluteUrl), {
|
|
1116
|
-
retries: 3,
|
|
1117
|
-
baseDelay: 1000,
|
|
1118
1116
|
onRetry: (err, attempt) => {
|
|
1119
1117
|
console.error(`Retry ${attempt} fetching page: ${err.message}`);
|
|
1120
1118
|
},
|
|
@@ -1207,14 +1205,14 @@ async function captureUrl(url, options) {
|
|
|
1207
1205
|
if (imageMap.size > 0) {
|
|
1208
1206
|
for (const [imgUrl, localPath] of imageMap) {
|
|
1209
1207
|
try {
|
|
1210
|
-
const
|
|
1211
|
-
const resp = await retry(() => fetchFn(imgUrl), {
|
|
1208
|
+
const resp = await retry(() => fetch(imgUrl), {
|
|
1212
1209
|
retries: 2,
|
|
1213
1210
|
baseDelay: 500,
|
|
1214
1211
|
});
|
|
1215
1212
|
if (resp.ok) {
|
|
1216
|
-
|
|
1217
|
-
|
|
1213
|
+
archive.append(Buffer.from(await resp.arrayBuffer()), {
|
|
1214
|
+
name: localPath,
|
|
1215
|
+
});
|
|
1218
1216
|
}
|
|
1219
1217
|
} catch {
|
|
1220
1218
|
/* skip failed image downloads */
|
package/package.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/web-capture",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "CLI and microservice to render web pages as HTML, Markdown, or PNG",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"web-capture": "
|
|
7
|
+
"web-capture": "bin/web-capture.js"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
9
15
|
"scripts": {
|
|
10
16
|
"start": "docker compose up -d",
|
|
11
|
-
"dev": "
|
|
17
|
+
"dev": "node --watch bin/web-capture.js --serve",
|
|
12
18
|
"test": "node --experimental-vm-modules ./node_modules/.bin/jest",
|
|
13
19
|
"test:watch": "node --experimental-vm-modules ./node_modules/.bin/jest --watch",
|
|
14
20
|
"test:e2e:process": "node --experimental-vm-modules ./node_modules/.bin/jest tests/e2e/process.test.js",
|
|
@@ -16,16 +22,16 @@
|
|
|
16
22
|
"test:e2e": "npm run test:e2e:process && npm run test:e2e:docker",
|
|
17
23
|
"test:all": "npm run build && npm test && npm run test:e2e",
|
|
18
24
|
"build": "docker compose down && docker compose build && npm start",
|
|
19
|
-
"examples:python": "
|
|
25
|
+
"examples:python": "uv run --project .. --locked python examples/python/html_download.py && uv run --project .. --locked python examples/python/markdown_download.py && uv run --project .. --locked python examples/python/image_download.py",
|
|
20
26
|
"examples:javascript": "node examples/js/html_download.js && node examples/js/markdown_download.js && node examples/js/image_download.js",
|
|
21
27
|
"examples": "npm run build && npm run examples:javascript && npm run examples:python",
|
|
22
|
-
"lint": "
|
|
28
|
+
"lint": "node ../scripts/lint.mjs",
|
|
23
29
|
"lint:fix": "eslint . --fix",
|
|
24
30
|
"format": "prettier --write .",
|
|
25
31
|
"format:check": "prettier --check .",
|
|
26
32
|
"check:duplication": "jscpd . --baseline-from-ref origin/main --fail-on-new-clones --fail-on-empty",
|
|
27
33
|
"check": "npm run lint && npm run format:check && npm run check:duplication",
|
|
28
|
-
"prepare": "
|
|
34
|
+
"prepare": "node ../scripts/install-git-hooks.mjs",
|
|
29
35
|
"changeset": "changeset",
|
|
30
36
|
"changeset:version": "node ../scripts/changeset-version.mjs",
|
|
31
37
|
"changeset:publish": "changeset publish",
|
|
@@ -42,19 +48,16 @@
|
|
|
42
48
|
"iconv-lite": "^0.7.3",
|
|
43
49
|
"lino-arguments": "^0.3.0",
|
|
44
50
|
"log-lazy": "^1.0.4",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"puppeteer": "^25.
|
|
48
|
-
"puppeteer-core": "^25.12.0",
|
|
51
|
+
"playwright": "^1.64.0",
|
|
52
|
+
"puppeteer": "^25.13.0",
|
|
53
|
+
"puppeteer-core": "^25.13.0",
|
|
49
54
|
"turndown": "^7.2.4",
|
|
50
55
|
"turndown-plugin-gfm": "^1.0.2"
|
|
51
56
|
},
|
|
52
57
|
"devDependencies": {
|
|
53
|
-
"@babel/core": "^8.0.7",
|
|
54
|
-
"@babel/preset-env": "^8.0.7",
|
|
55
58
|
"@changesets/cli": "^3.0.3",
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
56
60
|
"@types/archiver": "^8.0.0",
|
|
57
|
-
"babel-jest": "^30.5.2",
|
|
58
61
|
"eslint": "^10.12.0",
|
|
59
62
|
"eslint-config-prettier": "^10.1.8",
|
|
60
63
|
"eslint-plugin-prettier": "^5.5.6",
|
|
@@ -67,8 +70,7 @@
|
|
|
67
70
|
"nock": "^15.0.1",
|
|
68
71
|
"prettier": "^3.9.9",
|
|
69
72
|
"supertest": "^7.3.1",
|
|
70
|
-
"unzipper": "^0.12.5"
|
|
71
|
-
"@eslint/js": "^10.0.1"
|
|
73
|
+
"unzipper": "^0.12.5"
|
|
72
74
|
},
|
|
73
75
|
"type": "module",
|
|
74
76
|
"keywords": [
|
|
@@ -80,14 +82,14 @@
|
|
|
80
82
|
"license": "Unlicense",
|
|
81
83
|
"repository": {
|
|
82
84
|
"type": "git",
|
|
83
|
-
"url": "https://github.com/link-assistant/web-capture"
|
|
85
|
+
"url": "git+https://github.com/link-assistant/web-capture.git"
|
|
84
86
|
},
|
|
85
87
|
"engines": {
|
|
86
|
-
"node": ">=
|
|
88
|
+
"node": ">=26.10.0"
|
|
87
89
|
},
|
|
88
90
|
"lint-staged": {
|
|
89
91
|
"*.{js,mjs,cjs}": [
|
|
90
|
-
"eslint --fix --
|
|
92
|
+
"eslint --fix --no-warn-ignored",
|
|
91
93
|
"prettier --write",
|
|
92
94
|
"prettier --check"
|
|
93
95
|
],
|
|
@@ -105,6 +107,18 @@
|
|
|
105
107
|
"overrides": {
|
|
106
108
|
"@istanbuljs/load-nyc-config": {
|
|
107
109
|
"js-yaml": "^4.1.1"
|
|
110
|
+
},
|
|
111
|
+
"cheerio": {
|
|
112
|
+
"encoding-sniffer": "^1.0.2"
|
|
113
|
+
},
|
|
114
|
+
"babel-plugin-istanbul": {
|
|
115
|
+
"test-exclude": "^8.0.0"
|
|
108
116
|
}
|
|
117
|
+
},
|
|
118
|
+
"packageManager": "npm@12.2.0",
|
|
119
|
+
"allowScripts": {
|
|
120
|
+
"@parcel/watcher": true,
|
|
121
|
+
"puppeteer": true,
|
|
122
|
+
"unrs-resolver": true
|
|
109
123
|
}
|
|
110
124
|
}
|
package/src/archive.js
CHANGED
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { ZipArchive } from 'archiver';
|
|
19
|
-
import fetch from 'node-fetch';
|
|
20
19
|
import * as cheerio from 'cheerio';
|
|
21
20
|
import { URL } from 'url';
|
|
22
21
|
import {
|
|
@@ -200,7 +199,7 @@ export async function archiveHandler(req, res) {
|
|
|
200
199
|
baseDelay: 500,
|
|
201
200
|
});
|
|
202
201
|
if (imgResp.ok) {
|
|
203
|
-
const buffer = await imgResp.
|
|
202
|
+
const buffer = Buffer.from(await imgResp.arrayBuffer());
|
|
204
203
|
archive.append(buffer, { name: localPath });
|
|
205
204
|
}
|
|
206
205
|
} catch {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { retry } from './retry.js';
|
|
2
|
+
|
|
3
|
+
// Shared image-download policy; keep HTTP errors distinct from network retries.
|
|
4
|
+
export async function downloadBinary(url) {
|
|
5
|
+
const response = await retry(() => fetch(url), {
|
|
6
|
+
retries: 3,
|
|
7
|
+
baseDelay: 1000,
|
|
8
|
+
});
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`HTTP ${response.status}`);
|
|
11
|
+
}
|
|
12
|
+
return Buffer.from(await response.arrayBuffer());
|
|
13
|
+
}
|
package/src/docx.js
CHANGED
|
@@ -9,18 +9,8 @@
|
|
|
9
9
|
* engine - 'puppeteer' or 'playwright' (only used for browser rendering fallback)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import fetch from 'node-fetch';
|
|
13
12
|
import * as cheerio from 'cheerio';
|
|
14
13
|
import { URL } from 'url';
|
|
15
|
-
import {
|
|
16
|
-
Document,
|
|
17
|
-
Packer,
|
|
18
|
-
Paragraph,
|
|
19
|
-
TextRun,
|
|
20
|
-
HeadingLevel,
|
|
21
|
-
ImageRun,
|
|
22
|
-
ExternalHyperlink,
|
|
23
|
-
} from 'docx';
|
|
24
14
|
import { fetchHtml, convertRelativeUrls } from './lib.js';
|
|
25
15
|
|
|
26
16
|
export async function docxHandler(req, res) {
|
|
@@ -35,6 +25,19 @@ export async function docxHandler(req, res) {
|
|
|
35
25
|
const absHtml = convertRelativeUrls(html, absoluteUrl);
|
|
36
26
|
const $ = cheerio.load(absHtml);
|
|
37
27
|
|
|
28
|
+
// Loaded on demand: docx bundles a browser util-deprecate that reads
|
|
29
|
+
// globalThis.localStorage on import, which makes Node >=25 print an
|
|
30
|
+
// ExperimentalWarning for every process that merely imports the app.
|
|
31
|
+
const {
|
|
32
|
+
Document,
|
|
33
|
+
Packer,
|
|
34
|
+
Paragraph,
|
|
35
|
+
TextRun,
|
|
36
|
+
HeadingLevel,
|
|
37
|
+
ImageRun,
|
|
38
|
+
ExternalHyperlink,
|
|
39
|
+
} = await import('docx');
|
|
40
|
+
|
|
38
41
|
// Remove unwanted elements
|
|
39
42
|
$('style, script, noscript, nav, footer, header').remove();
|
|
40
43
|
|
|
@@ -75,7 +78,7 @@ export async function docxHandler(req, res) {
|
|
|
75
78
|
const imgUrl = new URL(src, absoluteUrl).href;
|
|
76
79
|
const imgResp = await fetch(imgUrl);
|
|
77
80
|
if (imgResp.ok) {
|
|
78
|
-
const buffer = await imgResp.
|
|
81
|
+
const buffer = Buffer.from(await imgResp.arrayBuffer());
|
|
79
82
|
const contentType = imgResp.headers.get('content-type') || '';
|
|
80
83
|
children.push(
|
|
81
84
|
new Paragraph({
|
package/src/fetch.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fetch from 'node-fetch';
|
|
2
1
|
import { convertGoogleDriveUrl } from './lib.js';
|
|
3
2
|
import { copyProxyResponseHeaders } from './proxy-headers.js';
|
|
4
3
|
|
|
@@ -14,7 +13,7 @@ export async function fetchHandler(req, res) {
|
|
|
14
13
|
copyProxyResponseHeaders(response.headers, res);
|
|
15
14
|
|
|
16
15
|
// Get the response body as buffer and send it
|
|
17
|
-
const buffer = await response.
|
|
16
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
18
17
|
res.send(buffer);
|
|
19
18
|
} catch (err) {
|
|
20
19
|
console.error('Fetch error:', err);
|
package/src/figures.js
CHANGED
|
@@ -10,10 +10,9 @@
|
|
|
10
10
|
* @module figures
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import fetch from 'node-fetch';
|
|
14
13
|
import * as cheerio from 'cheerio';
|
|
15
14
|
import { URL } from 'url';
|
|
16
|
-
import {
|
|
15
|
+
import { downloadBinary } from './binary-download.js';
|
|
17
16
|
import { createBrowser, getBrowserEngine } from './browser.js';
|
|
18
17
|
import { dismissPopups, scrollToLoadContent } from './popups.js';
|
|
19
18
|
|
|
@@ -86,16 +85,7 @@ export async function downloadFigures(figures, options = {}) {
|
|
|
86
85
|
const filename = `figure-${figure.figureNum}.${ext}`;
|
|
87
86
|
|
|
88
87
|
try {
|
|
89
|
-
const
|
|
90
|
-
retries: 3,
|
|
91
|
-
baseDelay: 1000,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
if (!resp.ok) {
|
|
95
|
-
throw new Error(`HTTP ${resp.status}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const buffer = await resp.buffer();
|
|
88
|
+
const buffer = await downloadBinary(figure.src);
|
|
99
89
|
|
|
100
90
|
if (options.onProgress) {
|
|
101
91
|
options.onProgress(figure.figureNum, 'downloaded');
|
package/src/gdocs-images.js
CHANGED
package/src/gdocs.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
// https://docs.googleapis.com/v1/documents/{DOCUMENT_ID}
|
|
8
8
|
// Browser-model capture loads /edit and extracts DOCS_modelChunk data.
|
|
9
9
|
|
|
10
|
-
import fetch from 'node-fetch';
|
|
11
10
|
import * as he from 'he';
|
|
12
11
|
import * as cheerio from 'cheerio';
|
|
13
12
|
import { convertHtmlToMarkdown } from './lib.js';
|
package/src/github.js
CHANGED
package/src/lib.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-useless-escape */
|
|
2
2
|
// Common logic for the web-capture microservice
|
|
3
|
-
import fetch from 'node-fetch';
|
|
4
3
|
import * as cheerio from 'cheerio';
|
|
5
4
|
import TurndownService from 'turndown';
|
|
6
5
|
import iconv from 'iconv-lite';
|
|
@@ -151,7 +150,7 @@ export async function fetchGoogleDriveImage(url) {
|
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
return {
|
|
154
|
-
buffer: await response.
|
|
153
|
+
buffer: Buffer.from(await response.arrayBuffer()),
|
|
155
154
|
contentType,
|
|
156
155
|
downloadUrl,
|
|
157
156
|
filename: `google-drive-${fileId}.${imageExtensionForContentType(contentType)}`,
|
package/src/localize-images.js
CHANGED
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
* @module localize-images
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import fetch from 'node-fetch';
|
|
17
16
|
import { URL } from 'url';
|
|
18
|
-
import {
|
|
17
|
+
import { downloadBinary } from './binary-download.js';
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Extract image references from markdown text.
|
|
@@ -165,16 +164,7 @@ export async function localizeImages(markdownText, options = {}) {
|
|
|
165
164
|
}
|
|
166
165
|
|
|
167
166
|
try {
|
|
168
|
-
const
|
|
169
|
-
retries: 3,
|
|
170
|
-
baseDelay: 1000,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
if (!resp.ok) {
|
|
174
|
-
throw new Error(`HTTP ${resp.status}`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const buffer = await resp.buffer();
|
|
167
|
+
const buffer = await downloadBinary(image.url);
|
|
178
168
|
downloadedCount++;
|
|
179
169
|
|
|
180
170
|
replacements.push({
|
package/src/markdown.js
CHANGED
|
@@ -18,7 +18,6 @@ import { applyImageMode } from './extract-images.js';
|
|
|
18
18
|
import { createBrowser, getBrowserEngine } from './browser.js';
|
|
19
19
|
import { retry } from './retry.js';
|
|
20
20
|
import { ZipArchive } from 'archiver';
|
|
21
|
-
import fetch from 'node-fetch';
|
|
22
21
|
import * as cheerio from 'cheerio';
|
|
23
22
|
|
|
24
23
|
const INLINE_MARKDOWN_LINE_LIMIT = 1500;
|
package/src/shared-dialog.js
CHANGED
package/src/stream.js
CHANGED
package/src/transport.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fetch from 'node-fetch';
|
|
2
|
-
|
|
3
1
|
export const RECEIPT_HEADERS = [
|
|
4
2
|
'cache-control',
|
|
5
3
|
'content-encoding',
|
|
@@ -22,22 +20,42 @@ function selectedHeaders(headers) {
|
|
|
22
20
|
return selected;
|
|
23
21
|
}
|
|
24
22
|
|
|
23
|
+
const TIMEOUT_CAUSE_CODES = new Set([
|
|
24
|
+
'ETIMEDOUT',
|
|
25
|
+
'UND_ERR_CONNECT_TIMEOUT',
|
|
26
|
+
'UND_ERR_HEADERS_TIMEOUT',
|
|
27
|
+
'UND_ERR_BODY_TIMEOUT',
|
|
28
|
+
]);
|
|
29
|
+
|
|
25
30
|
function classifyTransportError(error, signal) {
|
|
26
31
|
if (signal?.aborted || error?.name === 'AbortError') {
|
|
27
32
|
return 'cancelled';
|
|
28
33
|
}
|
|
29
|
-
if (
|
|
34
|
+
if (
|
|
35
|
+
error?.name === 'TimeoutError' ||
|
|
36
|
+
TIMEOUT_CAUSE_CODES.has(error?.cause?.code)
|
|
37
|
+
) {
|
|
30
38
|
return 'timeout';
|
|
31
39
|
}
|
|
32
|
-
|
|
40
|
+
// Node's built-in fetch rejects every network failure with
|
|
41
|
+
// TypeError('fetch failed') and the real reason in `cause`. Browsers give a
|
|
42
|
+
// cause-less TypeError for CORS and network errors alike.
|
|
43
|
+
if (error?.name === 'TypeError' && !error.cause) {
|
|
33
44
|
return 'cors_or_transport';
|
|
34
45
|
}
|
|
35
46
|
return 'transport';
|
|
36
47
|
}
|
|
37
48
|
|
|
49
|
+
/** Message of `error` including its `cause`, e.g. "fetch failed: getaddrinfo ENOTFOUND host". */
|
|
50
|
+
export function describeTransportError(error) {
|
|
51
|
+
const message = error?.message || String(error);
|
|
52
|
+
const cause = error?.cause?.message;
|
|
53
|
+
return cause && !message.includes(cause) ? `${message}: ${cause}` : message;
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
export class CaptureTransportError extends Error {
|
|
39
57
|
constructor(error, url, signal) {
|
|
40
|
-
super(
|
|
58
|
+
super(describeTransportError(error));
|
|
41
59
|
this.name = 'CaptureTransportError';
|
|
42
60
|
this.cause = error;
|
|
43
61
|
this.diagnostics = {
|
package/src/txt.js
CHANGED
package/.changeset/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
-
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
-
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
-
|
|
7
|
-
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
-
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
package/.changeset/config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": "@changesets/cli/changelog",
|
|
4
|
-
"commit": false,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "public",
|
|
8
|
-
"baseBranch": "main",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|
package/.dockerignore
DELETED
package/.jscpd.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"minTokens": 30,
|
|
3
|
-
"minLines": 5,
|
|
4
|
-
"ignore": [
|
|
5
|
-
"**/node_modules/**",
|
|
6
|
-
"**/build/**",
|
|
7
|
-
"**/dist/**",
|
|
8
|
-
"**/*.min.js",
|
|
9
|
-
"**/coverage/**",
|
|
10
|
-
"**/.changeset/**",
|
|
11
|
-
"**/package-lock.json",
|
|
12
|
-
"**/pnpm-lock.yaml",
|
|
13
|
-
"**/yarn.lock",
|
|
14
|
-
"**/reports/**"
|
|
15
|
-
],
|
|
16
|
-
"reporters": ["console", "html"],
|
|
17
|
-
"output": "./reports/jscpd",
|
|
18
|
-
"mode": "weak"
|
|
19
|
-
}
|
package/.lenv
DELETED
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/Dockerfile
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
FROM node:24-bookworm
|
|
2
|
-
|
|
3
|
-
WORKDIR /app
|
|
4
|
-
|
|
5
|
-
# Install dependencies for headless Chrome (used by both Puppeteer and Playwright)
|
|
6
|
-
# Retry loop handles transient network errors from Debian mirrors in CI
|
|
7
|
-
RUN apt-get update && \
|
|
8
|
-
for i in 1 2 3; do \
|
|
9
|
-
apt-get install -y \
|
|
10
|
-
chromium \
|
|
11
|
-
fonts-liberation \
|
|
12
|
-
libasound2 \
|
|
13
|
-
libatk-bridge2.0-0 \
|
|
14
|
-
libatk1.0-0 \
|
|
15
|
-
libatspi2.0-0 \
|
|
16
|
-
libcups2 \
|
|
17
|
-
libdbus-1-3 \
|
|
18
|
-
libdrm2 \
|
|
19
|
-
libgbm1 \
|
|
20
|
-
libgtk-3-0 \
|
|
21
|
-
libnspr4 \
|
|
22
|
-
libnss3 \
|
|
23
|
-
libxcomposite1 \
|
|
24
|
-
libxdamage1 \
|
|
25
|
-
libxfixes3 \
|
|
26
|
-
libxrandr2 \
|
|
27
|
-
libxshmfence1 \
|
|
28
|
-
xdg-utils \
|
|
29
|
-
--no-install-recommends && break || \
|
|
30
|
-
{ if [ "$i" -eq 3 ]; then exit 1; fi; \
|
|
31
|
-
echo "apt-get install attempt $i failed, retrying..."; \
|
|
32
|
-
apt-get update && sleep 5; }; \
|
|
33
|
-
done && \
|
|
34
|
-
rm -rf /var/lib/apt/lists/*
|
|
35
|
-
|
|
36
|
-
# Set Puppeteer environment variables
|
|
37
|
-
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
|
38
|
-
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
39
|
-
ENV PUPPETEER_ARGS="--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage"
|
|
40
|
-
|
|
41
|
-
# Set Playwright environment variables
|
|
42
|
-
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
|
43
|
-
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
|
|
44
|
-
|
|
45
|
-
COPY package.json package-lock.json ./
|
|
46
|
-
RUN npm ci
|
|
47
|
-
|
|
48
|
-
COPY . .
|
|
49
|
-
|
|
50
|
-
EXPOSE 3000
|
|
51
|
-
|
|
52
|
-
ENTRYPOINT ["node", "bin/web-capture.js", "--serve"]
|
package/babel.config.cjs
DELETED