Fix: Use JSON config files for ESM compatibility

- Replace @simpleworkjs/conf with simple custom loader
- Use JSON config files (base, development, production, secrets)
- Add config.js with ESM-compatible deep merge
- Support env var overrides for critical settings
- Auth disabled in dev mode via development.json
This commit is contained in:
2026-02-25 03:24:27 +00:00
parent 748636591b
commit 0aa7751356
13 changed files with 153 additions and 123 deletions

View File

@@ -1,36 +0,0 @@
/**
* Base configuration - shared across all environments
*/
module.exports = {
server: {
port: 3000,
host: '0.0.0.0'
},
gateway: {
url: 'http://127.0.0.1:18789',
token: 'a41984619a5f4b9bf9148ab6eb4abca53eb796d046cbbec5'
},
session: {
secret: 'change-me-in-production',
maxAge: 24 * 60 * 60 * 1000 // 24 hours
},
auth: {
disabled: false,
ldap: {
enabled: false,
url: 'ldap://localhost:389',
baseDN: 'ou=users,dc=example,dc=com',
bindDN: '',
bindPassword: '',
searchFilter: '(uid={{username}})'
}
},
data: {
dir: './data'
}
};

27
conf/base.json Normal file
View File

@@ -0,0 +1,27 @@
{
"server": {
"port": 3000,
"host": "0.0.0.0"
},
"gateway": {
"url": "http://127.0.0.1:18789"
},
"session": {
"secret": "change-me-in-production",
"maxAge": 86400000
},
"auth": {
"disabled": false,
"ldap": {
"enabled": false,
"url": "ldap://localhost:389",
"baseDN": "ou=users,dc=example,dc=com",
"bindDN": "",
"bindPassword": "",
"searchFilter": "(uid={{username}})"
}
},
"data": {
"dir": "./data"
}
}

View File

@@ -1,16 +0,0 @@
/**
* Development environment configuration
*/
module.exports = {
auth: {
disabled: true, // Skip auth in dev
ldap: {
enabled: false
}
},
server: {
// Vite runs on 5173, proxy from there
}
};

8
conf/development.json Normal file
View File

@@ -0,0 +1,8 @@
{
"auth": {
"disabled": true,
"ldap": {
"enabled": false
}
}
}

View File

@@ -1,22 +0,0 @@
/**
* Production environment configuration
*/
module.exports = {
server: {
// Use PORT env var if set, otherwise default
port: parseInt(process.env.PORT) || 3000
},
session: {
// Should be set via secrets.js in production
secret: process.env.SESSION_SECRET || 'CHANGE-ME-NOW'
},
auth: {
disabled: false,
ldap: {
enabled: process.env.LDAP_ENABLED === 'true'
}
}
};

11
conf/production.json Normal file
View File

@@ -0,0 +1,11 @@
{
"server": {
"port": 3000
},
"session": {
"secret": "CHANGE-ME-NOW"
},
"auth": {
"disabled": false
}
}

View File

@@ -1,26 +0,0 @@
/**
* Example secrets file
*
* Copy this to secrets.js and fill in your actual values
* secrets.js is ignored by git
*/
module.exports = {
gateway: {
// Your OpenClaw gateway token
token: 'your-gateway-token-here'
},
session: {
// Random string for session signing
secret: 'generate-a-random-string-here'
},
auth: {
ldap: {
// LDAP bind credentials (if needed for search)
bindDN: 'cn=admin,dc=example,dc=com',
bindPassword: 'ldap-admin-password'
}
}
};

14
conf/secrets.example.json Normal file
View File

@@ -0,0 +1,14 @@
{
"gateway": {
"token": "your-gateway-token-here"
},
"session": {
"secret": "generate-a-random-string-here"
},
"auth": {
"ldap": {
"bindDN": "cn=admin,dc=example,dc=com",
"bindPassword": "ldap-admin-password"
}
}
}

14
conf/secrets.json Normal file
View File

@@ -0,0 +1,14 @@
{
"gateway": {
"token": "a41984619a5f4b9bf9148ab6eb4abca53eb796d046cbbec5"
},
"session": {
"secret": "dev-session-secret-change-in-production"
},
"auth": {
"ldap": {
"bindDN": "",
"bindPassword": ""
}
}
}

19
package-lock.json generated
View File

@@ -8,7 +8,6 @@
"name": "openclaw-webui",
"version": "1.0.0",
"dependencies": {
"@simpleworkjs/conf": "^1.0.0",
"eventsource": "^2.0.2",
"express": "^4.18.2",
"express-session": "^1.17.3",
@@ -871,18 +870,6 @@
"win32"
]
},
"node_modules/@simpleworkjs/conf": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@simpleworkjs/conf/-/conf-1.0.0.tgz",
"integrity": "sha512-p1dQAELW0oUBRpDoz260TYw18IMI/Y11xYAb17P1MEPjsTAUB0LWE/6ZeA2VQmpU/LXoRnDysg0G/oASGILyUA==",
"license": "MIT",
"dependencies": {
"extend": "^3.0.2"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -1448,12 +1435,6 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"license": "MIT"
},
"node_modules/extsprintf": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",

View File

@@ -14,7 +14,6 @@
"preview": "vite preview"
},
"dependencies": {
"@simpleworkjs/conf": "^1.0.0",
"eventsource": "^2.0.2",
"express": "^4.18.2",
"express-session": "^1.17.3",

75
server/config.js Normal file
View File

@@ -0,0 +1,75 @@
/**
* Simple ESM-compatible configuration loader
* Loads JSON files: base.json -> environment.json -> secrets.json
*/
import { readFileSync, existsSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
function deepMerge(target, source) {
const result = { ...target };
for (const key of Object.keys(source)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = deepMerge(result[key] || {}, source[key]);
} else {
result[key] = source[key];
}
}
return result;
}
function loadJsonFile(filename) {
const path = join(__dirname, '..', 'conf', filename);
if (!existsSync(path)) return {};
try {
return JSON.parse(readFileSync(path, 'utf-8'));
} catch (err) {
console.warn(`Warning: Failed to load ${filename}:`, err.message);
return {};
}
}
// Load configuration
const environment = process.env.NODE_ENV || 'development';
const base = loadJsonFile('base.json');
const envConfig = loadJsonFile(`${environment}.json`);
const secrets = loadJsonFile('secrets.json');
// Merge all configs
const config = deepMerge(deepMerge(base, envConfig), secrets);
// Add environment info
config.environment = environment;
// Allow env var overrides for critical settings
if (process.env.PORT) {
config.server = config.server || {};
config.server.port = parseInt(process.env.PORT);
}
if (process.env.OPENCLAW_GATEWAY) {
config.gateway = config.gateway || {};
config.gateway.url = process.env.OPENCLAW_GATEWAY;
}
if (process.env.OPENCLAW_TOKEN) {
config.gateway = config.gateway || {};
config.gateway.token = process.env.OPENCLAW_TOKEN;
}
if (process.env.SESSION_SECRET) {
config.session = config.session || {};
config.session.secret = process.env.SESSION_SECRET;
}
if (process.env.LDAP_ENABLED === 'true') {
config.auth = config.auth || {};
config.auth.ldap = config.auth.ldap || {};
config.auth.ldap.enabled = true;
}
export default config;

View File

@@ -18,11 +18,11 @@ import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import ldap from 'ldapjs';
import { v4 as uuidv4 } from 'uuid';
import conf from '@simpleworkjs/conf';
import conf from './config.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
// Configuration via @simpleworkjs/conf
// Configuration
const CONFIG = {
port: conf.server?.port || 3000,
gatewayUrl: conf.gateway?.url || 'http://127.0.0.1:18789',
@@ -38,7 +38,8 @@ const CONFIG = {
bindPassword: conf.auth?.ldap?.bindPassword || '',
searchFilter: conf.auth?.ldap?.searchFilter || '(uid={{username}})'
},
dataDir: conf.data?.dir || join(__dirname, '../data')
dataDir: conf.data?.dir || join(__dirname, '../data'),
environment: conf.environment
};
// Ensure data directory exists