@doppelgangerdev/doppelganger 0.4.0 → 0.4.3

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 (33) hide show
  1. package/README.md +1 -1
  2. package/agent.js +49 -40
  3. package/dist/assets/index-D68YZVOp.js +19 -0
  4. package/dist/assets/index-WbwoTnJa.css +1 -0
  5. package/dist/index.html +3 -3
  6. package/headful.js +23 -23
  7. package/package.json +1 -1
  8. package/proxy-rotation.js +245 -230
  9. package/scrape.js +25 -25
  10. package/server.js +343 -296
  11. package/dist/assets/index-B7ntJ0pF.js +0 -18
  12. package/dist/assets/index-OOTrc7_f.css +0 -1
  13. package/dist/screenshots/agent_1768764625684.png +0 -0
  14. package/dist/screenshots/agent_1768765565909.png +0 -0
  15. package/dist/screenshots/agent_1768765581979.png +0 -0
  16. package/dist/screenshots/scrape_1768764416615.png +0 -0
  17. package/dist/screenshots/scrape_1768764452033.png +0 -0
  18. package/dist/screenshots/scrape_1768765064688.png +0 -0
  19. package/dist/screenshots/scrape_1768765090587.png +0 -0
  20. package/dist/screenshots/scrape_1768765100798.png +0 -0
  21. package/dist/screenshots/scrape_1768765114782.png +0 -0
  22. package/dist/screenshots/scrape_1768765127463.png +0 -0
  23. package/public/screenshots/agent_1768764625684.png +0 -0
  24. package/public/screenshots/agent_1768765565909.png +0 -0
  25. package/public/screenshots/agent_1768765581979.png +0 -0
  26. package/public/screenshots/scrape_1768764416615.png +0 -0
  27. package/public/screenshots/scrape_1768764452033.png +0 -0
  28. package/public/screenshots/scrape_1768765064688.png +0 -0
  29. package/public/screenshots/scrape_1768765090587.png +0 -0
  30. package/public/screenshots/scrape_1768765100798.png +0 -0
  31. package/public/screenshots/scrape_1768765114782.png +0 -0
  32. package/public/screenshots/scrape_1768765127463.png +0 -0
  33. package/public/screenshots/scrape_1768769463201.png +0 -0
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Doppelganger - Self-hosted Browser Automation
1
+ # Doppelganger - Browser Automation for Everyone
2
2
 
3
3
  [![Docker](https://img.shields.io/badge/docker-mnemosyneai%2Fdoppelganger-0db7ed)](https://hub.docker.com/r/mnemosyneai/doppelganger)
4
4
  [![Self-Hosted](https://img.shields.io/badge/self--hosted-local--first-2f855a)](#getting-started)
package/agent.js CHANGED
@@ -1,8 +1,8 @@
1
- const { chromium } = require('playwright');
2
- const { JSDOM } = require('jsdom');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { getProxySelection } = require('./proxy-rotation');
1
+ const { chromium } = require('playwright');
2
+ const { JSDOM } = require('jsdom');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { getProxySelection } = require('./proxy-rotation');
6
6
 
7
7
  const STORAGE_STATE_PATH = path.join(__dirname, 'storage_state.json');
8
8
  const STORAGE_STATE_FILE = (() => {
@@ -168,7 +168,7 @@ async function humanType(page, selector, text, options = {}) {
168
168
 
169
169
  async function handleAgent(req, res) {
170
170
  const data = (req.method === 'POST') ? req.body : req.query;
171
- let { url, actions, wait: globalWait, rotateUserAgents, rotateProxies, humanTyping, stealth = {} } = data;
171
+ let { url, actions, wait: globalWait, rotateUserAgents, rotateProxies, humanTyping, stealth = {} } = data;
172
172
  const runId = data.runId ? String(data.runId) : null;
173
173
  const includeShadowDomRaw = data.includeShadowDom ?? req.query.includeShadowDom;
174
174
  const includeShadowDom = includeShadowDomRaw === undefined
@@ -198,7 +198,9 @@ async function handleAgent(req, res) {
198
198
  });
199
199
  }
200
200
 
201
- const baseUrl = `${req.protocol || 'http'}://${req.get('host')}`;
201
+ const localPort = req.socket && req.socket.localPort;
202
+ const localHost = localPort ? `127.0.0.1:${localPort}` : req.get('host');
203
+ const baseUrl = `${req.protocol || 'http'}://${localHost}`;
202
204
  const runtimeVars = { ...(data.taskVariables || data.variables || {}) };
203
205
  let lastBlockOutput = null;
204
206
  runtimeVars['block.output'] = lastBlockOutput;
@@ -396,24 +398,24 @@ async function handleAgent(req, res) {
396
398
 
397
399
  let browser;
398
400
  try {
399
- const launchOptions = {
400
- headless: true,
401
- channel: 'chrome',
402
- args: [
403
- '--no-sandbox',
404
- '--disable-setuid-sandbox',
405
- '--disable-blink-features=AutomationControlled',
406
- '--hide-scrollbars',
407
- '--mute-audio'
408
- ]
409
- };
410
- const useRotateProxies = String(rotateProxies).toLowerCase() === 'true' || rotateProxies === true;
411
- const selection = getProxySelection(useRotateProxies);
412
- if (selection.proxy) {
413
- launchOptions.proxy = selection.proxy;
414
- }
415
- console.log(`[PROXY] Mode: ${selection.mode}; Target: ${selection.proxy ? selection.proxy.server : 'host_ip'}`);
416
- browser = await chromium.launch(launchOptions);
401
+ const launchOptions = {
402
+ headless: true,
403
+ channel: 'chrome',
404
+ args: [
405
+ '--no-sandbox',
406
+ '--disable-setuid-sandbox',
407
+ '--disable-blink-features=AutomationControlled',
408
+ '--hide-scrollbars',
409
+ '--mute-audio'
410
+ ]
411
+ };
412
+ const useRotateProxies = String(rotateProxies).toLowerCase() === 'true' || rotateProxies === true;
413
+ const selection = getProxySelection(useRotateProxies);
414
+ if (selection.proxy) {
415
+ launchOptions.proxy = selection.proxy;
416
+ }
417
+ console.log(`[PROXY] Mode: ${selection.mode}; Target: ${selection.proxy ? selection.proxy.server : 'host_ip'}`);
418
+ browser = await chromium.launch(launchOptions);
417
419
 
418
420
  const contextOptions = {
419
421
  userAgent: selectedUA,
@@ -827,18 +829,24 @@ async function handleAgent(req, res) {
827
829
  case 'start': {
828
830
  const taskId = resolveMaybe(act.value);
829
831
  if (!taskId) throw new Error('Missing task id.');
830
- const apiKey = loadApiKey() || data.apiKey || data.key;
831
- if (!apiKey) throw new Error('API key is required to start a task.');
832
- logs.push(`Starting task: ${taskId}`);
833
- const response = await fetch(`${baseUrl}/tasks/${taskId}/api`, {
834
- method: 'POST',
835
- headers: {
836
- 'Content-Type': 'application/json',
837
- 'x-api-key': apiKey
838
- },
839
- body: JSON.stringify({
840
- variables: runtimeVars,
841
- taskVariables: runtimeVars,
832
+ const apiKey = loadApiKey() || data.apiKey || data.key;
833
+ if (!apiKey) {
834
+ logs.push('No API key available; attempting internal start.');
835
+ }
836
+ logs.push(`Starting task: ${taskId}`);
837
+ const headers = {
838
+ 'Content-Type': 'application/json',
839
+ 'x-internal-run': '1'
840
+ };
841
+ if (apiKey) {
842
+ headers['x-api-key'] = apiKey;
843
+ }
844
+ const response = await fetch(`${baseUrl}/tasks/${taskId}/api`, {
845
+ method: 'POST',
846
+ headers,
847
+ body: JSON.stringify({
848
+ variables: runtimeVars,
849
+ taskVariables: runtimeVars,
842
850
  runSource: 'agent_block',
843
851
  taskId
844
852
  })
@@ -848,9 +856,10 @@ async function handleAgent(req, res) {
848
856
  const detail = payload?.error || payload?.message || response.statusText;
849
857
  throw new Error(`Start task failed: ${detail}`);
850
858
  }
851
- result = payload?.data ?? payload?.html ?? payload;
852
- break;
853
- }
859
+ result = payload?.data ?? payload?.html ?? payload;
860
+ setBlockOutput(result);
861
+ break;
862
+ }
854
863
  }
855
864
  return result;
856
865
  };