@link-assistant/web-capture 1.1.2 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +17 -14
  2. package/README.md +256 -146
  3. package/bin/web-capture.js +403 -6
  4. package/package.json +11 -4
  5. package/src/animation.js +283 -0
  6. package/src/archive.js +212 -0
  7. package/src/batch.js +180 -0
  8. package/src/browser.js +150 -111
  9. package/src/docx.js +182 -0
  10. package/src/figures.js +208 -0
  11. package/src/gdocs.js +333 -0
  12. package/src/image.js +65 -8
  13. package/src/index.js +15 -0
  14. package/src/latex.js +127 -0
  15. package/src/lib.js +226 -1
  16. package/src/localize-images.js +202 -0
  17. package/src/metadata.js +333 -0
  18. package/src/pdf.js +76 -0
  19. package/src/popups.js +171 -0
  20. package/src/postprocess.js +265 -0
  21. package/src/retry.js +48 -0
  22. package/src/themed-image.js +167 -0
  23. package/src/verify.js +312 -0
  24. package/tests/e2e/docker.test.js +51 -12
  25. package/tests/e2e/process.test.js +34 -10
  26. package/tests/fixtures/habr-articles.js +45 -0
  27. package/tests/integration/api-endpoints.test.js +231 -0
  28. package/tests/integration/habr-article.test.js +337 -0
  29. package/tests/mock/index.test.js +5 -3
  30. package/tests/unit/animation.test.js +33 -0
  31. package/tests/unit/batch.test.js +114 -0
  32. package/tests/unit/browser.test.js +38 -2
  33. package/tests/unit/figures.test.js +74 -0
  34. package/tests/unit/gdocs.test.js +203 -0
  35. package/tests/unit/latex.test.js +123 -0
  36. package/tests/unit/localize-images.test.js +78 -0
  37. package/tests/unit/metadata.test.js +140 -0
  38. package/tests/unit/postprocess.test.js +108 -0
  39. package/tests/unit/retry.test.js +111 -0
  40. package/tests/unit/verify.test.js +182 -0
  41. package/.github/workflows/release.yml +0 -294
  42. package/ARCHITECTURE.md +0 -982
  43. package/LICENSE +0 -24
  44. package/apply.sh +0 -166
  45. package/docs/market-analysis-2025-05-13.md +0 -64
  46. package/scripts/changeset-version.mjs +0 -38
  47. package/scripts/create-github-release.mjs +0 -93
  48. package/scripts/create-manual-changeset.mjs +0 -88
  49. package/scripts/format-github-release.mjs +0 -83
  50. package/scripts/format-release-notes.mjs +0 -218
  51. package/scripts/instant-version-bump.mjs +0 -121
  52. package/scripts/publish-to-npm.mjs +0 -128
  53. package/scripts/setup-npm.mjs +0 -37
  54. package/scripts/validate-changeset.mjs +0 -106
  55. package/scripts/version-and-commit.mjs +0 -237
package/LICENSE DELETED
@@ -1,24 +0,0 @@
1
- This is free and unencumbered software released into the public domain.
2
-
3
- Anyone is free to copy, modify, publish, use, compile, sell, or
4
- distribute this software, either in source code form or as a compiled
5
- binary, for any purpose, commercial or non-commercial, and by any
6
- means.
7
-
8
- In jurisdictions that recognize copyright laws, the author or authors
9
- of this software dedicate any and all copyright interest in the
10
- software to the public domain. We make this dedication for the benefit
11
- of the public at large and to the detriment of our heirs and
12
- successors. We intend this dedication to be an overt act of
13
- relinquishment in perpetuity of all present and future rights to this
14
- software under copyright law.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
- OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- For more information, please refer to <https://unlicense.org>
package/apply.sh DELETED
@@ -1,166 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Usage: ./init.sh [directory]
5
- DIR=${1:-web-capture}
6
- echo "Initializing web-capture microservice in '$DIR'..."
7
-
8
- # Create project directory and enter
9
- mkdir -p "$DIR"
10
- cd "$DIR"
11
-
12
- # Initialize git
13
- git init
14
-
15
- echo "# Creating package.json"
16
- cat > package.json << 'EOF'
17
- {
18
- "name": "web-capture",
19
- "version": "1.0.0",
20
- "description": "Microservice to render web pages as HTML, Markdown, or PNG",
21
- "main": "index.js",
22
- "scripts": {
23
- "start": "node index.js",
24
- "dev": "nodemon index.js"
25
- },
26
- "dependencies": {
27
- "express": "^4.18.2",
28
- "turndown": "^7.1.1",
29
- "capture-website": "^4.0.0"
30
- },
31
- "type": "module",
32
- "keywords": ["render", "markdown", "screenshot", "microservice"],
33
- "license": "MIT"
34
- }
35
- EOF
36
-
37
- # Install dependencies
38
- if command -v yarn >/dev/null 2>&1; then
39
- echo "Installing dependencies with yarn..."
40
- yarn install
41
- else
42
- echo "Installing dependencies with npm..."
43
- npm install
44
- fi
45
-
46
- echo "# Writing index.js"
47
- cat > index.js << 'EOF'
48
- import express from 'express';
49
- import fetch from 'node:fetch'; // Node 18+ has native fetch
50
- import TurndownService from 'turndown';
51
- import captureWebsite from 'capture-website';
52
-
53
- const app = express();
54
- const port = process.env.PORT || 3000;
55
-
56
- // Route: Fetch raw HTML
57
- app.get('/html', async (req, res) => {
58
- const url = req.query.url;
59
- if (!url) return res.status(400).send('Missing `url` parameter');
60
- try {
61
- const response = await fetch(url);
62
- const html = await response.text();
63
- res.type('text/html').send(html);
64
- } catch (err) {
65
- console.error(err);
66
- res.status(500).send('Error fetching HTML');
67
- }
68
- });
69
-
70
- // Route: Convert HTML to Markdown
71
- app.get('/markdown', async (req, res) => {
72
- const url = req.query.url;
73
- if (!url) return res.status(400).send('Missing `url` parameter');
74
- try {
75
- const response = await fetch(url);
76
- const html = await response.text();
77
- const turndown = new TurndownService();
78
- const markdown = turndown.turndown(html);
79
- res.type('text/markdown').send(markdown);
80
- } catch (err) {
81
- console.error(err);
82
- res.status(500).send('Error converting to Markdown');
83
- }
84
- });
85
-
86
- // Route: Capture screenshot as PNG
87
- app.get('/image', async (req, res) => {
88
- const url = req.query.url;
89
- if (!url) return res.status(400).send('Missing `url` parameter');
90
- try {
91
- const buffer = await captureWebsite.buffer(url, { fullPage: true });
92
- res.type('image/png').send(buffer);
93
- } catch (err) {
94
- console.error(err);
95
- res.status(500).send('Error capturing screenshot');
96
- }
97
- });
98
-
99
- app.listen(port, () => {
100
- console.log(`Renderer service listening on http://localhost:${port}`);
101
- });
102
- EOF
103
-
104
- echo "# Writing Dockerfile"
105
- cat > Dockerfile << 'EOF'
106
- FROM node:20-slim
107
-
108
- WORKDIR /usr/src/app
109
- COPY package.json yarn.lock* ./
110
-
111
- # Install production dependencies and Chrome deps
112
- RUN apt-get update && apt-get install -y \
113
- gconf-service libasound2 libatk1.0-0 libc6 libcairo2 \
114
- libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 \
115
- libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libstdc++6 \
116
- libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 \
117
- libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
118
- ca-certificates fonts-liberation lsb-release xdg-utils wget \
119
- --no-install-recommends && rm -rf /var/lib/apt/lists/* \
120
- && npm install --production
121
-
122
- COPY . .
123
- ENV NODE_ENV=production
124
- EXPOSE 3000
125
- CMD ["node", "index.js"]
126
- EOF
127
-
128
- echo "# Creating .gitignore"
129
- cat > .gitignore << 'EOF'
130
- node_modules
131
- .env
132
- EOF
133
-
134
- echo "# Creating README.md"
135
- cat > README.md << 'EOF'
136
- # web-capture
137
-
138
- A microservice to fetch URLs and render them as:
139
-
140
- - **HTML**: GET /html?url=<URL>
141
- - **Markdown**: GET /markdown?url=<URL>
142
- - **PNG screenshot**: GET /image?url=<URL>
143
-
144
- ## Usage
145
-
146
- ```bash
147
- npm start
148
- # or
149
- yarn start
150
- curl http://localhost:3000/html?url=https://example.com
151
- ```
152
-
153
- ## Docker
154
-
155
- ```bash
156
- docker build -t web-capture .
157
- docker run -p 3000:3000 web-capture
158
- ```
159
- EOF
160
-
161
- echo "
162
- ✔ Project 'web-capture' scaffolded successfully in $(pwd)
163
- Next steps:
164
- cd "$(pwd)"
165
- npm start
166
- "
@@ -1,64 +0,0 @@
1
- # Market Analysis Report: 13 May 2025
2
-
3
- This report analyzes open-source projects similar to "web-capture," a microservice for capturing web content in HTML, Markdown, and PNG formats. The projects are grouped into **microservices** and **libraries**, with each evaluated for its features and relevance to web content capture. Below are two tables summarizing the findings, followed by detailed feature lists for each project.
4
-
5
- ---
6
-
7
- ## Microservices for Web Capture
8
-
9
- | **Project** | **License** | **GitHub Link** |
10
- | ----------------------- | ----------- | ----------------------------------------------------------------------------------------- |
11
- | **screeenly** | MIT | [stefanzweifel/screeenly](https://github.com/stefanzweifel/screeenly) |
12
- | **capture-website-api** | ISC | [robvanderleek/capture-website-api](https://github.com/robvanderleek/capture-website-api) |
13
- | **captino** | MIT | [pistatium/captino](https://github.com/pistatium/captino) |
14
- | **gowitness** | MIT | [gowitness/gowitness](https://github.com/gowitness/gowitness) |
15
-
16
- ### Features of Microservices
17
-
18
- - **screeenly**
19
- - API for screenshots (PNG), PDFs, and HTML rendering
20
- - Customizable via pixel density and image loading options
21
- - Self-hosting support via Heroku, Zeet, or Docker
22
-
23
- - **capture-website-api**
24
- - API for website screenshots (PNG)
25
- - Customizable via query parameters (e.g., width, height, scale)
26
- - Uses Puppeteer for rendering complex sites
27
- - Configurable via environment variables
28
-
29
- - **captino**
30
- - API for webpage screenshots (PNG)
31
- - Supports full-page captures
32
- - Easy deployment with Docker
33
-
34
- - **gowitness**
35
- - Command-line tool for website screenshots (PNG)
36
- - Batch processing and report generation
37
- - Built with Golang and Chrome Headless
38
-
39
- ---
40
-
41
- ## Libraries for Web Capture
42
-
43
- | **Project** | **License** | **GitHub Link** |
44
- | -------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- |
45
- | **webpage-capture** | MIT | [b4dnewz/webpage-capture](https://github.com/b4dnewz/webpage-capture) |
46
- | **html-screen-capture-js** | MIT | [html-screen-capture-js/html-screen-capture-js](https://github.com/html-screen-capture-js/html-screen-capture-js) |
47
-
48
- ### Features of Libraries
49
-
50
- - **webpage-capture**
51
- - Captures web pages in PNG, JPEG, PDF, HTML, and other formats
52
- - Customizable via options like timeout and headers
53
- - Supports single and batch captures
54
-
55
- - **html-screen-capture-js**
56
- - Captures webpages as self-contained HTML
57
- - Removes external dependencies while preserving appearance
58
- - Lightweight (12KB)
59
-
60
- ---
61
-
62
- ## Summary
63
-
64
- The report identifies four microservices (**screeenly**, **capture-website-api**, **captino**, **gowitness**) and two libraries (**webpage-capture**, **html-screen-capture-js**) that align with the functionality of "web-capture." Microservices provide API-driven solutions, while libraries offer flexibility for custom implementations. All projects are open-source, licensed under permissive terms (MIT or ISC), and actively maintained as of May 13, 2025.
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Custom changeset version script that ensures package-lock.json is synchronized
5
- * with package.json after version bumps.
6
- *
7
- * This script:
8
- * 1. Runs `changeset version` to update package versions
9
- * 2. Runs `npm install` to synchronize package-lock.json with the new versions
10
- *
11
- * Uses link-foundation libraries:
12
- * - use-m: Dynamic package loading without package.json dependencies
13
- * - command-stream: Modern shell command execution with streaming support
14
- */
15
-
16
- // Load use-m dynamically
17
- const { use } = eval(
18
- await (await fetch('https://unpkg.com/use-m/use.js')).text()
19
- );
20
-
21
- // Import command-stream for shell command execution
22
- const { $ } = await use('command-stream');
23
-
24
- try {
25
- console.log('Running changeset version...');
26
- await $`npx changeset version`;
27
-
28
- console.log('\nSynchronizing package-lock.json...');
29
- await $`npm install --package-lock-only`;
30
-
31
- console.log('\n✅ Version bump complete with synchronized package-lock.json');
32
- } catch (error) {
33
- console.error('Error during version bump:', error.message);
34
- if (process.env.DEBUG) {
35
- console.error('Stack trace:', error.stack);
36
- }
37
- process.exit(1);
38
- }
@@ -1,93 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Create GitHub Release from CHANGELOG.md
5
- * Usage: node scripts/create-github-release.mjs --release-version <version> --repository <repository>
6
- * release-version: Version number (e.g., 1.0.0)
7
- * repository: GitHub repository (e.g., owner/repo)
8
- *
9
- * Uses link-foundation libraries:
10
- * - use-m: Dynamic package loading without package.json dependencies
11
- * - command-stream: Modern shell command execution with streaming support
12
- * - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
13
- */
14
-
15
- import { readFileSync } from 'fs';
16
-
17
- // Load use-m dynamically
18
- const { use } = eval(
19
- await (await fetch('https://unpkg.com/use-m/use.js')).text()
20
- );
21
-
22
- // Import link-foundation libraries
23
- const { $ } = await use('command-stream');
24
- const { makeConfig } = await use('lino-arguments');
25
-
26
- // Parse CLI arguments using lino-arguments
27
- // Note: Using --release-version instead of --version to avoid conflict with yargs' built-in --version flag
28
- const config = makeConfig({
29
- yargs: ({ yargs, getenv }) =>
30
- yargs
31
- .option('release-version', {
32
- type: 'string',
33
- default: getenv('VERSION', ''),
34
- describe: 'Version number (e.g., 1.0.0)',
35
- })
36
- .option('repository', {
37
- type: 'string',
38
- default: getenv('REPOSITORY', ''),
39
- describe: 'GitHub repository (e.g., owner/repo)',
40
- }),
41
- });
42
-
43
- const { releaseVersion: version, repository } = config;
44
-
45
- if (!version || !repository) {
46
- console.error('Error: Missing required arguments');
47
- console.error(
48
- 'Usage: node scripts/create-github-release.mjs --release-version <version> --repository <repository>'
49
- );
50
- process.exit(1);
51
- }
52
-
53
- const tag = `v${version}`;
54
-
55
- console.log(`Creating GitHub release for ${tag}...`);
56
-
57
- try {
58
- // Read CHANGELOG.md
59
- const changelog = readFileSync('./CHANGELOG.md', 'utf8');
60
-
61
- // Extract changelog entry for this version
62
- // Read from CHANGELOG.md between this version header and the next version header
63
- const versionHeaderRegex = new RegExp(`## ${version}[\\s\\S]*?(?=## \\d|$)`);
64
- const match = changelog.match(versionHeaderRegex);
65
-
66
- let releaseNotes = '';
67
- if (match) {
68
- // Remove the version header itself and trim
69
- releaseNotes = match[0].replace(`## ${version}`, '').trim();
70
- }
71
-
72
- if (!releaseNotes) {
73
- releaseNotes = `Release ${version}`;
74
- }
75
-
76
- // Create release using GitHub API with JSON input
77
- // This avoids shell escaping issues that occur when passing text via command-line arguments
78
- // (Previously caused apostrophes like "didn't" to appear as "didn'''" in releases)
79
- const payload = JSON.stringify({
80
- tag_name: tag,
81
- name: version,
82
- body: releaseNotes,
83
- });
84
-
85
- await $`gh api repos/${repository}/releases -X POST --input -`.run({
86
- stdin: payload,
87
- });
88
-
89
- console.log(`\u2705 Created GitHub release: ${tag}`);
90
- } catch (error) {
91
- console.error('Error creating release:', error.message);
92
- process.exit(1);
93
- }
@@ -1,88 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Create a changeset file for manual releases
5
- * Usage: node scripts/create-manual-changeset.mjs --bump-type <major|minor|patch> [--description <description>]
6
- *
7
- * IMPORTANT: Update the PACKAGE_NAME constant below to match your package.json
8
- *
9
- * Uses link-foundation libraries:
10
- * - use-m: Dynamic package loading without package.json dependencies
11
- * - command-stream: Modern shell command execution with streaming support
12
- * - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
13
- */
14
-
15
- import { writeFileSync } from 'fs';
16
- import { randomBytes } from 'crypto';
17
-
18
- const PACKAGE_NAME = '@link-assistant/web-capture';
19
-
20
- // Load use-m dynamically
21
- const { use } = eval(
22
- await (await fetch('https://unpkg.com/use-m/use.js')).text()
23
- );
24
-
25
- // Import link-foundation libraries
26
- const { $ } = await use('command-stream');
27
- const { makeConfig } = await use('lino-arguments');
28
-
29
- // Parse CLI arguments using lino-arguments
30
- const config = makeConfig({
31
- yargs: ({ yargs, getenv }) =>
32
- yargs
33
- .option('bump-type', {
34
- type: 'string',
35
- default: getenv('BUMP_TYPE', ''),
36
- describe: 'Version bump type: major, minor, or patch',
37
- choices: ['major', 'minor', 'patch'],
38
- })
39
- .option('description', {
40
- type: 'string',
41
- default: getenv('DESCRIPTION', ''),
42
- describe: 'Description for the changeset',
43
- }),
44
- });
45
-
46
- try {
47
- const { bumpType, description: descriptionArg } = config;
48
-
49
- // Use provided description or default based on bump type
50
- const description = descriptionArg || `Manual ${bumpType} release`;
51
-
52
- if (!bumpType || !['major', 'minor', 'patch'].includes(bumpType)) {
53
- console.error(
54
- 'Usage: node scripts/create-manual-changeset.mjs --bump-type <major|minor|patch> [--description <description>]'
55
- );
56
- process.exit(1);
57
- }
58
-
59
- // Generate a random changeset ID
60
- const changesetId = randomBytes(4).toString('hex');
61
- const changesetFile = `.changeset/manual-release-${changesetId}.md`;
62
-
63
- // Create the changeset file with single quotes to match Prettier config
64
- const content = `---
65
- '${PACKAGE_NAME}': ${bumpType}
66
- ---
67
-
68
- ${description}
69
- `;
70
-
71
- writeFileSync(changesetFile, content, 'utf-8');
72
-
73
- console.log(`Created changeset: ${changesetFile}`);
74
- console.log('Content:');
75
- console.log(content);
76
-
77
- // Format with Prettier
78
- console.log('\nFormatting with Prettier...');
79
- await $`npx prettier --write "${changesetFile}"`;
80
-
81
- console.log('\n✅ Changeset created and formatted successfully');
82
- } catch (error) {
83
- console.error('Error creating changeset:', error.message);
84
- if (process.env.DEBUG) {
85
- console.error('Stack trace:', error.stack);
86
- }
87
- process.exit(1);
88
- }
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Format GitHub release notes using the format-release-notes.mjs script
5
- * Usage: node scripts/format-github-release.mjs --release-version <version> --repository <repository> --commit-sha <commit_sha>
6
- * release-version: Version number (e.g., 1.0.0)
7
- * repository: GitHub repository (e.g., owner/repo)
8
- * commit_sha: Commit SHA for PR detection
9
- *
10
- * Uses link-foundation libraries:
11
- * - use-m: Dynamic package loading without package.json dependencies
12
- * - command-stream: Modern shell command execution with streaming support
13
- * - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
14
- */
15
-
16
- // Load use-m dynamically
17
- const { use } = eval(
18
- await (await fetch('https://unpkg.com/use-m/use.js')).text()
19
- );
20
-
21
- // Import link-foundation libraries
22
- const { $ } = await use('command-stream');
23
- const { makeConfig } = await use('lino-arguments');
24
-
25
- // Parse CLI arguments using lino-arguments
26
- // Note: Using --release-version instead of --version to avoid conflict with yargs' built-in --version flag
27
- const config = makeConfig({
28
- yargs: ({ yargs, getenv }) =>
29
- yargs
30
- .option('release-version', {
31
- type: 'string',
32
- default: getenv('VERSION', ''),
33
- describe: 'Version number (e.g., 1.0.0)',
34
- })
35
- .option('repository', {
36
- type: 'string',
37
- default: getenv('REPOSITORY', ''),
38
- describe: 'GitHub repository (e.g., owner/repo)',
39
- })
40
- .option('commit-sha', {
41
- type: 'string',
42
- default: getenv('COMMIT_SHA', ''),
43
- describe: 'Commit SHA for PR detection',
44
- }),
45
- });
46
-
47
- const { releaseVersion: version, repository, commitSha } = config;
48
-
49
- if (!version || !repository || !commitSha) {
50
- console.error('Error: Missing required arguments');
51
- console.error(
52
- 'Usage: node scripts/format-github-release.mjs --release-version <version> --repository <repository> --commit-sha <commit_sha>'
53
- );
54
- process.exit(1);
55
- }
56
-
57
- const tag = `v${version}`;
58
-
59
- try {
60
- // Get the release ID for this version
61
- let releaseId = '';
62
- try {
63
- const result =
64
- await $`gh api "repos/${repository}/releases/tags/${tag}" --jq '.id'`.run(
65
- { capture: true }
66
- );
67
- releaseId = result.stdout.trim();
68
- } catch {
69
- console.log(`\u26A0\uFE0F Could not find release for ${tag}`);
70
- process.exit(0);
71
- }
72
-
73
- if (releaseId) {
74
- console.log(`Formatting release notes for ${tag}...`);
75
- // Pass the trigger commit SHA for PR detection
76
- // This allows proper PR lookup even if the changelog doesn't have a commit hash
77
- await $`node scripts/format-release-notes.mjs --release-id "${releaseId}" --release-version "${tag}" --repository "${repository}" --commit-sha "${commitSha}"`;
78
- console.log(`\u2705 Formatted release notes for ${tag}`);
79
- }
80
- } catch (error) {
81
- console.error('Error formatting release:', error.message);
82
- process.exit(1);
83
- }