web-agent-bridge 1.0.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/LICENSE +21 -0
- package/README.ar.md +446 -0
- package/README.md +544 -0
- package/bin/cli.js +80 -0
- package/bin/wab.js +80 -0
- package/examples/bidi-agent.js +119 -0
- package/examples/puppeteer-agent.js +108 -0
- package/examples/vision-agent.js +159 -0
- package/package.json +67 -0
- package/public/css/styles.css +1235 -0
- package/public/dashboard.html +566 -0
- package/public/docs.html +582 -0
- package/public/index.html +306 -0
- package/public/login.html +81 -0
- package/public/register.html +94 -0
- package/script/ai-agent-bridge.js +1282 -0
- package/sdk/README.md +55 -0
- package/sdk/index.js +167 -0
- package/sdk/package.json +14 -0
- package/server/index.js +105 -0
- package/server/middleware/auth.js +44 -0
- package/server/models/adapters/index.js +33 -0
- package/server/models/adapters/mysql.js +183 -0
- package/server/models/adapters/postgresql.js +172 -0
- package/server/models/adapters/sqlite.js +7 -0
- package/server/models/db.js +205 -0
- package/server/routes/api.js +121 -0
- package/server/routes/auth.js +51 -0
- package/server/routes/license.js +51 -0
- package/server/ws.js +81 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: AI Agent using WebDriver BiDi Protocol via WAB
|
|
3
|
+
*
|
|
4
|
+
* This agent connects to a website using the __wab_bidi interface,
|
|
5
|
+
* which follows WebDriver BiDi conventions for standardized communication.
|
|
6
|
+
*
|
|
7
|
+
* Prerequisites:
|
|
8
|
+
* npm install puppeteer
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node examples/bidi-agent.js <url>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const puppeteer = require('puppeteer');
|
|
15
|
+
|
|
16
|
+
const TARGET_URL = process.argv[2] || 'http://localhost:3000';
|
|
17
|
+
|
|
18
|
+
let commandId = 0;
|
|
19
|
+
|
|
20
|
+
function bidiCommand(method, params = {}) {
|
|
21
|
+
return { id: ++commandId, method, params };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function main() {
|
|
25
|
+
console.log(`\nš WAB BiDi Agent`);
|
|
26
|
+
console.log(` Target: ${TARGET_URL}\n`);
|
|
27
|
+
|
|
28
|
+
const browser = await puppeteer.launch({ headless: true });
|
|
29
|
+
const page = await browser.newPage();
|
|
30
|
+
|
|
31
|
+
await page.goto(TARGET_URL, { waitUntil: 'networkidle2' });
|
|
32
|
+
console.log(`ā Page loaded: ${await page.title()}`);
|
|
33
|
+
|
|
34
|
+
// Check for BiDi interface
|
|
35
|
+
const hasBiDi = await page.evaluate(() => {
|
|
36
|
+
return typeof window.__wab_bidi !== 'undefined' && typeof window.__wab_bidi.send === 'function';
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!hasBiDi) {
|
|
40
|
+
console.log('ā WAB BiDi interface not found on this page.');
|
|
41
|
+
await browser.close();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log('ā WAB BiDi interface detected\n');
|
|
46
|
+
|
|
47
|
+
// Step 1: Get BiDi context
|
|
48
|
+
const context = await page.evaluate(() => window.__wab_bidi.getContext());
|
|
49
|
+
console.log('š BiDi Context:');
|
|
50
|
+
console.log(` URL: ${context.context.url}`);
|
|
51
|
+
console.log(` Title: ${context.context.title}`);
|
|
52
|
+
console.log(` Version: ${context.version}`);
|
|
53
|
+
console.log(` Tier: ${context.capabilities.tier}`);
|
|
54
|
+
console.log(` Capabilities: ${context.capabilities.actions.length} actions\n`);
|
|
55
|
+
|
|
56
|
+
// Step 2: Get actions via BiDi command
|
|
57
|
+
const actionsResult = await page.evaluate((cmd) => {
|
|
58
|
+
return window.__wab_bidi.send(cmd);
|
|
59
|
+
}, bidiCommand('wab.getActions'));
|
|
60
|
+
|
|
61
|
+
console.log(`š Actions (via BiDi):`);
|
|
62
|
+
if (actionsResult.result) {
|
|
63
|
+
actionsResult.result.forEach((action) => {
|
|
64
|
+
console.log(` ⢠${action.name} [${action.trigger}] ā ${action.description}`);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Step 3: Get page info via BiDi
|
|
69
|
+
const infoResult = await page.evaluate((cmd) => {
|
|
70
|
+
return window.__wab_bidi.send(cmd);
|
|
71
|
+
}, bidiCommand('wab.getPageInfo'));
|
|
72
|
+
|
|
73
|
+
console.log('\nš Page Info (via BiDi):');
|
|
74
|
+
if (infoResult.result) {
|
|
75
|
+
console.log(` Title: ${infoResult.result.title}`);
|
|
76
|
+
console.log(` Domain: ${infoResult.result.domain}`);
|
|
77
|
+
console.log(` Bridge: v${infoResult.result.bridgeVersion}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Step 4: Read content via BiDi command
|
|
81
|
+
const readResult = await page.evaluate((cmd) => {
|
|
82
|
+
return window.__wab_bidi.send(cmd);
|
|
83
|
+
}, bidiCommand('wab.readContent', { selector: 'h1' }));
|
|
84
|
+
|
|
85
|
+
if (readResult.result && readResult.result.success) {
|
|
86
|
+
console.log(`\nš Content: "${readResult.result.text}"`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Step 5: Execute an action via BiDi
|
|
90
|
+
const actions = actionsResult.result || [];
|
|
91
|
+
const firstAction = actions.find((a) => a.trigger === 'click');
|
|
92
|
+
if (firstAction) {
|
|
93
|
+
console.log(`\nā¶ Executing via BiDi: "${firstAction.name}"`);
|
|
94
|
+
const execResult = await page.evaluate((cmd) => {
|
|
95
|
+
return window.__wab_bidi.send(cmd);
|
|
96
|
+
}, bidiCommand('wab.executeAction', { name: firstAction.name }));
|
|
97
|
+
|
|
98
|
+
const r = execResult.result;
|
|
99
|
+
console.log(` Result: ${r && r.success ? 'ā Success' : 'ā ' + (r?.error || 'Unknown error')}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Step 6: Test error handling
|
|
103
|
+
console.log('\nš§Ŗ Testing error handling:');
|
|
104
|
+
const errorResult = await page.evaluate((cmd) => {
|
|
105
|
+
return window.__wab_bidi.send(cmd);
|
|
106
|
+
}, bidiCommand('wab.unknownMethod'));
|
|
107
|
+
|
|
108
|
+
if (errorResult.error) {
|
|
109
|
+
console.log(` ā Unknown command handled: ${errorResult.error.code} ā ${errorResult.error.message}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log('\nā BiDi agent session complete.');
|
|
113
|
+
await browser.close();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().catch((err) => {
|
|
117
|
+
console.error('Agent error:', err.message);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Basic AI Agent using Puppeteer + WAB
|
|
3
|
+
*
|
|
4
|
+
* This agent connects to a website that has the Web Agent Bridge script installed,
|
|
5
|
+
* discovers available actions, and executes them.
|
|
6
|
+
*
|
|
7
|
+
* Prerequisites:
|
|
8
|
+
* npm install puppeteer
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node examples/puppeteer-agent.js <url>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const puppeteer = require('puppeteer');
|
|
15
|
+
|
|
16
|
+
const TARGET_URL = process.argv[2] || 'http://localhost:3000';
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
console.log(`\nš¤ WAB Puppeteer Agent`);
|
|
20
|
+
console.log(` Target: ${TARGET_URL}\n`);
|
|
21
|
+
|
|
22
|
+
const browser = await puppeteer.launch({ headless: true });
|
|
23
|
+
const page = await browser.newPage();
|
|
24
|
+
|
|
25
|
+
// Navigate to the target site
|
|
26
|
+
await page.goto(TARGET_URL, { waitUntil: 'networkidle2' });
|
|
27
|
+
console.log(`ā Page loaded: ${await page.title()}`);
|
|
28
|
+
|
|
29
|
+
// Wait for WAB bridge to be ready
|
|
30
|
+
const hasBridge = await page.evaluate(() => {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
if (window.AICommands && window.AICommands._ready) {
|
|
33
|
+
resolve(true);
|
|
34
|
+
} else {
|
|
35
|
+
// Wait up to 5 seconds for bridge
|
|
36
|
+
const timeout = setTimeout(() => resolve(false), 5000);
|
|
37
|
+
document.addEventListener('wab:ready', () => {
|
|
38
|
+
clearTimeout(timeout);
|
|
39
|
+
resolve(true);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!hasBridge) {
|
|
46
|
+
console.log('ā Web Agent Bridge not found on this page.');
|
|
47
|
+
await browser.close();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('ā Web Agent Bridge detected\n');
|
|
52
|
+
|
|
53
|
+
// Step 1: Get page info
|
|
54
|
+
const pageInfo = await page.evaluate(() => window.AICommands.getPageInfo());
|
|
55
|
+
console.log('š Page Info:');
|
|
56
|
+
console.log(` Title: ${pageInfo.title}`);
|
|
57
|
+
console.log(` URL: ${pageInfo.url}`);
|
|
58
|
+
console.log(` Bridge Version: ${pageInfo.bridgeVersion}`);
|
|
59
|
+
console.log(` Tier: ${pageInfo.tier}`);
|
|
60
|
+
console.log(` Actions Available: ${pageInfo.actionsCount}`);
|
|
61
|
+
console.log(` Rate Limit Remaining: ${pageInfo.rateLimitRemaining}\n`);
|
|
62
|
+
|
|
63
|
+
// Step 2: Discover all available actions
|
|
64
|
+
const actions = await page.evaluate(() => window.AICommands.getActions());
|
|
65
|
+
console.log(`š Discovered ${actions.length} actions:`);
|
|
66
|
+
actions.forEach((action) => {
|
|
67
|
+
console.log(` ⢠${action.name} (${action.trigger}) ā ${action.description}`);
|
|
68
|
+
if (action.fields) {
|
|
69
|
+
action.fields.forEach((f) => {
|
|
70
|
+
console.log(` āā ${f.name}: ${f.type}${f.required ? ' (required)' : ''}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Step 3: Read content from the page
|
|
76
|
+
const content = await page.evaluate(() => {
|
|
77
|
+
return window.AICommands.readContent('h1') || window.AICommands.readContent('title');
|
|
78
|
+
});
|
|
79
|
+
if (content && content.success) {
|
|
80
|
+
console.log(`\nš Page heading: "${content.text}"`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Step 4: Execute a click action (first available)
|
|
84
|
+
const clickAction = actions.find((a) => a.trigger === 'click');
|
|
85
|
+
if (clickAction) {
|
|
86
|
+
console.log(`\nā¶ Executing action: "${clickAction.name}"`);
|
|
87
|
+
const result = await page.evaluate(
|
|
88
|
+
(name) => window.AICommands.execute(name),
|
|
89
|
+
clickAction.name
|
|
90
|
+
);
|
|
91
|
+
console.log(` Result: ${result.success ? 'ā Success' : 'ā ' + result.error}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Step 5: List permissions
|
|
95
|
+
const permissions = pageInfo.permissions;
|
|
96
|
+
console.log('\nš Permissions:');
|
|
97
|
+
Object.entries(permissions).forEach(([key, value]) => {
|
|
98
|
+
console.log(` ${value ? 'ā' : 'ā'} ${key}`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log('\nā Agent session complete.');
|
|
102
|
+
await browser.close();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main().catch((err) => {
|
|
106
|
+
console.error('Agent error:', err.message);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Vision-based AI Agent using WAB
|
|
3
|
+
*
|
|
4
|
+
* This agent demonstrates how a "vision" or "natural language" AI agent
|
|
5
|
+
* (like OpenAI Operator, Claude Computer Use, etc.) can interact with
|
|
6
|
+
* WAB using descriptive intent instead of explicit action names.
|
|
7
|
+
*
|
|
8
|
+
* The agent describes what it wants to do in natural language,
|
|
9
|
+
* and the IntentResolver matches it to available WAB actions.
|
|
10
|
+
*
|
|
11
|
+
* Prerequisites:
|
|
12
|
+
* npm install puppeteer
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node examples/vision-agent.js <url>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const puppeteer = require('puppeteer');
|
|
19
|
+
|
|
20
|
+
const TARGET_URL = process.argv[2] || 'http://localhost:3000';
|
|
21
|
+
|
|
22
|
+
// āāā Intent Resolver: maps natural language to WAB actions āāāāāāāāāāāā
|
|
23
|
+
class IntentResolver {
|
|
24
|
+
constructor(actions) {
|
|
25
|
+
this.actions = actions;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Find the best matching action for a natural language intent.
|
|
30
|
+
* Uses keyword matching and description similarity.
|
|
31
|
+
* @param {string} intent ā Natural language description (e.g., "sign up for an account")
|
|
32
|
+
* @returns {{ action: object, confidence: number } | null}
|
|
33
|
+
*/
|
|
34
|
+
resolve(intent) {
|
|
35
|
+
const intentLower = intent.toLowerCase();
|
|
36
|
+
const intentWords = intentLower.split(/\s+/);
|
|
37
|
+
let bestMatch = null;
|
|
38
|
+
let bestScore = 0;
|
|
39
|
+
|
|
40
|
+
for (const action of this.actions) {
|
|
41
|
+
const descLower = (action.description + ' ' + action.name).toLowerCase();
|
|
42
|
+
let score = 0;
|
|
43
|
+
|
|
44
|
+
// Exact name match
|
|
45
|
+
if (intentLower.includes(action.name.replace(/_/g, ' '))) {
|
|
46
|
+
score += 5;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Word overlap scoring
|
|
50
|
+
for (const word of intentWords) {
|
|
51
|
+
if (word.length < 3) continue;
|
|
52
|
+
if (descLower.includes(word)) score += 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Category bonus
|
|
56
|
+
if (action.category === 'navigation' && /navigate|go to|open|visit/i.test(intent)) score += 2;
|
|
57
|
+
if (action.trigger === 'fill_and_submit' && /fill|submit|sign up|register|login|form/i.test(intent)) score += 2;
|
|
58
|
+
if (action.trigger === 'click' && /click|press|tap|select|button/i.test(intent)) score += 1;
|
|
59
|
+
|
|
60
|
+
// Synonym matching
|
|
61
|
+
const synonyms = {
|
|
62
|
+
'sign up': ['register', 'create account', 'signup'],
|
|
63
|
+
'log in': ['login', 'sign in', 'signin'],
|
|
64
|
+
'search': ['find', 'look for', 'query'],
|
|
65
|
+
'submit': ['send', 'post', 'confirm'],
|
|
66
|
+
'navigate': ['go to', 'open', 'visit']
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
for (const [key, syns] of Object.entries(synonyms)) {
|
|
70
|
+
if (syns.some(s => intentLower.includes(s)) && descLower.includes(key)) score += 3;
|
|
71
|
+
if (intentLower.includes(key) && syns.some(s => descLower.includes(s))) score += 3;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (score > bestScore) {
|
|
75
|
+
bestScore = score;
|
|
76
|
+
bestMatch = action;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!bestMatch || bestScore < 1) return null;
|
|
81
|
+
|
|
82
|
+
const confidence = Math.min(1, bestScore / 10);
|
|
83
|
+
return { action: bestMatch, confidence };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// āāā Vision Agent āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
88
|
+
async function main() {
|
|
89
|
+
console.log(`\nšļø WAB Vision Agent`);
|
|
90
|
+
console.log(` Target: ${TARGET_URL}\n`);
|
|
91
|
+
|
|
92
|
+
const browser = await puppeteer.launch({ headless: true });
|
|
93
|
+
const page = await browser.newPage();
|
|
94
|
+
|
|
95
|
+
await page.goto(TARGET_URL, { waitUntil: 'networkidle2' });
|
|
96
|
+
console.log(`ā Page loaded: ${await page.title()}`);
|
|
97
|
+
|
|
98
|
+
// Wait for bridge
|
|
99
|
+
await page.waitForFunction(() => typeof window.AICommands !== 'undefined', { timeout: 10000 });
|
|
100
|
+
console.log('ā WAB bridge detected\n');
|
|
101
|
+
|
|
102
|
+
// Get available actions
|
|
103
|
+
const actions = await page.evaluate(() => window.AICommands.getActions());
|
|
104
|
+
const resolver = new IntentResolver(actions);
|
|
105
|
+
|
|
106
|
+
console.log(`š Available actions: ${actions.length}`);
|
|
107
|
+
actions.forEach(a => console.log(` ⢠${a.name} ā ${a.description}`));
|
|
108
|
+
|
|
109
|
+
// āā Simulate vision agent intents āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
110
|
+
const intents = [
|
|
111
|
+
'I want to create a new account',
|
|
112
|
+
'Take me to the documentation page',
|
|
113
|
+
'Click the login button',
|
|
114
|
+
'Show me the dashboard'
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
console.log('\nš§ Resolving natural language intents:\n');
|
|
118
|
+
|
|
119
|
+
for (const intent of intents) {
|
|
120
|
+
const match = resolver.resolve(intent);
|
|
121
|
+
|
|
122
|
+
if (match) {
|
|
123
|
+
console.log(` Intent: "${intent}"`);
|
|
124
|
+
console.log(` ā Action: ${match.action.name} (${match.action.trigger})`);
|
|
125
|
+
console.log(` ā Confidence: ${(match.confidence * 100).toFixed(0)}%`);
|
|
126
|
+
console.log(` ā Description: ${match.action.description}`);
|
|
127
|
+
|
|
128
|
+
// Execute if confidence is high enough
|
|
129
|
+
if (match.confidence >= 0.3) {
|
|
130
|
+
const result = await page.evaluate(
|
|
131
|
+
(name) => window.AICommands.execute(name),
|
|
132
|
+
match.action.name
|
|
133
|
+
);
|
|
134
|
+
console.log(` ā Executed: ${result.success ? 'ā' : 'ā ' + result.error}`);
|
|
135
|
+
} else {
|
|
136
|
+
console.log(` ā Skipped: confidence too low`);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
console.log(` Intent: "${intent}"`);
|
|
140
|
+
console.log(` ā No matching action found`);
|
|
141
|
+
}
|
|
142
|
+
console.log('');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// āā Demonstrate page info with security context āāāāāāāāāāāāāāāāāāā
|
|
146
|
+
const pageInfo = await page.evaluate(() => window.AICommands.getPageInfo());
|
|
147
|
+
console.log('š Page Info:');
|
|
148
|
+
console.log(` Security sandbox: ${pageInfo.security.sandboxActive ? 'ā Active' : 'ā Inactive'}`);
|
|
149
|
+
console.log(` Self-healing: ${pageInfo.selfHealing.tracked} tracked, ${pageInfo.selfHealing.healed} healed`);
|
|
150
|
+
console.log(` Stealth mode: ${pageInfo.stealthMode ? 'Enabled' : 'Disabled'}`);
|
|
151
|
+
|
|
152
|
+
console.log('\nā Vision agent session complete.');
|
|
153
|
+
await browser.close();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
main().catch((err) => {
|
|
157
|
+
console.error('Agent error:', err.message);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "web-agent-bridge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Open-source middleware that bridges AI agents and websites ā providing a standardized command interface for intelligent automation",
|
|
5
|
+
"main": "server/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"web-agent-bridge": "./bin/cli.js",
|
|
8
|
+
"wab": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node server/index.js",
|
|
12
|
+
"dev": "node server/index.js",
|
|
13
|
+
"test": "jest --forceExit --detectOpenHandles",
|
|
14
|
+
"build:script": "node scripts/build.js",
|
|
15
|
+
"prepublishOnly": "npm test"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ai",
|
|
19
|
+
"agent",
|
|
20
|
+
"bridge",
|
|
21
|
+
"automation",
|
|
22
|
+
"web",
|
|
23
|
+
"middleware",
|
|
24
|
+
"ai-agent",
|
|
25
|
+
"browser-automation",
|
|
26
|
+
"webdriver-bidi"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/abokenan444/web-agent-bridge.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/abokenan444/web-agent-bridge#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/abokenan444/web-agent-bridge/issues"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/",
|
|
38
|
+
"server/",
|
|
39
|
+
"public/",
|
|
40
|
+
"script/",
|
|
41
|
+
"sdk/",
|
|
42
|
+
"examples/",
|
|
43
|
+
"README.md",
|
|
44
|
+
"README.ar.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"bcryptjs": "^2.4.3",
|
|
53
|
+
"better-sqlite3": "^11.6.0",
|
|
54
|
+
"cors": "^2.8.5",
|
|
55
|
+
"dotenv": "^16.4.5",
|
|
56
|
+
"express": "^4.21.0",
|
|
57
|
+
"express-rate-limit": "^7.4.1",
|
|
58
|
+
"helmet": "^8.0.0",
|
|
59
|
+
"jsonwebtoken": "^9.0.2",
|
|
60
|
+
"uuid": "^10.0.0",
|
|
61
|
+
"ws": "^8.19.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"jest": "^30.3.0",
|
|
65
|
+
"supertest": "^7.2.2"
|
|
66
|
+
}
|
|
67
|
+
}
|