aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.js
blob: d29ada43ab879b67301b0cbe9bfd4da8abf82994 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Paths, accounts and user config.
//
// Everything follows XDG, split per account (like gws with several accounts):
//   config   ~/.config/wa-cli/config.json, hooks/
//   session  ~/.local/share/wa-cli/<account>/   (LocalAuth: Chrome profile)
//   state    ~/.local/state/wa-cli/<account>/   (pid, daemon log)
//   media    ~/.local/share/wa-cli/<account>/media/
//   socket   $XDG_RUNTIME_DIR/wa-cli/<account>.sock

import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';

const env = process.env;
const HOME = os.homedir();
const XDG_CONFIG = env.XDG_CONFIG_HOME || path.join(HOME, '.config');
const XDG_DATA = env.XDG_DATA_HOME || path.join(HOME, '.local/share');
const XDG_STATE = env.XDG_STATE_HOME || path.join(HOME, '.local/state');
const XDG_CACHE = env.XDG_CACHE_HOME || path.join(HOME, '.cache');
const RUNTIME = env.XDG_RUNTIME_DIR || path.join(os.tmpdir(), `wa-cli-${process.getuid()}`);

const ACCOUNT_RE = /^[A-Za-z0-9_-]+$/;

export const VERSION = JSON.parse(
    fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
).version;

export function accountName(flag) {
    const name = flag || env.WA_CLI_ACCOUNT || 'default';
    if (!ACCOUNT_RE.test(name)) {
        throw Object.assign(new Error(`invalid account name: ${name} (only [A-Za-z0-9_-])`), { code: 'EINVAL' });
    }
    return name;
}

export function paths(account) {
    const configDir = env.WA_CLI_CONFIG_DIR || path.join(XDG_CONFIG, 'wa-cli');
    const dataDir = path.join(env.WA_CLI_DATA_DIR || path.join(XDG_DATA, 'wa-cli'), account);
    const stateDir = path.join(XDG_STATE, 'wa-cli', account);
    return {
        configDir,
        configFile: path.join(configDir, 'config.json'),
        hooksDir: path.join(configDir, 'hooks'),
        dataDir,
        mediaDir: path.join(dataDir, 'media'),
        stateDir,
        pidFile: path.join(stateDir, 'daemon.pid'),
        logFile: path.join(stateDir, 'daemon.log'),
        cacheDir: path.join(XDG_CACHE, 'wa-cli'),
        socket: env.WA_CLI_SOCKET || path.join(RUNTIME, 'wa-cli', `${account}.sock`),
    };
}

const DEFAULTS = {
    autostart: true,          // the CLI starts the daemon if it is not running
    readyTimeoutMs: 120000,   // how long a command waits for the session to be ready
    startTimeoutMs: 180000,   // if WhatsApp Web does not load within this time, the daemon exits (and is restarted)
    hooks: true,              // ejecutar ~/.config/wa-cli/hooks/<evento>
    hookTimeoutMs: 60000,
    browserName: 'wa-cli',    // shows as "wa-cli (Linux)" under Linked devices
    deviceName: 'Linux',
    puppeteer: { headless: true },
};

// config.json: { ...globals, "accounts": { "<account>": { ...overrides } } }
export function loadConfig(account) {
    const p = paths(account);
    let file = {};
    try {
        file = JSON.parse(fs.readFileSync(p.configFile, 'utf8'));
    } catch (e) {
        if (e.code !== 'ENOENT') {
            throw Object.assign(new Error(`${p.configFile}: ${e.message}`), { code: 'EINVAL' });
        }
    }
    const { accounts = {}, ...global } = file;
    const cfg = { ...DEFAULTS, ...global, ...(accounts[account] || {}) };
    cfg.puppeteer = { ...DEFAULTS.puppeteer, ...global.puppeteer, ...accounts[account]?.puppeteer };
    cfg.wamail = { ...global.wamail, ...accounts[account]?.wamail };
    if (env.WA_CLI_AUTOSTART !== undefined) cfg.autostart = !/^(0|false|no)$/i.test(env.WA_CLI_AUTOSTART);
    return cfg;
}