admindb 1.2.1 → 2.1.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 (208) hide show
  1. package/README.md +262 -329
  2. package/dist/app.d.ts +25 -4
  3. package/dist/app.js +79 -15
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/config.d.ts +19 -0
  6. package/dist/auth/config.js +147 -0
  7. package/dist/auth/config.js.map +1 -0
  8. package/dist/auth/crypto.d.ts +27 -0
  9. package/dist/auth/crypto.js +133 -0
  10. package/dist/auth/crypto.js.map +1 -0
  11. package/dist/auth/index.d.ts +5 -0
  12. package/dist/auth/index.js +22 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/auth/middleware.d.ts +14 -0
  15. package/dist/auth/middleware.js +100 -0
  16. package/dist/auth/middleware.js.map +1 -0
  17. package/dist/auth/routes.d.ts +7 -0
  18. package/dist/auth/routes.js +78 -0
  19. package/dist/auth/routes.js.map +1 -0
  20. package/dist/auth/types.d.ts +35 -0
  21. package/dist/auth/types.js +11 -0
  22. package/dist/auth/types.js.map +1 -0
  23. package/dist/cli/args.d.ts +45 -0
  24. package/dist/cli/args.js +328 -0
  25. package/dist/cli/args.js.map +1 -0
  26. package/dist/cli/config.d.ts +56 -0
  27. package/dist/cli/config.js +133 -0
  28. package/dist/cli/config.js.map +1 -0
  29. package/dist/cli/index.d.ts +4 -0
  30. package/dist/cli/index.js +21 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/runner.d.ts +1 -0
  33. package/dist/cli/runner.js +222 -0
  34. package/dist/cli/runner.js.map +1 -0
  35. package/dist/cli.js +2 -127
  36. package/dist/cli.js.map +1 -1
  37. package/dist/data/datasets.d.ts +17 -0
  38. package/dist/data/datasets.js +133 -0
  39. package/dist/data/datasets.js.map +1 -0
  40. package/dist/data/detector.d.ts +30 -0
  41. package/dist/data/detector.js +472 -0
  42. package/dist/data/detector.js.map +1 -0
  43. package/dist/data/engine.d.ts +10 -0
  44. package/dist/data/engine.js +211 -0
  45. package/dist/data/engine.js.map +1 -0
  46. package/dist/data/index.d.ts +5 -0
  47. package/dist/data/index.js +22 -0
  48. package/dist/data/index.js.map +1 -0
  49. package/dist/data/strategies.d.ts +30 -0
  50. package/dist/data/strategies.js +343 -0
  51. package/dist/data/strategies.js.map +1 -0
  52. package/dist/data/types.d.ts +73 -0
  53. package/dist/data/types.js +8 -0
  54. package/dist/data/types.js.map +1 -0
  55. package/dist/db/database.d.ts +14 -146
  56. package/dist/db/database.js +208 -461
  57. package/dist/db/database.js.map +1 -1
  58. package/dist/db/export.d.ts +2 -2
  59. package/dist/db/export.js +7 -2
  60. package/dist/db/export.js.map +1 -1
  61. package/dist/db/filters.d.ts +22 -0
  62. package/dist/db/filters.js +158 -0
  63. package/dist/db/filters.js.map +1 -0
  64. package/dist/db/index.d.ts +8 -0
  65. package/dist/db/index.js +25 -0
  66. package/dist/db/index.js.map +1 -0
  67. package/dist/db/introspection.d.ts +6 -0
  68. package/dist/db/introspection.js +172 -0
  69. package/dist/db/introspection.js.map +1 -0
  70. package/dist/db/manager.d.ts +32 -19
  71. package/dist/db/manager.js +203 -44
  72. package/dist/db/manager.js.map +1 -1
  73. package/dist/db/migrations.d.ts +5 -0
  74. package/dist/db/migrations.js +110 -0
  75. package/dist/db/migrations.js.map +1 -0
  76. package/dist/db/postgres.d.ts +85 -0
  77. package/dist/db/postgres.js +745 -0
  78. package/dist/db/postgres.js.map +1 -0
  79. package/dist/db/types.d.ts +206 -0
  80. package/dist/db/types.js +7 -0
  81. package/dist/db/types.js.map +1 -0
  82. package/dist/index.d.ts +9 -2
  83. package/dist/index.js +46 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/public/css/app.css +1 -1
  86. package/dist/public/css/input.css +74 -11
  87. package/dist/public/js/app.js +142 -0
  88. package/dist/public/js/browse.js +591 -104
  89. package/dist/public/js/databases.js +105 -13
  90. package/dist/public/js/designer.js +55 -2
  91. package/dist/public/js/forms.js +610 -28
  92. package/dist/public/js/icons.js +51 -0
  93. package/dist/public/js/inspector.js +638 -0
  94. package/dist/public/js/query.js +93 -3
  95. package/dist/public/js/schema.js +185 -52
  96. package/dist/public/js/seed.js +865 -152
  97. package/dist/routes/api/helpers.d.ts +42 -0
  98. package/dist/routes/api/helpers.js +133 -0
  99. package/dist/routes/api/helpers.js.map +1 -0
  100. package/dist/routes/api/import-export.d.ts +3 -0
  101. package/dist/routes/api/import-export.js +85 -0
  102. package/dist/routes/api/import-export.js.map +1 -0
  103. package/dist/routes/api/index.d.ts +4 -0
  104. package/dist/routes/api/index.js +37 -0
  105. package/dist/routes/api/index.js.map +1 -0
  106. package/dist/routes/api/query.d.ts +3 -0
  107. package/dist/routes/api/query.js +76 -0
  108. package/dist/routes/api/query.js.map +1 -0
  109. package/dist/routes/api/rows.d.ts +3 -0
  110. package/dist/routes/api/rows.js +373 -0
  111. package/dist/routes/api/rows.js.map +1 -0
  112. package/dist/routes/api/seed.d.ts +3 -0
  113. package/dist/routes/api/seed.js +82 -0
  114. package/dist/routes/api/seed.js.map +1 -0
  115. package/dist/routes/api/tables.d.ts +3 -0
  116. package/dist/routes/api/tables.js +160 -0
  117. package/dist/routes/api/tables.js.map +1 -0
  118. package/dist/routes/databases.d.ts +8 -11
  119. package/dist/routes/databases.js +100 -66
  120. package/dist/routes/databases.js.map +1 -1
  121. package/dist/routes/index.d.ts +3 -0
  122. package/dist/routes/index.js +20 -0
  123. package/dist/routes/index.js.map +1 -0
  124. package/dist/routes/pages.d.ts +3 -3
  125. package/dist/routes/pages.js +157 -64
  126. package/dist/routes/pages.js.map +1 -1
  127. package/dist/serverless.d.ts +40 -0
  128. package/dist/serverless.js +210 -0
  129. package/dist/serverless.js.map +1 -0
  130. package/dist/sql/generator.d.ts +7 -3
  131. package/dist/sql/generator.js +144 -7
  132. package/dist/sql/generator.js.map +1 -1
  133. package/dist/sql/index.d.ts +2 -0
  134. package/dist/sql/index.js +19 -0
  135. package/dist/sql/index.js.map +1 -0
  136. package/dist/types/api.d.ts +412 -0
  137. package/dist/types/api.js +9 -0
  138. package/dist/types/api.js.map +1 -0
  139. package/dist/utils/colors.d.ts +40 -0
  140. package/dist/utils/colors.js +64 -0
  141. package/dist/utils/colors.js.map +1 -0
  142. package/dist/{util.d.ts → utils/common.d.ts} +10 -6
  143. package/dist/{util.js → utils/common.js} +80 -13
  144. package/dist/utils/common.js.map +1 -0
  145. package/dist/utils/csv.js.map +1 -0
  146. package/dist/utils/datatype.d.ts +49 -0
  147. package/dist/utils/datatype.js +222 -0
  148. package/dist/utils/datatype.js.map +1 -0
  149. package/dist/utils/icons.d.ts +11 -0
  150. package/dist/utils/icons.js +72 -0
  151. package/dist/utils/icons.js.map +1 -0
  152. package/dist/utils/index.d.ts +4 -0
  153. package/dist/utils/index.js +21 -0
  154. package/dist/utils/index.js.map +1 -0
  155. package/dist/{logger.d.ts → utils/logger.d.ts} +1 -1
  156. package/dist/utils/logger.js +40 -0
  157. package/dist/utils/logger.js.map +1 -0
  158. package/dist/views/layouts/main.hbs +40 -11
  159. package/dist/views/pages/databases.hbs +182 -74
  160. package/dist/views/pages/designer.hbs +29 -11
  161. package/dist/views/pages/error.hbs +3 -3
  162. package/dist/views/pages/form.hbs +5 -3
  163. package/dist/views/pages/home.hbs +22 -13
  164. package/dist/views/pages/login.hbs +111 -0
  165. package/dist/views/pages/query.hbs +8 -6
  166. package/dist/views/pages/schema.hbs +41 -13
  167. package/dist/views/pages/seed.hbs +200 -54
  168. package/dist/views/pages/table.hbs +152 -72
  169. package/dist/views/partials/icon.hbs +2 -0
  170. package/dist/views/partials/navbar.hbs +69 -25
  171. package/dist/views/partials/sidebar.hbs +108 -94
  172. package/docs/API.md +144 -0
  173. package/docs/EXAMPLES.md +576 -0
  174. package/docs/SECURITY.md +265 -0
  175. package/package.json +15 -4
  176. package/dist/args.d.ts +0 -28
  177. package/dist/args.js +0 -187
  178. package/dist/args.js.map +0 -1
  179. package/dist/config.d.ts +0 -17
  180. package/dist/config.js +0 -23
  181. package/dist/config.js.map +0 -1
  182. package/dist/csv.js.map +0 -1
  183. package/dist/data/generator.d.ts +0 -86
  184. package/dist/data/generator.js +0 -1031
  185. package/dist/data/generator.js.map +0 -1
  186. package/dist/logger.js +0 -25
  187. package/dist/logger.js.map +0 -1
  188. package/dist/routes/api.d.ts +0 -9
  189. package/dist/routes/api.js +0 -848
  190. package/dist/routes/api.js.map +0 -1
  191. package/dist/test/classifier.test.d.ts +0 -1
  192. package/dist/test/classifier.test.js +0 -44
  193. package/dist/test/classifier.test.js.map +0 -1
  194. package/dist/test/csv.test.d.ts +0 -1
  195. package/dist/test/csv.test.js +0 -64
  196. package/dist/test/csv.test.js.map +0 -1
  197. package/dist/test/database.test.d.ts +0 -1
  198. package/dist/test/database.test.js +0 -402
  199. package/dist/test/database.test.js.map +0 -1
  200. package/dist/test/generator.test.d.ts +0 -1
  201. package/dist/test/generator.test.js +0 -132
  202. package/dist/test/generator.test.js.map +0 -1
  203. package/dist/test/manager.test.d.ts +0 -1
  204. package/dist/test/manager.test.js +0 -146
  205. package/dist/test/manager.test.js.map +0 -1
  206. package/dist/util.js.map +0 -1
  207. /package/dist/{csv.d.ts → utils/csv.d.ts} +0 -0
  208. /package/dist/{csv.js → utils/csv.js} +0 -0
@@ -0,0 +1,22 @@
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("./types"), exports);
18
+ __exportStar(require("./crypto"), exports);
19
+ __exportStar(require("./config"), exports);
20
+ __exportStar(require("./middleware"), exports);
21
+ __exportStar(require("./routes"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,2CAAyB;AACzB,2CAAyB;AACzB,+CAA6B;AAC7B,2CAAyB"}
@@ -0,0 +1,14 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ import type { Logger } from '../utils/logger';
3
+ import { type ResolvedAuthConfig } from './types';
4
+ /**
5
+ * Checks incoming request headers and cookies for valid authentication.
6
+ */
7
+ export declare function authenticateRequest(req: Request, config: ResolvedAuthConfig): {
8
+ authenticated: boolean;
9
+ user?: string;
10
+ };
11
+ /**
12
+ * Express middleware to protect routes.
13
+ */
14
+ export declare function createAuthMiddleware(config: ResolvedAuthConfig, basePath: string, _logger: Logger): (req: Request, res: Response, next: NextFunction) => void;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authenticateRequest = authenticateRequest;
4
+ exports.createAuthMiddleware = createAuthMiddleware;
5
+ const types_1 = require("./types");
6
+ const crypto_1 = require("./crypto");
7
+ /**
8
+ * Checks incoming request headers and cookies for valid authentication.
9
+ */
10
+ function authenticateRequest(req, config) {
11
+ if (!config.enabled) {
12
+ return { authenticated: true, user: 'anonymous' };
13
+ }
14
+ // 1. Check HTTP Authorization header (Basic or Bearer)
15
+ const authHeader = req.headers.authorization;
16
+ if (authHeader) {
17
+ const [scheme, credentials] = authHeader.split(/\s+/, 2);
18
+ if (scheme && credentials) {
19
+ if (scheme.toLowerCase() === 'basic') {
20
+ try {
21
+ const decoded = Buffer.from(credentials, 'base64').toString('utf8');
22
+ const colonIdx = decoded.indexOf(':');
23
+ if (colonIdx !== -1) {
24
+ const user = decoded.slice(0, colonIdx);
25
+ const pass = decoded.slice(colonIdx + 1);
26
+ if ((0, crypto_1.constantTimeCompare)(user, config.username) && (0, crypto_1.verifyPassword)(pass, config.password)) {
27
+ return { authenticated: true, user };
28
+ }
29
+ }
30
+ }
31
+ catch {
32
+ // Ignore parse errors
33
+ }
34
+ }
35
+ else if (scheme.toLowerCase() === 'bearer') {
36
+ const user = (0, crypto_1.verifySessionToken)(credentials, config.secret, config.username);
37
+ if (user) {
38
+ return { authenticated: true, user };
39
+ }
40
+ // Direct password comparison as bearer token
41
+ if ((0, crypto_1.verifyPassword)(credentials, config.password)) {
42
+ return { authenticated: true, user: config.username };
43
+ }
44
+ }
45
+ }
46
+ }
47
+ // 2. Check Cookie session
48
+ const cookies = (0, crypto_1.parseCookies)(req.headers.cookie);
49
+ const sessionCookie = cookies[types_1.SESSION_COOKIE_NAME];
50
+ if (sessionCookie) {
51
+ const user = (0, crypto_1.verifySessionToken)(sessionCookie, config.secret, config.username);
52
+ if (user) {
53
+ return { authenticated: true, user };
54
+ }
55
+ }
56
+ return { authenticated: false };
57
+ }
58
+ /**
59
+ * Express middleware to protect routes.
60
+ */
61
+ function createAuthMiddleware(config, basePath, _logger) {
62
+ return (req, res, next) => {
63
+ // Expose auth state to templates
64
+ res.locals.authEnabled = config.enabled;
65
+ res.locals.isDefaultPassword = config.isDefaultPassword;
66
+ if (!config.enabled) {
67
+ res.locals.authUser = null;
68
+ return next();
69
+ }
70
+ const p = req.path;
71
+ // Public static assets and auth endpoints bypass authentication
72
+ if (p.startsWith('/css/') ||
73
+ p.startsWith('/js/') ||
74
+ p === '/favicon.ico' ||
75
+ p === '/login' ||
76
+ p === '/logout') {
77
+ return next();
78
+ }
79
+ const auth = authenticateRequest(req, config);
80
+ if (auth.authenticated && auth.user) {
81
+ res.locals.authUser = auth.user;
82
+ req.user = auth.user;
83
+ return next();
84
+ }
85
+ // Unauthenticated: API requests get 401 JSON
86
+ if (p.startsWith('/api/') || req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
87
+ res.setHeader('WWW-Authenticate', 'Basic realm="AdminDB", Bearer');
88
+ res.status(401).json({
89
+ success: false,
90
+ error: 'Authentication required. Please log in or provide valid credentials.',
91
+ });
92
+ return;
93
+ }
94
+ // Web UI: Redirect to login with return path
95
+ const returnUrl = req.originalUrl || `${basePath}${req.url}`;
96
+ const loginUrl = `${basePath}/login${returnUrl && returnUrl !== `${basePath}/` ? `?next=${encodeURIComponent(returnUrl)}` : ''}`;
97
+ res.redirect(loginUrl);
98
+ };
99
+ }
100
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Router } from 'express';
2
+ import type { Logger } from '../utils/logger';
3
+ import { type ResolvedAuthConfig } from './types';
4
+ /**
5
+ * Registers /login and /logout routes.
6
+ */
7
+ export declare function registerAuthRoutes(router: Router, config: ResolvedAuthConfig, basePath: string, logger: Logger): void;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerAuthRoutes = registerAuthRoutes;
4
+ const types_1 = require("./types");
5
+ const middleware_1 = require("./middleware");
6
+ const crypto_1 = require("./crypto");
7
+ /**
8
+ * Registers /login and /logout routes.
9
+ */
10
+ function registerAuthRoutes(router, config, basePath, logger) {
11
+ // GET /login - render login screen
12
+ router.get('/login', (req, res) => {
13
+ if (!config.enabled) {
14
+ return res.redirect(`${basePath}/`);
15
+ }
16
+ const auth = (0, middleware_1.authenticateRequest)(req, config);
17
+ if (auth.authenticated) {
18
+ const nextUrl = String(req.query.next ?? '').trim();
19
+ return res.redirect(nextUrl.startsWith('/') ? nextUrl : `${basePath}/`);
20
+ }
21
+ const nextUrl = String(req.query.next ?? '').trim();
22
+ res.render('pages/login', {
23
+ title: 'Sign in',
24
+ noSidebar: true,
25
+ next: nextUrl.startsWith('/') ? nextUrl : '',
26
+ isDefaultPassword: config.isDefaultPassword,
27
+ error: req.query.error ? String(req.query.error) : null,
28
+ });
29
+ });
30
+ // POST /login - process login submission
31
+ router.post('/login', (req, res) => {
32
+ if (!config.enabled) {
33
+ return res.redirect(`${basePath}/`);
34
+ }
35
+ const username = String(req.body?.username ?? '').trim();
36
+ const password = String(req.body?.password ?? '').trim();
37
+ const nextUrl = String(req.body?.next ?? req.query.next ?? '').trim();
38
+ const isValid = (0, crypto_1.constantTimeCompare)(username, config.username) &&
39
+ (0, crypto_1.verifyPassword)(password, config.password);
40
+ if (!isValid) {
41
+ logger.warn(`Failed login attempt for user "${username || '<empty>'}"`);
42
+ if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
43
+ return res.status(401).json({ success: false, error: 'Invalid username or password.' });
44
+ }
45
+ return res.status(401).render('pages/login', {
46
+ title: 'Sign in',
47
+ noSidebar: true,
48
+ username,
49
+ next: nextUrl.startsWith('/') ? nextUrl : '',
50
+ isDefaultPassword: config.isDefaultPassword,
51
+ error: 'Invalid username or password. Please check your credentials.',
52
+ });
53
+ }
54
+ // Successful authentication: issue signed session cookie
55
+ const token = (0, crypto_1.createSessionToken)(config.username, config.secret, config.sessionDurationMs);
56
+ const maxAgeSec = Math.floor(config.sessionDurationMs / 1000);
57
+ const expiresUtc = new Date(Date.now() + config.sessionDurationMs).toUTCString();
58
+ const cookiePath = basePath || '/';
59
+ res.setHeader('Set-Cookie', `${types_1.SESSION_COOKIE_NAME}=${encodeURIComponent(token)}; Path=${cookiePath}; Max-Age=${maxAgeSec}; Expires=${expiresUtc}; HttpOnly; SameSite=Lax`);
60
+ if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
61
+ return res.json({ success: true, message: 'Logged in successfully.', user: config.username, token });
62
+ }
63
+ const target = nextUrl.startsWith('/') ? nextUrl : `${basePath}/`;
64
+ res.redirect(target);
65
+ });
66
+ // POST & GET /logout - clear session and redirect to login
67
+ const handleLogout = (req, res) => {
68
+ const cookiePath = basePath || '/';
69
+ 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`);
70
+ if (req.xhr || (req.headers.accept && req.headers.accept.includes('application/json'))) {
71
+ return res.json({ success: true, message: 'Logged out successfully.' });
72
+ }
73
+ res.redirect(`${basePath}/login`);
74
+ };
75
+ router.post('/logout', handleLogout);
76
+ router.get('/logout', handleLogout);
77
+ }
78
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/auth/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export interface AuthConfig {
2
+ /**
3
+ * Whether authentication is enabled.
4
+ * Set to `false` to disable protection entirely (e.g. for development or custom upstream auth).
5
+ * Defaults to `true`.
6
+ */
7
+ enabled?: boolean;
8
+ /** Admin username. Defaults to `process.env.ADMINDB_USERNAME` or `'admin'`. */
9
+ username?: string;
10
+ /**
11
+ * Admin password or password hash (e.g. `scrypt:<salt>:<hash>`).
12
+ * Generate a hash using `npm run generatehash`.
13
+ * Defaults to `process.env.ADMINDB_PASSWORD` or the hardcoded default hash for `'admin'`.
14
+ */
15
+ password?: string;
16
+ /** Secret key used to sign session cookies. Defaults to `process.env.ADMINDB_SECRET` or auto-generated. */
17
+ secret?: string;
18
+ /** Session expiration time in milliseconds. Defaults to 7 days (604800000 ms). */
19
+ sessionDurationMs?: number;
20
+ }
21
+ export interface ResolvedAuthConfig {
22
+ enabled: boolean;
23
+ username: string;
24
+ password: string;
25
+ secret: string;
26
+ sessionDurationMs: number;
27
+ isDefaultPassword: boolean;
28
+ }
29
+ export declare const DEFAULT_USERNAME = "admin";
30
+ /**
31
+ * Hardcoded default scrypt hash for password 'admin' (salt: d9f2e64b8a1c3d5e7f0a2b4c6e801357, keyLen: 64).
32
+ */
33
+ export declare const DEFAULT_PASSWORD_HASH = "scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2";
34
+ export declare const DEFAULT_SESSION_DURATION_MS: number;
35
+ export declare const SESSION_COOKIE_NAME = "admindb_session";
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SESSION_COOKIE_NAME = exports.DEFAULT_SESSION_DURATION_MS = exports.DEFAULT_PASSWORD_HASH = exports.DEFAULT_USERNAME = void 0;
4
+ exports.DEFAULT_USERNAME = 'admin';
5
+ /**
6
+ * Hardcoded default scrypt hash for password 'admin' (salt: d9f2e64b8a1c3d5e7f0a2b4c6e801357, keyLen: 64).
7
+ */
8
+ exports.DEFAULT_PASSWORD_HASH = 'scrypt:d9f2e64b8a1c3d5e7f0a2b4c6e801357:cb3032b16f29c8d44f75c779f070c61c846b17eb333d07596ceb8470fc1b4c06cc720c08796ebc86937dab28a3ef580ced38a71c940fd4a169fd2e9cb9fa40e2';
9
+ exports.DEFAULT_SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
10
+ exports.SESSION_COOKIE_NAME = 'admindb_session';
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":";;;AA8Ba,QAAA,gBAAgB,GAAG,OAAO,CAAC;AAExC;;GAEG;AACU,QAAA,qBAAqB,GAChC,0KAA0K,CAAC;AAEhK,QAAA,2BAA2B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAChE,QAAA,mBAAmB,GAAG,iBAAiB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { LogLevel } from '../utils/logger';
2
+ export interface CliArgs {
3
+ help: boolean;
4
+ version: boolean;
5
+ /** Bind host/interface (`--host`, `-H`). */
6
+ host?: string;
7
+ /** Port to listen on (`--port`, `-p`). */
8
+ port?: number;
9
+ /** A single database file to open directly (`--open`/`--db`/`--file`/`--db-path`). */
10
+ dbPath?: string;
11
+ /** PostgreSQL or database connection string (`--connection`/`--conn`/`--pg`). */
12
+ connection?: string;
13
+ /** Database connections map (from JSON config file). */
14
+ connections?: Record<string, string>;
15
+ /** Path to a JSON configuration file (`--config`, `-C`). */
16
+ configPath?: string;
17
+ /** Directory of database files to manage (`--dir`/`--folder`/`--db-dir`, `-d`). */
18
+ dbDir?: string;
19
+ /** Explicit database file paths (`--files`/`--db-files`). */
20
+ dbFiles?: string[];
21
+ /** URL prefix to serve under (`--base-path`/`--base`, `-b`). */
22
+ basePath?: string;
23
+ /** Log level filter (`--log-level`, `-l`). */
24
+ logLevel?: LogLevel;
25
+ /** Open databases read-only (`--readonly`, `-r`). */
26
+ readonly: boolean;
27
+ /** Serverless mode (enforces read-only database operations) (`--serverless`). */
28
+ serverless?: boolean;
29
+ /** Whether authentication is enabled (defaults to true). Set to false via `--no-auth`. */
30
+ auth?: boolean;
31
+ /** Custom admin username (`--username`/`--user`/`--auth-username`, `-u`). */
32
+ authUsername?: string;
33
+ /** Custom admin password (`--password`/`--pass`/`--auth-password`, `-P`). */
34
+ authPassword?: string;
35
+ /** Secret key for session cookie signing (`--auth-secret`/`--secret`). */
36
+ authSecret?: string;
37
+ }
38
+ export declare function helpText(): string;
39
+ /** The installed `admindb` package version (from package.json), or '' when unknown. */
40
+ export declare function getPackageVersion(): string;
41
+ export declare function versionText(): string;
42
+ export declare function parseArgs(argv: string[]): {
43
+ args: CliArgs;
44
+ error?: string;
45
+ };