real-browser-mcp-server 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -9
- package/dist/lib/cjs/index.d.ts +2 -0
- package/dist/lib/cjs/index.d.ts.map +1 -0
- package/dist/lib/cjs/index.js +386 -0
- package/dist/lib/cjs/index.js.map +1 -0
- package/dist/lib/cjs/module/pageController.d.ts +2 -0
- package/dist/lib/cjs/module/pageController.d.ts.map +1 -0
- package/{lib → dist/lib}/cjs/module/pageController.js +28 -29
- package/dist/lib/cjs/module/pageController.js.map +1 -0
- package/dist/lib/cjs/module/turnstile.d.ts +2 -0
- package/dist/lib/cjs/module/turnstile.d.ts.map +1 -0
- package/{lib → dist/lib}/cjs/module/turnstile.js +24 -12
- package/dist/lib/cjs/module/turnstile.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +118 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/handlers/browser.d.ts +30 -0
- package/dist/src/mcp/handlers/browser.d.ts.map +1 -0
- package/dist/src/mcp/handlers/browser.js +232 -0
- package/dist/src/mcp/handlers/browser.js.map +1 -0
- package/dist/src/mcp/handlers/dom.d.ts +149 -0
- package/dist/src/mcp/handlers/dom.d.ts.map +1 -0
- package/dist/src/mcp/handlers/dom.js +577 -0
- package/dist/src/mcp/handlers/dom.js.map +1 -0
- package/dist/src/mcp/handlers/extract.d.ts +59 -0
- package/dist/src/mcp/handlers/extract.d.ts.map +1 -0
- package/dist/src/mcp/handlers/extract.js +455 -0
- package/dist/src/mcp/handlers/extract.js.map +1 -0
- package/dist/src/mcp/handlers/form-handlers.d.ts +9 -0
- package/dist/src/mcp/handlers/form-handlers.d.ts.map +1 -0
- package/dist/src/mcp/handlers/form-handlers.js +56 -0
- package/dist/src/mcp/handlers/form-handlers.js.map +1 -0
- package/dist/src/mcp/handlers/helpers.d.ts +47 -0
- package/dist/src/mcp/handlers/helpers.d.ts.map +1 -0
- package/dist/src/mcp/handlers/helpers.js +515 -0
- package/dist/src/mcp/handlers/helpers.js.map +1 -0
- package/dist/src/mcp/handlers/index.d.ts +6 -0
- package/dist/src/mcp/handlers/index.d.ts.map +1 -0
- package/dist/src/mcp/handlers/index.js +61 -0
- package/dist/src/mcp/handlers/index.js.map +1 -0
- package/dist/src/mcp/handlers/media-handlers.d.ts +10 -0
- package/dist/src/mcp/handlers/media-handlers.d.ts.map +1 -0
- package/dist/src/mcp/handlers/media-handlers.js +535 -0
- package/dist/src/mcp/handlers/media-handlers.js.map +1 -0
- package/dist/src/mcp/handlers/network.d.ts +147 -0
- package/dist/src/mcp/handlers/network.d.ts.map +1 -0
- package/dist/src/mcp/handlers/network.js +1135 -0
- package/dist/src/mcp/handlers/network.js.map +1 -0
- package/dist/src/mcp/handlers/state.d.ts +34 -0
- package/dist/src/mcp/handlers/state.d.ts.map +1 -0
- package/dist/src/mcp/handlers/state.js +226 -0
- package/dist/src/mcp/handlers/state.js.map +1 -0
- package/dist/src/mcp/handlers/utility-handlers.d.ts +167 -0
- package/dist/src/mcp/handlers/utility-handlers.d.ts.map +1 -0
- package/dist/src/mcp/handlers/utility-handlers.js +280 -0
- package/dist/src/mcp/handlers/utility-handlers.js.map +1 -0
- package/dist/src/mcp/handlers/vision.d.ts +127 -0
- package/dist/src/mcp/handlers/vision.d.ts.map +1 -0
- package/dist/src/mcp/handlers/vision.js +549 -0
- package/dist/src/mcp/handlers/vision.js.map +1 -0
- package/dist/src/mcp/index.d.ts +3 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +166 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/server.d.ts +2 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +117 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +8 -0
- package/dist/src/mcp/tools.d.ts.map +1 -0
- package/{src → dist/src}/mcp/tools.js +12 -11
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/shared/cache-manager.d.ts +80 -0
- package/dist/src/shared/cache-manager.d.ts.map +1 -0
- package/dist/src/shared/cache-manager.js +221 -0
- package/dist/src/shared/cache-manager.js.map +1 -0
- package/dist/src/shared/tools.d.ts +2 -0
- package/dist/src/shared/tools.d.ts.map +1 -0
- package/dist/src/shared/tools.js +606 -0
- package/dist/src/shared/tools.js.map +1 -0
- package/dist/src/types.d.ts +376 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +9 -0
- package/dist/src/types.js.map +1 -0
- package/dist/test/cjs/test.d.ts +11 -0
- package/dist/test/cjs/test.d.ts.map +1 -0
- package/dist/test/cjs/test.js +289 -0
- package/dist/test/cjs/test.js.map +1 -0
- package/dist/test/mcp/smoke-test.d.ts +29 -0
- package/dist/test/mcp/smoke-test.d.ts.map +1 -0
- package/dist/test/mcp/smoke-test.js +132 -0
- package/dist/test/mcp/smoke-test.js.map +1 -0
- package/lib/esm/index.mjs +230 -154
- package/lib/esm/module/pageController.mjs +21 -18
- package/lib/esm/module/turnstile.mjs +7 -0
- package/package.json +25 -16
- package/typings.d.ts +7 -1
- package/.github/ISSUE_TEMPLATE/general_issue.yaml +0 -58
- package/.github/SETUP.md +0 -111
- package/.github/workflows/publish.yml +0 -135
- package/Dockerfile +0 -79
- package/lib/cjs/adblocker.bin +0 -0
- package/lib/cjs/index.js +0 -321
- package/src/ai/action-parser.js +0 -274
- package/src/ai/core.js +0 -378
- package/src/ai/element-finder.js +0 -466
- package/src/ai/index.js +0 -82
- package/src/ai/page-analyzer.js +0 -304
- package/src/ai/selector-healer.js +0 -236
- package/src/index.js +0 -121
- package/src/mcp/handlers.js +0 -5071
- package/src/mcp/index.js +0 -190
- package/src/mcp/server.js +0 -144
- package/src/shared/tools.js +0 -618
- package/test/cjs/test.js +0 -259
- package/test/esm/package.json +0 -13
- package/test/esm/test.js +0 -226
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
name: Report Issue
|
|
2
|
-
description: Please use this to report any issue
|
|
3
|
-
labels: [triage]
|
|
4
|
-
assignees:
|
|
5
|
-
- zfcsoftware
|
|
6
|
-
body:
|
|
7
|
-
- type: markdown
|
|
8
|
-
attributes:
|
|
9
|
-
value: |
|
|
10
|
-
Please take care to fill in all fields. Recreating the issue will speed up its resolution. Thank you for contributing to the betterment of the library by reporting issues.
|
|
11
|
-
- type: textarea
|
|
12
|
-
id: issue-detail
|
|
13
|
-
attributes:
|
|
14
|
-
label: Description
|
|
15
|
-
description: Please describe the problem you are experiencing. You only need to provide information about the problem in this field.
|
|
16
|
-
validations:
|
|
17
|
-
required: true
|
|
18
|
-
- type: textarea
|
|
19
|
-
id: issue-recreate
|
|
20
|
-
attributes:
|
|
21
|
-
label: Full steps to reproduce the issue
|
|
22
|
-
description: Please provide a full working code to reproduce the issue. Make sure that the code you provide is directly executable. This step is very important to resolve the issue.
|
|
23
|
-
validations:
|
|
24
|
-
required: true
|
|
25
|
-
- type: dropdown
|
|
26
|
-
id: issue-type
|
|
27
|
-
attributes:
|
|
28
|
-
label: Issue Type
|
|
29
|
-
description: What type of issue would you like to report?
|
|
30
|
-
multiple: true
|
|
31
|
-
options:
|
|
32
|
-
- Bug
|
|
33
|
-
- Build/Install
|
|
34
|
-
- Performance
|
|
35
|
-
- Support
|
|
36
|
-
- Feature Request
|
|
37
|
-
- Documentation Request
|
|
38
|
-
- Others
|
|
39
|
-
- type: dropdown
|
|
40
|
-
id: Operating-System
|
|
41
|
-
attributes:
|
|
42
|
-
label: Operating System
|
|
43
|
-
description: What OS are you seeing the issue in? If you don't see your OS listed, please provide more details in the "Description" section above.
|
|
44
|
-
multiple: true
|
|
45
|
-
options:
|
|
46
|
-
- Windows 10
|
|
47
|
-
- Linux
|
|
48
|
-
- Mac OS
|
|
49
|
-
- Other
|
|
50
|
-
- type: dropdown
|
|
51
|
-
id: use-type
|
|
52
|
-
attributes:
|
|
53
|
-
label: Do you use Docker?
|
|
54
|
-
description: Are you running it with Docker or on your local computer?
|
|
55
|
-
multiple: false
|
|
56
|
-
options:
|
|
57
|
-
- Docker
|
|
58
|
-
- I don't use Docker
|
package/.github/SETUP.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# 🔧 GitHub Actions Setup Guide
|
|
2
|
-
|
|
3
|
-
यह गाइड बताएगी कि GitHub Actions workflow को कैसे setup करना है।
|
|
4
|
-
|
|
5
|
-
## 🔐 Required Secrets
|
|
6
|
-
|
|
7
|
-
आपको अपनी GitHub repository में निम्नलिखित secrets को add करना होगा:
|
|
8
|
-
|
|
9
|
-
### 1. GH_TOKEN
|
|
10
|
-
- **Purpose**: Repository access और GitHub releases के लिए
|
|
11
|
-
- **कैसे बनाएं**:
|
|
12
|
-
1. GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
|
|
13
|
-
2. "Generate new token (classic)" पर click करें
|
|
14
|
-
3. निम्नलिखित permissions select करें:
|
|
15
|
-
- `repo` (Full control of private repositories)
|
|
16
|
-
- `write:packages` (Write packages to GitHub Package Registry)
|
|
17
|
-
- `workflow` (Update GitHub Action workflows)
|
|
18
|
-
4. Token generate करें और copy करें
|
|
19
|
-
|
|
20
|
-
### 2. NPM_TOKEN
|
|
21
|
-
- **Purpose**: NPM पर package publish करने के लिए
|
|
22
|
-
- **कैसे बनाएं**:
|
|
23
|
-
1. NPM website पर login करें (https://www.npmjs.com/)
|
|
24
|
-
2. Profile → Access Tokens → Generate New Token
|
|
25
|
-
3. "Automation" type select करें (recommended for CI/CD)
|
|
26
|
-
4. Token generate करें और copy करें
|
|
27
|
-
|
|
28
|
-
## 🛠️ Secrets को Repository में Add करना
|
|
29
|
-
|
|
30
|
-
1. GitHub repository पर जाएं
|
|
31
|
-
2. Settings → Secrets and variables → Actions
|
|
32
|
-
3. "New repository secret" पर click करें
|
|
33
|
-
4. निम्नलिखित secrets add करें:
|
|
34
|
-
|
|
35
|
-
| Secret Name | Value |
|
|
36
|
-
|-------------|-------|
|
|
37
|
-
| `GH_TOKEN` | आपका GitHub Personal Access Token |
|
|
38
|
-
| `NPM_TOKEN` | आपका NPM Automation Token |
|
|
39
|
-
|
|
40
|
-
## 🚀 Workflow Usage
|
|
41
|
-
|
|
42
|
-
इस project में **2 workflows** हैं:
|
|
43
|
-
|
|
44
|
-
### 1. 🤖 Auto Increment & Publish (Recommended)
|
|
45
|
-
**Simple Auto-Increment**: हमेशा patch version increment करता है
|
|
46
|
-
|
|
47
|
-
#### Automatic Publishing:
|
|
48
|
-
```bash
|
|
49
|
-
# कोई भी change push करें, automatic version increment होगा:
|
|
50
|
-
git commit -m "any change"
|
|
51
|
-
git push origin main # 1.5.0 → 1.5.1 → 1.5.2 → 1.5.3...
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
#### Manual Publishing:
|
|
55
|
-
1. GitHub repository → Actions → "🤖 Auto Increment & Publish"
|
|
56
|
-
2. "Run workflow" click करें
|
|
57
|
-
3. "Publish to NPM?" = `true` रखें
|
|
58
|
-
4. "Run workflow" पर click करें
|
|
59
|
-
|
|
60
|
-
### 2. 🚀 Publish to NPM (Tag-based)
|
|
61
|
-
Traditional tag-based publishing:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
# Manual tag push के लिए
|
|
65
|
-
git tag v1.5.1
|
|
66
|
-
git push origin v1.5.1
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## 🔢 Simple Auto-Increment System
|
|
70
|
-
|
|
71
|
-
**Current Version**: `1.5.0`
|
|
72
|
-
|
|
73
|
-
हर workflow run पर automatic patch increment:
|
|
74
|
-
- `1.5.0` → `1.5.1`
|
|
75
|
-
- `1.5.1` → `1.5.2`
|
|
76
|
-
- `1.5.2` → `1.5.3`
|
|
77
|
-
- `1.5.3` → `1.5.4`
|
|
78
|
-
- ... and so on
|
|
79
|
-
|
|
80
|
-
**बिल्कुल simple!** 🚀 कोई complex commit message analysis नहीं चाहिए।
|
|
81
|
-
|
|
82
|
-
## 📋 Workflow Features
|
|
83
|
-
|
|
84
|
-
✅ **Automatic Triggers**: Version tags पर auto-publish
|
|
85
|
-
✅ **Manual Triggers**: GitHub UI से manual control
|
|
86
|
-
✅ **Security**: Secrets का safe उपयोग
|
|
87
|
-
✅ **Testing**: Publish से पहले automated tests
|
|
88
|
-
✅ **Version Management**: Automatic version bumping
|
|
89
|
-
✅ **GitHub Releases**: Auto-generated releases
|
|
90
|
-
✅ **Error Handling**: Comprehensive error reporting
|
|
91
|
-
✅ **Summary Reports**: Detailed workflow summaries
|
|
92
|
-
|
|
93
|
-
## 🔍 Troubleshooting
|
|
94
|
-
|
|
95
|
-
### Common Issues:
|
|
96
|
-
|
|
97
|
-
1. **Token Permissions**:
|
|
98
|
-
- GH_TOKEN में सही permissions हों
|
|
99
|
-
- NPM_TOKEN "Automation" type का हो
|
|
100
|
-
|
|
101
|
-
2. **Repository Access**:
|
|
102
|
-
- Repository में Actions enabled हों
|
|
103
|
-
- Secrets properly configured हों
|
|
104
|
-
|
|
105
|
-
3. **Publishing Errors**:
|
|
106
|
-
- Package name conflicts check करें
|
|
107
|
-
- NPM account verified हो
|
|
108
|
-
|
|
109
|
-
## 📞 Support
|
|
110
|
-
|
|
111
|
-
अगर कोई issue आए तो GitHub Issues में report करें।
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
name: 🚀 Build, Version & Publish to NPM
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main, master]
|
|
6
|
-
paths-ignore:
|
|
7
|
-
- 'README.md'
|
|
8
|
-
- 'docs/**'
|
|
9
|
-
- '*.md'
|
|
10
|
-
- 'LICENSE.md'
|
|
11
|
-
- '.gitignore'
|
|
12
|
-
|
|
13
|
-
workflow_dispatch:
|
|
14
|
-
inputs:
|
|
15
|
-
increment_type:
|
|
16
|
-
description: '📈 Version increment type'
|
|
17
|
-
required: true
|
|
18
|
-
default: 'patch'
|
|
19
|
-
type: choice
|
|
20
|
-
options:
|
|
21
|
-
- patch
|
|
22
|
-
- minor
|
|
23
|
-
- major
|
|
24
|
-
dry_run:
|
|
25
|
-
description: '🧪 Dry run (check build/test without publishing to NPM)'
|
|
26
|
-
required: false
|
|
27
|
-
default: false
|
|
28
|
-
type: boolean
|
|
29
|
-
|
|
30
|
-
jobs:
|
|
31
|
-
publish:
|
|
32
|
-
name: 🚀 Publish to NPM
|
|
33
|
-
runs-on: ubuntu-latest
|
|
34
|
-
permissions:
|
|
35
|
-
contents: write
|
|
36
|
-
id-token: write
|
|
37
|
-
|
|
38
|
-
steps:
|
|
39
|
-
- name: 📥 Checkout Repository
|
|
40
|
-
uses: actions/checkout@v4
|
|
41
|
-
with:
|
|
42
|
-
fetch-depth: 0
|
|
43
|
-
token: ${{ secrets.GH_TOKEN || github.token }}
|
|
44
|
-
|
|
45
|
-
- name: 🟢 Setup Node.js
|
|
46
|
-
uses: actions/setup-node@v4
|
|
47
|
-
with:
|
|
48
|
-
node-version: '20'
|
|
49
|
-
registry-url: 'https://registry.npmjs.org'
|
|
50
|
-
|
|
51
|
-
- name: ⚙️ Configure Git
|
|
52
|
-
run: |
|
|
53
|
-
git config --global user.name "github-actions[bot]"
|
|
54
|
-
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
55
|
-
|
|
56
|
-
- name: 📦 Install Dependencies
|
|
57
|
-
run: npm ci || npm install
|
|
58
|
-
|
|
59
|
-
- name: 🧪 Pre-Publish Verification
|
|
60
|
-
run: |
|
|
61
|
-
echo "💡 Running basic syntax and file checks..."
|
|
62
|
-
node -c lib/cjs/index.js
|
|
63
|
-
node -c lib/esm/index.mjs
|
|
64
|
-
echo "✅ Code syntax is valid."
|
|
65
|
-
|
|
66
|
-
- name: 📈 Increment Version
|
|
67
|
-
id: versioning
|
|
68
|
-
run: |
|
|
69
|
-
# Determine the increment type (major, minor, or patch)
|
|
70
|
-
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
71
|
-
INCREMENT_TYPE="${{ github.event.inputs.increment_type }}"
|
|
72
|
-
else
|
|
73
|
-
COMMIT_MSG=$(git log -1 --pretty=%B)
|
|
74
|
-
if echo "$COMMIT_MSG" | grep -qE "\[major\]|BREAKING CHANGE"; then
|
|
75
|
-
INCREMENT_TYPE="major"
|
|
76
|
-
elif echo "$COMMIT_MSG" | grep -qE "\[minor\]|feat:"; then
|
|
77
|
-
INCREMENT_TYPE="minor"
|
|
78
|
-
else
|
|
79
|
-
INCREMENT_TYPE="patch"
|
|
80
|
-
fi
|
|
81
|
-
fi
|
|
82
|
-
|
|
83
|
-
echo "📈 Selected increment type: $INCREMENT_TYPE"
|
|
84
|
-
|
|
85
|
-
# Bump version, commit changes and create tag
|
|
86
|
-
npm version $INCREMENT_TYPE -m "🔖 Release: v%s [skip ci]"
|
|
87
|
-
|
|
88
|
-
# Capture new version for subsequent steps
|
|
89
|
-
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
90
|
-
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
|
|
91
|
-
echo "version=v$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
92
|
-
|
|
93
|
-
- name: 🚀 Push Version Bump & Tag
|
|
94
|
-
if: github.event.inputs.dry_run != 'true'
|
|
95
|
-
run: |
|
|
96
|
-
git push origin HEAD --follow-tags
|
|
97
|
-
|
|
98
|
-
- name: 📦 Publish Package to NPM
|
|
99
|
-
if: github.event.inputs.dry_run != 'true'
|
|
100
|
-
run: |
|
|
101
|
-
npm publish --access public
|
|
102
|
-
env:
|
|
103
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
104
|
-
|
|
105
|
-
- name: 📋 Create GitHub Release
|
|
106
|
-
if: github.event.inputs.dry_run != 'true'
|
|
107
|
-
run: |
|
|
108
|
-
TAG="v${{ env.NEW_VERSION }}"
|
|
109
|
-
|
|
110
|
-
cat > release_body.md << EOF
|
|
111
|
-
## 🚀 Real Browser MCP Server v${{ env.NEW_VERSION }}
|
|
112
|
-
|
|
113
|
-
### 📦 Published Packages
|
|
114
|
-
- **NPM Package**: [real-browser-mcp-server](https://www.npmjs.com/package/real-browser-mcp-server)
|
|
115
|
-
- **Stealth automation**: Powered by Patchright (undetected Playwright fork).
|
|
116
|
-
|
|
117
|
-
### 🛠️ Key Capabilities
|
|
118
|
-
* **Turnstile Bypass**: Solves Cloudflare Turnstile automatically.
|
|
119
|
-
* **Ad Blocker**: Integrated `@ghostery/adblocker-playwright` with binary caching.
|
|
120
|
-
* **Stealth Evasion**: Passes advanced bot checkers like CreepJS, Datadome, Pixelscan, and FingerprintJS.
|
|
121
|
-
|
|
122
|
-
### 📥 Installation
|
|
123
|
-
\`\`\`bash
|
|
124
|
-
npm install real-browser-mcp-server@${{ env.NEW_VERSION }}
|
|
125
|
-
\`\`\`
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
*Auto-generated with ❤️ by GitHub Actions*
|
|
129
|
-
EOF
|
|
130
|
-
|
|
131
|
-
gh release create "$TAG" \
|
|
132
|
-
--title "Release $TAG" \
|
|
133
|
-
--notes-file release_body.md
|
|
134
|
-
env:
|
|
135
|
-
GITHUB_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
package/Dockerfile
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Stage 1: Build
|
|
2
|
-
FROM node:20-slim AS builder
|
|
3
|
-
|
|
4
|
-
WORKDIR /app
|
|
5
|
-
|
|
6
|
-
# Copy package files first for better caching
|
|
7
|
-
COPY package*.json ./
|
|
8
|
-
|
|
9
|
-
# Install all dependencies (including devDependencies for build)
|
|
10
|
-
RUN npm ci
|
|
11
|
-
|
|
12
|
-
# Copy source files
|
|
13
|
-
COPY . .
|
|
14
|
-
|
|
15
|
-
# Stage 2: Production
|
|
16
|
-
FROM node:20-slim AS production
|
|
17
|
-
|
|
18
|
-
# Install Chromium and required dependencies
|
|
19
|
-
RUN apt-get update && apt-get install -y \
|
|
20
|
-
wget \
|
|
21
|
-
gnupg \
|
|
22
|
-
ca-certificates \
|
|
23
|
-
apt-transport-https \
|
|
24
|
-
chromium \
|
|
25
|
-
fonts-liberation \
|
|
26
|
-
libasound2 \
|
|
27
|
-
libatk-bridge2.0-0 \
|
|
28
|
-
libatk1.0-0 \
|
|
29
|
-
libcups2 \
|
|
30
|
-
libdbus-1-3 \
|
|
31
|
-
libdrm2 \
|
|
32
|
-
libgbm1 \
|
|
33
|
-
libgtk-3-0 \
|
|
34
|
-
libnspr4 \
|
|
35
|
-
libnss3 \
|
|
36
|
-
libxcomposite1 \
|
|
37
|
-
libxdamage1 \
|
|
38
|
-
libxfixes3 \
|
|
39
|
-
libxkbcommon0 \
|
|
40
|
-
libxrandr2 \
|
|
41
|
-
xdg-utils \
|
|
42
|
-
xvfb \
|
|
43
|
-
&& rm -rf /var/lib/apt/lists/* \
|
|
44
|
-
&& apt-get clean
|
|
45
|
-
|
|
46
|
-
# Set Chrome binary path
|
|
47
|
-
ENV CHROME_BIN=/usr/bin/chromium
|
|
48
|
-
|
|
49
|
-
# Create non-root user for security
|
|
50
|
-
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
|
|
51
|
-
&& mkdir -p /home/pptruser/Downloads \
|
|
52
|
-
&& chown -R pptruser:pptruser /home/pptruser
|
|
53
|
-
|
|
54
|
-
WORKDIR /app
|
|
55
|
-
|
|
56
|
-
# Copy from builder stage
|
|
57
|
-
COPY --from=builder /app/node_modules ./node_modules
|
|
58
|
-
COPY --from=builder /app/package*.json ./
|
|
59
|
-
COPY --from=builder /app/lib ./lib
|
|
60
|
-
COPY --from=builder /app/test ./test
|
|
61
|
-
COPY --from=builder /app/packages ./packages
|
|
62
|
-
COPY --from=builder /app/typings.d.ts ./
|
|
63
|
-
|
|
64
|
-
# Set ownership to non-root user
|
|
65
|
-
RUN chown -R pptruser:pptruser /app
|
|
66
|
-
|
|
67
|
-
# Switch to non-root user
|
|
68
|
-
USER pptruser
|
|
69
|
-
|
|
70
|
-
# Set headless mode for container
|
|
71
|
-
ENV HEADLESS=true
|
|
72
|
-
ENV NODE_ENV=production
|
|
73
|
-
|
|
74
|
-
# Health check
|
|
75
|
-
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
76
|
-
CMD node -e "console.log('OK')" || exit 1
|
|
77
|
-
|
|
78
|
-
# Default command: run CJS tests
|
|
79
|
-
CMD ["npm", "run", "cjs_test"]
|
package/lib/cjs/adblocker.bin
DELETED
|
Binary file
|
package/lib/cjs/index.js
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
const { PlaywrightBlocker } = require("@ghostery/adblocker-playwright");
|
|
2
|
-
const { pageController } = require("./module/pageController.js");
|
|
3
|
-
|
|
4
|
-
const { chromium } = require("patchright");
|
|
5
|
-
const { createCursor } = require("ghost-cursor-patchright");
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
let adBlockerInstance = null;
|
|
10
|
-
let adBlockerPromise = null;
|
|
11
|
-
function getAdBlocker() {
|
|
12
|
-
if (!adBlockerPromise) {
|
|
13
|
-
const cachePath = path.join(__dirname, 'adblocker.bin');
|
|
14
|
-
adBlockerPromise = PlaywrightBlocker.fromPrebuiltAdsAndTracking(fetch, {
|
|
15
|
-
path: cachePath,
|
|
16
|
-
read: fs.promises.readFile,
|
|
17
|
-
write: fs.promises.writeFile,
|
|
18
|
-
}).then(blocker => {
|
|
19
|
-
adBlockerInstance = blocker;
|
|
20
|
-
return blocker;
|
|
21
|
-
}).catch(err => {
|
|
22
|
-
console.error('[adblocker] Failed to initialize adblocker:', err.message);
|
|
23
|
-
return null;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
return adBlockerPromise;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function loadEnvFile() {
|
|
30
|
-
const envPaths = [
|
|
31
|
-
path.join(process.cwd(), '.env'),
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
let currentDir = process.cwd();
|
|
35
|
-
for (let i = 0; i < 5; i++) {
|
|
36
|
-
const envPath = path.join(currentDir, '.env');
|
|
37
|
-
if (fs.existsSync(envPath) && !envPaths.includes(envPath)) {
|
|
38
|
-
envPaths.push(envPath);
|
|
39
|
-
}
|
|
40
|
-
const parentDir = path.dirname(currentDir);
|
|
41
|
-
if (parentDir === currentDir) break;
|
|
42
|
-
currentDir = parentDir;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
for (const envPath of envPaths) {
|
|
46
|
-
try {
|
|
47
|
-
if (fs.existsSync(envPath)) {
|
|
48
|
-
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
49
|
-
envContent.split('\n').forEach(line => {
|
|
50
|
-
const trimmed = line.trim();
|
|
51
|
-
if (trimmed && !trimmed.startsWith('#')) {
|
|
52
|
-
const [key, ...valueParts] = trimmed.split('=');
|
|
53
|
-
const value = valueParts.join('=').replace(/^["']|["']$/g, '');
|
|
54
|
-
if (key && !process.env[key]) {
|
|
55
|
-
process.env[key] = value;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
// Silently ignore .env loading errors
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
loadEnvFile();
|
|
68
|
-
|
|
69
|
-
function getDefaultHeadless() {
|
|
70
|
-
const envHeadless = (process.env.HEADLESS || '').toLowerCase();
|
|
71
|
-
return envHeadless === 'true';
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function applyBrowserShims(browser, page) {
|
|
75
|
-
if (page._shimsApplied) return page;
|
|
76
|
-
page._shimsApplied = true;
|
|
77
|
-
|
|
78
|
-
// Enable ad blocker
|
|
79
|
-
if (adBlockerInstance) {
|
|
80
|
-
adBlockerInstance.enableBlockingInPage(page).catch(() => {});
|
|
81
|
-
} else {
|
|
82
|
-
getAdBlocker().then(blocker => {
|
|
83
|
-
if (blocker) {
|
|
84
|
-
blocker.enableBlockingInPage(page).catch(() => {});
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Cookie shims (Compatibility adapter for Playwright context)
|
|
90
|
-
if (!page.cookies) {
|
|
91
|
-
page.cookies = async (urls) => {
|
|
92
|
-
return await page.context().cookies(urls ? (Array.isArray(urls) ? urls : [urls]) : []);
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (!page.setCookie) {
|
|
97
|
-
page.setCookie = async (...cookies) => {
|
|
98
|
-
const formatted = cookies.map(c => ({
|
|
99
|
-
name: c.name,
|
|
100
|
-
value: c.value,
|
|
101
|
-
domain: c.domain || new URL(page.url()).hostname,
|
|
102
|
-
path: c.path || '/',
|
|
103
|
-
expires: c.expires || undefined,
|
|
104
|
-
httpOnly: c.httpOnly,
|
|
105
|
-
secure: c.secure,
|
|
106
|
-
sameSite: c.sameSite
|
|
107
|
-
}));
|
|
108
|
-
await page.context().addCookies(formatted);
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!page.deleteCookie) {
|
|
113
|
-
page.deleteCookie = async (...cookies) => {
|
|
114
|
-
await page.context().clearCookies();
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Navigation shims
|
|
119
|
-
if (!page.waitForNetworkIdle) {
|
|
120
|
-
page.waitForNetworkIdle = async (options = {}) => {
|
|
121
|
-
try {
|
|
122
|
-
await page.waitForLoadState('networkidle', { timeout: options.timeout });
|
|
123
|
-
} catch (e) {
|
|
124
|
-
// Ignore networkidle timeouts if they are non-fatal
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (!page.evaluateOnNewDocument) {
|
|
130
|
-
page.evaluateOnNewDocument = async (fn, ...args) => {
|
|
131
|
-
return await page.addInitScript(fn, ...args);
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Ghost Cursor integration via ghost-cursor-patchright
|
|
136
|
-
const cursorPromise = createCursor(page).catch(err => {
|
|
137
|
-
console.error("Failed to create cursor:", err);
|
|
138
|
-
return null;
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
page.realCursor = {
|
|
142
|
-
move: async (selector, options = {}) => {
|
|
143
|
-
try {
|
|
144
|
-
const cursor = await cursorPromise;
|
|
145
|
-
if (cursor) {
|
|
146
|
-
await cursor.move(selector, options);
|
|
147
|
-
} else {
|
|
148
|
-
await page.hover(selector, options);
|
|
149
|
-
}
|
|
150
|
-
} catch (e) {
|
|
151
|
-
// Silently fallback if element is not found
|
|
152
|
-
try {
|
|
153
|
-
await page.hover(selector, options);
|
|
154
|
-
} catch (err) {}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
page.realClick = async (selector, options = {}) => {
|
|
159
|
-
try {
|
|
160
|
-
const cursor = await cursorPromise;
|
|
161
|
-
if (cursor) {
|
|
162
|
-
await cursor.click(selector, options);
|
|
163
|
-
} else {
|
|
164
|
-
await page.click(selector, options);
|
|
165
|
-
}
|
|
166
|
-
} catch (e) {
|
|
167
|
-
await page.click(selector, options);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Mouse wheel shim (Adapter for Playwright positional args)
|
|
172
|
-
if (page.mouse && page.mouse.wheel) {
|
|
173
|
-
const originalWheel = page.mouse.wheel.bind(page.mouse);
|
|
174
|
-
page.mouse.wheel = async (x, y) => {
|
|
175
|
-
if (typeof x === 'object' && x !== null) {
|
|
176
|
-
const deltaX = x.deltaX || 0;
|
|
177
|
-
const deltaY = x.deltaY || 0;
|
|
178
|
-
return await originalWheel(deltaX, deltaY);
|
|
179
|
-
}
|
|
180
|
-
return await originalWheel(x, y);
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Browser shims
|
|
185
|
-
if (!browser.process) {
|
|
186
|
-
browser.process = () => ({
|
|
187
|
-
pid: browser._childProcess?.pid || 1337
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (!browser.pages) {
|
|
192
|
-
browser.pages = async () => {
|
|
193
|
-
return browser.contexts().flatMap(c => c.pages());
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return page;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async function connect({
|
|
201
|
-
args = [],
|
|
202
|
-
headless = getDefaultHeadless(),
|
|
203
|
-
proxy = {},
|
|
204
|
-
turnstile = false,
|
|
205
|
-
disableXvfb = false,
|
|
206
|
-
} = {}) {
|
|
207
|
-
let xvfbInstance = null;
|
|
208
|
-
if (process.platform === 'linux' && !process.env.DISPLAY && !disableXvfb) {
|
|
209
|
-
try {
|
|
210
|
-
const Xvfb = require('xvfb');
|
|
211
|
-
xvfbInstance = new Xvfb({
|
|
212
|
-
silent: true,
|
|
213
|
-
xvfb_args: ['-screen', '0', '1280x1024x24', '-ac']
|
|
214
|
-
});
|
|
215
|
-
xvfbInstance.startSync();
|
|
216
|
-
} catch (err) {
|
|
217
|
-
console.error('[xvfb] Failed to start Xvfb server automatically:', err.message);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let playwrightProxy = undefined;
|
|
222
|
-
if (proxy && proxy.host && proxy.port) {
|
|
223
|
-
playwrightProxy = {
|
|
224
|
-
server: `${proxy.host}:${proxy.port}`
|
|
225
|
-
};
|
|
226
|
-
if (proxy.username && proxy.password) {
|
|
227
|
-
playwrightProxy.username = proxy.username;
|
|
228
|
-
playwrightProxy.password = proxy.password;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const chromiumArgs = [
|
|
233
|
-
'--disable-blink-features=AutomationControlled',
|
|
234
|
-
'--no-sandbox',
|
|
235
|
-
'--disable-setuid-sandbox',
|
|
236
|
-
'--window-size=1920,1080',
|
|
237
|
-
...args
|
|
238
|
-
];
|
|
239
|
-
|
|
240
|
-
if (headless) {
|
|
241
|
-
chromiumArgs.push(
|
|
242
|
-
'--disable-gpu',
|
|
243
|
-
'--hide-scrollbars',
|
|
244
|
-
'--mute-audio'
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
let browser;
|
|
249
|
-
try {
|
|
250
|
-
// Try launching using the system's real installed Google Chrome first for maximum stealth/fingerprint integrity
|
|
251
|
-
browser = await chromium.launch({
|
|
252
|
-
headless,
|
|
253
|
-
args: chromiumArgs,
|
|
254
|
-
proxy: playwrightProxy,
|
|
255
|
-
channel: 'chrome'
|
|
256
|
-
});
|
|
257
|
-
console.error('[Launch] Successfully launched using system Google Chrome channel');
|
|
258
|
-
} catch (e) {
|
|
259
|
-
// Fallback to pre-packaged Chromium if Chrome is not installed
|
|
260
|
-
browser = await chromium.launch({
|
|
261
|
-
headless,
|
|
262
|
-
args: chromiumArgs,
|
|
263
|
-
proxy: playwrightProxy
|
|
264
|
-
});
|
|
265
|
-
console.error('[Launch] Google Chrome channel not available, falling back to pre-packaged Chromium');
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (xvfbInstance) {
|
|
269
|
-
browser.on('disconnected', () => {
|
|
270
|
-
try {
|
|
271
|
-
xvfbInstance.stopSync();
|
|
272
|
-
} catch (e) {
|
|
273
|
-
console.error('[xvfb] Failed to stop Xvfb server:', e.message);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
const originalClose = browser.close.bind(browser);
|
|
277
|
-
browser.close = async () => {
|
|
278
|
-
await originalClose();
|
|
279
|
-
try {
|
|
280
|
-
xvfbInstance.stopSync();
|
|
281
|
-
} catch (e) {
|
|
282
|
-
console.error('[xvfb] Failed to stop Xvfb server during close:', e.message);
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Ensure ad blocker is ready
|
|
288
|
-
await getAdBlocker();
|
|
289
|
-
|
|
290
|
-
const context = await browser.newContext({
|
|
291
|
-
viewport: null,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
let page = await context.newPage();
|
|
295
|
-
|
|
296
|
-
applyBrowserShims(browser, page);
|
|
297
|
-
|
|
298
|
-
page = await pageController({
|
|
299
|
-
browser,
|
|
300
|
-
page,
|
|
301
|
-
proxy,
|
|
302
|
-
turnstile,
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
context.on('page', async (newPage) => {
|
|
306
|
-
applyBrowserShims(browser, newPage);
|
|
307
|
-
await pageController({
|
|
308
|
-
browser,
|
|
309
|
-
page: newPage,
|
|
310
|
-
proxy,
|
|
311
|
-
turnstile,
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
browser,
|
|
317
|
-
page,
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
module.exports = { connect };
|