@link-assistant/web-capture 1.1.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 (56) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/workflows/release.yml +294 -0
  4. package/.jscpd.json +20 -0
  5. package/.lenv +8 -0
  6. package/.prettierignore +7 -0
  7. package/.prettierrc +10 -0
  8. package/ARCHITECTURE.md +982 -0
  9. package/CHANGELOG.md +22 -0
  10. package/Dockerfile +45 -0
  11. package/LICENSE +24 -0
  12. package/README.md +268 -0
  13. package/apply.sh +166 -0
  14. package/babel.config.cjs +13 -0
  15. package/bin/web-capture.js +285 -0
  16. package/docker-compose.yml +9 -0
  17. package/docs/market-analysis-2025-05-13.md +64 -0
  18. package/eslint.config.js +112 -0
  19. package/examples/js/engine_comparison.js +39 -0
  20. package/examples/js/html_download.js +23 -0
  21. package/examples/js/image_download.js +36 -0
  22. package/examples/js/markdown_download.js +23 -0
  23. package/examples/js/playwright_example.js +23 -0
  24. package/examples/python/html_download.py +15 -0
  25. package/examples/python/image_download.py +20 -0
  26. package/examples/python/markdown_download.py +15 -0
  27. package/examples/python/playwright_example.py +22 -0
  28. package/jest.config.mjs +18 -0
  29. package/package.json +83 -0
  30. package/scripts/changeset-version.mjs +38 -0
  31. package/scripts/create-github-release.mjs +93 -0
  32. package/scripts/create-manual-changeset.mjs +88 -0
  33. package/scripts/format-github-release.mjs +83 -0
  34. package/scripts/format-release-notes.mjs +218 -0
  35. package/scripts/instant-version-bump.mjs +121 -0
  36. package/scripts/publish-to-npm.mjs +128 -0
  37. package/scripts/setup-npm.mjs +37 -0
  38. package/scripts/validate-changeset.mjs +106 -0
  39. package/scripts/version-and-commit.mjs +237 -0
  40. package/src/browser.js +207 -0
  41. package/src/fetch.js +38 -0
  42. package/src/html.js +64 -0
  43. package/src/image.js +41 -0
  44. package/src/index.js +55 -0
  45. package/src/lib.js +330 -0
  46. package/src/markdown.js +17 -0
  47. package/src/stream.js +50 -0
  48. package/tests/e2e/docker.test.js +148 -0
  49. package/tests/e2e/process.test.js +117 -0
  50. package/tests/integration/browser-engines.test.js +128 -0
  51. package/tests/jest.setup.mjs +7 -0
  52. package/tests/mock/index.test.js +223 -0
  53. package/tests/unit/browser.test.js +136 -0
  54. package/tests/unit/cli.test.js +151 -0
  55. package/tests/unit/convertRelativeUrls.test.js +34 -0
  56. package/tests/unit/html2md.test.js +610 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # web-capture
2
+
3
+ ## 1.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a9ebb49: fix: configure scoped package name @link-assistant/web-capture for npm publishing
8
+
9
+ Updated package.json and all release scripts to use the correct scoped npm package name `@link-assistant/web-capture` instead of the incorrectly configured `my-package` and unscoped `web-capture` names.
10
+
11
+ ## 1.1.1
12
+
13
+ ### Patch Changes
14
+
15
+ - 155d3a6: Add comprehensive CI/CD pipeline based on js-ai-driven-development-pipeline-template
16
+ - Add GitHub Actions workflow for automated testing, linting, and releases
17
+ - Integrate changesets for version management and changelog generation
18
+ - Add ESLint, Prettier, and JSCPD for code quality checks
19
+ - Configure lint-staged and Husky for pre-commit hooks
20
+ - Add e2e tests that work in CI with Playwright
21
+ - Automated npm publishing via OIDC trusted publishing
22
+ - GitHub release generation with formatted notes
package/Dockerfile ADDED
@@ -0,0 +1,45 @@
1
+ FROM node:22-bullseye
2
+
3
+ WORKDIR /app
4
+
5
+ # Install dependencies for headless Chrome (used by both Puppeteer and Playwright)
6
+ RUN apt-get update && apt-get install -y \
7
+ chromium \
8
+ fonts-liberation \
9
+ libasound2 \
10
+ libatk-bridge2.0-0 \
11
+ libatk1.0-0 \
12
+ libatspi2.0-0 \
13
+ libcups2 \
14
+ libdbus-1-3 \
15
+ libdrm2 \
16
+ libgbm1 \
17
+ libgtk-3-0 \
18
+ libnspr4 \
19
+ libnss3 \
20
+ libxcomposite1 \
21
+ libxdamage1 \
22
+ libxfixes3 \
23
+ libxrandr2 \
24
+ libxshmfence1 \
25
+ xdg-utils \
26
+ --no-install-recommends && \
27
+ rm -rf /var/lib/apt/lists/*
28
+
29
+ # Set Puppeteer environment variables
30
+ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
31
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
32
+ ENV PUPPETEER_ARGS="--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage"
33
+
34
+ # Set Playwright environment variables
35
+ ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
36
+ ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
37
+
38
+ COPY package.json yarn.lock ./
39
+ RUN yarn install --frozen-lockfile
40
+
41
+ COPY . .
42
+
43
+ EXPOSE 3000
44
+
45
+ ENTRYPOINT ["node", "bin/web-capture.js", "--serve"]
package/LICENSE ADDED
@@ -0,0 +1,24 @@
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/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # web-capture
2
+
3
+ <img width="1824" alt="Screenshot 2025-05-12 at 3 49 32 AM" src="https://github.com/user-attachments/assets/cbf63dec-7dcd-40e7-9d5d-eddc49fe6169" />
4
+
5
+ A CLI and microservice to fetch URLs and render them as:
6
+
7
+ - **HTML**: Rendered page content
8
+ - **Markdown**: Converted from HTML
9
+ - **PNG screenshot**: Full page capture
10
+
11
+ ## Quick Start
12
+
13
+ ### CLI Usage
14
+
15
+ ```bash
16
+ # Install globally
17
+ npm install -g web-capture
18
+
19
+ # Capture a URL as HTML (output to stdout)
20
+ web-capture https://example.com
21
+
22
+ # Capture as Markdown and save to file
23
+ web-capture https://example.com --format markdown --output page.md
24
+
25
+ # Take a screenshot
26
+ web-capture https://example.com --format png --output screenshot.png
27
+
28
+ # Start as API server
29
+ web-capture --serve
30
+
31
+ # Start server on custom port
32
+ web-capture --serve --port 8080
33
+ ```
34
+
35
+ ### API Endpoints (Server Mode)
36
+
37
+ - **HTML**: GET /html?url=<URL>
38
+ - **Markdown**: GET /markdown?url=<URL>
39
+ - **PNG screenshot**: GET /image?url=<URL>
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ npm install
45
+ # or
46
+ yarn install
47
+ ```
48
+
49
+ ## CLI Reference
50
+
51
+ ### Server Mode
52
+
53
+ Start the API server:
54
+
55
+ ```bash
56
+ web-capture --serve [--port <port>]
57
+ ```
58
+
59
+ | Option | Short | Description | Default |
60
+ | --------- | ----- | ------------------------ | ------------------ |
61
+ | `--serve` | `-s` | Start as HTTP API server | - |
62
+ | `--port` | `-p` | Port to listen on | 3000 (or PORT env) |
63
+
64
+ ### Capture Mode
65
+
66
+ Capture a URL directly:
67
+
68
+ ```bash
69
+ web-capture <url> [options]
70
+ ```
71
+
72
+ | Option | Short | Description | Default |
73
+ | ---------- | ----- | ----------------------------------------------------- | ---------------------------------------- |
74
+ | `--format` | `-f` | Output format: `html`, `markdown`/`md`, `image`/`png` | `html` |
75
+ | `--output` | `-o` | Output file path | stdout (text) or auto-generated (images) |
76
+ | `--engine` | `-e` | Browser engine: `puppeteer`, `playwright` | `puppeteer` (or BROWSER_ENGINE env) |
77
+
78
+ ### Examples
79
+
80
+ ```bash
81
+ # Capture HTML to stdout
82
+ web-capture https://example.com
83
+
84
+ # Capture Markdown to file
85
+ web-capture https://example.com -f markdown -o page.md
86
+
87
+ # Take screenshot with Playwright engine
88
+ web-capture https://example.com -f png -e playwright -o screenshot.png
89
+
90
+ # Pipe HTML to another command
91
+ web-capture https://example.com | grep "title"
92
+ ```
93
+
94
+ ## Available Commands
95
+
96
+ ### Development
97
+
98
+ - `yarn dev` - Start the development server with hot reloading using nodemon
99
+ - `yarn start` - Start the service using Docker Compose
100
+
101
+ ### Testing
102
+
103
+ - `yarn test` - Run all unit tests
104
+ - `yarn test:watch` - Run tests in watch mode
105
+ - `yarn test:e2e` - Run end-to-end tests
106
+ - `yarn test:e2e:docker` - Run end-to-end tests against Docker container
107
+ - `yarn test:all` - Run all tests including build and e2e tests
108
+
109
+ ### Building
110
+
111
+ - `yarn build` - Build and start the Docker container
112
+
113
+ ### Examples
114
+
115
+ - `yarn examples:python` - Run Python example scripts
116
+ - `yarn examples:javascript` - Run JavaScript example scripts
117
+ - `yarn examples` - Run all examples (requires build)
118
+
119
+ ## Usage
120
+
121
+ ### Local Development
122
+
123
+ ```bash
124
+ yarn dev
125
+ curl http://localhost:3000/html?url=https://example.com
126
+ ```
127
+
128
+ ### Docker
129
+
130
+ ```bash
131
+ # Build and run using Docker Compose
132
+ yarn start
133
+
134
+ # Or manually
135
+ docker build -t web-capture .
136
+ docker run -p 3000:3000 web-capture
137
+ ```
138
+
139
+ ## API Endpoints
140
+
141
+ ### HTML Endpoint
142
+
143
+ ```bash
144
+ GET /html?url=<URL>&engine=<ENGINE>
145
+ ```
146
+
147
+ Returns the raw HTML content of the specified URL.
148
+
149
+ **Parameters:**
150
+
151
+ - `url` (required): The URL to fetch
152
+ - `engine` (optional): Browser engine to use (`puppeteer` or `playwright`). Default: `puppeteer`
153
+
154
+ **Examples:**
155
+
156
+ ```bash
157
+ # Using default Puppeteer engine
158
+ curl http://localhost:3000/html?url=https://example.com
159
+
160
+ # Using Playwright engine
161
+ curl http://localhost:3000/html?url=https://example.com&engine=playwright
162
+ ```
163
+
164
+ ### Markdown Endpoint
165
+
166
+ ```bash
167
+ GET /markdown?url=<URL>
168
+ ```
169
+
170
+ Converts the HTML content of the specified URL to Markdown format.
171
+
172
+ ### Image Endpoint
173
+
174
+ ```bash
175
+ GET /image?url=<URL>&engine=<ENGINE>
176
+ ```
177
+
178
+ Returns a PNG screenshot of the specified URL.
179
+
180
+ **Parameters:**
181
+
182
+ - `url` (required): The URL to capture
183
+ - `engine` (optional): Browser engine to use (`puppeteer` or `playwright`). Default: `puppeteer`
184
+
185
+ **Examples:**
186
+
187
+ ```bash
188
+ # Using default Puppeteer engine
189
+ curl http://localhost:3000/image?url=https://example.com > screenshot.png
190
+
191
+ # Using Playwright engine
192
+ curl http://localhost:3000/image?url=https://example.com&engine=playwright > screenshot.png
193
+ ```
194
+
195
+ ## Configuration
196
+
197
+ web-capture uses [lino-arguments](https://github.com/link-foundation/lino-arguments) for unified configuration management. Configuration values are resolved with the following priority (highest to lowest):
198
+
199
+ 1. **CLI arguments**: `--port 8080`
200
+ 2. **Environment variables**: `PORT=8080`
201
+ 3. **Custom configuration file**: `--configuration path/to/custom.lenv`
202
+ 4. **Default .lenv file**: `.lenv` in the project root
203
+ 5. **Built-in defaults**
204
+
205
+ ### Configuration File (.lenv)
206
+
207
+ Create a `.lenv` file in your project root using Links Notation format:
208
+
209
+ ```lenv
210
+ # Server configuration
211
+ PORT: 3000
212
+
213
+ # Browser engine (puppeteer or playwright)
214
+ BROWSER_ENGINE: puppeteer
215
+ ```
216
+
217
+ ### Using Custom Configuration Files
218
+
219
+ Specify a custom configuration file path:
220
+
221
+ ```bash
222
+ web-capture --serve --configuration /path/to/custom.lenv
223
+ ```
224
+
225
+ ### Environment Variables
226
+
227
+ All configuration options support environment variables:
228
+
229
+ ```bash
230
+ # Set port via environment variable
231
+ export PORT=8080
232
+ web-capture --serve
233
+
234
+ # Set browser engine
235
+ export BROWSER_ENGINE=playwright
236
+ web-capture https://example.com --format png
237
+ ```
238
+
239
+ ## Browser Engine Support
240
+
241
+ The service supports both **Puppeteer** and **Playwright** browser engines:
242
+
243
+ - **Puppeteer**: Default engine, mature and well-tested
244
+ - **Playwright**: Alternative engine with similar capabilities
245
+
246
+ You can choose the engine using:
247
+
248
+ - CLI argument: `--engine playwright`
249
+ - Environment variable: `BROWSER_ENGINE=playwright`
250
+ - Configuration file: `BROWSER_ENGINE: playwright` in `.lenv`
251
+
252
+ **Supported engine values:**
253
+
254
+ - `puppeteer` or `pptr` - Use Puppeteer
255
+ - `playwright` or `pw` - Use Playwright
256
+
257
+ ## Development
258
+
259
+ The service is built with:
260
+
261
+ - Express.js for the web server
262
+ - Puppeteer and Playwright for headless browser automation and screenshots
263
+ - Turndown for HTML to Markdown conversion
264
+ - Jest for testing
265
+
266
+ ## License
267
+
268
+ UNLICENSED
package/apply.sh ADDED
@@ -0,0 +1,166 @@
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
+ "
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ presets: [
3
+ [
4
+ '@babel/preset-env',
5
+ {
6
+ targets: {
7
+ node: 'current',
8
+ },
9
+ modules: false,
10
+ },
11
+ ],
12
+ ],
13
+ };