admindb 2.0.0 → 2.1.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 +2 -2
- package/dist/app.d.ts +1 -69
- package/dist/app.js +1 -257
- package/dist/auth/config.d.ts +1 -19
- package/dist/auth/config.js +1 -147
- package/dist/auth/crypto.d.ts +1 -27
- package/dist/auth/crypto.js +1 -133
- package/dist/auth/index.d.ts +1 -5
- package/dist/auth/index.js +1 -22
- package/dist/auth/middleware.d.ts +1 -14
- package/dist/auth/middleware.js +1 -100
- package/dist/auth/routes.d.ts +1 -7
- package/dist/auth/routes.js +1 -78
- package/dist/auth/types.d.ts +1 -35
- package/dist/auth/types.js +1 -11
- package/dist/cli/args.d.ts +1 -45
- package/dist/cli/args.js +1 -328
- package/dist/cli/config.d.ts +1 -56
- package/dist/cli/config.js +1 -133
- package/dist/cli/index.d.ts +1 -4
- package/dist/cli/index.js +1 -21
- package/dist/cli/runner.d.ts +1 -1
- package/dist/cli/runner.js +1 -222
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +1 -5
- package/dist/data/datasets.d.ts +1 -17
- package/dist/data/datasets.js +1 -133
- package/dist/data/detector.d.ts +1 -30
- package/dist/data/detector.js +1 -472
- package/dist/data/engine.d.ts +1 -10
- package/dist/data/engine.js +1 -211
- package/dist/data/index.d.ts +1 -5
- package/dist/data/index.js +1 -22
- package/dist/data/strategies.d.ts +1 -30
- package/dist/data/strategies.js +1 -343
- package/dist/data/types.d.ts +1 -73
- package/dist/data/types.js +1 -8
- package/dist/db/database.d.ts +1 -119
- package/dist/db/database.js +1 -471
- package/dist/db/export.d.ts +1 -12
- package/dist/db/export.js +1 -42
- package/dist/db/filters.d.ts +1 -22
- package/dist/db/filters.js +1 -158
- package/dist/db/index.d.ts +1 -8
- package/dist/db/index.js +1 -25
- package/dist/db/introspection.d.ts +1 -6
- package/dist/db/introspection.js +1 -172
- package/dist/db/manager.d.ts +1 -81
- package/dist/db/manager.js +1 -397
- package/dist/db/migrations.d.ts +1 -5
- package/dist/db/migrations.js +1 -110
- package/dist/db/postgres.d.ts +1 -85
- package/dist/db/postgres.js +1 -745
- package/dist/db/types.d.ts +1 -206
- package/dist/db/types.js +1 -7
- package/dist/index.d.ts +1 -23
- package/dist/index.js +1 -66
- package/dist/public/js/api.js +1 -47
- package/dist/public/js/app.js +1 -262
- package/dist/public/js/browse.js +1 -1371
- package/dist/public/js/databases.js +1 -235
- package/dist/public/js/designer.js +1 -243
- package/dist/public/js/forms.js +1 -826
- package/dist/public/js/icons.js +1 -51
- package/dist/public/js/inspector.js +1 -638
- package/dist/public/js/query.js +1 -322
- package/dist/public/js/schema.js +1 -432
- package/dist/public/js/seed.js +1 -1090
- package/dist/routes/api/helpers.d.ts +1 -42
- package/dist/routes/api/helpers.js +1 -133
- package/dist/routes/api/import-export.d.ts +1 -3
- package/dist/routes/api/import-export.js +1 -85
- package/dist/routes/api/index.d.ts +1 -4
- package/dist/routes/api/index.js +1 -37
- package/dist/routes/api/query.d.ts +1 -3
- package/dist/routes/api/query.js +1 -76
- package/dist/routes/api/rows.d.ts +1 -3
- package/dist/routes/api/rows.js +1 -373
- package/dist/routes/api/seed.d.ts +1 -3
- package/dist/routes/api/seed.js +1 -82
- package/dist/routes/api/tables.d.ts +1 -3
- package/dist/routes/api/tables.js +1 -160
- package/dist/routes/databases.d.ts +1 -26
- package/dist/routes/databases.js +1 -230
- package/dist/routes/index.d.ts +1 -3
- package/dist/routes/index.js +1 -20
- package/dist/routes/pages.d.ts +1 -9
- package/dist/routes/pages.js +1 -382
- package/dist/serverless.d.ts +1 -40
- package/dist/serverless.js +1 -210
- package/dist/sql/classifier.d.ts +1 -19
- package/dist/sql/classifier.js +1 -37
- package/dist/sql/generator.d.ts +1 -78
- package/dist/sql/generator.js +1 -308
- package/dist/sql/index.d.ts +1 -2
- package/dist/sql/index.js +1 -19
- package/dist/types/api.d.ts +1 -412
- package/dist/types/api.js +1 -9
- package/dist/utils/colors.d.ts +1 -40
- package/dist/utils/colors.js +1 -64
- package/dist/utils/common.d.ts +1 -50
- package/dist/utils/common.js +1 -229
- package/dist/utils/csv.d.ts +1 -15
- package/dist/utils/csv.js +1 -80
- package/dist/utils/datatype.d.ts +1 -49
- package/dist/utils/datatype.js +1 -222
- package/dist/utils/icons.d.ts +1 -11
- package/dist/utils/icons.js +1 -72
- package/dist/utils/index.d.ts +1 -4
- package/dist/utils/index.js +1 -21
- package/dist/utils/logger.d.ts +1 -10
- package/dist/utils/logger.js +1 -40
- package/dist/views/layouts/main.hbs +8 -5
- package/dist/views/pages/databases.hbs +0 -18
- package/dist/views/pages/designer.hbs +22 -17
- package/dist/views/pages/error.hbs +0 -2
- package/dist/views/pages/form.hbs +0 -5
- package/dist/views/pages/home.hbs +0 -8
- package/dist/views/pages/login.hbs +0 -13
- package/dist/views/pages/query.hbs +0 -9
- package/dist/views/pages/schema.hbs +0 -20
- package/dist/views/pages/seed.hbs +0 -31
- package/dist/views/pages/table.hbs +0 -14
- package/dist/views/partials/icon.hbs +0 -1
- package/dist/views/partials/navbar.hbs +0 -6
- package/dist/views/partials/sidebar.hbs +0 -8
- package/docs/API.md +144 -0
- package/docs/EXAMPLES.md +576 -0
- package/docs/SECURITY.md +265 -0
- package/package.json +7 -2
- package/dist/app.js.map +0 -1
- package/dist/auth/config.js.map +0 -1
- package/dist/auth/crypto.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/middleware.js.map +0 -1
- package/dist/auth/routes.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/cli/args.js.map +0 -1
- package/dist/cli/config.js.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/runner.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/data/datasets.js.map +0 -1
- package/dist/data/detector.js.map +0 -1
- package/dist/data/engine.js.map +0 -1
- package/dist/data/index.js.map +0 -1
- package/dist/data/strategies.js.map +0 -1
- package/dist/data/types.js.map +0 -1
- package/dist/db/database.js.map +0 -1
- package/dist/db/export.js.map +0 -1
- package/dist/db/filters.js.map +0 -1
- package/dist/db/index.js.map +0 -1
- package/dist/db/introspection.js.map +0 -1
- package/dist/db/manager.js.map +0 -1
- package/dist/db/migrations.js.map +0 -1
- package/dist/db/postgres.js.map +0 -1
- package/dist/db/types.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/public/css/input.css +0 -302
- package/dist/routes/api/helpers.js.map +0 -1
- package/dist/routes/api/import-export.js.map +0 -1
- package/dist/routes/api/index.js.map +0 -1
- package/dist/routes/api/query.js.map +0 -1
- package/dist/routes/api/rows.js.map +0 -1
- package/dist/routes/api/seed.js.map +0 -1
- package/dist/routes/api/tables.js.map +0 -1
- package/dist/routes/databases.js.map +0 -1
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/pages.js.map +0 -1
- package/dist/serverless.js.map +0 -1
- package/dist/sql/classifier.js.map +0 -1
- package/dist/sql/generator.js.map +0 -1
- package/dist/sql/index.js.map +0 -1
- package/dist/types/api.js.map +0 -1
- package/dist/utils/colors.js.map +0 -1
- package/dist/utils/common.js.map +0 -1
- package/dist/utils/csv.js.map +0 -1
- package/dist/utils/datatype.js.map +0 -1
- package/dist/utils/icons.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.js.map +0 -1
package/dist/utils/common.js
CHANGED
|
@@ -1,229 +1 @@
|
|
|
1
|
-
"
|
|
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.isPathWithinRoot = isPathWithinRoot;
|
|
8
|
-
exports.parseFilters = parseFilters;
|
|
9
|
-
exports.filtersToQS = filtersToQS;
|
|
10
|
-
exports.isInternalTable = isInternalTable;
|
|
11
|
-
exports.encodePk = encodePk;
|
|
12
|
-
exports.decodePk = decodePk;
|
|
13
|
-
exports.normalizeCell = normalizeCell;
|
|
14
|
-
exports.normalizeRow = normalizeRow;
|
|
15
|
-
exports.coerceFormValue = coerceFormValue;
|
|
16
|
-
exports.formatBytes = formatBytes;
|
|
17
|
-
exports.truncate = truncate;
|
|
18
|
-
const node_fs_1 = require("node:fs");
|
|
19
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
-
function errorMessage(err) {
|
|
21
|
-
if (err instanceof Error)
|
|
22
|
-
return err.message;
|
|
23
|
-
return String(err);
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* True when `p` is equal to `root` or lives inside it (both treated as
|
|
27
|
-
* absolute). Used to sandbox the filesystem file-browser to an allowed folder.
|
|
28
|
-
* Resolves symlinks and rejects null-byte injections.
|
|
29
|
-
*/
|
|
30
|
-
function isPathWithinRoot(root, p) {
|
|
31
|
-
if (!root || !p || typeof root !== 'string' || typeof p !== 'string')
|
|
32
|
-
return false;
|
|
33
|
-
if (p.includes('\0') || root.includes('\0'))
|
|
34
|
-
return false;
|
|
35
|
-
const absRoot = node_path_1.default.resolve(root);
|
|
36
|
-
const absPath = node_path_1.default.resolve(p);
|
|
37
|
-
let realRoot = absRoot;
|
|
38
|
-
let realPath = absPath;
|
|
39
|
-
try {
|
|
40
|
-
if ((0, node_fs_1.existsSync)(absRoot))
|
|
41
|
-
realRoot = (0, node_fs_1.realpathSync)(absRoot);
|
|
42
|
-
}
|
|
43
|
-
catch { }
|
|
44
|
-
try {
|
|
45
|
-
if ((0, node_fs_1.existsSync)(absPath))
|
|
46
|
-
realPath = (0, node_fs_1.realpathSync)(absPath);
|
|
47
|
-
}
|
|
48
|
-
catch { }
|
|
49
|
-
const rel = node_path_1.default.relative(realRoot, realPath);
|
|
50
|
-
return rel === '' || (!rel.startsWith('..') && !node_path_1.default.isAbsolute(rel));
|
|
51
|
-
}
|
|
52
|
-
/** Parse the `f` query parameter (URL-encoded JSON object) into row filters. */
|
|
53
|
-
function parseFilters(raw) {
|
|
54
|
-
const out = {};
|
|
55
|
-
const add = (obj) => {
|
|
56
|
-
if (obj && typeof obj === 'object') {
|
|
57
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
58
|
-
if (v === undefined || v === null || v === '')
|
|
59
|
-
continue;
|
|
60
|
-
if (Array.isArray(v)) {
|
|
61
|
-
if (v.length)
|
|
62
|
-
out[k] = v;
|
|
63
|
-
}
|
|
64
|
-
else if (typeof v === 'object') {
|
|
65
|
-
out[k] = v;
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
out[k] = String(v);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
if (typeof raw === 'string' && raw) {
|
|
74
|
-
try {
|
|
75
|
-
add(JSON.parse(raw));
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
return {};
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
add(raw);
|
|
83
|
-
}
|
|
84
|
-
return out;
|
|
85
|
-
}
|
|
86
|
-
/** Encode filters back into a `f=…` query string (empty when no filters). */
|
|
87
|
-
function filtersToQS(filters) {
|
|
88
|
-
const out = {};
|
|
89
|
-
for (const [k, v] of Object.entries(filters ?? {})) {
|
|
90
|
-
if (v === undefined || v === null)
|
|
91
|
-
continue;
|
|
92
|
-
if (Array.isArray(v)) {
|
|
93
|
-
if (v.length)
|
|
94
|
-
out[k] = v;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
if (typeof v === 'object') {
|
|
98
|
-
if (Object.keys(v).length)
|
|
99
|
-
out[k] = v;
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
if (String(v).trim() !== '')
|
|
103
|
-
out[k] = String(v).trim();
|
|
104
|
-
}
|
|
105
|
-
const keys = Object.keys(out);
|
|
106
|
-
if (!keys.length)
|
|
107
|
-
return '';
|
|
108
|
-
return 'f=' + encodeURIComponent(JSON.stringify(out));
|
|
109
|
-
}
|
|
110
|
-
/** Internal tables (kept out of user-facing pickers) start with an underscore. */
|
|
111
|
-
function isInternalTable(name) {
|
|
112
|
-
return name.startsWith('_');
|
|
113
|
-
}
|
|
114
|
-
/** Encode primary-key values into a single URL path segment (comma-joined, URL-encoded). */
|
|
115
|
-
function encodePk(values) {
|
|
116
|
-
return values.map((v) => encodeURIComponent(v == null ? '' : String(v))).join(',');
|
|
117
|
-
}
|
|
118
|
-
/** Decode a primary-key path segment back into individual values. */
|
|
119
|
-
function decodePk(encoded) {
|
|
120
|
-
return String(encoded)
|
|
121
|
-
.split(',')
|
|
122
|
-
.map((s) => {
|
|
123
|
-
try {
|
|
124
|
-
return decodeURIComponent(s);
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return s;
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
/** Normalize a single cell for JSON / display (BLOB → 0x-hex string, undefined → null). */
|
|
132
|
-
function normalizeCell(value) {
|
|
133
|
-
if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
|
|
134
|
-
return `0x${Buffer.from(value).toString('hex')}`;
|
|
135
|
-
}
|
|
136
|
-
if (value instanceof Date) {
|
|
137
|
-
return value.toISOString();
|
|
138
|
-
}
|
|
139
|
-
if (typeof value === 'object' && value !== null) {
|
|
140
|
-
return JSON.stringify(value);
|
|
141
|
-
}
|
|
142
|
-
if (value === undefined)
|
|
143
|
-
return null;
|
|
144
|
-
return value;
|
|
145
|
-
}
|
|
146
|
-
/** Normalize every cell in a row. */
|
|
147
|
-
function normalizeRow(row) {
|
|
148
|
-
const out = {};
|
|
149
|
-
for (const [k, v] of Object.entries(row ?? {}))
|
|
150
|
-
out[k] = normalizeCell(v);
|
|
151
|
-
return out;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Coerce a raw form value into a value suitable for SQLite or Postgres binding.
|
|
155
|
-
* - empty string / null / undefined → null ("not set")
|
|
156
|
-
* - `0` stays valid
|
|
157
|
-
* - BOOLEAN → 1/0 (SQLite) or boolean (PostgreSQL)
|
|
158
|
-
* - INTEGER/REAL/BIGINT/NUMERIC → number when numeric
|
|
159
|
-
* - BLOB / BYTEA → Buffer (0x-hex, \x-hex, or raw text)
|
|
160
|
-
*/
|
|
161
|
-
function coerceFormValue(raw, columnType, dialect = 'sqlite') {
|
|
162
|
-
const type = (columnType || '').toUpperCase();
|
|
163
|
-
if (raw === undefined || raw === null)
|
|
164
|
-
return null;
|
|
165
|
-
if (type === 'BOOLEAN' || type === 'BOOL') {
|
|
166
|
-
const s = String(raw).trim().toLowerCase();
|
|
167
|
-
if (s === '')
|
|
168
|
-
return null;
|
|
169
|
-
const boolVal = s === 'true' || s === '1' || s === 'on' || s === 'yes' || s === 'checked';
|
|
170
|
-
return dialect === 'postgres' ? boolVal : (boolVal ? 1 : 0);
|
|
171
|
-
}
|
|
172
|
-
if (type.startsWith('INT') ||
|
|
173
|
-
type === 'REAL' ||
|
|
174
|
-
type === 'NUMERIC' ||
|
|
175
|
-
type.startsWith('DECIMAL') ||
|
|
176
|
-
type === 'FLOAT' ||
|
|
177
|
-
type === 'DOUBLE' ||
|
|
178
|
-
type.startsWith('BIGINT') ||
|
|
179
|
-
type.startsWith('SMALLINT') ||
|
|
180
|
-
type.startsWith('SERIAL')) {
|
|
181
|
-
const s = String(raw).trim();
|
|
182
|
-
if (s === '')
|
|
183
|
-
return null;
|
|
184
|
-
const n = Number(s);
|
|
185
|
-
return Number.isFinite(n) ? n : s;
|
|
186
|
-
}
|
|
187
|
-
if (type === 'BLOB' || type === 'BYTEA') {
|
|
188
|
-
const s = String(raw);
|
|
189
|
-
if (/^0x[0-9a-f]*$/i.test(s))
|
|
190
|
-
return Buffer.from(s.slice(2), 'hex');
|
|
191
|
-
if (/^\\x[0-9a-f]*$/i.test(s))
|
|
192
|
-
return Buffer.from(s.slice(2), 'hex');
|
|
193
|
-
return Buffer.from(s, 'utf8');
|
|
194
|
-
}
|
|
195
|
-
if (type === 'JSON' || type === 'JSONB') {
|
|
196
|
-
const s = String(raw).trim();
|
|
197
|
-
if (s === '')
|
|
198
|
-
return null;
|
|
199
|
-
return s;
|
|
200
|
-
}
|
|
201
|
-
if (type.endsWith('[]') || type.startsWith('_') || type.includes('ARRAY')) {
|
|
202
|
-
if (Array.isArray(raw))
|
|
203
|
-
return raw;
|
|
204
|
-
const s = String(raw).trim();
|
|
205
|
-
if (s === '')
|
|
206
|
-
return null;
|
|
207
|
-
return s;
|
|
208
|
-
}
|
|
209
|
-
const s = String(raw);
|
|
210
|
-
if (s === '')
|
|
211
|
-
return null;
|
|
212
|
-
return s;
|
|
213
|
-
}
|
|
214
|
-
/** Format byte size to human readable string (e.g. 1.2 MB). */
|
|
215
|
-
function formatBytes(bytes) {
|
|
216
|
-
if (bytes === 0)
|
|
217
|
-
return '0 B';
|
|
218
|
-
const k = 1024;
|
|
219
|
-
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
220
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
221
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
222
|
-
}
|
|
223
|
-
/** Truncate a string with an ellipsis if it exceeds maxLength. */
|
|
224
|
-
function truncate(str, maxLength) {
|
|
225
|
-
if (!str || str.length <= maxLength)
|
|
226
|
-
return str;
|
|
227
|
-
return `${str.slice(0, maxLength)}…`;
|
|
228
|
-
}
|
|
229
|
-
//# sourceMappingURL=common.js.map
|
|
1
|
+
var __importDefault=this&&this.__importDefault||function(mod){return mod&&mod.__esModule?mod:{default:mod}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.errorMessage=function(err){return err instanceof Error?err.message:String(err)},exports.isPathWithinRoot=function(root,p){if(!root||!p||"string"!=typeof root||"string"!=typeof p)return!1;if(p.includes("\0")||root.includes("\0"))return!1;const absRoot=node_path_1.default.resolve(root),absPath=node_path_1.default.resolve(p);let realRoot=absRoot,realPath=absPath;try{(0,node_fs_1.existsSync)(absRoot)&&(realRoot=(0,node_fs_1.realpathSync)(absRoot))}catch{}try{(0,node_fs_1.existsSync)(absPath)&&(realPath=(0,node_fs_1.realpathSync)(absPath))}catch{}const rel=node_path_1.default.relative(realRoot,realPath);return""===rel||!rel.startsWith("..")&&!node_path_1.default.isAbsolute(rel)},exports.parseFilters=function(raw){const out={},add=obj=>{if(obj&&"object"==typeof obj)for(const[k,v]of Object.entries(obj))null!=v&&""!==v&&(Array.isArray(v)?v.length&&(out[k]=v):out[k]="object"==typeof v?v:String(v))};if("string"==typeof raw&&raw)try{add(JSON.parse(raw))}catch{return{}}else add(raw);return out},exports.filtersToQS=function(filters){const out={};for(const[k,v]of Object.entries(filters??{}))null!=v&&(Array.isArray(v)?v.length&&(out[k]=v):"object"!=typeof v?""!==String(v).trim()&&(out[k]=String(v).trim()):Object.keys(v).length&&(out[k]=v));return Object.keys(out).length?"f="+encodeURIComponent(JSON.stringify(out)):""},exports.isInternalTable=function(name){return name.startsWith("_")},exports.encodePk=function(values){return values.map(v=>encodeURIComponent(null==v?"":String(v))).join(",")},exports.decodePk=function(encoded){return String(encoded).split(",").map(s=>{try{return decodeURIComponent(s)}catch{return s}})},exports.normalizeCell=normalizeCell,exports.normalizeRow=function(row){const out={};for(const[k,v]of Object.entries(row??{}))out[k]=normalizeCell(v);return out},exports.coerceFormValue=function(raw,columnType,dialect="sqlite"){const type=(columnType||"").toUpperCase();if(null==raw)return null;if("BOOLEAN"===type||"BOOL"===type){const s=String(raw).trim().toLowerCase();if(""===s)return null;const boolVal="true"===s||"1"===s||"on"===s||"yes"===s||"checked"===s;return"postgres"===dialect?boolVal:boolVal?1:0}if(type.startsWith("INT")||"REAL"===type||"NUMERIC"===type||type.startsWith("DECIMAL")||"FLOAT"===type||"DOUBLE"===type||type.startsWith("BIGINT")||type.startsWith("SMALLINT")||type.startsWith("SERIAL")){const s=String(raw).trim();if(""===s)return null;const n=Number(s);return Number.isFinite(n)?n:s}if("BLOB"===type||"BYTEA"===type){const s=String(raw);return/^0x[0-9a-f]*$/i.test(s)||/^\\x[0-9a-f]*$/i.test(s)?Buffer.from(s.slice(2),"hex"):Buffer.from(s,"utf8")}if("JSON"===type||"JSONB"===type){const s=String(raw).trim();return""===s?null:s}if(type.endsWith("[]")||type.startsWith("_")||type.includes("ARRAY")){if(Array.isArray(raw))return raw;const s=String(raw).trim();return""===s?null:s}const s=String(raw);return""===s?null:s},exports.formatBytes=function(bytes){if(0===bytes)return"0 B";const i=Math.floor(Math.log(bytes)/Math.log(1024));return`${parseFloat((bytes/Math.pow(1024,i)).toFixed(1))} ${["B","KB","MB","GB","TB"][i]}`},exports.truncate=function(str,maxLength){return!str||str.length<=maxLength?str:`${str.slice(0,maxLength)}…`};const node_fs_1=require("node:fs"),node_path_1=__importDefault(require("node:path"));function normalizeCell(value){return value instanceof Uint8Array||Buffer.isBuffer(value)?`0x${Buffer.from(value).toString("hex")}`:value instanceof Date?value.toISOString():"object"==typeof value&&null!==value?JSON.stringify(value):void 0===value?null:value}
|
package/dist/utils/csv.d.ts
CHANGED
|
@@ -1,15 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Minimal RFC 4180-style CSV serialization and parsing, used for table and
|
|
3
|
-
* query export/import. Pure functions with no I/O so they are easy to test.
|
|
4
|
-
*/
|
|
5
|
-
/** Escape a single CSV field (quote when it contains comma, quote or newline). */
|
|
6
|
-
export declare function csvEscape(value: unknown): string;
|
|
7
|
-
/** Serialize rows to CSV with an explicit column order. */
|
|
8
|
-
export declare function toCsv(rows: Record<string, unknown>[], columns: string[]): string;
|
|
9
|
-
/** Serialize rows to JSON (values are expected to be already normalized). */
|
|
10
|
-
export declare function toJson(rows: Record<string, unknown>[]): string;
|
|
11
|
-
/**
|
|
12
|
-
* Parse CSV text into rows of string fields. Handles quoted fields containing
|
|
13
|
-
* commas, quotes and embedded newlines. Blank lines are skipped.
|
|
14
|
-
*/
|
|
15
|
-
export declare function parseCsv(text: string): string[][];
|
|
1
|
+
export declare function csvEscape(value:unknown):string;export declare function toCsv(rows:Record<string,unknown>[],columns:string[]):string;export declare function toJson(rows:Record<string,unknown>[]):string;export declare function parseCsv(text:string):string[][];
|
package/dist/utils/csv.js
CHANGED
|
@@ -1,80 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
/**
|
|
3
|
-
* Minimal RFC 4180-style CSV serialization and parsing, used for table and
|
|
4
|
-
* query export/import. Pure functions with no I/O so they are easy to test.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.csvEscape = csvEscape;
|
|
8
|
-
exports.toCsv = toCsv;
|
|
9
|
-
exports.toJson = toJson;
|
|
10
|
-
exports.parseCsv = parseCsv;
|
|
11
|
-
/** Escape a single CSV field (quote when it contains comma, quote or newline). */
|
|
12
|
-
function csvEscape(value) {
|
|
13
|
-
const s = value === null || value === undefined ? '' : String(value);
|
|
14
|
-
if (/[",\r\n]/.test(s))
|
|
15
|
-
return `"${s.replace(/"/g, '""')}"`;
|
|
16
|
-
return s;
|
|
17
|
-
}
|
|
18
|
-
/** Serialize rows to CSV with an explicit column order. */
|
|
19
|
-
function toCsv(rows, columns) {
|
|
20
|
-
const header = columns.map(csvEscape).join(',');
|
|
21
|
-
const body = rows.map((row) => columns.map((c) => csvEscape(row[c])).join(','));
|
|
22
|
-
return [header, ...body].join('\r\n');
|
|
23
|
-
}
|
|
24
|
-
/** Serialize rows to JSON (values are expected to be already normalized). */
|
|
25
|
-
function toJson(rows) {
|
|
26
|
-
return JSON.stringify(rows, null, 2);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Parse CSV text into rows of string fields. Handles quoted fields containing
|
|
30
|
-
* commas, quotes and embedded newlines. Blank lines are skipped.
|
|
31
|
-
*/
|
|
32
|
-
function parseCsv(text) {
|
|
33
|
-
const rows = [];
|
|
34
|
-
let row = [];
|
|
35
|
-
let field = '';
|
|
36
|
-
let inQuotes = false;
|
|
37
|
-
const src = String(text ?? '');
|
|
38
|
-
for (let i = 0; i < src.length; i++) {
|
|
39
|
-
const ch = src[i];
|
|
40
|
-
if (inQuotes) {
|
|
41
|
-
if (ch === '"') {
|
|
42
|
-
if (src[i + 1] === '"') {
|
|
43
|
-
field += '"';
|
|
44
|
-
i++;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
inQuotes = false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
field += ch;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
else if (ch === '"') {
|
|
55
|
-
inQuotes = true;
|
|
56
|
-
}
|
|
57
|
-
else if (ch === ',') {
|
|
58
|
-
row.push(field);
|
|
59
|
-
field = '';
|
|
60
|
-
}
|
|
61
|
-
else if (ch === '\n') {
|
|
62
|
-
row.push(field);
|
|
63
|
-
field = '';
|
|
64
|
-
if (row.length > 1 || row[0] !== '')
|
|
65
|
-
rows.push(row);
|
|
66
|
-
row = [];
|
|
67
|
-
}
|
|
68
|
-
else if (ch === '\r') {
|
|
69
|
-
// Ignore — part of CRLF line endings.
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
field += ch;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
row.push(field);
|
|
76
|
-
if (row.length > 1 || row[0] !== '')
|
|
77
|
-
rows.push(row);
|
|
78
|
-
return rows;
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=csv.js.map
|
|
1
|
+
function csvEscape(value){const s=null==value?"":String(value);return/[",\r\n]/.test(s)?`"${s.replace(/"/g,'""')}"`:s}Object.defineProperty(exports,"__esModule",{value:!0}),exports.csvEscape=csvEscape,exports.toCsv=function(rows,columns){const header=columns.map(csvEscape).join(","),body=rows.map(row=>columns.map(c=>csvEscape(row[c])).join(","));return[header,...body].join("\r\n")},exports.toJson=function(rows){return JSON.stringify(rows,null,2)},exports.parseCsv=function(text){const rows=[];let row=[],field="",inQuotes=!1;const src=String(text??"");for(let i=0;i<src.length;i++){const ch=src[i];inQuotes?'"'===ch?'"'===src[i+1]?(field+='"',i++):inQuotes=!1:field+=ch:'"'===ch?inQuotes=!0:","===ch?(row.push(field),field=""):"\n"===ch?(row.push(field),field="",(row.length>1||""!==row[0])&&rows.push(row),row=[]):"\r"===ch||(field+=ch)}row.push(field),(row.length>1||""!==row[0])&&rows.push(row);return rows};
|
package/dist/utils/datatype.d.ts
CHANGED
|
@@ -1,49 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Utilities for rich data type detection, MIME sniffing, hex dump generation,
|
|
3
|
-
* and JSON inspection in AdminDB.
|
|
4
|
-
*/
|
|
5
|
-
export interface MimeAnalysis {
|
|
6
|
-
mime: string;
|
|
7
|
-
ext: string;
|
|
8
|
-
isImage: boolean;
|
|
9
|
-
isText: boolean;
|
|
10
|
-
isPdf: boolean;
|
|
11
|
-
isAudio: boolean;
|
|
12
|
-
isVideo: boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface HexDumpLine {
|
|
15
|
-
offset: string;
|
|
16
|
-
hex: string;
|
|
17
|
-
ascii: string;
|
|
18
|
-
}
|
|
19
|
-
export interface HexDumpResult {
|
|
20
|
-
lines: HexDumpLine[];
|
|
21
|
-
totalBytes: number;
|
|
22
|
-
truncated: boolean;
|
|
23
|
-
}
|
|
24
|
-
export interface BlobMetadata extends MimeAnalysis {
|
|
25
|
-
size: number;
|
|
26
|
-
sizeFormatted: string;
|
|
27
|
-
hexDump?: HexDumpResult;
|
|
28
|
-
textPreview?: string | null;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Sniff MIME type and file extension from magic bytes of a buffer.
|
|
32
|
-
*/
|
|
33
|
-
export declare function sniffMimeType(buf: Uint8Array | Buffer): MimeAnalysis;
|
|
34
|
-
/**
|
|
35
|
-
* Generate formatted 3-column Hex Dump (Offset | Hex Bytes | ASCII).
|
|
36
|
-
*/
|
|
37
|
-
export declare function generateHexDump(buf: Uint8Array | Buffer, maxBytes?: number, bytesPerLine?: number): HexDumpResult;
|
|
38
|
-
/**
|
|
39
|
-
* Get comprehensive metadata for a binary buffer or hex string.
|
|
40
|
-
*/
|
|
41
|
-
export declare function analyzeBlob(data: Uint8Array | Buffer | string): BlobMetadata;
|
|
42
|
-
/**
|
|
43
|
-
* Detect whether a value is a valid JSON string (Object or Array).
|
|
44
|
-
*/
|
|
45
|
-
export declare function isJsonString(value: unknown): boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Parse and pretty format JSON string. Returns null if invalid.
|
|
48
|
-
*/
|
|
49
|
-
export declare function formatJsonSafely(value: unknown, indent?: number): string | null;
|
|
1
|
+
export interface MimeAnalysis{mime:string;ext:string;isImage:boolean;isText:boolean;isPdf:boolean;isAudio:boolean;isVideo:boolean;}export interface HexDumpLine{offset:string;hex:string;ascii:string;}export interface HexDumpResult{lines:HexDumpLine[];totalBytes:number;truncated:boolean;}export interface BlobMetadata extends MimeAnalysis{size:number;sizeFormatted:string;hexDump?:HexDumpResult;textPreview?:string|null;}export declare function sniffMimeType(buf:Uint8Array|Buffer):MimeAnalysis;export declare function generateHexDump(buf:Uint8Array|Buffer,maxBytes?:number,bytesPerLine?:number):HexDumpResult;export declare function analyzeBlob(data:Uint8Array|Buffer|string):BlobMetadata;export declare function isJsonString(value:unknown):boolean;export declare function formatJsonSafely(value:unknown,indent?:number):string|null;
|
package/dist/utils/datatype.js
CHANGED
|
@@ -1,222 +1 @@
|
|
|
1
|
-
"
|
|
2
|
-
/**
|
|
3
|
-
* Utilities for rich data type detection, MIME sniffing, hex dump generation,
|
|
4
|
-
* and JSON inspection in AdminDB.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.sniffMimeType = sniffMimeType;
|
|
8
|
-
exports.generateHexDump = generateHexDump;
|
|
9
|
-
exports.analyzeBlob = analyzeBlob;
|
|
10
|
-
exports.isJsonString = isJsonString;
|
|
11
|
-
exports.formatJsonSafely = formatJsonSafely;
|
|
12
|
-
const common_js_1 = require("./common.js");
|
|
13
|
-
/**
|
|
14
|
-
* Sniff MIME type and file extension from magic bytes of a buffer.
|
|
15
|
-
*/
|
|
16
|
-
function sniffMimeType(buf) {
|
|
17
|
-
const len = buf.length;
|
|
18
|
-
if (len === 0) {
|
|
19
|
-
return { mime: 'application/octet-stream', ext: 'bin', isImage: false, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
20
|
-
}
|
|
21
|
-
// PNG: 89 50 4E 47 0D 0A 1A 0A
|
|
22
|
-
if (len >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47 && buf[4] === 0x0d && buf[5] === 0x0a && buf[6] === 0x1a && buf[7] === 0x0a) {
|
|
23
|
-
return { mime: 'image/png', ext: 'png', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
24
|
-
}
|
|
25
|
-
// JPEG: FF D8 FF
|
|
26
|
-
if (len >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) {
|
|
27
|
-
return { mime: 'image/jpeg', ext: 'jpg', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
28
|
-
}
|
|
29
|
-
// GIF: GIF87a or GIF89a (47 49 46 38 37/39 61)
|
|
30
|
-
if (len >= 6 && buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38 && (buf[4] === 0x37 || buf[4] === 0x39) && buf[5] === 0x61) {
|
|
31
|
-
return { mime: 'image/gif', ext: 'gif', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
32
|
-
}
|
|
33
|
-
// WebP: RIFF....WEBP (52 49 46 46 ... 57 45 42 50)
|
|
34
|
-
if (len >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
|
|
35
|
-
return { mime: 'image/webp', ext: 'webp', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
36
|
-
}
|
|
37
|
-
// BMP: 42 4D
|
|
38
|
-
if (len >= 2 && buf[0] === 0x42 && buf[1] === 0x4d) {
|
|
39
|
-
return { mime: 'image/bmp', ext: 'bmp', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
40
|
-
}
|
|
41
|
-
// ICO: 00 00 01 00
|
|
42
|
-
if (len >= 4 && buf[0] === 0x00 && buf[1] === 0x00 && buf[2] === 0x01 && buf[3] === 0x00) {
|
|
43
|
-
return { mime: 'image/x-icon', ext: 'ico', isImage: true, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
44
|
-
}
|
|
45
|
-
// PDF: %PDF (25 50 44 46)
|
|
46
|
-
if (len >= 4 && buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46) {
|
|
47
|
-
return { mime: 'application/pdf', ext: 'pdf', isImage: false, isText: false, isPdf: true, isAudio: false, isVideo: false };
|
|
48
|
-
}
|
|
49
|
-
// MP3: ID3 (49 44 33) or Sync 0xFF 0xFB/0xF3/0xF2
|
|
50
|
-
if (len >= 3 && buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) {
|
|
51
|
-
return { mime: 'audio/mpeg', ext: 'mp3', isImage: false, isText: false, isPdf: false, isAudio: true, isVideo: false };
|
|
52
|
-
}
|
|
53
|
-
if (len >= 2 && buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0) {
|
|
54
|
-
return { mime: 'audio/mpeg', ext: 'mp3', isImage: false, isText: false, isPdf: false, isAudio: true, isVideo: false };
|
|
55
|
-
}
|
|
56
|
-
// WAV: RIFF....WAVE
|
|
57
|
-
if (len >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45) {
|
|
58
|
-
return { mime: 'audio/wav', ext: 'wav', isImage: false, isText: false, isPdf: false, isAudio: true, isVideo: false };
|
|
59
|
-
}
|
|
60
|
-
// OGG: OggS (4F 67 67 53)
|
|
61
|
-
if (len >= 4 && buf[0] === 0x4f && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53) {
|
|
62
|
-
return { mime: 'audio/ogg', ext: 'ogg', isImage: false, isText: false, isPdf: false, isAudio: true, isVideo: false };
|
|
63
|
-
}
|
|
64
|
-
// MP4 video: ....ftyp (66 74 79 70)
|
|
65
|
-
if (len >= 8 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) {
|
|
66
|
-
return { mime: 'video/mp4', ext: 'mp4', isImage: false, isText: false, isPdf: false, isAudio: false, isVideo: true };
|
|
67
|
-
}
|
|
68
|
-
// WebM: 1A 45 DF A3
|
|
69
|
-
if (len >= 4 && buf[0] === 0x1a && buf[1] === 0x45 && buf[2] === 0xdf && buf[3] === 0xa3) {
|
|
70
|
-
return { mime: 'video/webm', ext: 'webm', isImage: false, isText: false, isPdf: false, isAudio: false, isVideo: true };
|
|
71
|
-
}
|
|
72
|
-
// Check for UTF-8 Text / SVG / JSON
|
|
73
|
-
const sampleLen = Math.min(len, 1024);
|
|
74
|
-
const sample = Buffer.from(buf.subarray(0, sampleLen)).toString('utf8');
|
|
75
|
-
const trimmed = sample.trim();
|
|
76
|
-
// SVG: starts with <?xml or <svg
|
|
77
|
-
if (trimmed.startsWith('<svg') || (trimmed.startsWith('<?xml') && trimmed.includes('<svg'))) {
|
|
78
|
-
return { mime: 'image/svg+xml', ext: 'svg', isImage: true, isText: true, isPdf: false, isAudio: false, isVideo: false };
|
|
79
|
-
}
|
|
80
|
-
// JSON
|
|
81
|
-
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
82
|
-
try {
|
|
83
|
-
JSON.parse(sample);
|
|
84
|
-
return { mime: 'application/json', ext: 'json', isImage: false, isText: true, isPdf: false, isAudio: false, isVideo: false };
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
/* not valid json in sample */
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// Check if buffer contains mostly printable ASCII / UTF-8
|
|
91
|
-
let nonPrintable = 0;
|
|
92
|
-
for (let i = 0; i < sampleLen; i++) {
|
|
93
|
-
const byte = buf[i];
|
|
94
|
-
if (byte === 0 || (byte < 7 && byte !== 9 && byte !== 10 && byte !== 13)) {
|
|
95
|
-
nonPrintable++;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (nonPrintable === 0) {
|
|
99
|
-
return { mime: 'text/plain; charset=utf-8', ext: 'txt', isImage: false, isText: true, isPdf: false, isAudio: false, isVideo: false };
|
|
100
|
-
}
|
|
101
|
-
return { mime: 'application/octet-stream', ext: 'bin', isImage: false, isText: false, isPdf: false, isAudio: false, isVideo: false };
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Generate formatted 3-column Hex Dump (Offset | Hex Bytes | ASCII).
|
|
105
|
-
*/
|
|
106
|
-
function generateHexDump(buf, maxBytes = 4096, bytesPerLine = 16) {
|
|
107
|
-
const totalBytes = buf.length;
|
|
108
|
-
const limit = Math.min(totalBytes, maxBytes);
|
|
109
|
-
const truncated = totalBytes > maxBytes;
|
|
110
|
-
const lines = [];
|
|
111
|
-
for (let i = 0; i < limit; i += bytesPerLine) {
|
|
112
|
-
const offset = i.toString(16).padStart(8, '0');
|
|
113
|
-
const chunk = buf.subarray(i, Math.min(i + bytesPerLine, limit));
|
|
114
|
-
const hexParts = [];
|
|
115
|
-
let asciiPart = '';
|
|
116
|
-
for (let j = 0; j < bytesPerLine; j++) {
|
|
117
|
-
if (j < chunk.length) {
|
|
118
|
-
const byte = chunk[j];
|
|
119
|
-
hexParts.push(byte.toString(16).padStart(2, '0'));
|
|
120
|
-
// Printable ASCII between 32 (space) and 126 (~)
|
|
121
|
-
asciiPart += (byte >= 32 && byte <= 126) ? String.fromCharCode(byte) : '.';
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
hexParts.push(' ');
|
|
125
|
-
asciiPart += ' ';
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// Insert extra space in the middle for readability (e.g. after 8 bytes)
|
|
129
|
-
const mid = Math.floor(bytesPerLine / 2);
|
|
130
|
-
const hexFormatted = hexParts.slice(0, mid).join(' ') + ' ' + hexParts.slice(mid).join(' ');
|
|
131
|
-
lines.push({
|
|
132
|
-
offset,
|
|
133
|
-
hex: hexFormatted,
|
|
134
|
-
ascii: asciiPart,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return { lines, totalBytes, truncated };
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Get comprehensive metadata for a binary buffer or hex string.
|
|
141
|
-
*/
|
|
142
|
-
function analyzeBlob(data) {
|
|
143
|
-
let buf;
|
|
144
|
-
if (typeof data === 'string') {
|
|
145
|
-
if (data.startsWith('0x') || data.startsWith('0X')) {
|
|
146
|
-
buf = Buffer.from(data.slice(2), 'hex');
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
buf = Buffer.from(data, 'utf8');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
154
|
-
}
|
|
155
|
-
const analysis = sniffMimeType(buf);
|
|
156
|
-
let textPreview = null;
|
|
157
|
-
if (analysis.isText || buf.length < 2048) {
|
|
158
|
-
try {
|
|
159
|
-
const txt = buf.toString('utf8');
|
|
160
|
-
// If it looks like valid text
|
|
161
|
-
if (!/[\x00-\x08\x0E-\x1F]/.test(txt.slice(0, 512))) {
|
|
162
|
-
textPreview = txt.slice(0, 4000);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
/* ignore */
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
...analysis,
|
|
171
|
-
size: buf.length,
|
|
172
|
-
sizeFormatted: (0, common_js_1.formatBytes)(buf.length),
|
|
173
|
-
hexDump: generateHexDump(buf),
|
|
174
|
-
textPreview,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Detect whether a value is a valid JSON string (Object or Array).
|
|
179
|
-
*/
|
|
180
|
-
function isJsonString(value) {
|
|
181
|
-
if (typeof value !== 'string')
|
|
182
|
-
return false;
|
|
183
|
-
const trimmed = value.trim();
|
|
184
|
-
if (!trimmed)
|
|
185
|
-
return false;
|
|
186
|
-
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
187
|
-
try {
|
|
188
|
-
JSON.parse(trimmed);
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Parse and pretty format JSON string. Returns null if invalid.
|
|
199
|
-
*/
|
|
200
|
-
function formatJsonSafely(value, indent = 2) {
|
|
201
|
-
if (value === null || value === undefined)
|
|
202
|
-
return null;
|
|
203
|
-
if (typeof value === 'object') {
|
|
204
|
-
try {
|
|
205
|
-
return JSON.stringify(value, null, indent);
|
|
206
|
-
}
|
|
207
|
-
catch {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (typeof value === 'string') {
|
|
212
|
-
try {
|
|
213
|
-
const parsed = JSON.parse(value);
|
|
214
|
-
return JSON.stringify(parsed, null, indent);
|
|
215
|
-
}
|
|
216
|
-
catch {
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return null;
|
|
221
|
-
}
|
|
222
|
-
//# sourceMappingURL=datatype.js.map
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.sniffMimeType=sniffMimeType,exports.generateHexDump=generateHexDump,exports.analyzeBlob=function(data){let buf;buf="string"==typeof data?data.startsWith("0x")||data.startsWith("0X")?Buffer.from(data.slice(2),"hex"):Buffer.from(data,"utf8"):Buffer.isBuffer(data)?data:Buffer.from(data);const analysis=sniffMimeType(buf);let textPreview=null;if(analysis.isText||buf.length<2048)try{const txt=buf.toString("utf8");/[\x00-\x08\x0E-\x1F]/.test(txt.slice(0,512))||(textPreview=txt.slice(0,4e3))}catch{}return{...analysis,size:buf.length,sizeFormatted:(0,common_js_1.formatBytes)(buf.length),hexDump:generateHexDump(buf),textPreview:textPreview}},exports.isJsonString=function(value){if("string"!=typeof value)return!1;const trimmed=value.trim();if(!trimmed)return!1;if(trimmed.startsWith("{")&&trimmed.endsWith("}")||trimmed.startsWith("[")&&trimmed.endsWith("]"))try{return JSON.parse(trimmed),!0}catch{return!1}return!1},exports.formatJsonSafely=function(value,indent=2){if(null==value)return null;if("object"==typeof value)try{return JSON.stringify(value,null,indent)}catch{return null}if("string"==typeof value)try{const parsed=JSON.parse(value);return JSON.stringify(parsed,null,indent)}catch{return null}return null};const common_js_1=require("./common.js");function sniffMimeType(buf){const len=buf.length;if(0===len)return{mime:"application/octet-stream",ext:"bin",isImage:!1,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=8&&137===buf[0]&&80===buf[1]&&78===buf[2]&&71===buf[3]&&13===buf[4]&&10===buf[5]&&26===buf[6]&&10===buf[7])return{mime:"image/png",ext:"png",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=3&&255===buf[0]&&216===buf[1]&&255===buf[2])return{mime:"image/jpeg",ext:"jpg",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=6&&71===buf[0]&&73===buf[1]&&70===buf[2]&&56===buf[3]&&(55===buf[4]||57===buf[4])&&97===buf[5])return{mime:"image/gif",ext:"gif",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=12&&82===buf[0]&&73===buf[1]&&70===buf[2]&&70===buf[3]&&87===buf[8]&&69===buf[9]&&66===buf[10]&&80===buf[11])return{mime:"image/webp",ext:"webp",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=2&&66===buf[0]&&77===buf[1])return{mime:"image/bmp",ext:"bmp",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=4&&0===buf[0]&&0===buf[1]&&1===buf[2]&&0===buf[3])return{mime:"image/x-icon",ext:"ico",isImage:!0,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1};if(len>=4&&37===buf[0]&&80===buf[1]&&68===buf[2]&&70===buf[3])return{mime:"application/pdf",ext:"pdf",isImage:!1,isText:!1,isPdf:!0,isAudio:!1,isVideo:!1};if(len>=3&&73===buf[0]&&68===buf[1]&&51===buf[2])return{mime:"audio/mpeg",ext:"mp3",isImage:!1,isText:!1,isPdf:!1,isAudio:!0,isVideo:!1};if(len>=2&&255===buf[0]&&!(224&~buf[1]))return{mime:"audio/mpeg",ext:"mp3",isImage:!1,isText:!1,isPdf:!1,isAudio:!0,isVideo:!1};if(len>=12&&82===buf[0]&&73===buf[1]&&70===buf[2]&&70===buf[3]&&87===buf[8]&&65===buf[9]&&86===buf[10]&&69===buf[11])return{mime:"audio/wav",ext:"wav",isImage:!1,isText:!1,isPdf:!1,isAudio:!0,isVideo:!1};if(len>=4&&79===buf[0]&&103===buf[1]&&103===buf[2]&&83===buf[3])return{mime:"audio/ogg",ext:"ogg",isImage:!1,isText:!1,isPdf:!1,isAudio:!0,isVideo:!1};if(len>=8&&102===buf[4]&&116===buf[5]&&121===buf[6]&&112===buf[7])return{mime:"video/mp4",ext:"mp4",isImage:!1,isText:!1,isPdf:!1,isAudio:!1,isVideo:!0};if(len>=4&&26===buf[0]&&69===buf[1]&&223===buf[2]&&163===buf[3])return{mime:"video/webm",ext:"webm",isImage:!1,isText:!1,isPdf:!1,isAudio:!1,isVideo:!0};const sampleLen=Math.min(len,1024),sample=Buffer.from(buf.subarray(0,sampleLen)).toString("utf8"),trimmed=sample.trim();if(trimmed.startsWith("<svg")||trimmed.startsWith("<?xml")&&trimmed.includes("<svg"))return{mime:"image/svg+xml",ext:"svg",isImage:!0,isText:!0,isPdf:!1,isAudio:!1,isVideo:!1};if(trimmed.startsWith("{")&&trimmed.endsWith("}")||trimmed.startsWith("[")&&trimmed.endsWith("]"))try{return JSON.parse(sample),{mime:"application/json",ext:"json",isImage:!1,isText:!0,isPdf:!1,isAudio:!1,isVideo:!1}}catch{}let nonPrintable=0;for(let i=0;i<sampleLen;i++){const byte=buf[i];(0===byte||byte<7&&9!==byte&&10!==byte&&13!==byte)&&nonPrintable++}return 0===nonPrintable?{mime:"text/plain; charset=utf-8",ext:"txt",isImage:!1,isText:!0,isPdf:!1,isAudio:!1,isVideo:!1}:{mime:"application/octet-stream",ext:"bin",isImage:!1,isText:!1,isPdf:!1,isAudio:!1,isVideo:!1}}function generateHexDump(buf,maxBytes=4096,bytesPerLine=16){const totalBytes=buf.length,limit=Math.min(totalBytes,maxBytes),truncated=totalBytes>maxBytes,lines=[];for(let i=0;i<limit;i+=bytesPerLine){const offset=i.toString(16).padStart(8,"0"),chunk=buf.subarray(i,Math.min(i+bytesPerLine,limit)),hexParts=[];let asciiPart="";for(let j=0;j<bytesPerLine;j++)if(j<chunk.length){const byte=chunk[j];hexParts.push(byte.toString(16).padStart(2,"0")),asciiPart+=byte>=32&&byte<=126?String.fromCharCode(byte):"."}else hexParts.push(" "),asciiPart+=" ";const mid=Math.floor(bytesPerLine/2),hexFormatted=hexParts.slice(0,mid).join(" ")+" "+hexParts.slice(mid).join(" ");lines.push({offset:offset,hex:hexFormatted,ascii:asciiPart})}return{lines:lines,totalBytes:totalBytes,truncated:truncated}}
|
package/dist/utils/icons.d.ts
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* SVG Icons registry for AdminDB.
|
|
3
|
-
*
|
|
4
|
-
* Centralizes all SVG icons in a single module, providing consistent
|
|
5
|
-
* styling, clean templates, and zero inline SVG duplication.
|
|
6
|
-
*/
|
|
7
|
-
export declare const ICONS: Record<string, string>;
|
|
8
|
-
/**
|
|
9
|
-
* Renders an SVG icon by name with optional custom CSS classes.
|
|
10
|
-
*/
|
|
11
|
-
export declare function renderIcon(name: string, customClass?: string): string;
|
|
1
|
+
export declare const ICONS:Record<string,string>;export declare function renderIcon(name:string,customClass?:string):string;
|