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/sql/generator.js
CHANGED
|
@@ -1 +1,319 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DESIGNER_TYPES = exports.POSTGRES_DESIGNER_TYPES = exports.SQLITE_DESIGNER_TYPES = void 0;
|
|
4
|
+
exports.getDesignerTypes = getDesignerTypes;
|
|
5
|
+
exports.quoteIdentifier = quoteIdentifier;
|
|
6
|
+
exports.escapeString = escapeString;
|
|
7
|
+
exports.sqlValue = sqlValue;
|
|
8
|
+
exports.mapColumnType = mapColumnType;
|
|
9
|
+
exports.formatSqlDefault = formatSqlDefault;
|
|
10
|
+
exports.renderColumnDef = renderColumnDef;
|
|
11
|
+
exports.generateCreateTable = generateCreateTable;
|
|
12
|
+
exports.generateAddColumn = generateAddColumn;
|
|
13
|
+
exports.generateRenameTable = generateRenameTable;
|
|
14
|
+
exports.generateRenameColumn = generateRenameColumn;
|
|
15
|
+
exports.generateDropColumn = generateDropColumn;
|
|
16
|
+
exports.generateDropTable = generateDropTable;
|
|
17
|
+
exports.generateCreateIndex = generateCreateIndex;
|
|
18
|
+
exports.generateDropIndex = generateDropIndex;
|
|
19
|
+
exports.generateInsert = generateInsert;
|
|
20
|
+
exports.generateUpdate = generateUpdate;
|
|
21
|
+
exports.SQLITE_DESIGNER_TYPES = [
|
|
22
|
+
'TEXT',
|
|
23
|
+
'INTEGER',
|
|
24
|
+
'REAL',
|
|
25
|
+
'BLOB',
|
|
26
|
+
'BOOLEAN',
|
|
27
|
+
'DATE',
|
|
28
|
+
'DATETIME',
|
|
29
|
+
'NUMERIC',
|
|
30
|
+
'VARCHAR(255)',
|
|
31
|
+
'JSON',
|
|
32
|
+
];
|
|
33
|
+
exports.POSTGRES_DESIGNER_TYPES = [
|
|
34
|
+
'TEXT',
|
|
35
|
+
'VARCHAR(255)',
|
|
36
|
+
'INTEGER',
|
|
37
|
+
'BIGINT',
|
|
38
|
+
'SMALLINT',
|
|
39
|
+
'SERIAL',
|
|
40
|
+
'BIGSERIAL',
|
|
41
|
+
'REAL',
|
|
42
|
+
'DECIMAL(10,2)',
|
|
43
|
+
'NUMERIC',
|
|
44
|
+
'BOOLEAN',
|
|
45
|
+
'DATE',
|
|
46
|
+
'DATETIME',
|
|
47
|
+
'TIMESTAMP',
|
|
48
|
+
'TIMESTAMPTZ',
|
|
49
|
+
'TIME',
|
|
50
|
+
'INTERVAL',
|
|
51
|
+
'JSON',
|
|
52
|
+
'JSONB',
|
|
53
|
+
'UUID',
|
|
54
|
+
'BYTEA',
|
|
55
|
+
'INET',
|
|
56
|
+
];
|
|
57
|
+
exports.DESIGNER_TYPES = [
|
|
58
|
+
'TEXT',
|
|
59
|
+
'VARCHAR(255)',
|
|
60
|
+
'INTEGER',
|
|
61
|
+
'BIGINT',
|
|
62
|
+
'SMALLINT',
|
|
63
|
+
'SERIAL',
|
|
64
|
+
'BIGSERIAL',
|
|
65
|
+
'REAL',
|
|
66
|
+
'DECIMAL(10,2)',
|
|
67
|
+
'NUMERIC',
|
|
68
|
+
'BOOLEAN',
|
|
69
|
+
'DATE',
|
|
70
|
+
'DATETIME',
|
|
71
|
+
'TIMESTAMP',
|
|
72
|
+
'TIMESTAMPTZ',
|
|
73
|
+
'TIME',
|
|
74
|
+
'INTERVAL',
|
|
75
|
+
'JSON',
|
|
76
|
+
'JSONB',
|
|
77
|
+
'UUID',
|
|
78
|
+
'BYTEA',
|
|
79
|
+
'BLOB',
|
|
80
|
+
'INET',
|
|
81
|
+
];
|
|
82
|
+
function getDesignerTypes(dialect = 'sqlite') {
|
|
83
|
+
return dialect === 'postgres' ? exports.POSTGRES_DESIGNER_TYPES : exports.SQLITE_DESIGNER_TYPES;
|
|
84
|
+
}
|
|
85
|
+
const IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
86
|
+
function quoteIdentifier(identifier) {
|
|
87
|
+
return `"${String(identifier).replace(/"/g, '""')}"`;
|
|
88
|
+
}
|
|
89
|
+
function escapeString(value) {
|
|
90
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
91
|
+
}
|
|
92
|
+
function sqlValue(value) {
|
|
93
|
+
if (value === null || value === undefined)
|
|
94
|
+
return 'NULL';
|
|
95
|
+
if (typeof value === 'number')
|
|
96
|
+
return Number.isFinite(value) ? String(value) : 'NULL';
|
|
97
|
+
if (typeof value === 'bigint')
|
|
98
|
+
return String(value);
|
|
99
|
+
if (typeof value === 'boolean')
|
|
100
|
+
return value ? '1' : '0';
|
|
101
|
+
if (value instanceof Uint8Array)
|
|
102
|
+
return `X'${Buffer.from(value).toString('hex')}'`;
|
|
103
|
+
if (value instanceof Date)
|
|
104
|
+
return escapeString(value.toISOString());
|
|
105
|
+
return escapeString(String(value));
|
|
106
|
+
}
|
|
107
|
+
function mapColumnType(type) {
|
|
108
|
+
const t = String(type ?? '').trim().toUpperCase();
|
|
109
|
+
if (!t)
|
|
110
|
+
return { sqlType: 'TEXT' };
|
|
111
|
+
switch (t) {
|
|
112
|
+
case 'INTEGER':
|
|
113
|
+
case 'INT':
|
|
114
|
+
case 'TINYINT':
|
|
115
|
+
return { sqlType: 'INTEGER' };
|
|
116
|
+
case 'BIGINT':
|
|
117
|
+
case 'SMALLINT':
|
|
118
|
+
case 'SERIAL':
|
|
119
|
+
case 'BIGSERIAL':
|
|
120
|
+
case 'SMALLSERIAL':
|
|
121
|
+
return { sqlType: t };
|
|
122
|
+
case 'TEXT':
|
|
123
|
+
case 'VARCHAR':
|
|
124
|
+
case 'CHAR':
|
|
125
|
+
case 'CLOB':
|
|
126
|
+
case 'STRING':
|
|
127
|
+
case 'CITEXT':
|
|
128
|
+
return { sqlType: 'TEXT' };
|
|
129
|
+
case 'REAL':
|
|
130
|
+
case 'FLOAT':
|
|
131
|
+
case 'DOUBLE':
|
|
132
|
+
case 'DECIMAL':
|
|
133
|
+
case 'NUMERIC':
|
|
134
|
+
case 'NUMBER':
|
|
135
|
+
case 'MONEY':
|
|
136
|
+
return { sqlType: 'REAL' };
|
|
137
|
+
case 'BLOB':
|
|
138
|
+
case 'BINARY':
|
|
139
|
+
case 'VARBINARY':
|
|
140
|
+
return { sqlType: 'BLOB' };
|
|
141
|
+
case 'BYTEA':
|
|
142
|
+
return { sqlType: 'BYTEA' };
|
|
143
|
+
case 'BOOLEAN':
|
|
144
|
+
case 'BOOL':
|
|
145
|
+
return { sqlType: 'INTEGER' };
|
|
146
|
+
case 'DATE':
|
|
147
|
+
return { sqlType: 'DATETIME', defaultAuto: 'CURRENT_TIMESTAMP' };
|
|
148
|
+
case 'DATETIME':
|
|
149
|
+
return { sqlType: 'DATETIME' };
|
|
150
|
+
case 'TIMESTAMP':
|
|
151
|
+
case 'TIMESTAMPTZ':
|
|
152
|
+
case 'TIMESTAMP WITHOUT TIME ZONE':
|
|
153
|
+
case 'TIMESTAMP WITH TIME ZONE':
|
|
154
|
+
return { sqlType: t };
|
|
155
|
+
case 'TIME':
|
|
156
|
+
case 'TIMETZ':
|
|
157
|
+
case 'TIME WITHOUT TIME ZONE':
|
|
158
|
+
case 'TIME WITH TIME ZONE':
|
|
159
|
+
return { sqlType: t };
|
|
160
|
+
case 'INTERVAL':
|
|
161
|
+
case 'JSON':
|
|
162
|
+
case 'JSONB':
|
|
163
|
+
case 'UUID':
|
|
164
|
+
case 'INET':
|
|
165
|
+
case 'CIDR':
|
|
166
|
+
case 'MACADDR':
|
|
167
|
+
case 'SERIAL':
|
|
168
|
+
case 'BIGSERIAL':
|
|
169
|
+
case 'SMALLSERIAL':
|
|
170
|
+
return { sqlType: t };
|
|
171
|
+
default:
|
|
172
|
+
if (/^[A-Za-z0-9_(),\s\[\]]+$/.test(t)) {
|
|
173
|
+
return { sqlType: t };
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`Unsupported column type: "${type}". Supported types include: ${exports.DESIGNER_TYPES.join(', ')} or standard SQL types.`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function validateIdentifier(kind, name) {
|
|
179
|
+
const label = kind.charAt(0).toUpperCase() + kind.slice(1);
|
|
180
|
+
const trimmed = String(name ?? '').trim();
|
|
181
|
+
if (!trimmed)
|
|
182
|
+
throw new Error(`${label} name is required.`);
|
|
183
|
+
if (!IDENTIFIER_RE.test(trimmed)) {
|
|
184
|
+
throw new Error(`Invalid ${label.toLowerCase()} name: "${trimmed}". Use letters, digits and underscores.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function formatSqlDefault(raw, colType) {
|
|
188
|
+
const s = String(raw ?? '').trim().replace(/;/g, '');
|
|
189
|
+
if (!s)
|
|
190
|
+
return '';
|
|
191
|
+
if (/^null$/i.test(s))
|
|
192
|
+
return 'NULL';
|
|
193
|
+
if (/^[-+]?\d+(\.\d+)?$/.test(s))
|
|
194
|
+
return s;
|
|
195
|
+
if (/^(true|false)$/i.test(s))
|
|
196
|
+
return s.toUpperCase() === 'TRUE' ? '1' : '0';
|
|
197
|
+
if (/^'.*'$/s.test(s) || /^".*"$/s.test(s))
|
|
198
|
+
return s;
|
|
199
|
+
if (/^[a-zA-Z_]\w*\s*\(.*\)$/s.test(s))
|
|
200
|
+
return s;
|
|
201
|
+
if (/^CURRENT_TIMESTAMP|CURRENT_DATE|CURRENT_TIME$/i.test(s))
|
|
202
|
+
return s.toUpperCase();
|
|
203
|
+
const t = (colType || '').toUpperCase();
|
|
204
|
+
if (t.includes('TEXT') || t.includes('CHAR') || t.includes('CLOB') || t.includes('VARCHAR') || t.includes('STRING')) {
|
|
205
|
+
return escapeString(s);
|
|
206
|
+
}
|
|
207
|
+
return s;
|
|
208
|
+
}
|
|
209
|
+
function renderColumnDef(col, opts = {}) {
|
|
210
|
+
const colName = String(col?.name ?? '').trim();
|
|
211
|
+
validateIdentifier('column', colName);
|
|
212
|
+
const mapped = mapColumnType(col.type);
|
|
213
|
+
if (opts.forAddColumn) {
|
|
214
|
+
if (col.primaryKey) {
|
|
215
|
+
throw new Error(`Cannot add "${colName}" as PRIMARY KEY: ALTER TABLE ADD COLUMN does not support primary keys.`);
|
|
216
|
+
}
|
|
217
|
+
if (col.unique) {
|
|
218
|
+
throw new Error(`Cannot add "${colName}" with UNIQUE: ALTER TABLE ADD COLUMN does not support UNIQUE constraints.`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
let def = `${quoteIdentifier(colName)} ${mapped.sqlType}`;
|
|
222
|
+
if (!opts.forAddColumn && col.primaryKey)
|
|
223
|
+
def += ' PRIMARY KEY';
|
|
224
|
+
if (col.notNull)
|
|
225
|
+
def += ' NOT NULL';
|
|
226
|
+
if (!opts.forAddColumn && col.unique)
|
|
227
|
+
def += ' UNIQUE';
|
|
228
|
+
const rawDefault = formatSqlDefault(String(col.defaultValue ?? ''), col.type);
|
|
229
|
+
const dflt = rawDefault || mapped.defaultAuto || '';
|
|
230
|
+
if (dflt)
|
|
231
|
+
def += ` DEFAULT ${dflt}`;
|
|
232
|
+
else if (opts.forAddColumn && col.notNull) {
|
|
233
|
+
throw new Error(`Cannot add "${colName}" as NOT NULL without a default value.`);
|
|
234
|
+
}
|
|
235
|
+
if (col.foreignKey?.table && col.foreignKey.column) {
|
|
236
|
+
if (opts.forAddColumn && (col.notNull || dflt)) {
|
|
237
|
+
throw new Error(`Cannot add "${colName}" as a foreign key with NOT NULL or a non-NULL default.`);
|
|
238
|
+
}
|
|
239
|
+
def += ` REFERENCES ${quoteIdentifier(col.foreignKey.table)}(${quoteIdentifier(col.foreignKey.column)})`;
|
|
240
|
+
}
|
|
241
|
+
return def;
|
|
242
|
+
}
|
|
243
|
+
function generateCreateTable(tableName, columns) {
|
|
244
|
+
const table = String(tableName ?? '').trim();
|
|
245
|
+
validateIdentifier('table', table);
|
|
246
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
247
|
+
throw new Error('At least one column is required.');
|
|
248
|
+
}
|
|
249
|
+
const seen = new Set();
|
|
250
|
+
let pkCount = 0;
|
|
251
|
+
const parts = [];
|
|
252
|
+
for (const col of columns) {
|
|
253
|
+
const colName = String(col?.name ?? '').trim();
|
|
254
|
+
validateIdentifier('column', colName);
|
|
255
|
+
if (seen.has(colName))
|
|
256
|
+
throw new Error(`Duplicate column name: "${colName}".`);
|
|
257
|
+
seen.add(colName);
|
|
258
|
+
if (col.primaryKey)
|
|
259
|
+
pkCount += 1;
|
|
260
|
+
parts.push(renderColumnDef(col));
|
|
261
|
+
}
|
|
262
|
+
if (pkCount > 1)
|
|
263
|
+
throw new Error('At most one primary key column is allowed.');
|
|
264
|
+
return `CREATE TABLE ${quoteIdentifier(table)} (\n ${parts.join(',\n ')}\n);`;
|
|
265
|
+
}
|
|
266
|
+
function generateAddColumn(tableName, col) {
|
|
267
|
+
const table = String(tableName ?? '').trim();
|
|
268
|
+
validateIdentifier('table', table);
|
|
269
|
+
const def = renderColumnDef(col, { forAddColumn: true });
|
|
270
|
+
return `ALTER TABLE ${quoteIdentifier(table)} ADD COLUMN ${def};`;
|
|
271
|
+
}
|
|
272
|
+
function generateRenameTable(tableName, newName) {
|
|
273
|
+
validateIdentifier('table', tableName);
|
|
274
|
+
validateIdentifier('table', newName);
|
|
275
|
+
return `ALTER TABLE ${quoteIdentifier(tableName)} RENAME TO ${quoteIdentifier(newName)};`;
|
|
276
|
+
}
|
|
277
|
+
function generateRenameColumn(tableName, oldName, newName) {
|
|
278
|
+
validateIdentifier('table', tableName);
|
|
279
|
+
validateIdentifier('column', oldName);
|
|
280
|
+
validateIdentifier('column', newName);
|
|
281
|
+
return `ALTER TABLE ${quoteIdentifier(tableName)} RENAME COLUMN ${quoteIdentifier(oldName)} TO ${quoteIdentifier(newName)};`;
|
|
282
|
+
}
|
|
283
|
+
function generateDropColumn(tableName, column) {
|
|
284
|
+
validateIdentifier('table', tableName);
|
|
285
|
+
validateIdentifier('column', column);
|
|
286
|
+
return `ALTER TABLE ${quoteIdentifier(tableName)} DROP COLUMN ${quoteIdentifier(column)};`;
|
|
287
|
+
}
|
|
288
|
+
function generateDropTable(tableName) {
|
|
289
|
+
validateIdentifier('table', tableName);
|
|
290
|
+
return `DROP TABLE ${quoteIdentifier(tableName)};`;
|
|
291
|
+
}
|
|
292
|
+
function generateCreateIndex(tableName, index) {
|
|
293
|
+
validateIdentifier('table', tableName);
|
|
294
|
+
const cols = Array.isArray(index?.columns) ? index.columns : [];
|
|
295
|
+
if (!cols.length)
|
|
296
|
+
throw new Error('At least one column is required for an index.');
|
|
297
|
+
for (const c of cols)
|
|
298
|
+
validateIdentifier('column', c);
|
|
299
|
+
const unique = index.unique ? 'UNIQUE ' : '';
|
|
300
|
+
let name = String(index?.name ?? '').trim();
|
|
301
|
+
if (!name)
|
|
302
|
+
name = `idx_${tableName}_${cols.join('_')}`;
|
|
303
|
+
validateIdentifier('index', name);
|
|
304
|
+
return `CREATE ${unique}INDEX ${quoteIdentifier(name)} ON ${quoteIdentifier(tableName)} (${cols.map(quoteIdentifier).join(', ')});`;
|
|
305
|
+
}
|
|
306
|
+
function generateDropIndex(indexName) {
|
|
307
|
+
validateIdentifier('index', indexName);
|
|
308
|
+
return `DROP INDEX ${quoteIdentifier(indexName)};`;
|
|
309
|
+
}
|
|
310
|
+
function generateInsert(table, fields) {
|
|
311
|
+
const cols = fields.map((f) => quoteIdentifier(f.column));
|
|
312
|
+
const vals = fields.map((f) => sqlValue(f.value));
|
|
313
|
+
return `INSERT INTO ${quoteIdentifier(table)} (${cols.join(', ')}) VALUES (${vals.join(', ')});`;
|
|
314
|
+
}
|
|
315
|
+
function generateUpdate(table, fields, where) {
|
|
316
|
+
const sets = fields.map((f) => `${quoteIdentifier(f.column)} = ${sqlValue(f.value)}`);
|
|
317
|
+
const conds = where.map((w) => `${quoteIdentifier(w.column)} = ${sqlValue(w.value)}`);
|
|
318
|
+
return `UPDATE ${quoteIdentifier(table)} SET ${sets.join(', ')} WHERE ${conds.join(' AND ')};`;
|
|
319
|
+
}
|
package/dist/sql/index.js
CHANGED
|
@@ -1 +1,18 @@
|
|
|
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("./classifier"), exports);
|
|
18
|
+
__exportStar(require("./generator"), exports);
|
package/dist/types/api.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/utils/colors.js
CHANGED
|
@@ -1 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.c = void 0;
|
|
4
|
+
exports.supportsColor = supportsColor;
|
|
5
|
+
function supportsColor() {
|
|
6
|
+
if (process.env.NO_COLOR || process.env.NODE_DISABLE_COLORS)
|
|
7
|
+
return false;
|
|
8
|
+
if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== '0')
|
|
9
|
+
return true;
|
|
10
|
+
if (process.env.TERM === 'dumb')
|
|
11
|
+
return false;
|
|
12
|
+
if (process.env.CI)
|
|
13
|
+
return true;
|
|
14
|
+
return Boolean(process.stdout && process.stdout.isTTY);
|
|
15
|
+
}
|
|
16
|
+
const wrap = (open, close) => (str) => {
|
|
17
|
+
const text = String(str ?? '');
|
|
18
|
+
if (!supportsColor() || !text)
|
|
19
|
+
return text;
|
|
20
|
+
return `${open}${text}${close}`;
|
|
21
|
+
};
|
|
22
|
+
exports.c = {
|
|
23
|
+
reset: wrap('\x1b[0m', '\x1b[0m'),
|
|
24
|
+
bold: wrap('\x1b[1m', '\x1b[22m'),
|
|
25
|
+
dim: wrap('\x1b[2m', '\x1b[22m'),
|
|
26
|
+
italic: wrap('\x1b[3m', '\x1b[23m'),
|
|
27
|
+
underline: wrap('\x1b[4m', '\x1b[24m'),
|
|
28
|
+
inverse: wrap('\x1b[7m', '\x1b[27m'),
|
|
29
|
+
black: wrap('\x1b[30m', '\x1b[39m'),
|
|
30
|
+
red: wrap('\x1b[31m', '\x1b[39m'),
|
|
31
|
+
green: wrap('\x1b[32m', '\x1b[39m'),
|
|
32
|
+
yellow: wrap('\x1b[33m', '\x1b[39m'),
|
|
33
|
+
blue: wrap('\x1b[34m', '\x1b[39m'),
|
|
34
|
+
magenta: wrap('\x1b[35m', '\x1b[39m'),
|
|
35
|
+
cyan: wrap('\x1b[36m', '\x1b[39m'),
|
|
36
|
+
white: wrap('\x1b[37m', '\x1b[39m'),
|
|
37
|
+
gray: wrap('\x1b[90m', '\x1b[39m'),
|
|
38
|
+
brightRed: wrap('\x1b[91m', '\x1b[39m'),
|
|
39
|
+
brightGreen: wrap('\x1b[92m', '\x1b[39m'),
|
|
40
|
+
brightYellow: wrap('\x1b[93m', '\x1b[39m'),
|
|
41
|
+
brightBlue: wrap('\x1b[94m', '\x1b[39m'),
|
|
42
|
+
brightMagenta: wrap('\x1b[95m', '\x1b[39m'),
|
|
43
|
+
brightCyan: wrap('\x1b[96m', '\x1b[39m'),
|
|
44
|
+
brightWhite: wrap('\x1b[97m', '\x1b[39m'),
|
|
45
|
+
bgBlack: wrap('\x1b[40m', '\x1b[49m'),
|
|
46
|
+
bgRed: wrap('\x1b[41m', '\x1b[49m'),
|
|
47
|
+
bgGreen: wrap('\x1b[42m', '\x1b[49m'),
|
|
48
|
+
bgYellow: wrap('\x1b[43m', '\x1b[49m'),
|
|
49
|
+
bgBlue: wrap('\x1b[44m', '\x1b[49m'),
|
|
50
|
+
bgMagenta: wrap('\x1b[45m', '\x1b[49m'),
|
|
51
|
+
bgCyan: wrap('\x1b[46m', '\x1b[49m'),
|
|
52
|
+
bgWhite: wrap('\x1b[47m', '\x1b[49m'),
|
|
53
|
+
bgGray: wrap('\x1b[100m', '\x1b[49m'),
|
|
54
|
+
};
|
package/dist/utils/common.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function errorMessage(err:unknown):string;export declare function isPathWithinRoot(root:string,p:string):boolean;export type FilterOp='eq'|'neq'|'gt'|'gte'|'lt'|'lte'|'like'|'prefix'|'between'|'null'|'notnull';export interface FilterCondition{op:FilterOp;value?:string;max?:string;}export type FilterValue=string|FilterCondition|FilterCondition[];export interface RowFilters{[column:string]:FilterValue;}export declare function parseFilters(raw:unknown):RowFilters;export declare function filtersToQS(filters:RowFilters|undefined):string;export declare function isInternalTable(name:string):boolean;export declare function encodePk(values:unknown[]):string;export declare function decodePk(encoded:string):string[];export declare function normalizeCell(value:unknown):unknown;export declare function normalizeRow(row:Record<string,unknown>):Record<string,unknown>;export declare function coerceFormValue(raw:unknown,columnType:string,dialect?:'sqlite'|'postgres'):unknown;export declare function formatBytes(bytes:number):string;export declare function truncate(str:string,maxLength:number):string;
|
|
1
|
+
export declare function errorMessage(err:unknown):string;export declare function isPostgresConnectionString(target:unknown):boolean;export declare function sanitizeConnectionString(conn:string):string;export declare function isPathWithinRoot(root:string,p:string):boolean;export type FilterOp='eq'|'neq'|'gt'|'gte'|'lt'|'lte'|'like'|'prefix'|'between'|'null'|'notnull';export interface FilterCondition{op:FilterOp;value?:string;max?:string;}export type FilterValue=string|FilterCondition|FilterCondition[];export interface RowFilters{[column:string]:FilterValue;}export declare function parseFilters(raw:unknown):RowFilters;export declare function filtersToQS(filters:RowFilters|undefined):string;export declare function isInternalTable(name:string):boolean;export declare function encodePk(values:unknown[]):string;export declare function decodePk(encoded:string):string[];export declare function normalizeCell(value:unknown):unknown;export declare function normalizeRow(row:Record<string,unknown>):Record<string,unknown>;export declare function coerceFormValue(raw:unknown,columnType:string,dialect?:'sqlite'|'postgres'):unknown;export declare function formatBytes(bytes:number):string;export declare function truncate(str:string,maxLength:number):string;
|
package/dist/utils/common.js
CHANGED
|
@@ -1 +1,225 @@
|
|
|
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.errorMessage = errorMessage;
|
|
7
|
+
exports.isPostgresConnectionString = isPostgresConnectionString;
|
|
8
|
+
exports.sanitizeConnectionString = sanitizeConnectionString;
|
|
9
|
+
exports.isPathWithinRoot = isPathWithinRoot;
|
|
10
|
+
exports.parseFilters = parseFilters;
|
|
11
|
+
exports.filtersToQS = filtersToQS;
|
|
12
|
+
exports.isInternalTable = isInternalTable;
|
|
13
|
+
exports.encodePk = encodePk;
|
|
14
|
+
exports.decodePk = decodePk;
|
|
15
|
+
exports.normalizeCell = normalizeCell;
|
|
16
|
+
exports.normalizeRow = normalizeRow;
|
|
17
|
+
exports.coerceFormValue = coerceFormValue;
|
|
18
|
+
exports.formatBytes = formatBytes;
|
|
19
|
+
exports.truncate = truncate;
|
|
20
|
+
const node_fs_1 = require("node:fs");
|
|
21
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
22
|
+
function errorMessage(err) {
|
|
23
|
+
if (err instanceof Error)
|
|
24
|
+
return err.message;
|
|
25
|
+
return String(err);
|
|
26
|
+
}
|
|
27
|
+
function isPostgresConnectionString(target) {
|
|
28
|
+
return (typeof target === 'string' &&
|
|
29
|
+
(target.startsWith('postgres://') || target.startsWith('postgresql://')));
|
|
30
|
+
}
|
|
31
|
+
function sanitizeConnectionString(conn) {
|
|
32
|
+
if (!conn || typeof conn !== 'string')
|
|
33
|
+
return '';
|
|
34
|
+
try {
|
|
35
|
+
const u = new URL(conn);
|
|
36
|
+
if (u.password) {
|
|
37
|
+
u.password = '****';
|
|
38
|
+
return u.toString();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch { }
|
|
42
|
+
return conn.replace(/:([^:@]+)@/, ':****@');
|
|
43
|
+
}
|
|
44
|
+
function isPathWithinRoot(root, p) {
|
|
45
|
+
if (!root || !p || typeof root !== 'string' || typeof p !== 'string')
|
|
46
|
+
return false;
|
|
47
|
+
if (p.includes('\0') || root.includes('\0'))
|
|
48
|
+
return false;
|
|
49
|
+
const absRoot = node_path_1.default.resolve(root);
|
|
50
|
+
const absPath = node_path_1.default.resolve(p);
|
|
51
|
+
let realRoot = absRoot;
|
|
52
|
+
let realPath = absPath;
|
|
53
|
+
try {
|
|
54
|
+
if ((0, node_fs_1.existsSync)(absRoot))
|
|
55
|
+
realRoot = (0, node_fs_1.realpathSync)(absRoot);
|
|
56
|
+
}
|
|
57
|
+
catch { }
|
|
58
|
+
try {
|
|
59
|
+
if ((0, node_fs_1.existsSync)(absPath))
|
|
60
|
+
realPath = (0, node_fs_1.realpathSync)(absPath);
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
const rel = node_path_1.default.relative(realRoot, realPath);
|
|
64
|
+
return rel === '' || (!rel.startsWith('..') && !node_path_1.default.isAbsolute(rel));
|
|
65
|
+
}
|
|
66
|
+
function parseFilters(raw) {
|
|
67
|
+
const out = {};
|
|
68
|
+
const add = (obj) => {
|
|
69
|
+
if (obj && typeof obj === 'object') {
|
|
70
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
71
|
+
if (v === undefined || v === null || v === '')
|
|
72
|
+
continue;
|
|
73
|
+
if (Array.isArray(v)) {
|
|
74
|
+
if (v.length)
|
|
75
|
+
out[k] = v;
|
|
76
|
+
}
|
|
77
|
+
else if (typeof v === 'object') {
|
|
78
|
+
out[k] = v;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
out[k] = String(v);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
if (typeof raw === 'string' && raw) {
|
|
87
|
+
try {
|
|
88
|
+
add(JSON.parse(raw));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
add(raw);
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
function filtersToQS(filters) {
|
|
100
|
+
const out = {};
|
|
101
|
+
for (const [k, v] of Object.entries(filters ?? {})) {
|
|
102
|
+
if (v === undefined || v === null)
|
|
103
|
+
continue;
|
|
104
|
+
if (Array.isArray(v)) {
|
|
105
|
+
if (v.length)
|
|
106
|
+
out[k] = v;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (typeof v === 'object') {
|
|
110
|
+
if (Object.keys(v).length)
|
|
111
|
+
out[k] = v;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (String(v).trim() !== '')
|
|
115
|
+
out[k] = String(v).trim();
|
|
116
|
+
}
|
|
117
|
+
const keys = Object.keys(out);
|
|
118
|
+
if (!keys.length)
|
|
119
|
+
return '';
|
|
120
|
+
return 'f=' + encodeURIComponent(JSON.stringify(out));
|
|
121
|
+
}
|
|
122
|
+
function isInternalTable(name) {
|
|
123
|
+
return name.startsWith('_');
|
|
124
|
+
}
|
|
125
|
+
function encodePk(values) {
|
|
126
|
+
return values.map((v) => encodeURIComponent(v == null ? '' : String(v))).join(',');
|
|
127
|
+
}
|
|
128
|
+
function decodePk(encoded) {
|
|
129
|
+
return String(encoded)
|
|
130
|
+
.split(',')
|
|
131
|
+
.map((s) => {
|
|
132
|
+
try {
|
|
133
|
+
return decodeURIComponent(s);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return s;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function normalizeCell(value) {
|
|
141
|
+
if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
|
|
142
|
+
return `0x${Buffer.from(value).toString('hex')}`;
|
|
143
|
+
}
|
|
144
|
+
if (value instanceof Date) {
|
|
145
|
+
return value.toISOString();
|
|
146
|
+
}
|
|
147
|
+
if (typeof value === 'object' && value !== null) {
|
|
148
|
+
return JSON.stringify(value);
|
|
149
|
+
}
|
|
150
|
+
if (value === undefined)
|
|
151
|
+
return null;
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function normalizeRow(row) {
|
|
155
|
+
const out = {};
|
|
156
|
+
for (const [k, v] of Object.entries(row ?? {}))
|
|
157
|
+
out[k] = normalizeCell(v);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
function coerceFormValue(raw, columnType, dialect = 'sqlite') {
|
|
161
|
+
const type = (columnType || '').toUpperCase();
|
|
162
|
+
if (raw === undefined || raw === null)
|
|
163
|
+
return null;
|
|
164
|
+
if (type === 'BOOLEAN' || type === 'BOOL') {
|
|
165
|
+
const s = String(raw).trim().toLowerCase();
|
|
166
|
+
if (s === '')
|
|
167
|
+
return null;
|
|
168
|
+
const boolVal = s === 'true' || s === '1' || s === 'on' || s === 'yes' || s === 'checked';
|
|
169
|
+
return dialect === 'postgres' ? boolVal : (boolVal ? 1 : 0);
|
|
170
|
+
}
|
|
171
|
+
if (type.startsWith('INT') ||
|
|
172
|
+
type === 'REAL' ||
|
|
173
|
+
type === 'NUMERIC' ||
|
|
174
|
+
type.startsWith('DECIMAL') ||
|
|
175
|
+
type === 'FLOAT' ||
|
|
176
|
+
type === 'DOUBLE' ||
|
|
177
|
+
type.startsWith('BIGINT') ||
|
|
178
|
+
type.startsWith('SMALLINT') ||
|
|
179
|
+
type.startsWith('SERIAL')) {
|
|
180
|
+
const s = String(raw).trim();
|
|
181
|
+
if (s === '')
|
|
182
|
+
return null;
|
|
183
|
+
const n = Number(s);
|
|
184
|
+
return Number.isFinite(n) ? n : s;
|
|
185
|
+
}
|
|
186
|
+
if (type === 'BLOB' || type === 'BYTEA') {
|
|
187
|
+
const s = String(raw);
|
|
188
|
+
if (/^0x[0-9a-f]*$/i.test(s))
|
|
189
|
+
return Buffer.from(s.slice(2), 'hex');
|
|
190
|
+
if (/^\\x[0-9a-f]*$/i.test(s))
|
|
191
|
+
return Buffer.from(s.slice(2), 'hex');
|
|
192
|
+
return Buffer.from(s, 'utf8');
|
|
193
|
+
}
|
|
194
|
+
if (type === 'JSON' || type === 'JSONB') {
|
|
195
|
+
const s = String(raw).trim();
|
|
196
|
+
if (s === '')
|
|
197
|
+
return null;
|
|
198
|
+
return s;
|
|
199
|
+
}
|
|
200
|
+
if (type.endsWith('[]') || type.startsWith('_') || type.includes('ARRAY')) {
|
|
201
|
+
if (Array.isArray(raw))
|
|
202
|
+
return raw;
|
|
203
|
+
const s = String(raw).trim();
|
|
204
|
+
if (s === '')
|
|
205
|
+
return null;
|
|
206
|
+
return s;
|
|
207
|
+
}
|
|
208
|
+
const s = String(raw);
|
|
209
|
+
if (s === '')
|
|
210
|
+
return null;
|
|
211
|
+
return s;
|
|
212
|
+
}
|
|
213
|
+
function formatBytes(bytes) {
|
|
214
|
+
if (bytes === 0)
|
|
215
|
+
return '0 B';
|
|
216
|
+
const k = 1024;
|
|
217
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
218
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
219
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
220
|
+
}
|
|
221
|
+
function truncate(str, maxLength) {
|
|
222
|
+
if (!str || str.length <= maxLength)
|
|
223
|
+
return str;
|
|
224
|
+
return `${str.slice(0, maxLength)}…`;
|
|
225
|
+
}
|