botforje 0.0.1

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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/dist/action/action.js +44 -0
  4. package/dist/action/catalog.js +40 -0
  5. package/dist/action/cooldown.js +60 -0
  6. package/dist/action/executor.js +23 -0
  7. package/dist/action/template.js +13 -0
  8. package/dist/action/types.js +2 -0
  9. package/dist/action/webhook.js +36 -0
  10. package/dist/actions/action.js +26 -0
  11. package/dist/actions/cooldown.js +66 -0
  12. package/dist/actions/request.js +40 -0
  13. package/dist/api/routes/auth.js +56 -0
  14. package/dist/api/routes/bots.js +51 -0
  15. package/dist/api/routes/config.js +24 -0
  16. package/dist/api/routes/health.js +15 -0
  17. package/dist/api/routes/index.js +14 -0
  18. package/dist/api/routes/messages.js +69 -0
  19. package/dist/api/routes/sessions.js +97 -0
  20. package/dist/api/routes/status.js +38 -0
  21. package/dist/api/server.js +153 -0
  22. package/dist/auth/service.js +102 -0
  23. package/dist/boot/fleet.js +207 -0
  24. package/dist/bot/bot.js +30 -0
  25. package/dist/bot/fleet.js +211 -0
  26. package/dist/bot/fuzzy.js +20 -0
  27. package/dist/bot/mapper.js +47 -0
  28. package/dist/bot/types.js +2 -0
  29. package/dist/bot/validation.js +38 -0
  30. package/dist/bot.js +31 -0
  31. package/dist/cli/create-bot.js +84 -0
  32. package/dist/cli.js +138 -0
  33. package/dist/commands/auth.js +200 -0
  34. package/dist/commands/create-bot.js +64 -0
  35. package/dist/commands/guide.js +563 -0
  36. package/dist/commands/lock.js +73 -0
  37. package/dist/commands/status.js +145 -0
  38. package/dist/commands/unlock.js +88 -0
  39. package/dist/commands/validate.js +19 -0
  40. package/dist/config/mapper.js +152 -0
  41. package/dist/config/schema.js +2 -0
  42. package/dist/config/validation.js +705 -0
  43. package/dist/config/watcher.js +145 -0
  44. package/dist/config/yaml.js +197 -0
  45. package/dist/fleet.js +247 -0
  46. package/dist/flow/executor.js +286 -0
  47. package/dist/flow/flow.js +2 -0
  48. package/dist/flow/mapper.js +72 -0
  49. package/dist/flow/state.js +115 -0
  50. package/dist/flow/types.js +2 -0
  51. package/dist/graph/executor.js +294 -0
  52. package/dist/graph/graph.js +2 -0
  53. package/dist/graph/state.js +118 -0
  54. package/dist/helpers/data.js +42 -0
  55. package/dist/helpers/fuzzy.js +30 -0
  56. package/dist/helpers/logger.js +89 -0
  57. package/dist/helpers/validation.js +38 -0
  58. package/dist/index.js +92 -0
  59. package/dist/messages/contracts.js +2 -0
  60. package/dist/messages/inbox.js +58 -0
  61. package/dist/messages/outbox.js +136 -0
  62. package/dist/services/auto-response.js +62 -0
  63. package/dist/services/cooldown.js +60 -0
  64. package/dist/services/fleet.js +207 -0
  65. package/dist/services/flow-executor.js +195 -0
  66. package/dist/services/flow-state.js +118 -0
  67. package/dist/services/inbox.js +50 -0
  68. package/dist/services/message-handler.js +78 -0
  69. package/dist/services/message-queue.js +138 -0
  70. package/dist/services/outbox.js +138 -0
  71. package/dist/services/session.js +118 -0
  72. package/dist/services/webhook.js +87 -0
  73. package/dist/utils/logger.js +89 -0
  74. package/dist/utils/webhook.js +36 -0
  75. package/dist/validation/validate.js +592 -0
  76. package/dist/whatsapp/client.js +293 -0
  77. package/dist/whatsapp/session.js +158 -0
  78. package/dist/whatsapp/types.js +109 -0
  79. package/dist/whatsapp/whatsapp.js +109 -0
  80. package/package.json +97 -0
  81. package/scripts/postinstall.js +45 -0
  82. package/scripts/preuninstall.js +48 -0
  83. package/scripts/setup-systemd.js +91 -0
  84. package/service/botforje.service.template +25 -0
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "botforje",
3
+ "version": "0.0.1",
4
+ "description": "Create powerful WhatsApp bots with YAML configuration",
5
+ "jest": {
6
+ "preset": "ts-jest",
7
+ "testEnvironment": "node",
8
+ "roots": [
9
+ "<rootDir>/src",
10
+ "<rootDir>/tests/unit",
11
+ "<rootDir>/tests/integration"
12
+ ],
13
+ "testMatch": [
14
+ "**/__tests__/**/*.test.ts",
15
+ "**/?(*.)+(spec|test).ts"
16
+ ],
17
+ "collectCoverageFrom": [
18
+ "src/**/*.ts",
19
+ "!src/**/*.d.ts"
20
+ ]
21
+ },
22
+ "keywords": [
23
+ "whatsapp",
24
+ "whatsapp-web",
25
+ "bot",
26
+ "automation",
27
+ "service",
28
+ "systemd",
29
+ "chatbot",
30
+ "cli",
31
+ "yaml",
32
+ "no-code"
33
+ ],
34
+ "author": {
35
+ "name": "Félix Sánchez (@felixzsh)",
36
+ "email": "felix.sanchez.dev@gmail.com",
37
+ "url": "https://github.com/felixzsh"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/felixzsh/botforje.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/felixzsh/botforje/issues"
45
+ },
46
+ "homepage": "https://github.com/felixzsh/botforje#readme",
47
+ "license": "MIT",
48
+ "devDependencies": {
49
+ "@types/inquirer": "^9.0.7",
50
+ "@types/jest": "^30.0.0",
51
+ "@types/js-yaml": "^4.0.9",
52
+ "@types/node": "^24.6.1",
53
+ "@types/qrcode-terminal": "^0.12.2",
54
+ "jest": "^30.2.0",
55
+ "ts-jest": "^29.4.4",
56
+ "ts-node": "^10.9.2",
57
+ "typescript": "^5.9.3"
58
+ },
59
+ "dependencies": {
60
+ "@types/express": "^5.0.3",
61
+ "commander": "^12.1.0",
62
+ "express": "^5.1.0",
63
+ "fuse.js": "^7.4.2",
64
+ "js-yaml": "^4.1.0",
65
+ "pino": "^10.0.0",
66
+ "pino-pretty": "^13.1.2",
67
+ "qrcode-terminal": "^0.12.0",
68
+ "whatsapp-web.js": "^1.34.7",
69
+ "botforje": "link:"
70
+ },
71
+ "engines": {
72
+ "node": ">=22.13.0"
73
+ },
74
+ "bin": {
75
+ "botforje": "dist/cli.js"
76
+ },
77
+ "files": [
78
+ "dist",
79
+ "scripts",
80
+ "service",
81
+ "README.md",
82
+ "LICENSE"
83
+ ],
84
+ "os": [
85
+ "linux"
86
+ ],
87
+ "scripts": {
88
+ "build": "tsc",
89
+ "dev": "ts-node src/cli.ts",
90
+ "start": "node ./dist/cli.js",
91
+ "test": "jest",
92
+ "test:watch": "jest --watch",
93
+ "test:coverage": "jest --coverage",
94
+ "postinstall": "node scripts/postinstall.js",
95
+ "preuninstall": "node scripts/preuninstall.js"
96
+ }
97
+ }
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require('child_process');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ console.log('\nSetting up Botforje...\n');
8
+
9
+ function hasSystemd() {
10
+ if (os.platform() !== 'linux') return false;
11
+ try {
12
+ execSync('systemctl --version', { stdio: 'ignore' });
13
+ return true;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ if (hasSystemd()) {
20
+ try {
21
+ console.log('Detected Linux system with systemd');
22
+ console.log('Configuring systemd service automatically...\n');
23
+
24
+ const setupScript = path.join(__dirname, 'setup-systemd.js');
25
+ execSync(`node "${setupScript}"`, { stdio: 'inherit' });
26
+
27
+ console.log('Installation complete!\n');
28
+ console.log('Quick Start:\n');
29
+ console.log(' 1. Start service: systemctl --user start botforje');
30
+ console.log(' 2. Enable on boot: systemctl --user enable botforje');
31
+ console.log(' 3. Check status: botforje status');
32
+ console.log(' 4. Authenticate: botforje auth <botId>');
33
+ console.log(' 5. View logs: journalctl --user -u botforje -f\n');
34
+
35
+ } catch (error) {
36
+ console.error('Automatic setup failed:', error.message);
37
+ console.log('\nYou can set it up manually: botforje setup\n');
38
+ process.exit(0);
39
+ }
40
+ } else {
41
+ console.log('Systemd not detected (macOS/Windows/Container)');
42
+ console.log('\nTo use Botforje:\n');
43
+ console.log('\n 1. Start daemon: botforje daemon');
44
+ console.log(' 2. Authenticate: botforje auth <botId>\n');
45
+ }
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+ const os = require('os');
7
+
8
+ function uninstallService() {
9
+ if (os.platform() !== 'linux') return;
10
+
11
+ try {
12
+ const homeDir = os.homedir();
13
+ const servicePath = path.join(homeDir, '.config', 'systemd', 'user', 'botforje.service');
14
+ const configDir = path.join(homeDir, '.config', 'botforje');
15
+
16
+ if (!fs.existsSync(servicePath)) return;
17
+
18
+ console.log('\nUninstalling Botforje service...\n');
19
+
20
+ // Stop service first to prevent hanging
21
+ console.log('Stopping service...');
22
+ try {
23
+ execSync('systemctl --user stop botforje 2>/dev/null', { stdio: 'inherit', timeout: 10000 });
24
+ } catch (error) {
25
+ console.log('Service may not be running or failed to stop gracefully');
26
+ }
27
+
28
+ // Disable service
29
+ try {
30
+ execSync('systemctl --user disable botforje 2>/dev/null', { stdio: 'ignore' });
31
+ } catch {}
32
+
33
+ // Eliminar archivo .service
34
+ fs.unlinkSync(servicePath);
35
+ console.log('Service removed');
36
+
37
+ // Recargar systemd
38
+ execSync('systemctl --user daemon-reload', { stdio: 'ignore' });
39
+
40
+ console.log(`\nConfiguration kept at: ${configDir}`);
41
+ console.log(` To remove: rm -rf ${configDir}\n`);
42
+
43
+ } catch (error) {
44
+ console.error('Cleanup warning:', error.message);
45
+ }
46
+ }
47
+
48
+ uninstallService();
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+ const os = require('os');
7
+
8
+ function setupSystemd() {
9
+ try {
10
+ if (os.platform() !== 'linux') {
11
+ console.log('Systemd setup is only available on Linux');
12
+ return;
13
+ }
14
+
15
+ const user = os.userInfo().username;
16
+ const homeDir = os.homedir();
17
+ const configDir = path.join(homeDir, '.config', 'botforje');
18
+ const systemdUserDir = path.join(homeDir, '.config', 'systemd', 'user');
19
+
20
+ const globalNpmRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
21
+ const scriptDir = path.dirname(__filename);
22
+ const projectRoot = path.resolve(scriptDir, '..');
23
+
24
+ // Detect mode: If project root is within global npm root, it's production
25
+ const isProduction = projectRoot.startsWith(globalNpmRoot);
26
+ const installDir = isProduction
27
+ ? path.join(globalNpmRoot, 'botforje')
28
+ : projectRoot;
29
+
30
+ // For Node path, use 'which node' in both cases, but log a warning for dev
31
+ const nodePath = execSync('which node', { encoding: 'utf8' }).trim();
32
+ if (!isProduction) {
33
+ console.log('Development mode detected: Using local paths for testing');
34
+ console.log(` Install dir: ${installDir}`);
35
+ console.log(` Node path: ${nodePath}`);
36
+ console.log(' Note: Ensure dist/cli.js exists (run build first)');
37
+ }
38
+
39
+ console.log('Setting up Botforje systemd service...');
40
+
41
+ if (!fs.existsSync(configDir)) {
42
+ fs.mkdirSync(configDir, { recursive: true });
43
+ console.log(`Created config directory: ${configDir}`);
44
+ }
45
+
46
+ // Create example config file only if config.yml doesn't exist
47
+ const exampleConfigPath = path.join(__dirname, '..', 'config.example.yml');
48
+ const targetConfigPath = path.join(configDir, 'config.yml');
49
+
50
+ if (fs.existsSync(exampleConfigPath) && !fs.existsSync(targetConfigPath)) {
51
+ const exampleContent = fs.readFileSync(exampleConfigPath, 'utf8');
52
+ // Comment out all lines for the default config
53
+ const commentedContent = exampleContent
54
+ .split('\n')
55
+ .map(line => line.trim() ? `# ${line}` : line)
56
+ .join('\n');
57
+ fs.writeFileSync(targetConfigPath, commentedContent);
58
+ console.log(`Created example config file: ${targetConfigPath}`);
59
+ console.log(` Uncomment and edit this file to configure your bots`);
60
+ } else if (fs.existsSync(targetConfigPath)) {
61
+ console.log(`Config file already exists: ${targetConfigPath}`);
62
+ }
63
+
64
+ if (!fs.existsSync(systemdUserDir)) {
65
+ fs.mkdirSync(systemdUserDir, { recursive: true });
66
+ console.log(`Created systemd user directory: ${systemdUserDir}`);
67
+ }
68
+
69
+ const templatePath = path.join(__dirname, '..', 'service', 'botforje.service.template');
70
+ let serviceContent = fs.readFileSync(templatePath, 'utf8');
71
+
72
+ serviceContent = serviceContent
73
+ .replace(/{{USER}}/g, user)
74
+ .replace(/{{INSTALL_DIR}}/g, installDir)
75
+ .replace(/{{NODE_PATH}}/g, nodePath)
76
+ .replace(/{{CONFIG_DIR}}/g, configDir);
77
+
78
+ const servicePath = path.join(systemdUserDir, 'botforje.service');
79
+ fs.writeFileSync(servicePath, serviceContent);
80
+ console.log(`Created service file: ${servicePath}`);
81
+
82
+ execSync('systemctl --user daemon-reload', { stdio: 'inherit' });
83
+ console.log('Reloaded systemd daemon\n');
84
+
85
+ } catch (error) {
86
+ console.error('Error setting up systemd service:', error.message);
87
+ throw error;
88
+ }
89
+ }
90
+
91
+ setupSystemd();
@@ -0,0 +1,25 @@
1
+ [Unit]
2
+ Description=Botforje - WhatsApp Bot Service
3
+ After=network.target
4
+ Documentation=https://github.com/felixzsh/botforje
5
+
6
+ [Service]
7
+ Type=simple
8
+ WorkingDirectory={{INSTALL_DIR}}
9
+ ExecStart=xvfb-run -a {{NODE_PATH}} {{INSTALL_DIR}}/dist/cli.js daemon
10
+ Restart=on-failure
11
+ RestartSec=10
12
+ StandardOutput=journal
13
+ StandardError=journal
14
+ SyslogIdentifier=botforje
15
+
16
+ # Variables de entorno
17
+ Environment="NODE_ENV=production"
18
+ Environment="CONFIG_DIR={{CONFIG_DIR}}"
19
+
20
+ # Límites de seguridad
21
+ LimitNOFILE=65536
22
+ PrivateTmp=true
23
+
24
+ [Install]
25
+ WantedBy=multi-user.target