admindb 2.3.0 → 2.3.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 CHANGED
@@ -4,7 +4,7 @@
4
4
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
5
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
6
6
  [![Downloads](https://img.shields.io/npm/dm/admindb.svg)](https://www.npmjs.com/package/admindb)
7
- [![Publish](https://github.com/MIbnEKhalid/admindb/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/MIbnEKhalid/admindb/actions/workflows/publish.yml)
7
+ [![Check npm version](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/checkLatestVersion.yml/badge.svg)](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/checkLatestVersion.yml)
8
8
 
9
9
  **A modern, browser-based SQLite and PostgreSQL database administration tool.** Manage SQLite and PostgreSQL databases entirely from your browser — browse and edit rows, run arbitrary SQL queries, design schemas visually, seed realistic test data, inspect complex data types, and import/export CSV/JSON — with zero frontend build step.
10
10
 
package/dist/app.js CHANGED
@@ -68,18 +68,29 @@ function addErrorHandlers(app, logger) {
68
68
  }
69
69
  function createSingleDbApp(options) {
70
70
  const isServerless = options.serverless !== undefined ? options.serverless : (0, serverless_1.isServerlessEnvironment)();
71
- const rawTarget = options.connection || options.dbPath || '';
71
+ const envTarget = process.env.ADMINDB_CONNECTION ||
72
+ process.env.DATABASE_URL ||
73
+ process.env.POSTGRES_URL ||
74
+ process.env.PG_CONNECTION ||
75
+ '';
76
+ const rawTarget = options.connection || options.dbPath || ((0, common_1.isPostgresConnectionString)(envTarget) ? envTarget : '');
72
77
  const isPg = Boolean(options.pgOptions) ||
73
78
  (0, common_1.isPostgresConnectionString)(rawTarget) ||
74
79
  options.db?.dialect === 'postgres';
75
80
  const readonly = options.readonly !== undefined
76
81
  ? Boolean(options.readonly)
77
- : (isServerless && !isPg);
82
+ : (isServerless ? !isPg : false);
78
83
  const basePath = (options.basePath ?? '').replace(/\/+$/, '');
79
84
  const logger = options.logger ?? (0, logger_1.createLogger)(options.logLevel ?? 'info', 'admindb');
80
85
  let db;
81
86
  if (options.db) {
82
87
  db = options.db;
88
+ if (options.readonly !== undefined && db.isReadOnly !== Boolean(options.readonly)) {
89
+ try {
90
+ Object.defineProperty(db, 'isReadOnly', { value: Boolean(options.readonly), configurable: true });
91
+ }
92
+ catch { }
93
+ }
83
94
  }
84
95
  else if (isPg) {
85
96
  db = new postgres_1.PostgresDatabase(options.pgOptions || rawTarget, logger, { readonly });
@@ -135,8 +146,9 @@ function createSingleDbApp(options) {
135
146
  }
136
147
  function createManagerApp(options) {
137
148
  const isServerless = options.serverless !== undefined ? options.serverless : (0, serverless_1.isServerlessEnvironment)();
138
- const readonly = isServerless || Boolean(options.readonly);
149
+ const explicitReadonly = options.readonly !== undefined ? Boolean(options.readonly) : undefined;
139
150
  const manager = options.manager;
151
+ const globalReadonly = explicitReadonly ?? manager.isReadOnly;
140
152
  const basePath = (options.basePath ?? '').replace(/\/+$/, '');
141
153
  const logger = options.logger ?? (0, logger_1.createLogger)(options.logLevel ?? 'info', 'admindb');
142
154
  const authConfig = (0, auth_1.resolveAuthConfig)(options.auth);
@@ -157,7 +169,7 @@ function createManagerApp(options) {
157
169
  res.locals.dbId = null;
158
170
  res.locals.databasesUrl = null;
159
171
  res.locals.databasesMode = true;
160
- res.locals.readonly = readonly;
172
+ res.locals.readonly = globalReadonly;
161
173
  res.locals.serverless = isServerless;
162
174
  res.locals.version = APP_VERSION;
163
175
  res.locals.authEnabled = authConfig.enabled;
@@ -178,7 +190,7 @@ function createManagerApp(options) {
178
190
  manager,
179
191
  logger,
180
192
  basePath,
181
- readonly,
193
+ readonly: globalReadonly,
182
194
  allowBrowse: isServerless ? false : options.allowBrowse,
183
195
  browseRoot: options.browseRoot,
184
196
  invalidate: (id) => subApps.delete(id),
@@ -198,7 +210,7 @@ function createManagerApp(options) {
198
210
  const rawRo = req.query.readonly;
199
211
  if (rawRo !== undefined) {
200
212
  const explicitRo = rawRo === '1' || rawRo === 'true';
201
- if (!readonly || explicitRo) {
213
+ if (!globalReadonly || explicitRo) {
202
214
  manager.setReadonly(dbId, explicitRo);
203
215
  subApps.delete(dbId);
204
216
  }
@@ -206,7 +218,7 @@ function createManagerApp(options) {
206
218
  let sub = subApps.get(dbId);
207
219
  if (!sub) {
208
220
  const subBase = `${basePath || ''}/${encodeURIComponent(dbId)}`;
209
- const effectiveRo = readonly || manager.isDbReadOnly(dbId);
221
+ const effectiveRo = globalReadonly ? true : manager.isDbReadOnly(dbId);
210
222
  sub = createSingleDbApp({
211
223
  db: manager.open(dbId, effectiveRo),
212
224
  basePath: subBase,
@@ -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 const getPackageVersion:()=>string;export declare const 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;explicitReadonly?: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
@@ -38,7 +38,7 @@ function helpText() {
38
38
  ' --files, --db-files <list> Comma-separated database file paths [DB_FILES / ADMINDB_DB_FILES]',
39
39
  ' -b, --base-path, --base <p> URL prefix to serve under (default: /) [BASE_PATH / ADMINDB_BASE_PATH]',
40
40
  ' -r, --readonly, --read-only Open databases read-only (writes disabled) [READONLY / ADMINDB_READONLY]',
41
- ' --serverless Enable serverless mode (enforces read-only, disables writes) [SERVERLESS / ADMINDB_SERVERLESS]',
41
+ ' --serverless Enable serverless mode (SQLite defaults to read-only; PostgreSQL is editable unless --readonly is specified) [SERVERLESS / ADMINDB_SERVERLESS]',
42
42
  ' --auth Enable authentication (default: on) [ADMINDB_AUTH=true]',
43
43
  ' --no-auth, --disable-auth Disable authentication completely [ADMINDB_NO_AUTH=1 / ADMINDB_AUTH=false]',
44
44
  ' -u, --username, --user <user> Admin username (default: admin) [ADMINDB_USERNAME / ADMINDB_USER]',
@@ -122,8 +122,10 @@ function parseArgs(argv) {
122
122
  args.host = fileConf.host;
123
123
  if (fileConf.basePath !== undefined)
124
124
  args.basePath = fileConf.basePath;
125
- if (fileConf.readonly !== undefined)
125
+ if (fileConf.readonly !== undefined) {
126
126
  args.readonly = fileConf.readonly;
127
+ args.explicitReadonly = fileConf.readonly;
128
+ }
127
129
  if (fileConf.serverless !== undefined)
128
130
  args.serverless = fileConf.serverless;
129
131
  if (fileConf.logLevel !== undefined)
@@ -204,10 +206,10 @@ function parseArgs(argv) {
204
206
  }
205
207
  else if (tok === '-r' || tok === '--readonly' || tok === '--read-only') {
206
208
  args.readonly = true;
209
+ args.explicitReadonly = true;
207
210
  }
208
211
  else if (tok === '--serverless') {
209
212
  args.serverless = true;
210
- args.readonly = true;
211
213
  }
212
214
  else if (tok === '--no-auth' || tok === '--disable-auth') {
213
215
  args.auth = false;
@@ -1 +1 @@
1
- import type {LogLevel} from '../utils/logger';export interface DatabaseConfigFile{connections?:Record<string,string>;connection?:string;port?:number;host?:string;basePath?:string;readonly ?:boolean;serverless?:boolean;auth?:boolean|{username?:string;password?:string;secret?:string;};logLevel?:LogLevel;}export declare function parseConfigFile(filePath:string):DatabaseConfigFile|null;export interface Config{host:string;port:number;dbPath:string;connection?:string;connections?:Record<string,string>;dbDir?:string;dbFiles?:string[];basePath:string;logLevel:LogLevel;readonly :boolean;serverless:boolean;auth:boolean;authUsername?:string;authPassword?:string;authSecret?:string;}export declare function loadConfig(env?:NodeJS.ProcessEnv):Config;
1
+ import type {LogLevel} from '../utils/logger';export interface DatabaseConfigFile{connections?:Record<string,string>;connection?:string;port?:number;host?:string;basePath?:string;readonly ?:boolean;serverless?:boolean;auth?:boolean|{username?:string;password?:string;secret?:string;};logLevel?:LogLevel;}export declare function parseConfigFile(filePath:string):DatabaseConfigFile|null;export interface Config{host:string;port:number;dbPath:string;connection?:string;connections?:Record<string,string>;dbDir?:string;dbFiles?:string[];basePath:string;logLevel:LogLevel;readonly :boolean;explicitReadonly?:boolean;serverless:boolean;auth:boolean;authUsername?:string;authPassword?:string;authSecret?:string;}export declare function loadConfig(env?:NodeJS.ProcessEnv):Config;
@@ -79,8 +79,14 @@ function loadConfig(env = process.env) {
79
79
  const serverlessRaw = env.ADMINDB_SERVERLESS ?? env.SERVERLESS ?? env.IS_SERVERLESS ?? '';
80
80
  const serverless = ['1', 'true', 'yes', 'on'].includes(String(serverlessRaw).trim().toLowerCase()) ||
81
81
  (0, serverless_1.isServerlessEnvironment)(env);
82
- const readonlyRaw = env.ADMINDB_READONLY ?? env.READONLY ?? '';
83
- const readonly = serverless || ['1', 'true', 'yes', 'on'].includes(String(readonlyRaw).trim().toLowerCase());
82
+ const readonlyRaw = env.ADMINDB_READONLY ?? env.READONLY;
83
+ const explicitReadonly = readonlyRaw !== undefined && readonlyRaw !== ''
84
+ ? ['1', 'true', 'yes', 'on'].includes(String(readonlyRaw).trim().toLowerCase())
85
+ : undefined;
86
+ const isPg = Boolean((connectionRaw && (0, common_1.isPostgresConnectionString)(connectionRaw)) ||
87
+ (dbPathRaw && (0, common_1.isPostgresConnectionString)(dbPathRaw)));
88
+ const defaultReadonly = serverless ? !isPg : false;
89
+ const readonly = explicitReadonly !== undefined ? explicitReadonly : defaultReadonly;
84
90
  let connections;
85
91
  const configJsonRaw = env.ADMINDB_CONFIG_JSON ?? env.ADMINDB_CONNECTIONS;
86
92
  if (configJsonRaw) {
@@ -109,6 +115,7 @@ function loadConfig(env = process.env) {
109
115
  basePath: String(basePathRaw).replace(/\/+$/, ''),
110
116
  logLevel: logLevelRaw,
111
117
  readonly,
118
+ explicitReadonly,
112
119
  serverless,
113
120
  auth: !authDisabled,
114
121
  authUsername: (env.ADMINDB_USERNAME ?? env.ADMINDB_USER) ? String(env.ADMINDB_USERNAME ?? env.ADMINDB_USER).trim() : undefined,
@@ -38,9 +38,13 @@ function runCli() {
38
38
  const authPassword = args.authPassword ?? env.authPassword;
39
39
  const authSecret = args.authSecret ?? env.authSecret;
40
40
  const serverless = args.serverless !== undefined ? args.serverless : env.serverless;
41
- const readonly = serverless || args.readonly || env.readonly;
41
+ const explicitReadonly = args.explicitReadonly !== undefined ? args.explicitReadonly : env.explicitReadonly;
42
42
  const connections = args.connections ?? env.connections;
43
43
  const hasConnections = Boolean(connections && Object.keys(connections).length > 0);
44
+ const explicitFile = args.connection || args.dbPath || env.connection || env.dbPath;
45
+ const isPg = Boolean(explicitFile && (0, common_1.isPostgresConnectionString)(explicitFile));
46
+ const defaultReadonly = serverless ? !isPg : false;
47
+ const readonly = explicitReadonly !== undefined ? explicitReadonly : defaultReadonly;
44
48
  const config = {
45
49
  host: args.host ?? env.host,
46
50
  port: args.port ?? env.port,
@@ -52,6 +56,7 @@ function runCli() {
52
56
  basePath: (args.basePath ?? env.basePath).replace(/\/+$/, ''),
53
57
  logLevel: args.logLevel ?? env.logLevel,
54
58
  readonly,
59
+ explicitReadonly,
55
60
  serverless,
56
61
  auth: authEnabled
57
62
  ? {
@@ -67,8 +72,6 @@ function runCli() {
67
72
  app.disable('x-powered-by');
68
73
  const hasDir = Boolean(config.dbDir);
69
74
  const hasFiles = Boolean(config.dbFiles?.length);
70
- const explicitFile = args.connection || args.dbPath || config.connection || config.dbPath;
71
- const isPg = Boolean(explicitFile && (0, common_1.isPostgresConnectionString)(explicitFile));
72
75
  const singleFileOnly = !hasConnections && (Boolean(explicitFile) || isPg) && !hasDir && !hasFiles;
73
76
  const useManager = !singleFileOnly;
74
77
  const managerFiles = [...(config.dbFiles ?? [])];
@@ -79,10 +82,10 @@ function runCli() {
79
82
  const browseRoot = hasDir ? node_path_1.default.resolve(config.dbDir) : undefined;
80
83
  const router = useManager
81
84
  ? (0, app_1.createRouter)({
82
- manager: new manager_1.DbManager({ dir: managerDir, files: managerFiles, connections, readonly: config.readonly }, logger),
85
+ manager: new manager_1.DbManager({ dir: managerDir, files: managerFiles, connections, readonly: explicitReadonly, serverless: config.serverless }, logger),
83
86
  basePath: config.basePath,
84
87
  logger,
85
- readonly: config.readonly,
88
+ readonly: explicitReadonly,
86
89
  serverless: config.serverless,
87
90
  allowBrowse,
88
91
  browseRoot,
@@ -93,7 +96,7 @@ function runCli() {
93
96
  connection: explicitFile,
94
97
  basePath: config.basePath,
95
98
  logger,
96
- readonly: config.readonly,
99
+ readonly: explicitReadonly !== undefined ? explicitReadonly : (!isPg && config.serverless),
97
100
  serverless: config.serverless,
98
101
  auth: config.auth,
99
102
  });
@@ -1 +1 @@
1
- import type {IDatabase} from './types';import{type Logger} from '../utils/logger';export interface DbManagerOptions{dir?:string;files?:string[];connections?:Record<string,string>;readonly ?:boolean;}export interface DatabaseEntry{id:string;name:string;path:string;dialect:'sqlite'|'postgres';size:number;modified:string;readonly :boolean;}export declare class DbManager{private logger;private dir?;private createDir;private readonly readonlyMode;private files;private idByPath;private pathById;private nameById;private readonlyById;private openDbs;constructor(options:DbManagerOptions|string,logger?:Logger);get directory():string;get isReadOnly():boolean;isDbFile(name:string):boolean;private registerConnections;private registerDirFiles;private registerExplicitFiles;private addNamedTarget;private addFile;list():DatabaseEntry[];has(id:string):boolean;isDbReadOnly(id:string):boolean;setReadonly(id:string,readonly :boolean):void;open(id:string,readonlyOverride?:boolean):IDatabase;openFile(absPath:string,readonly ?:boolean):string;get(id:string):IDatabase|undefined;countTables(id:string):Promise<number>;create(name:string):string;addConnection(name:string,connectionString:string,readonly ?:boolean):string;remove(id:string):void;closeAll():void;}
1
+ import type {IDatabase} from './types';import{type Logger} from '../utils/logger';export interface DbManagerOptions{dir?:string;files?:string[];connections?:Record<string,string>;readonly ?:boolean;serverless?:boolean;}export interface DatabaseEntry{id:string;name:string;path:string;dialect:'sqlite'|'postgres';size:number;modified:string;readonly :boolean;}export declare class DbManager{private logger;private dir?;private createDir;private readonly readonlyMode;private readonly isServerless;private files;private idByPath;private pathById;private nameById;private readonlyById;private openDbs;constructor(options:DbManagerOptions|string,logger?:Logger);get directory():string;get isReadOnly():boolean;isDbFile(name:string):boolean;private registerConnections;private registerDirFiles;private registerExplicitFiles;private addNamedTarget;private addFile;list():DatabaseEntry[];has(id:string):boolean;isDbReadOnly(id:string):boolean;setReadonly(id:string,readonly :boolean):void;open(id:string,readonlyOverride?:boolean):IDatabase;openFile(absPath:string,readonly ?:boolean):string;get(id:string):IDatabase|undefined;countTables(id:string):Promise<number>;create(name:string):string;addConnection(name:string,connectionString:string,readonly ?:boolean):string;remove(id:string):void;closeAll():void;}
@@ -10,12 +10,14 @@ const database_1 = require("./database");
10
10
  const postgres_1 = require("./postgres");
11
11
  const logger_1 = require("../utils/logger");
12
12
  const common_1 = require("../utils/common");
13
+ const serverless_1 = require("../serverless");
13
14
  const DB_EXTENSIONS = ['.db', '.sqlite', '.sqlite3'];
14
15
  class DbManager {
15
16
  logger;
16
17
  dir;
17
18
  createDir;
18
19
  readonlyMode;
20
+ isServerless;
19
21
  files = [];
20
22
  idByPath = new Map();
21
23
  pathById = new Map();
@@ -28,6 +30,7 @@ class DbManager {
28
30
  this.dir = opts.dir ? node_path_1.default.resolve(opts.dir) : undefined;
29
31
  this.createDir = this.dir ?? process.cwd();
30
32
  this.readonlyMode = Boolean(opts.readonly);
33
+ this.isServerless = opts.serverless !== undefined ? opts.serverless : (0, serverless_1.isServerlessEnvironment)();
31
34
  if (this.dir)
32
35
  (0, node_fs_1.mkdirSync)(this.dir, { recursive: true });
33
36
  if (opts.connections)
@@ -157,12 +160,28 @@ class DbManager {
157
160
  return this.pathById.has(id);
158
161
  }
159
162
  isDbReadOnly(id) {
160
- return this.readonlyMode || (this.readonlyById.get(id) ?? false);
163
+ if (this.readonlyMode)
164
+ return true;
165
+ if (this.readonlyById.has(id))
166
+ return Boolean(this.readonlyById.get(id));
167
+ if (this.isServerless) {
168
+ const target = this.pathById.get(id);
169
+ const isPg = target ? (0, common_1.isPostgresConnectionString)(target) : false;
170
+ return !isPg;
171
+ }
172
+ return false;
161
173
  }
162
174
  setReadonly(id, readonly) {
163
175
  if (this.readonlyMode && !readonly) {
164
176
  throw new Error('Manager is in global read-only mode — databases cannot be made writable.');
165
177
  }
178
+ if (this.isServerless && !readonly) {
179
+ const target = this.pathById.get(id);
180
+ const isPg = target ? (0, common_1.isPostgresConnectionString)(target) : false;
181
+ if (!isPg) {
182
+ throw new Error('SQLite database cannot be made writable in a serverless environment.');
183
+ }
184
+ }
166
185
  if (this.readonlyById.get(id) === readonly)
167
186
  return;
168
187
  this.readonlyById.set(id, readonly);
@@ -179,7 +198,7 @@ class DbManager {
179
198
  const target = this.pathById.get(id);
180
199
  if (!target)
181
200
  throw new Error(`Database "${id}" is not registered.`);
182
- const isRo = this.readonlyMode || (readonlyOverride !== undefined ? readonlyOverride : (this.readonlyById.get(id) ?? false));
201
+ const isRo = readonlyOverride !== undefined ? readonlyOverride : this.isDbReadOnly(id);
183
202
  let db = this.openDbs.get(id);
184
203
  if (db && db.isReadOnly !== isRo) {
185
204
  try {
@@ -19,30 +19,42 @@ function isServerlessEnvironment(env = process.env) {
19
19
  env.CF_PAGES);
20
20
  }
21
21
  function createServerlessHandler(options = {}) {
22
- const rawTarget = options.connection || options.dbPath || '';
22
+ const envTarget = process.env.ADMINDB_CONNECTION ||
23
+ process.env.DATABASE_URL ||
24
+ process.env.POSTGRES_URL ||
25
+ process.env.PG_CONNECTION ||
26
+ '';
27
+ const rawTarget = options.connection || options.dbPath || ((0, common_1.isPostgresConnectionString)(envTarget) ? envTarget : '');
23
28
  const isPg = Boolean(options.pgOptions) ||
24
29
  (0, common_1.isPostgresConnectionString)(rawTarget) ||
25
30
  options.db?.dialect === 'postgres';
26
31
  const defaultReadonly = !isPg;
27
32
  const app = (0, app_1.createRouter)({
28
33
  ...options,
34
+ connection: options.connection || ((0, common_1.isPostgresConnectionString)(rawTarget) ? rawTarget : undefined),
29
35
  serverless: options.serverless ?? true,
30
- readonly: options.readonly ?? defaultReadonly,
36
+ readonly: options.readonly !== undefined ? Boolean(options.readonly) : defaultReadonly,
31
37
  });
32
38
  return (req, res) => {
33
39
  app(req, res);
34
40
  };
35
41
  }
36
42
  function createLambdaHandler(options = {}) {
37
- const rawTarget = options.connection || options.dbPath || '';
43
+ const envTarget = process.env.ADMINDB_CONNECTION ||
44
+ process.env.DATABASE_URL ||
45
+ process.env.POSTGRES_URL ||
46
+ process.env.PG_CONNECTION ||
47
+ '';
48
+ const rawTarget = options.connection || options.dbPath || ((0, common_1.isPostgresConnectionString)(envTarget) ? envTarget : '');
38
49
  const isPg = Boolean(options.pgOptions) ||
39
50
  (0, common_1.isPostgresConnectionString)(rawTarget) ||
40
51
  options.db?.dialect === 'postgres';
41
52
  const defaultReadonly = !isPg;
42
53
  const app = (0, app_1.createRouter)({
43
54
  ...options,
55
+ connection: options.connection || ((0, common_1.isPostgresConnectionString)(rawTarget) ? rawTarget : undefined),
44
56
  serverless: options.serverless ?? true,
45
- readonly: options.readonly ?? defaultReadonly,
57
+ readonly: options.readonly !== undefined ? Boolean(options.readonly) : defaultReadonly,
46
58
  });
47
59
  return async (event, _context) => {
48
60
  return new Promise((resolve) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "admindb",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Browser-based SQLite & PostgreSQL database administration tool — embed it in your Express app or run it standalone.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,7 +15,8 @@
15
15
  "generatehash": "node scripts/generate-hash.mjs",
16
16
  "screenshots": "npm run build && node scripts/capture-screenshots.mjs",
17
17
  "lint": "tsc --noEmit",
18
- "testapp": "node testapp/server.js"
18
+ "testapp": "node testapp/server.js",
19
+ "publish": "node scripts/publish.js"
19
20
  },
20
21
  "dependencies": {
21
22
  "better-sqlite3": "^11.9.1",