admindb 2.2.1 → 2.3.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.
Files changed (87) hide show
  1. package/README.md +368 -364
  2. package/dist/app.js +6 -9
  3. package/dist/auth/config.d.ts +1 -1
  4. package/dist/auth/config.js +18 -30
  5. package/dist/auth/crypto.js +11 -21
  6. package/dist/auth/middleware.js +9 -16
  7. package/dist/auth/routes.js +9 -15
  8. package/dist/cli/args.d.ts +1 -1
  9. package/dist/cli/args.js +15 -26
  10. package/dist/cli/config.js +6 -16
  11. package/dist/cli/runner.js +4 -7
  12. package/dist/data/chain.d.ts +1 -1
  13. package/dist/data/chain.js +40 -617
  14. package/dist/data/datasets.d.ts +1 -1
  15. package/dist/data/datasets.js +43 -1
  16. package/dist/data/detector.js +45 -21
  17. package/dist/data/engine.d.ts +1 -1
  18. package/dist/data/engine.js +483 -142
  19. package/dist/data/index.d.ts +1 -1
  20. package/dist/data/index.js +8 -0
  21. package/dist/data/prng.d.ts +1 -0
  22. package/dist/data/prng.js +73 -0
  23. package/dist/data/registry.d.ts +1 -0
  24. package/dist/data/registry.js +805 -0
  25. package/dist/data/schema-graph.d.ts +1 -0
  26. package/dist/data/schema-graph.js +210 -0
  27. package/dist/data/strategies.d.ts +1 -1
  28. package/dist/data/strategies.js +44 -283
  29. package/dist/data/templates.d.ts +1 -0
  30. package/dist/data/templates.js +134 -0
  31. package/dist/data/types.d.ts +1 -1
  32. package/dist/data/validator.d.ts +1 -0
  33. package/dist/data/validator.js +160 -0
  34. package/dist/db/database.js +9 -14
  35. package/dist/db/export.js +32 -55
  36. package/dist/db/filters.d.ts +1 -1
  37. package/dist/db/filters.js +15 -38
  38. package/dist/db/introspection.js +4 -7
  39. package/dist/db/manager.js +27 -51
  40. package/dist/db/migrations.js +7 -14
  41. package/dist/db/postgres.js +30 -78
  42. package/dist/index.d.ts +1 -1
  43. package/dist/public/css/app.css +1 -1
  44. package/dist/public/js/browse.js +1 -1
  45. package/dist/public/js/inspector.js +1 -1
  46. package/dist/public/js/query.js +1 -1
  47. package/dist/public/js/seed.js +1 -1
  48. package/dist/routes/api/erd.js +3 -8
  49. package/dist/routes/api/helpers.d.ts +1 -1
  50. package/dist/routes/api/helpers.js +75 -25
  51. package/dist/routes/api/import-export.js +1 -2
  52. package/dist/routes/api/query.js +2 -6
  53. package/dist/routes/api/rows.js +4 -8
  54. package/dist/routes/api/seed.js +35 -21
  55. package/dist/routes/api/tables.js +15 -30
  56. package/dist/routes/databases.js +8 -26
  57. package/dist/routes/pages.js +67 -18
  58. package/dist/serverless.js +15 -40
  59. package/dist/sql/generator.d.ts +1 -1
  60. package/dist/sql/generator.js +35 -109
  61. package/dist/types/api.d.ts +1 -1
  62. package/dist/utils/common.d.ts +1 -1
  63. package/dist/utils/common.js +45 -85
  64. package/dist/utils/csv.d.ts +1 -1
  65. package/dist/utils/csv.js +11 -17
  66. package/dist/utils/datatype.js +46 -60
  67. package/dist/utils/icons.js +8 -8
  68. package/dist/views/layouts/main.hbs +1 -87
  69. package/dist/views/pages/databases.hbs +1 -233
  70. package/dist/views/pages/designer.hbs +1 -89
  71. package/dist/views/pages/erd.hbs +1 -1241
  72. package/dist/views/pages/error.hbs +1 -10
  73. package/dist/views/pages/form.hbs +1 -59
  74. package/dist/views/pages/home.hbs +1 -220
  75. package/dist/views/pages/info.hbs +1 -107
  76. package/dist/views/pages/login.hbs +1 -98
  77. package/dist/views/pages/query.hbs +1 -129
  78. package/dist/views/pages/schema.hbs +1 -298
  79. package/dist/views/pages/seed-select.hbs +251 -0
  80. package/dist/views/pages/seed.hbs +256 -414
  81. package/dist/views/pages/table.hbs +1 -327
  82. package/dist/views/partials/navbar.hbs +1 -83
  83. package/dist/views/partials/sidebar.hbs +1 -129
  84. package/docs/API.md +149 -149
  85. package/docs/EXAMPLES.md +579 -579
  86. package/docs/SECURITY.md +265 -265
  87. package/package.json +79 -79
package/dist/app.js CHANGED
@@ -81,14 +81,11 @@ function createSingleDbApp(options) {
81
81
  if (options.db) {
82
82
  db = options.db;
83
83
  }
84
+ else if (isPg) {
85
+ db = new postgres_1.PostgresDatabase(options.pgOptions || rawTarget, logger, { readonly });
86
+ }
84
87
  else {
85
- if (isPg) {
86
- const conn = options.pgOptions || rawTarget;
87
- db = new postgres_1.PostgresDatabase(conn, logger, { readonly });
88
- }
89
- else {
90
- db = new database_1.SqliteDatabase(options.dbPath ?? 'admindb.db', logger, { readonly });
91
- }
88
+ db = new database_1.SqliteDatabase(options.dbPath ?? 'admindb.db', logger, { readonly });
92
89
  }
93
90
  const databasesUrl = options.databasesUrl;
94
91
  const authConfig = (0, auth_1.resolveAuthConfig)(options.auth);
@@ -208,7 +205,7 @@ function createManagerApp(options) {
208
205
  }
209
206
  let sub = subApps.get(dbId);
210
207
  if (!sub) {
211
- const subBase = `${basePath ? basePath : ''}/${encodeURIComponent(dbId)}`;
208
+ const subBase = `${basePath || ''}/${encodeURIComponent(dbId)}`;
212
209
  const effectiveRo = readonly || manager.isDbReadOnly(dbId);
213
210
  sub = createSingleDbApp({
214
211
  db: manager.open(dbId, effectiveRo),
@@ -216,7 +213,7 @@ function createManagerApp(options) {
216
213
  logger,
217
214
  logLevel: options.logLevel,
218
215
  dbId,
219
- databasesUrl: `${basePath ? basePath : ''}/`,
216
+ databasesUrl: `${basePath || ''}/`,
220
217
  readonly: effectiveRo,
221
218
  serverless: isServerless,
222
219
  auth: authConfig,
@@ -1 +1 @@
1
- import{type AuthConfig,type ResolvedAuthConfig} from './types';export declare function resetPersistentSecretCache():void;export declare function getOrCreatePersistentSecret(env?:NodeJS.ProcessEnv):string;export declare function resolveAuthConfig(optionsAuth?:boolean|AuthConfig,env?:NodeJS.ProcessEnv):ResolvedAuthConfig;
1
+ import{type AuthConfig,type ResolvedAuthConfig} from './types';export declare const resetPersistentSecretCache:()=>void;export declare function getOrCreatePersistentSecret(env?:NodeJS.ProcessEnv):string;export declare function resolveAuthConfig(optionsAuth?:boolean|AuthConfig,env?:NodeJS.ProcessEnv):ResolvedAuthConfig;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resetPersistentSecretCache = resetPersistentSecretCache;
6
+ exports.resetPersistentSecretCache = void 0;
7
7
  exports.getOrCreatePersistentSecret = getOrCreatePersistentSecret;
8
8
  exports.resolveAuthConfig = resolveAuthConfig;
9
9
  const node_crypto_1 = require("node:crypto");
@@ -12,18 +12,18 @@ const node_os_1 = __importDefault(require("node:os"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
13
  const types_1 = require("./types");
14
14
  let cachedFallbackSecret = null;
15
- function resetPersistentSecretCache() {
15
+ const resetPersistentSecretCache = () => {
16
16
  cachedFallbackSecret = null;
17
- }
17
+ };
18
+ exports.resetPersistentSecretCache = resetPersistentSecretCache;
18
19
  function getOrCreatePersistentSecret(env = process.env) {
19
20
  const envSecret = env.ADMINDB_SECRET ?? env.SESSION_SECRET;
20
21
  if (envSecret && String(envSecret).trim()) {
21
22
  return String(envSecret).trim();
22
23
  }
23
24
  const customSecretFile = env.ADMINDB_SECRET_FILE ? String(env.ADMINDB_SECRET_FILE).trim() : undefined;
24
- if (!customSecretFile && cachedFallbackSecret) {
25
+ if (!customSecretFile && cachedFallbackSecret)
25
26
  return cachedFallbackSecret;
26
- }
27
27
  const candidatePaths = [];
28
28
  if (customSecretFile) {
29
29
  candidatePaths.push(node_path_1.default.resolve(customSecretFile));
@@ -31,66 +31,54 @@ function getOrCreatePersistentSecret(env = process.env) {
31
31
  else {
32
32
  try {
33
33
  const home = node_os_1.default.homedir();
34
- if (home) {
34
+ if (home)
35
35
  candidatePaths.push(node_path_1.default.join(home, '.admindb-secret'));
36
- }
37
- }
38
- catch {
39
36
  }
37
+ catch { }
40
38
  try {
41
39
  const tmp = node_os_1.default.tmpdir();
42
- if (tmp) {
40
+ if (tmp)
43
41
  candidatePaths.push(node_path_1.default.join(tmp, '.admindb-secret'));
44
- }
45
- }
46
- catch {
47
42
  }
43
+ catch { }
48
44
  }
49
45
  for (const filePath of candidatePaths) {
50
46
  try {
51
47
  if ((0, node_fs_1.existsSync)(filePath)) {
52
48
  const content = (0, node_fs_1.readFileSync)(filePath, 'utf8').trim();
53
49
  if (content.length >= 16) {
54
- if (!customSecretFile) {
50
+ if (!customSecretFile)
55
51
  cachedFallbackSecret = content;
56
- }
57
52
  return content;
58
53
  }
59
54
  }
60
55
  }
61
- catch {
62
- }
56
+ catch { }
63
57
  }
64
58
  const newSecret = (0, node_crypto_1.randomBytes)(32).toString('hex');
65
59
  for (const filePath of candidatePaths) {
66
60
  try {
67
61
  const dir = node_path_1.default.dirname(filePath);
68
- if (!(0, node_fs_1.existsSync)(dir)) {
62
+ if (!(0, node_fs_1.existsSync)(dir))
69
63
  (0, node_fs_1.mkdirSync)(dir, { recursive: true });
70
- }
71
64
  (0, node_fs_1.writeFileSync)(filePath, newSecret, { encoding: 'utf8', mode: 0o600 });
72
- if (!customSecretFile) {
65
+ if (!customSecretFile)
73
66
  cachedFallbackSecret = newSecret;
74
- }
75
67
  return newSecret;
76
68
  }
77
- catch {
78
- }
69
+ catch { }
79
70
  }
80
- if (!customSecretFile) {
71
+ if (!customSecretFile)
81
72
  cachedFallbackSecret = newSecret;
82
- }
83
73
  return newSecret;
84
74
  }
85
75
  function resolveAuthConfig(optionsAuth, env = process.env) {
86
76
  const envDisabled = ['0', 'false', 'no', 'off'].includes(String(env.ADMINDB_AUTH ?? '').trim().toLowerCase()) ||
87
77
  ['1', 'true', 'yes'].includes(String(env.ADMINDB_NO_AUTH ?? env.ADMINDB_DISABLE_AUTH ?? '').trim().toLowerCase());
88
78
  let enabled = true;
89
- let username = (env.ADMINDB_USERNAME ?? env.ADMINDB_USER) ? String(env.ADMINDB_USERNAME ?? env.ADMINDB_USER).trim() : types_1.DEFAULT_USERNAME;
90
- let password = (env.ADMINDB_PASSWORD ?? env.ADMINDB_PASS) ? String(env.ADMINDB_PASSWORD ?? env.ADMINDB_PASS).trim() : types_1.DEFAULT_PASSWORD_HASH;
91
- let secret = (env.ADMINDB_SECRET ?? env.SESSION_SECRET)
92
- ? String(env.ADMINDB_SECRET ?? env.SESSION_SECRET).trim()
93
- : getOrCreatePersistentSecret(env);
79
+ let username = String(env.ADMINDB_USERNAME ?? env.ADMINDB_USER ?? types_1.DEFAULT_USERNAME).trim();
80
+ let password = String(env.ADMINDB_PASSWORD ?? env.ADMINDB_PASS ?? types_1.DEFAULT_PASSWORD_HASH).trim();
81
+ let secret = String(env.ADMINDB_SECRET ?? env.SESSION_SECRET ?? '').trim() || getOrCreatePersistentSecret(env);
94
82
  let sessionDurationMs = types_1.DEFAULT_SESSION_DURATION_MS;
95
83
  if (optionsAuth === false || envDisabled) {
96
84
  enabled = false;
@@ -28,17 +28,14 @@ function constantTimeCompare(a, b) {
28
28
  }
29
29
  }
30
30
  function verifyPassword(candidatePassword, storedPasswordOrHash) {
31
- if (typeof candidatePassword !== 'string' || typeof storedPasswordOrHash !== 'string') {
31
+ if (typeof candidatePassword !== 'string' || typeof storedPasswordOrHash !== 'string')
32
32
  return false;
33
- }
34
33
  if (storedPasswordOrHash.startsWith('scrypt:')) {
35
34
  const parts = storedPasswordOrHash.split(':');
36
35
  if (parts.length === 3 && parts[1] && parts[2]) {
37
- const salt = parts[1];
38
- const expectedKeyHex = parts[2];
39
36
  try {
40
- const derivedKey = (0, node_crypto_1.scryptSync)(candidatePassword, salt, 64).toString('hex');
41
- return constantTimeCompare(derivedKey, expectedKeyHex);
37
+ const derivedKey = (0, node_crypto_1.scryptSync)(candidatePassword, parts[1], 64).toString('hex');
38
+ return constantTimeCompare(derivedKey, parts[2]);
42
39
  }
43
40
  catch {
44
41
  return false;
@@ -57,9 +54,8 @@ function parseCookies(cookieHeader) {
57
54
  continue;
58
55
  const key = pair.slice(0, idx).trim();
59
56
  let val = pair.slice(idx + 1).trim();
60
- if (val.startsWith('"') && val.endsWith('"') && val.length >= 2) {
57
+ if (val.startsWith('"') && val.endsWith('"') && val.length >= 2)
61
58
  val = val.slice(1, -1);
62
- }
63
59
  if (key) {
64
60
  try {
65
61
  cookies[key] = decodeURIComponent(val);
@@ -72,9 +68,7 @@ function parseCookies(cookieHeader) {
72
68
  return cookies;
73
69
  }
74
70
  function createSessionToken(username, secret, durationMs = types_1.DEFAULT_SESSION_DURATION_MS) {
75
- const expiresAt = Date.now() + durationMs;
76
- const userPayload = Buffer.from(username, 'utf8').toString('base64url');
77
- const data = `${userPayload}.${expiresAt}`;
71
+ const data = `${Buffer.from(username, 'utf8').toString('base64url')}.${Date.now() + durationMs}`;
78
72
  const signature = (0, node_crypto_1.createHmac)('sha256', secret).update(data).digest('base64url');
79
73
  return `${data}.${signature}`;
80
74
  }
@@ -87,22 +81,18 @@ function verifySessionToken(token, secret, expectedUser) {
87
81
  const [userPayload, expiresStr, providedSignature] = parts;
88
82
  const data = `${userPayload}.${expiresStr}`;
89
83
  const expectedSignature = (0, node_crypto_1.createHmac)('sha256', secret).update(data).digest('base64url');
90
- if (!constantTimeCompare(providedSignature, expectedSignature)) {
84
+ if (!constantTimeCompare(providedSignature, expectedSignature))
91
85
  return null;
92
- }
93
86
  const expiresAt = Number.parseInt(expiresStr, 10);
94
- if (!Number.isFinite(expiresAt) || Date.now() > expiresAt) {
87
+ if (!Number.isFinite(expiresAt) || Date.now() > expiresAt)
95
88
  return null;
96
- }
97
- let username;
98
89
  try {
99
- username = Buffer.from(userPayload, 'base64url').toString('utf8');
90
+ const username = Buffer.from(userPayload, 'base64url').toString('utf8');
91
+ if (expectedUser && !constantTimeCompare(username, expectedUser))
92
+ return null;
93
+ return username;
100
94
  }
101
95
  catch {
102
96
  return null;
103
97
  }
104
- if (expectedUser && !constantTimeCompare(username, expectedUser)) {
105
- return null;
106
- }
107
- return username;
108
98
  }
@@ -5,14 +5,14 @@ exports.createAuthMiddleware = createAuthMiddleware;
5
5
  const types_1 = require("./types");
6
6
  const crypto_1 = require("./crypto");
7
7
  function authenticateRequest(req, config) {
8
- if (!config.enabled) {
8
+ if (!config.enabled)
9
9
  return { authenticated: true, user: 'anonymous' };
10
- }
11
10
  const authHeader = req.headers.authorization;
12
11
  if (authHeader) {
13
12
  const [scheme, credentials] = authHeader.split(/\s+/, 2);
14
13
  if (scheme && credentials) {
15
- if (scheme.toLowerCase() === 'basic') {
14
+ const lowerScheme = scheme.toLowerCase();
15
+ if (lowerScheme === 'basic') {
16
16
  try {
17
17
  const decoded = Buffer.from(credentials, 'base64').toString('utf8');
18
18
  const colonIdx = decoded.indexOf(':');
@@ -27,24 +27,21 @@ function authenticateRequest(req, config) {
27
27
  catch {
28
28
  }
29
29
  }
30
- else if (scheme.toLowerCase() === 'bearer') {
30
+ else if (lowerScheme === 'bearer') {
31
31
  const user = (0, crypto_1.verifySessionToken)(credentials, config.secret, config.username);
32
- if (user) {
32
+ if (user)
33
33
  return { authenticated: true, user };
34
- }
35
34
  if ((0, crypto_1.verifyPassword)(credentials, config.password)) {
36
35
  return { authenticated: true, user: config.username };
37
36
  }
38
37
  }
39
38
  }
40
39
  }
41
- const cookies = (0, crypto_1.parseCookies)(req.headers.cookie);
42
- const sessionCookie = cookies[types_1.SESSION_COOKIE_NAME];
40
+ const sessionCookie = (0, crypto_1.parseCookies)(req.headers.cookie)[types_1.SESSION_COOKIE_NAME];
43
41
  if (sessionCookie) {
44
42
  const user = (0, crypto_1.verifySessionToken)(sessionCookie, config.secret, config.username);
45
- if (user) {
43
+ if (user)
46
44
  return { authenticated: true, user };
47
- }
48
45
  }
49
46
  return { authenticated: false };
50
47
  }
@@ -57,11 +54,7 @@ function createAuthMiddleware(config, basePath, _logger) {
57
54
  return next();
58
55
  }
59
56
  const p = req.path;
60
- if (p.startsWith('/css/') ||
61
- p.startsWith('/js/') ||
62
- p === '/favicon.ico' ||
63
- p === '/login' ||
64
- p === '/logout') {
57
+ if (p.startsWith('/css/') || p.startsWith('/js/') || p === '/favicon.ico' || p === '/login' || p === '/logout') {
65
58
  return next();
66
59
  }
67
60
  const auth = authenticateRequest(req, config);
@@ -70,7 +63,7 @@ function createAuthMiddleware(config, basePath, _logger) {
70
63
  req.user = auth.user;
71
64
  return next();
72
65
  }
73
- if (p.startsWith('/api/') || req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
66
+ if (p.startsWith('/api/') || req.xhr || req.headers.accept?.includes('application/json')) {
74
67
  res.setHeader('WWW-Authenticate', 'Basic realm="AdminDB", Bearer');
75
68
  res.status(401).json({
76
69
  success: false,
@@ -6,15 +6,13 @@ const middleware_1 = require("./middleware");
6
6
  const crypto_1 = require("./crypto");
7
7
  function registerAuthRoutes(router, config, basePath, logger) {
8
8
  router.get('/login', (req, res) => {
9
- if (!config.enabled) {
9
+ if (!config.enabled)
10
10
  return res.redirect(`${basePath}/`);
11
- }
12
11
  const auth = (0, middleware_1.authenticateRequest)(req, config);
12
+ const nextUrl = String(req.query.next ?? '').trim();
13
13
  if (auth.authenticated) {
14
- const nextUrl = String(req.query.next ?? '').trim();
15
14
  return res.redirect(nextUrl.startsWith('/') ? nextUrl : `${basePath}/`);
16
15
  }
17
- const nextUrl = String(req.query.next ?? '').trim();
18
16
  res.render('pages/login', {
19
17
  title: 'Sign in',
20
18
  noSidebar: true,
@@ -24,17 +22,15 @@ function registerAuthRoutes(router, config, basePath, logger) {
24
22
  });
25
23
  });
26
24
  router.post('/login', (req, res) => {
27
- if (!config.enabled) {
25
+ if (!config.enabled)
28
26
  return res.redirect(`${basePath}/`);
29
- }
30
27
  const username = String(req.body?.username ?? '').trim();
31
28
  const password = String(req.body?.password ?? '').trim();
32
29
  const nextUrl = String(req.body?.next ?? req.query.next ?? '').trim();
33
- const isValid = (0, crypto_1.constantTimeCompare)(username, config.username) &&
34
- (0, crypto_1.verifyPassword)(password, config.password);
30
+ const isValid = (0, crypto_1.constantTimeCompare)(username, config.username) && (0, crypto_1.verifyPassword)(password, config.password);
35
31
  if (!isValid) {
36
32
  logger.warn(`Failed login attempt for user "${username || '<empty>'}"`);
37
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
33
+ if (req.xhr || req.headers.accept?.includes('application/json')) {
38
34
  return res.status(401).json({ success: false, error: 'Invalid username or password.' });
39
35
  }
40
36
  return res.status(401).render('pages/login', {
@@ -51,16 +47,14 @@ function registerAuthRoutes(router, config, basePath, logger) {
51
47
  const expiresUtc = new Date(Date.now() + config.sessionDurationMs).toUTCString();
52
48
  const cookiePath = basePath || '/';
53
49
  res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=${encodeURIComponent(token)}; Path=${cookiePath}; Max-Age=${maxAgeSec}; Expires=${expiresUtc}; HttpOnly; SameSite=Lax`);
54
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
50
+ if (req.xhr || req.headers.accept?.includes('application/json')) {
55
51
  return res.json({ success: true, message: 'Logged in successfully.', user: config.username, token });
56
52
  }
57
- const target = nextUrl.startsWith('/') ? nextUrl : `${basePath}/`;
58
- res.redirect(target);
53
+ res.redirect(nextUrl.startsWith('/') ? nextUrl : `${basePath}/`);
59
54
  });
60
55
  const handleLogout = (req, res) => {
61
- const cookiePath = basePath || '/';
62
- res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=; Path=${cookiePath}; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`);
63
- if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
56
+ res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=; Path=${basePath || '/'}; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`);
57
+ if (req.xhr || req.headers.accept?.includes('application/json')) {
64
58
  return res.json({ success: true, message: 'Logged out successfully.' });
65
59
  }
66
60
  res.redirect(`${basePath}/login`);
@@ -1 +1 @@
1
- import type {LogLevel} from '../utils/logger';export interface CliArgs{help:boolean;version:boolean;host?:string;port?:number;dbPath?:string;connection?:string;connections?:Record<string,string>;configPath?:string;dbDir?:string;dbFiles?:string[];basePath?:string;logLevel?:LogLevel;readonly :boolean;serverless?:boolean;auth?:boolean;authUsername?:string;authPassword?:string;authSecret?:string;}export declare function helpText():string;export declare function getPackageVersion():string;export declare function versionText():string;export declare function parseArgs(argv:string[]):{args:CliArgs;error?:string;};
1
+ import type {LogLevel} from '../utils/logger';export interface CliArgs{help:boolean;version:boolean;host?:string;port?:number;dbPath?:string;connection?:string;connections?:Record<string,string>;configPath?:string;dbDir?:string;dbFiles?:string[];basePath?:string;logLevel?:LogLevel;readonly :boolean;serverless?:boolean;auth?:boolean;authUsername?:string;authPassword?:string;authSecret?:string;}export declare function helpText():string;export declare const getPackageVersion:()=>string;export declare const versionText:()=>string;export declare function parseArgs(argv:string[]):{args:CliArgs;error?:string;};
package/dist/cli/args.js CHANGED
@@ -3,9 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.versionText = exports.getPackageVersion = void 0;
6
7
  exports.helpText = helpText;
7
- exports.getPackageVersion = getPackageVersion;
8
- exports.versionText = versionText;
9
8
  exports.parseArgs = parseArgs;
10
9
  const node_fs_1 = require("node:fs");
11
10
  const node_path_1 = __importDefault(require("node:path"));
@@ -68,28 +67,23 @@ function packageVersion() {
68
67
  ];
69
68
  for (const p of candidates) {
70
69
  if ((0, node_fs_1.existsSync)(p)) {
71
- const raw = (0, node_fs_1.readFileSync)(p, 'utf8');
72
- const pkg = JSON.parse(raw);
70
+ const pkg = JSON.parse((0, node_fs_1.readFileSync)(p, 'utf8'));
73
71
  if (pkg.version)
74
72
  return pkg.version;
75
73
  }
76
74
  }
77
- return '';
78
- }
79
- catch {
80
- return '';
81
75
  }
76
+ catch { }
77
+ return '';
82
78
  }
83
- function getPackageVersion() {
84
- return packageVersion();
85
- }
86
- function versionText() {
79
+ const getPackageVersion = () => packageVersion();
80
+ exports.getPackageVersion = getPackageVersion;
81
+ const versionText = () => {
87
82
  const v = packageVersion();
88
83
  return v ? `admindb v${v}` : 'admindb';
89
- }
90
- function isFlag(tok, ...names) {
91
- return names.includes(tok) || names.some((n) => n.length > 2 && tok.startsWith(n + '='));
92
- }
84
+ };
85
+ exports.versionText = versionText;
86
+ const isFlag = (tok, ...names) => names.includes(tok) || names.some((n) => n.length > 2 && tok.startsWith(`${n}=`));
93
87
  function parseArgs(argv) {
94
88
  const args = { help: false, version: false, readonly: false };
95
89
  const positional = [];
@@ -99,7 +93,7 @@ function parseArgs(argv) {
99
93
  const eq = argv[i].indexOf('=');
100
94
  if (eq !== -1)
101
95
  return argv[i].slice(eq + 1);
102
- i += 1;
96
+ i++;
103
97
  return argv[i];
104
98
  };
105
99
  while (i < argv.length) {
@@ -178,9 +172,8 @@ function parseArgs(argv) {
178
172
  if (v === undefined)
179
173
  return invalid('Missing value for --open / --db-path.');
180
174
  args.dbPath = v;
181
- if ((0, common_1.isPostgresConnectionString)(v)) {
175
+ if ((0, common_1.isPostgresConnectionString)(v))
182
176
  args.connection = v;
183
- }
184
177
  }
185
178
  else if (isFlag(tok, '-d', '--dir', '--folder', '--db-dir')) {
186
179
  const v = takeValue('--dir');
@@ -192,10 +185,7 @@ function parseArgs(argv) {
192
185
  const v = takeValue('--files');
193
186
  if (v === undefined)
194
187
  return invalid('Missing value for --files / --db-files.');
195
- args.dbFiles = v
196
- .split(',')
197
- .map((s) => s.trim())
198
- .filter(Boolean);
188
+ args.dbFiles = v.split(',').map((s) => s.trim()).filter(Boolean);
199
189
  }
200
190
  else if (isFlag(tok, '-b', '--base-path', '--base')) {
201
191
  const v = takeValue('--base-path');
@@ -249,7 +239,7 @@ function parseArgs(argv) {
249
239
  else {
250
240
  positional.push(tok);
251
241
  }
252
- i += 1;
242
+ i++;
253
243
  }
254
244
  if (positional.length > 1) {
255
245
  return invalid(`Unexpected extra arguments: ${positional.slice(1).join(' ')}.`);
@@ -306,9 +296,8 @@ function parseArgs(argv) {
306
296
  }
307
297
  }
308
298
  catch (err) {
309
- if (p.endsWith('.json')) {
299
+ if (p.endsWith('.json'))
310
300
  return invalid(err.message);
311
- }
312
301
  args.dbPath = p;
313
302
  }
314
303
  }
@@ -41,9 +41,8 @@ function parseConfigFile(filePath) {
41
41
  conns[k.trim()] = v.connection.trim();
42
42
  }
43
43
  }
44
- if (typeof parsed.connection === 'string' && parsed.connection.trim()) {
44
+ if (typeof parsed.connection === 'string' && parsed.connection.trim())
45
45
  result.connection = parsed.connection.trim();
46
- }
47
46
  if (typeof parsed.port === 'number')
48
47
  result.port = parsed.port;
49
48
  if (typeof parsed.host === 'string')
@@ -54,14 +53,12 @@ function parseConfigFile(filePath) {
54
53
  result.readonly = parsed.readonly;
55
54
  if (typeof parsed.serverless === 'boolean')
56
55
  result.serverless = parsed.serverless;
57
- if (typeof parsed.auth === 'boolean' || (parsed.auth && typeof parsed.auth === 'object')) {
56
+ if (typeof parsed.auth === 'boolean' || (parsed.auth && typeof parsed.auth === 'object'))
58
57
  result.auth = parsed.auth;
59
- }
60
58
  if (typeof parsed.logLevel === 'string')
61
59
  result.logLevel = parsed.logLevel;
62
- if (Object.keys(conns).length > 0) {
60
+ if (Object.keys(conns).length > 0)
63
61
  result.connections = conns;
64
- }
65
62
  return result;
66
63
  }
67
64
  catch (err) {
@@ -89,12 +86,10 @@ function loadConfig(env = process.env) {
89
86
  if (configJsonRaw) {
90
87
  try {
91
88
  const parsed = JSON.parse(configJsonRaw);
92
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
89
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
93
90
  connections = parsed;
94
- }
95
- }
96
- catch {
97
91
  }
92
+ catch { }
98
93
  }
99
94
  const configPath = env.ADMINDB_CONFIG;
100
95
  if (configPath && (0, node_fs_1.existsSync)(configPath)) {
@@ -110,12 +105,7 @@ function loadConfig(env = process.env) {
110
105
  connection: connectionRaw ? String(connectionRaw) : undefined,
111
106
  connections,
112
107
  dbDir: dbDirRaw ? String(dbDirRaw) : undefined,
113
- dbFiles: dbFilesRaw
114
- ? String(dbFilesRaw)
115
- .split(',')
116
- .map((s) => s.trim())
117
- .filter(Boolean)
118
- : undefined,
108
+ dbFiles: dbFilesRaw ? String(dbFilesRaw).split(',').map((s) => s.trim()).filter(Boolean) : undefined,
119
109
  basePath: String(basePathRaw).replace(/\/+$/, ''),
120
110
  logLevel: logLevelRaw,
121
111
  readonly,
@@ -66,7 +66,7 @@ function runCli() {
66
66
  const app = (0, express_1.default)();
67
67
  app.disable('x-powered-by');
68
68
  const hasDir = Boolean(config.dbDir);
69
- const hasFiles = Boolean(config.dbFiles && config.dbFiles.length > 0);
69
+ const hasFiles = Boolean(config.dbFiles?.length);
70
70
  const explicitFile = args.connection || args.dbPath || config.connection || config.dbPath;
71
71
  const isPg = Boolean(explicitFile && (0, common_1.isPostgresConnectionString)(explicitFile));
72
72
  const singleFileOnly = !hasConnections && (Boolean(explicitFile) || isPg) && !hasDir && !hasFiles;
@@ -103,14 +103,12 @@ function runCli() {
103
103
  const nets = node_os_1.default.networkInterfaces();
104
104
  for (const name of Object.keys(nets)) {
105
105
  for (const net of nets[name] ?? []) {
106
- if (net.family === 'IPv4' && !net.internal) {
106
+ if (net.family === 'IPv4' && !net.internal)
107
107
  return net.address;
108
- }
109
108
  }
110
109
  }
111
110
  }
112
- catch {
113
- }
111
+ catch { }
114
112
  return undefined;
115
113
  }
116
114
  const server = app.listen(config.port, config.host, () => {
@@ -126,8 +124,7 @@ function runCli() {
126
124
  if (isAnyHost) {
127
125
  const netIp = getNetworkIp();
128
126
  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)}`);
127
+ console.log(` ${colors_1.c.green('➜')} ${colors_1.c.bold('Network:')} ${colors_1.c.cyan(`http://${netIp}:${config.port}${config.basePath}/`)}`);
131
128
  }
132
129
  }
133
130
  if (useManager) {
@@ -1 +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[];}>;
1
+ import type {IDatabase,TableInfoData} from '../db/index';import{buildChainInsertSql} from './engine';import type {ColumnPlan,ErChainConfig,ErChainResult,ErChainScope,TableGenerationMode} from './types';export{buildChainInsertSql};export declare const buildErGraph:(tables:TableInfoData[])=>Map<string,import("./schema-graph").SchemaNode>;export declare const resolveErChain:(graph:Map<string,any>,rootTable:string,scope?:ErChainScope)=>import("./schema-graph").SchemaNode[];export declare const topologicalSort:(nodes:any[])=>{sorted:import("./schema-graph").SchemaNode[];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,modes?:Record<string,TableGenerationMode>,seed?:number|null):Promise<ErChainResult>;export declare function executeChainInsert(db:IDatabase,chainResult:ErChainResult,truncate?:boolean):Promise<{inserted:Record<string,number>;totalInserted:number;elapsedMs:number;warnings:string[];}>;