admindb 2.1.1 → 2.2.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.
- package/README.md +41 -12
- package/dist/app.js +230 -1
- package/dist/auth/config.js +121 -1
- package/dist/auth/crypto.js +108 -1
- package/dist/auth/index.js +21 -1
- package/dist/auth/middleware.js +85 -1
- package/dist/auth/routes.js +70 -1
- package/dist/auth/types.js +7 -1
- package/dist/cli/args.js +320 -1
- package/dist/cli/config.js +128 -1
- package/dist/cli/index.js +20 -1
- package/dist/cli/runner.js +211 -1
- package/dist/cli.js +4 -1
- package/dist/data/chain.d.ts +1 -0
- package/dist/data/chain.js +707 -0
- package/dist/data/datasets.js +129 -1
- package/dist/data/detector.d.ts +1 -1
- package/dist/data/detector.js +511 -1
- package/dist/data/engine.d.ts +1 -1
- package/dist/data/engine.js +245 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/index.js +22 -1
- package/dist/data/strategies.d.ts +1 -1
- package/dist/data/strategies.js +339 -1
- package/dist/data/types.d.ts +1 -1
- package/dist/data/types.js +5 -1
- package/dist/db/database.d.ts +1 -1
- package/dist/db/database.js +477 -1
- package/dist/db/export.d.ts +1 -1
- package/dist/db/export.js +90 -1
- package/dist/db/filters.js +142 -1
- package/dist/db/index.js +24 -1
- package/dist/db/introspection.js +167 -1
- package/dist/db/manager.js +351 -1
- package/dist/db/migrations.js +107 -1
- package/dist/db/postgres.d.ts +1 -1
- package/dist/db/postgres.js +735 -1
- package/dist/db/types.d.ts +1 -1
- package/dist/db/types.js +6 -1
- package/dist/index.js +52 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/js/api.js +1 -1
- package/dist/public/js/browse.js +1 -1
- package/dist/public/js/common.js +1 -0
- package/dist/public/js/databases.js +1 -1
- package/dist/public/js/designer.js +1 -1
- package/dist/public/js/forms.js +1 -1
- package/dist/public/js/home.js +1 -0
- package/dist/public/js/inspector.js +1 -1
- package/dist/public/js/query.js +1 -1
- package/dist/public/js/schema.js +1 -1
- package/dist/public/js/seed.js +1 -1
- package/dist/routes/api/erd.d.ts +1 -0
- package/dist/routes/api/erd.js +50 -0
- package/dist/routes/api/helpers.d.ts +1 -1
- package/dist/routes/api/helpers.js +163 -1
- package/dist/routes/api/import-export.js +83 -1
- package/dist/routes/api/index.js +48 -1
- package/dist/routes/api/query.js +78 -1
- package/dist/routes/api/rows.js +362 -1
- package/dist/routes/api/seed.js +153 -1
- package/dist/routes/api/tables.js +231 -1
- package/dist/routes/databases.js +228 -1
- package/dist/routes/index.js +19 -1
- package/dist/routes/pages.js +397 -1
- package/dist/serverless.js +174 -1
- package/dist/sql/classifier.js +24 -1
- package/dist/sql/error-analyzer.d.ts +1 -0
- package/dist/sql/error-analyzer.js +550 -0
- package/dist/sql/generator.js +319 -1
- package/dist/sql/index.js +18 -1
- package/dist/types/api.js +2 -1
- package/dist/utils/colors.js +54 -1
- package/dist/utils/common.d.ts +1 -1
- package/dist/utils/common.js +225 -1
- package/dist/utils/csv.js +67 -1
- package/dist/utils/datatype.js +181 -1
- package/dist/utils/icons.js +81 -1
- package/dist/utils/index.js +20 -1
- package/dist/utils/logger.js +36 -1
- package/dist/views/layouts/main.hbs +14 -1
- package/dist/views/pages/erd.hbs +1241 -0
- package/dist/views/pages/home.hbs +98 -2
- package/dist/views/pages/info.hbs +107 -0
- package/dist/views/pages/query.hbs +54 -12
- package/dist/views/pages/seed.hbs +435 -171
- package/dist/views/partials/sidebar.hbs +12 -0
- package/docs/API.md +6 -1
- package/docs/EXAMPLES.md +3 -0
- package/package.json +5 -4
- package/dist/public/js/icons.js +0 -1
package/dist/cli/config.js
CHANGED
|
@@ -1 +1,128 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseConfigFile = parseConfigFile;
|
|
7
|
+
exports.loadConfig = loadConfig;
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const serverless_1 = require("../serverless");
|
|
11
|
+
const common_1 = require("../utils/common");
|
|
12
|
+
function parseConfigFile(filePath) {
|
|
13
|
+
try {
|
|
14
|
+
const absPath = node_path_1.default.resolve(filePath);
|
|
15
|
+
if (!(0, node_fs_1.existsSync)(absPath))
|
|
16
|
+
return null;
|
|
17
|
+
const content = (0, node_fs_1.readFileSync)(absPath, 'utf8');
|
|
18
|
+
const parsed = JSON.parse(content);
|
|
19
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
20
|
+
return null;
|
|
21
|
+
const result = {};
|
|
22
|
+
const conns = {};
|
|
23
|
+
const topDbs = parsed.databases || parsed.connections;
|
|
24
|
+
if (topDbs && typeof topDbs === 'object' && !Array.isArray(topDbs)) {
|
|
25
|
+
for (const [k, v] of Object.entries(topDbs)) {
|
|
26
|
+
if (typeof v === 'string' && v.trim())
|
|
27
|
+
conns[k.trim()] = v.trim();
|
|
28
|
+
else if (v && typeof v === 'object' && typeof v.connection === 'string') {
|
|
29
|
+
conns[k.trim()] = v.connection.trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
34
|
+
if (['databases', 'connections', 'port', 'host', 'basePath', 'readonly', 'serverless', 'auth', 'logLevel', 'username', 'password', 'secret'].includes(k)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (typeof v === 'string' && v.trim()) {
|
|
38
|
+
conns[k.trim()] = v.trim();
|
|
39
|
+
}
|
|
40
|
+
else if (v && typeof v === 'object' && typeof v.connection === 'string') {
|
|
41
|
+
conns[k.trim()] = v.connection.trim();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (typeof parsed.connection === 'string' && parsed.connection.trim()) {
|
|
45
|
+
result.connection = parsed.connection.trim();
|
|
46
|
+
}
|
|
47
|
+
if (typeof parsed.port === 'number')
|
|
48
|
+
result.port = parsed.port;
|
|
49
|
+
if (typeof parsed.host === 'string')
|
|
50
|
+
result.host = parsed.host;
|
|
51
|
+
if (typeof parsed.basePath === 'string')
|
|
52
|
+
result.basePath = parsed.basePath;
|
|
53
|
+
if (typeof parsed.readonly === 'boolean')
|
|
54
|
+
result.readonly = parsed.readonly;
|
|
55
|
+
if (typeof parsed.serverless === 'boolean')
|
|
56
|
+
result.serverless = parsed.serverless;
|
|
57
|
+
if (typeof parsed.auth === 'boolean' || (parsed.auth && typeof parsed.auth === 'object')) {
|
|
58
|
+
result.auth = parsed.auth;
|
|
59
|
+
}
|
|
60
|
+
if (typeof parsed.logLevel === 'string')
|
|
61
|
+
result.logLevel = parsed.logLevel;
|
|
62
|
+
if (Object.keys(conns).length > 0) {
|
|
63
|
+
result.connections = conns;
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
throw new Error(`Failed to parse configuration file "${filePath}": ${(0, common_1.errorMessage)(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function loadConfig(env = process.env) {
|
|
72
|
+
const portRaw = env.ADMINDB_PORT ?? env.PORT ?? '45531';
|
|
73
|
+
const port = Number.parseInt(portRaw, 10);
|
|
74
|
+
const authDisabled = ['0', 'false', 'no', 'off'].includes(String(env.ADMINDB_AUTH ?? '').trim().toLowerCase()) ||
|
|
75
|
+
['1', 'true', 'yes'].includes(String(env.ADMINDB_NO_AUTH ?? env.ADMINDB_DISABLE_AUTH ?? '').trim().toLowerCase());
|
|
76
|
+
const dbDirRaw = env.ADMINDB_DB_DIR ?? env.ADMINDB_DIR ?? env.DB_DIR;
|
|
77
|
+
const dbFilesRaw = env.ADMINDB_DB_FILES ?? env.DB_FILES;
|
|
78
|
+
const connectionRaw = env.ADMINDB_CONNECTION ?? env.DATABASE_URL ?? env.PG_CONNECTION ?? env.POSTGRES_URL;
|
|
79
|
+
const dbPathRaw = env.ADMINDB_DB_PATH ?? env.ADMINDB_PATH ?? env.DB_PATH ?? connectionRaw;
|
|
80
|
+
const basePathRaw = env.ADMINDB_BASE_PATH ?? env.BASE_PATH ?? '';
|
|
81
|
+
const logLevelRaw = env.ADMINDB_LOG_LEVEL ?? env.LOG_LEVEL ?? 'info';
|
|
82
|
+
const serverlessRaw = env.ADMINDB_SERVERLESS ?? env.SERVERLESS ?? env.IS_SERVERLESS ?? '';
|
|
83
|
+
const serverless = ['1', 'true', 'yes', 'on'].includes(String(serverlessRaw).trim().toLowerCase()) ||
|
|
84
|
+
(0, serverless_1.isServerlessEnvironment)(env);
|
|
85
|
+
const readonlyRaw = env.ADMINDB_READONLY ?? env.READONLY ?? '';
|
|
86
|
+
const readonly = serverless || ['1', 'true', 'yes', 'on'].includes(String(readonlyRaw).trim().toLowerCase());
|
|
87
|
+
let connections;
|
|
88
|
+
const configJsonRaw = env.ADMINDB_CONFIG_JSON ?? env.ADMINDB_CONNECTIONS;
|
|
89
|
+
if (configJsonRaw) {
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(configJsonRaw);
|
|
92
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
93
|
+
connections = parsed;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const configPath = env.ADMINDB_CONFIG;
|
|
100
|
+
if (configPath && (0, node_fs_1.existsSync)(configPath)) {
|
|
101
|
+
const fileConf = parseConfigFile(configPath);
|
|
102
|
+
if (fileConf?.connections) {
|
|
103
|
+
connections = { ...(connections ?? {}), ...fileConf.connections };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
host: env.ADMINDB_HOST ?? env.HOST ?? '0.0.0.0',
|
|
108
|
+
port: Number.isFinite(port) ? port : 45531,
|
|
109
|
+
dbPath: dbPathRaw ? String(dbPathRaw) : 'admindb.db',
|
|
110
|
+
connection: connectionRaw ? String(connectionRaw) : undefined,
|
|
111
|
+
connections,
|
|
112
|
+
dbDir: dbDirRaw ? String(dbDirRaw) : undefined,
|
|
113
|
+
dbFiles: dbFilesRaw
|
|
114
|
+
? String(dbFilesRaw)
|
|
115
|
+
.split(',')
|
|
116
|
+
.map((s) => s.trim())
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
: undefined,
|
|
119
|
+
basePath: String(basePathRaw).replace(/\/+$/, ''),
|
|
120
|
+
logLevel: logLevelRaw,
|
|
121
|
+
readonly,
|
|
122
|
+
serverless,
|
|
123
|
+
auth: !authDisabled,
|
|
124
|
+
authUsername: (env.ADMINDB_USERNAME ?? env.ADMINDB_USER) ? String(env.ADMINDB_USERNAME ?? env.ADMINDB_USER).trim() : undefined,
|
|
125
|
+
authPassword: (env.ADMINDB_PASSWORD ?? env.ADMINDB_PASS) ? String(env.ADMINDB_PASSWORD ?? env.ADMINDB_PASS).trim() : undefined,
|
|
126
|
+
authSecret: (env.ADMINDB_SECRET ?? env.SESSION_SECRET) ? String(env.ADMINDB_SECRET ?? env.SESSION_SECRET).trim() : undefined,
|
|
127
|
+
};
|
|
128
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./args"), exports);
|
|
18
|
+
__exportStar(require("../utils/colors"), exports);
|
|
19
|
+
__exportStar(require("./config"), exports);
|
|
20
|
+
__exportStar(require("./runner"), exports);
|
package/dist/cli/runner.js
CHANGED
|
@@ -1 +1,211 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runCli = runCli;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const app_1 = require("../app");
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
const logger_1 = require("../utils/logger");
|
|
13
|
+
const manager_1 = require("../db/manager");
|
|
14
|
+
const args_1 = require("./args");
|
|
15
|
+
const auth_1 = require("../auth");
|
|
16
|
+
const common_1 = require("../utils/common");
|
|
17
|
+
const colors_1 = require("../utils/colors");
|
|
18
|
+
function runCli() {
|
|
19
|
+
const env = (0, config_1.loadConfig)();
|
|
20
|
+
const parsed = (0, args_1.parseArgs)(process.argv.slice(2));
|
|
21
|
+
if (parsed.error) {
|
|
22
|
+
console.error(colors_1.c.red(colors_1.c.bold(`Error: ${parsed.error}`)));
|
|
23
|
+
console.error();
|
|
24
|
+
console.error((0, args_1.helpText)());
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const args = parsed.args;
|
|
28
|
+
if (args.help) {
|
|
29
|
+
console.log((0, args_1.helpText)());
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
if (args.version) {
|
|
33
|
+
console.log((0, args_1.versionText)());
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const authEnabled = args.auth !== undefined ? args.auth : env.auth;
|
|
37
|
+
const authUsername = args.authUsername ?? env.authUsername ?? 'admin';
|
|
38
|
+
const authPassword = args.authPassword ?? env.authPassword;
|
|
39
|
+
const authSecret = args.authSecret ?? env.authSecret;
|
|
40
|
+
const serverless = args.serverless !== undefined ? args.serverless : env.serverless;
|
|
41
|
+
const readonly = serverless || args.readonly || env.readonly;
|
|
42
|
+
const connections = args.connections ?? env.connections;
|
|
43
|
+
const hasConnections = Boolean(connections && Object.keys(connections).length > 0);
|
|
44
|
+
const config = {
|
|
45
|
+
host: args.host ?? env.host,
|
|
46
|
+
port: args.port ?? env.port,
|
|
47
|
+
dbPath: args.dbPath ?? env.dbPath,
|
|
48
|
+
connection: args.connection ?? env.connection,
|
|
49
|
+
connections,
|
|
50
|
+
dbDir: args.dbDir ?? env.dbDir,
|
|
51
|
+
dbFiles: args.dbFiles ?? env.dbFiles,
|
|
52
|
+
basePath: (args.basePath ?? env.basePath).replace(/\/+$/, ''),
|
|
53
|
+
logLevel: args.logLevel ?? env.logLevel,
|
|
54
|
+
readonly,
|
|
55
|
+
serverless,
|
|
56
|
+
auth: authEnabled
|
|
57
|
+
? {
|
|
58
|
+
enabled: true,
|
|
59
|
+
username: authUsername,
|
|
60
|
+
password: authPassword,
|
|
61
|
+
secret: authSecret,
|
|
62
|
+
}
|
|
63
|
+
: false,
|
|
64
|
+
};
|
|
65
|
+
const logger = (0, logger_1.createLogger)(config.logLevel, 'admindb');
|
|
66
|
+
const app = (0, express_1.default)();
|
|
67
|
+
app.disable('x-powered-by');
|
|
68
|
+
const hasDir = Boolean(config.dbDir);
|
|
69
|
+
const hasFiles = Boolean(config.dbFiles && config.dbFiles.length > 0);
|
|
70
|
+
const explicitFile = args.connection || args.dbPath || config.connection || config.dbPath;
|
|
71
|
+
const isPg = Boolean(explicitFile && (0, common_1.isPostgresConnectionString)(explicitFile));
|
|
72
|
+
const singleFileOnly = !hasConnections && (Boolean(explicitFile) || isPg) && !hasDir && !hasFiles;
|
|
73
|
+
const useManager = !singleFileOnly;
|
|
74
|
+
const managerFiles = [...(config.dbFiles ?? [])];
|
|
75
|
+
if (useManager && explicitFile && !hasConnections)
|
|
76
|
+
managerFiles.push(explicitFile);
|
|
77
|
+
const managerDir = hasDir ? config.dbDir : hasFiles || explicitFile || hasConnections ? undefined : process.cwd();
|
|
78
|
+
const allowBrowse = useManager && (hasDir || (!hasFiles && !explicitFile && !hasConnections));
|
|
79
|
+
const browseRoot = hasDir ? node_path_1.default.resolve(config.dbDir) : undefined;
|
|
80
|
+
const router = useManager
|
|
81
|
+
? (0, app_1.createRouter)({
|
|
82
|
+
manager: new manager_1.DbManager({ dir: managerDir, files: managerFiles, connections, readonly: config.readonly }, logger),
|
|
83
|
+
basePath: config.basePath,
|
|
84
|
+
logger,
|
|
85
|
+
readonly: config.readonly,
|
|
86
|
+
serverless: config.serverless,
|
|
87
|
+
allowBrowse,
|
|
88
|
+
browseRoot,
|
|
89
|
+
auth: config.auth,
|
|
90
|
+
})
|
|
91
|
+
: (0, app_1.createRouter)({
|
|
92
|
+
dbPath: explicitFile,
|
|
93
|
+
connection: explicitFile,
|
|
94
|
+
basePath: config.basePath,
|
|
95
|
+
logger,
|
|
96
|
+
readonly: config.readonly,
|
|
97
|
+
serverless: config.serverless,
|
|
98
|
+
auth: config.auth,
|
|
99
|
+
});
|
|
100
|
+
app.use(config.basePath || '/', router);
|
|
101
|
+
function getNetworkIp() {
|
|
102
|
+
try {
|
|
103
|
+
const nets = node_os_1.default.networkInterfaces();
|
|
104
|
+
for (const name of Object.keys(nets)) {
|
|
105
|
+
for (const net of nets[name] ?? []) {
|
|
106
|
+
if (net.family === 'IPv4' && !net.internal) {
|
|
107
|
+
return net.address;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const server = app.listen(config.port, config.host, () => {
|
|
117
|
+
const v = (0, args_1.getPackageVersion)();
|
|
118
|
+
const versionStr = v ? ` v${v}` : '';
|
|
119
|
+
const isAnyHost = config.host === '0.0.0.0' || config.host === '::' || config.host === '';
|
|
120
|
+
const localHost = isAnyHost ? 'localhost' : config.host;
|
|
121
|
+
const localUrl = `http://${localHost}:${config.port}${config.basePath}/`;
|
|
122
|
+
console.log();
|
|
123
|
+
console.log(` ${colors_1.c.cyan(colors_1.c.bold('⚡ AdminDB'))}${colors_1.c.dim(versionStr)}`);
|
|
124
|
+
console.log();
|
|
125
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Local:')} ${colors_1.c.cyan(localUrl)}`);
|
|
126
|
+
if (isAnyHost) {
|
|
127
|
+
const netIp = getNetworkIp();
|
|
128
|
+
if (netIp) {
|
|
129
|
+
const netUrl = `http://${netIp}:${config.port}${config.basePath}/`;
|
|
130
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Network:')} ${colors_1.c.cyan(netUrl)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (useManager) {
|
|
134
|
+
const modeDesc = config.serverless
|
|
135
|
+
? 'Manager [Serverless Read-Only]'
|
|
136
|
+
: config.readonly
|
|
137
|
+
? 'Manager [Read-Only]'
|
|
138
|
+
: 'Manager';
|
|
139
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Mode:')} ${modeDesc}`);
|
|
140
|
+
if (args.configPath) {
|
|
141
|
+
const count = Object.keys(connections ?? {}).length;
|
|
142
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Config:')} ${colors_1.c.cyan(args.configPath)}${count ? ` (${count} connection(s))` : ''}`);
|
|
143
|
+
}
|
|
144
|
+
if (hasConnections) {
|
|
145
|
+
for (const [name, target] of Object.entries(connections)) {
|
|
146
|
+
const sanitized = (0, common_1.sanitizeConnectionString)(target);
|
|
147
|
+
const isTargetPg = (0, common_1.isPostgresConnectionString)(target);
|
|
148
|
+
const engine = isTargetPg ? 'PostgreSQL' : 'SQLite';
|
|
149
|
+
console.log(` ${colors_1.c.dim('•')} ${colors_1.c.bold(name)}: ${colors_1.c.cyan(engine)} ${colors_1.c.dim(sanitized)}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (managerDir) {
|
|
153
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Directory:')}${colors_1.c.dim(` ${managerDir}`)}`);
|
|
154
|
+
}
|
|
155
|
+
if (!allowBrowse) {
|
|
156
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Browse:')} ${colors_1.c.dim('Disabled (configured databases only)')}`);
|
|
157
|
+
}
|
|
158
|
+
else if (browseRoot) {
|
|
159
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Browse:')} ${colors_1.c.dim(`Limited to ${browseRoot}`)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const modeDesc = config.serverless
|
|
164
|
+
? 'Single DB [Serverless Read-Only]'
|
|
165
|
+
: config.readonly
|
|
166
|
+
? 'Single DB [Read-Only]'
|
|
167
|
+
: 'Single DB';
|
|
168
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Mode:')} ${modeDesc}`);
|
|
169
|
+
if (args.configPath) {
|
|
170
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Config:')} ${colors_1.c.cyan(args.configPath)}`);
|
|
171
|
+
}
|
|
172
|
+
if (isPg) {
|
|
173
|
+
const sanitized = (0, common_1.sanitizeConnectionString)(explicitFile || '');
|
|
174
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Engine:')} ${colors_1.c.cyan('PostgreSQL')}`);
|
|
175
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Database:')} ${sanitized}`);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Engine:')} ${colors_1.c.cyan('SQLite')}`);
|
|
179
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Database:')} ${explicitFile}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (authEnabled) {
|
|
183
|
+
const isDefaultPass = authUsername === 'admin' &&
|
|
184
|
+
(!authPassword || authPassword === 'admin' || authPassword === auth_1.DEFAULT_PASSWORD_HASH);
|
|
185
|
+
if (isDefaultPass) {
|
|
186
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Auth:')} User: ${colors_1.c.bold(authUsername)} ${colors_1.c.yellow('(default password)')}`);
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(` ${colors_1.c.yellow('⚠')} ${colors_1.c.yellow('Default password in use (admin).')} Generate a secure hash with:`);
|
|
189
|
+
console.log(` ${colors_1.c.dim('npm run generatehash')} and set ${colors_1.c.cyan('ADMINDB_PASSWORD')} or ${colors_1.c.cyan('-P <hash>')}`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Auth:')} User: ${colors_1.c.bold(authUsername)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(` ${colors_1.c.yellow('➜')} ${colors_1.c.bold('Auth:')} ${colors_1.c.yellow('Disabled (--no-auth)')}`);
|
|
197
|
+
console.log(` ${colors_1.c.dim('Warning: Anyone with network access can view and modify databases.')}`);
|
|
198
|
+
}
|
|
199
|
+
console.log();
|
|
200
|
+
});
|
|
201
|
+
const shutdown = (signal) => {
|
|
202
|
+
console.log(`\n ${colors_1.c.dim(`Received ${signal}, shutting down…`)}`);
|
|
203
|
+
server.close(() => {
|
|
204
|
+
console.log(` ${colors_1.c.green('✓')} ${colors_1.c.dim('AdminDB stopped.')}\n`);
|
|
205
|
+
process.exit(0);
|
|
206
|
+
});
|
|
207
|
+
setTimeout(() => process.exit(0), 2000).unref();
|
|
208
|
+
};
|
|
209
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
210
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
211
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type {IDatabase,TableInfoData} from '../db/index';import{type ColumnGeneratorConfig,type ColumnPlan,type ErChainConfig,type ErChainResult,type ErChainScope} from './types';export interface ErGraphNode{name:string;info:TableInfoData;columns:ColumnGeneratorConfig[];parents:{table:string; from :string;to:string;notnull:boolean;}[];children:{table:string; from :string;to:string;notnull:boolean;}[];hasSelfRef:boolean;depth:number;}export declare function buildErGraph(tables:TableInfoData[]):Map<string,ErGraphNode>;export declare function resolveErChain(graph:Map<string,ErGraphNode>,rootTable:string,scope?:ErChainScope):ErGraphNode[];export declare function topologicalSort(nodes:ErGraphNode[]):{sorted:ErGraphNode[];cycleDetected:boolean;cycleTables:string[];};export declare function getErChainConfig(db:IDatabase,rootTable:string,scope?:ErChainScope):Promise<ErChainConfig>;export declare function generateChainRows(db:IDatabase,chainConfig:ErChainConfig,customPlans?:Record<string,Record<string,ColumnPlan>>,customCounts?:Record<string,number>,truncate?:boolean):Promise<ErChainResult>;export declare function buildChainInsertSql(executionOrder:string[],tableResults:ErChainResult['tableResults']):string;export declare function executeChainInsert(db:IDatabase,chainResult:ErChainResult,truncate?:boolean):Promise<{inserted:Record<string,number>;totalInserted:number;elapsedMs:number;warnings:string[];}>;
|