admindb 1.2.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +262 -329
  2. package/dist/app.d.ts +25 -4
  3. package/dist/app.js +79 -15
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth/config.d.ts +19 -0
  6. package/dist/auth/config.js +147 -0
  7. package/dist/auth/config.js.map +1 -0
  8. package/dist/auth/crypto.d.ts +27 -0
  9. package/dist/auth/crypto.js +133 -0
  10. package/dist/auth/crypto.js.map +1 -0
  11. package/dist/auth/index.d.ts +5 -0
  12. package/dist/auth/index.js +22 -0
  13. package/dist/auth/index.js.map +1 -0
  14. package/dist/auth/middleware.d.ts +14 -0
  15. package/dist/auth/middleware.js +100 -0
  16. package/dist/auth/middleware.js.map +1 -0
  17. package/dist/auth/routes.d.ts +7 -0
  18. package/dist/auth/routes.js +78 -0
  19. package/dist/auth/routes.js.map +1 -0
  20. package/dist/auth/types.d.ts +35 -0
  21. package/dist/auth/types.js +11 -0
  22. package/dist/auth/types.js.map +1 -0
  23. package/dist/cli/args.d.ts +45 -0
  24. package/dist/cli/args.js +328 -0
  25. package/dist/cli/args.js.map +1 -0
  26. package/dist/cli/config.d.ts +56 -0
  27. package/dist/cli/config.js +133 -0
  28. package/dist/cli/config.js.map +1 -0
  29. package/dist/cli/index.d.ts +4 -0
  30. package/dist/cli/index.js +21 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/runner.d.ts +1 -0
  33. package/dist/cli/runner.js +222 -0
  34. package/dist/cli/runner.js.map +1 -0
  35. package/dist/cli.js +2 -127
  36. package/dist/cli.js.map +1 -1
  37. package/dist/data/datasets.d.ts +17 -0
  38. package/dist/data/datasets.js +133 -0
  39. package/dist/data/datasets.js.map +1 -0
  40. package/dist/data/detector.d.ts +30 -0
  41. package/dist/data/detector.js +472 -0
  42. package/dist/data/detector.js.map +1 -0
  43. package/dist/data/engine.d.ts +10 -0
  44. package/dist/data/engine.js +211 -0
  45. package/dist/data/engine.js.map +1 -0
  46. package/dist/data/index.d.ts +5 -0
  47. package/dist/data/index.js +22 -0
  48. package/dist/data/index.js.map +1 -0
  49. package/dist/data/strategies.d.ts +30 -0
  50. package/dist/data/strategies.js +343 -0
  51. package/dist/data/strategies.js.map +1 -0
  52. package/dist/data/types.d.ts +73 -0
  53. package/dist/data/types.js +8 -0
  54. package/dist/data/types.js.map +1 -0
  55. package/dist/db/database.d.ts +14 -146
  56. package/dist/db/database.js +208 -461
  57. package/dist/db/database.js.map +1 -1
  58. package/dist/db/export.d.ts +2 -2
  59. package/dist/db/export.js +7 -2
  60. package/dist/db/export.js.map +1 -1
  61. package/dist/db/filters.d.ts +22 -0
  62. package/dist/db/filters.js +158 -0
  63. package/dist/db/filters.js.map +1 -0
  64. package/dist/db/index.d.ts +8 -0
  65. package/dist/db/index.js +25 -0
  66. package/dist/db/index.js.map +1 -0
  67. package/dist/db/introspection.d.ts +6 -0
  68. package/dist/db/introspection.js +172 -0
  69. package/dist/db/introspection.js.map +1 -0
  70. package/dist/db/manager.d.ts +32 -19
  71. package/dist/db/manager.js +203 -44
  72. package/dist/db/manager.js.map +1 -1
  73. package/dist/db/migrations.d.ts +5 -0
  74. package/dist/db/migrations.js +110 -0
  75. package/dist/db/migrations.js.map +1 -0
  76. package/dist/db/postgres.d.ts +85 -0
  77. package/dist/db/postgres.js +745 -0
  78. package/dist/db/postgres.js.map +1 -0
  79. package/dist/db/types.d.ts +206 -0
  80. package/dist/db/types.js +7 -0
  81. package/dist/db/types.js.map +1 -0
  82. package/dist/index.d.ts +9 -2
  83. package/dist/index.js +46 -4
  84. package/dist/index.js.map +1 -1
  85. package/dist/public/css/app.css +1 -1
  86. package/dist/public/css/input.css +74 -11
  87. package/dist/public/js/app.js +142 -0
  88. package/dist/public/js/browse.js +591 -104
  89. package/dist/public/js/databases.js +105 -13
  90. package/dist/public/js/designer.js +55 -2
  91. package/dist/public/js/forms.js +610 -28
  92. package/dist/public/js/icons.js +51 -0
  93. package/dist/public/js/inspector.js +638 -0
  94. package/dist/public/js/query.js +93 -3
  95. package/dist/public/js/schema.js +185 -52
  96. package/dist/public/js/seed.js +865 -152
  97. package/dist/routes/api/helpers.d.ts +42 -0
  98. package/dist/routes/api/helpers.js +133 -0
  99. package/dist/routes/api/helpers.js.map +1 -0
  100. package/dist/routes/api/import-export.d.ts +3 -0
  101. package/dist/routes/api/import-export.js +85 -0
  102. package/dist/routes/api/import-export.js.map +1 -0
  103. package/dist/routes/api/index.d.ts +4 -0
  104. package/dist/routes/api/index.js +37 -0
  105. package/dist/routes/api/index.js.map +1 -0
  106. package/dist/routes/api/query.d.ts +3 -0
  107. package/dist/routes/api/query.js +76 -0
  108. package/dist/routes/api/query.js.map +1 -0
  109. package/dist/routes/api/rows.d.ts +3 -0
  110. package/dist/routes/api/rows.js +373 -0
  111. package/dist/routes/api/rows.js.map +1 -0
  112. package/dist/routes/api/seed.d.ts +3 -0
  113. package/dist/routes/api/seed.js +82 -0
  114. package/dist/routes/api/seed.js.map +1 -0
  115. package/dist/routes/api/tables.d.ts +3 -0
  116. package/dist/routes/api/tables.js +160 -0
  117. package/dist/routes/api/tables.js.map +1 -0
  118. package/dist/routes/databases.d.ts +8 -11
  119. package/dist/routes/databases.js +100 -66
  120. package/dist/routes/databases.js.map +1 -1
  121. package/dist/routes/index.d.ts +3 -0
  122. package/dist/routes/index.js +20 -0
  123. package/dist/routes/index.js.map +1 -0
  124. package/dist/routes/pages.d.ts +3 -3
  125. package/dist/routes/pages.js +157 -64
  126. package/dist/routes/pages.js.map +1 -1
  127. package/dist/serverless.d.ts +40 -0
  128. package/dist/serverless.js +210 -0
  129. package/dist/serverless.js.map +1 -0
  130. package/dist/sql/generator.d.ts +7 -3
  131. package/dist/sql/generator.js +144 -7
  132. package/dist/sql/generator.js.map +1 -1
  133. package/dist/sql/index.d.ts +2 -0
  134. package/dist/sql/index.js +19 -0
  135. package/dist/sql/index.js.map +1 -0
  136. package/dist/types/api.d.ts +412 -0
  137. package/dist/types/api.js +9 -0
  138. package/dist/types/api.js.map +1 -0
  139. package/dist/utils/colors.d.ts +40 -0
  140. package/dist/utils/colors.js +64 -0
  141. package/dist/utils/colors.js.map +1 -0
  142. package/dist/{util.d.ts → utils/common.d.ts} +10 -6
  143. package/dist/{util.js → utils/common.js} +80 -13
  144. package/dist/utils/common.js.map +1 -0
  145. package/dist/utils/csv.js.map +1 -0
  146. package/dist/utils/datatype.d.ts +49 -0
  147. package/dist/utils/datatype.js +222 -0
  148. package/dist/utils/datatype.js.map +1 -0
  149. package/dist/utils/icons.d.ts +11 -0
  150. package/dist/utils/icons.js +72 -0
  151. package/dist/utils/icons.js.map +1 -0
  152. package/dist/utils/index.d.ts +4 -0
  153. package/dist/utils/index.js +21 -0
  154. package/dist/utils/index.js.map +1 -0
  155. package/dist/{logger.d.ts → utils/logger.d.ts} +1 -1
  156. package/dist/utils/logger.js +40 -0
  157. package/dist/utils/logger.js.map +1 -0
  158. package/dist/views/layouts/main.hbs +40 -11
  159. package/dist/views/pages/databases.hbs +182 -74
  160. package/dist/views/pages/designer.hbs +29 -11
  161. package/dist/views/pages/error.hbs +3 -3
  162. package/dist/views/pages/form.hbs +5 -3
  163. package/dist/views/pages/home.hbs +22 -13
  164. package/dist/views/pages/login.hbs +111 -0
  165. package/dist/views/pages/query.hbs +8 -6
  166. package/dist/views/pages/schema.hbs +41 -13
  167. package/dist/views/pages/seed.hbs +200 -54
  168. package/dist/views/pages/table.hbs +152 -72
  169. package/dist/views/partials/icon.hbs +2 -0
  170. package/dist/views/partials/navbar.hbs +69 -25
  171. package/dist/views/partials/sidebar.hbs +108 -94
  172. package/docs/API.md +144 -0
  173. package/docs/EXAMPLES.md +576 -0
  174. package/docs/SECURITY.md +265 -0
  175. package/package.json +15 -4
  176. package/dist/args.d.ts +0 -28
  177. package/dist/args.js +0 -187
  178. package/dist/args.js.map +0 -1
  179. package/dist/config.d.ts +0 -17
  180. package/dist/config.js +0 -23
  181. package/dist/config.js.map +0 -1
  182. package/dist/csv.js.map +0 -1
  183. package/dist/data/generator.d.ts +0 -86
  184. package/dist/data/generator.js +0 -1031
  185. package/dist/data/generator.js.map +0 -1
  186. package/dist/logger.js +0 -25
  187. package/dist/logger.js.map +0 -1
  188. package/dist/routes/api.d.ts +0 -9
  189. package/dist/routes/api.js +0 -848
  190. package/dist/routes/api.js.map +0 -1
  191. package/dist/test/classifier.test.d.ts +0 -1
  192. package/dist/test/classifier.test.js +0 -44
  193. package/dist/test/classifier.test.js.map +0 -1
  194. package/dist/test/csv.test.d.ts +0 -1
  195. package/dist/test/csv.test.js +0 -64
  196. package/dist/test/csv.test.js.map +0 -1
  197. package/dist/test/database.test.d.ts +0 -1
  198. package/dist/test/database.test.js +0 -402
  199. package/dist/test/database.test.js.map +0 -1
  200. package/dist/test/generator.test.d.ts +0 -1
  201. package/dist/test/generator.test.js +0 -132
  202. package/dist/test/generator.test.js.map +0 -1
  203. package/dist/test/manager.test.d.ts +0 -1
  204. package/dist/test/manager.test.js +0 -146
  205. package/dist/test/manager.test.js.map +0 -1
  206. package/dist/util.js.map +0 -1
  207. /package/dist/{csv.d.ts → utils/csv.d.ts} +0 -0
  208. /package/dist/{csv.js → utils/csv.js} +0 -0
@@ -1,9 +1,14 @@
1
- /* Databases landing page: create/delete database files, and a filesystem
2
- * browser for opening existing SQLite files. */
1
+ /* Databases landing page: create SQLite databases, connect PostgreSQL databases,
2
+ * toggle readonly mode, delete/disconnect databases, and browse filesystem. */
3
3
  (function () {
4
4
  'use strict';
5
5
  const nameInput = document.getElementById('new-db-name');
6
6
  const createBtn = document.getElementById('create-db');
7
+ const pgNameInput = document.getElementById('pg-conn-name');
8
+ const pgUriInput = document.getElementById('pg-conn-uri');
9
+ const pgRoInput = document.getElementById('pg-conn-readonly');
10
+ const connectPgBtn = document.getElementById('connect-pg');
11
+ const fsRoInput = document.getElementById('fs-readonly');
7
12
 
8
13
  function escapeHtml(s) {
9
14
  return (window.UI && UI.escapeHtml) ? UI.escapeHtml(s) : String(s == null ? '' : s);
@@ -21,6 +26,8 @@
21
26
  return (u === 0 ? Math.round(v) : v.toFixed(1)) + ' ' + units[u];
22
27
  }
23
28
 
29
+ // ---- Create SQLite DB ----------------------------------------------------
30
+
24
31
  async function createDb() {
25
32
  const name = (nameInput.value || '').trim();
26
33
  if (!name) return UI.showError('Enter a database name.');
@@ -42,11 +49,75 @@
42
49
  });
43
50
  }
44
51
 
52
+ // ---- Connect PostgreSQL DB -----------------------------------------------
53
+
54
+ async function connectPg() {
55
+ const name = (pgNameInput ? pgNameInput.value : '').trim();
56
+ const connectionString = (pgUriInput ? pgUriInput.value : '').trim();
57
+ const readonly = pgRoInput ? pgRoInput.checked : false;
58
+ if (!connectionString) {
59
+ return UI.showError('Enter a PostgreSQL connection URI (e.g. postgresql://user:password@localhost:5432/dbname).');
60
+ }
61
+ if (connectPgBtn) {
62
+ connectPgBtn.disabled = true;
63
+ connectPgBtn.textContent = 'Connecting…';
64
+ }
65
+ try {
66
+ const data = await Api.post('/api/databases/connect-postgres', { name, connectionString, readonly });
67
+ UI.showToast(data.message || 'PostgreSQL connected.', 'success');
68
+ setTimeout(() => {
69
+ window.location.href = Api.basePath + '/' + encodeURIComponent(data.id);
70
+ }, 400);
71
+ } catch (e) {
72
+ UI.showError(e.message);
73
+ if (connectPgBtn) {
74
+ connectPgBtn.disabled = false;
75
+ connectPgBtn.innerHTML = (window.AdminIcons ? AdminIcons.get('plus', 'h-4 w-4') : '') + ' Connect PostgreSQL';
76
+ }
77
+ }
78
+ }
79
+
80
+ if (connectPgBtn) connectPgBtn.addEventListener('click', connectPg);
81
+ if (pgUriInput) {
82
+ pgUriInput.addEventListener('keydown', (e) => {
83
+ if (e.key === 'Enter') connectPg();
84
+ });
85
+ }
86
+
87
+ // ---- Toggle Read-only / Writable Mode ------------------------------------
88
+
89
+ document.querySelectorAll('.js-toggle-db-mode').forEach((btn) => {
90
+ btn.addEventListener('click', async () => {
91
+ const id = btn.dataset.id;
92
+ if (!id) return;
93
+ const currentRo = btn.dataset.readonly === 'true';
94
+ const targetRo = !currentRo;
95
+ try {
96
+ const data = await Api.post('/api/databases/' + encodeURIComponent(id) + '/mode', { readonly: targetRo });
97
+ UI.showToast(data.message || `Mode updated to ${targetRo ? 'Read-only' : 'Writable'}.`, 'success');
98
+ window.location.reload();
99
+ } catch (e) {
100
+ UI.showError(e.message);
101
+ }
102
+ });
103
+ });
104
+
105
+ // ---- Delete SQLite DB ----------------------------------------------------
106
+
45
107
  document.querySelectorAll('.js-delete-db').forEach((btn) => {
46
- btn.addEventListener('click', () => {
108
+ btn.addEventListener('click', async () => {
47
109
  const id = btn.dataset.id;
48
110
  if (!id) return;
49
- if (!window.confirm('Delete database "' + id + '" permanently? This removes the file and all of its data.')) return;
111
+ const confirmed = await UI.confirm({
112
+ title: 'Delete Database',
113
+ message: 'Are you sure you want to permanently delete database "' + id + '"? This will remove the SQLite database file and all stored tables and records from the disk.',
114
+ item: id,
115
+ itemType: 'Database',
116
+ requireInputMatch: id,
117
+ confirmText: 'Delete database',
118
+ danger: true,
119
+ });
120
+ if (!confirmed) return;
50
121
  Api.del('/api/databases/' + encodeURIComponent(id))
51
122
  .then((data) => {
52
123
  UI.showToast(data.message || 'Database deleted.', 'success');
@@ -56,6 +127,29 @@
56
127
  });
57
128
  });
58
129
 
130
+ // ---- Disconnect PostgreSQL DB --------------------------------------------
131
+
132
+ document.querySelectorAll('.js-disconnect-db').forEach((btn) => {
133
+ btn.addEventListener('click', async () => {
134
+ const id = btn.dataset.id;
135
+ const name = btn.dataset.name || id;
136
+ if (!id) return;
137
+ const confirmed = await UI.confirm({
138
+ title: 'Disconnect PostgreSQL Database',
139
+ message: 'Are you sure you want to disconnect database "' + name + '" from AdminDB? This closes the connection pool in AdminDB; your remote database and data are untouched.',
140
+ confirmText: 'Disconnect database',
141
+ danger: false,
142
+ });
143
+ if (!confirmed) return;
144
+ Api.del('/api/databases/' + encodeURIComponent(id))
145
+ .then((data) => {
146
+ UI.showToast(data.message || 'Database disconnected.', 'success');
147
+ window.location.reload();
148
+ })
149
+ .catch((e) => UI.showError(e.message));
150
+ });
151
+ });
152
+
59
153
  // ---- Filesystem browser --------------------------------------------------
60
154
 
61
155
  const fsPathInput = document.getElementById('fs-path');
@@ -64,11 +158,6 @@
64
158
  const fsCurrent = document.getElementById('fs-current');
65
159
  const fsListing = document.getElementById('fs-listing');
66
160
 
67
- const FOLDER_ICON =
68
- '<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" /></svg>';
69
- const DB_ICON =
70
- '<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" /></svg>';
71
-
72
161
  let fsState = { path: '', parent: null };
73
162
 
74
163
  function renderFs(data) {
@@ -82,6 +171,9 @@
82
171
  fsListing.innerHTML = '<div class="px-4 py-6 text-center text-sm text-base-content/40">No folders or database files here.</div>';
83
172
  return;
84
173
  }
174
+ const folderIcon = window.AdminIcons ? AdminIcons.get('folder', 'h-3.5 w-3.5') : '📁';
175
+ const dbIcon = window.AdminIcons ? AdminIcons.get('database', 'h-3.5 w-3.5') : '🗄️';
176
+
85
177
  data.entries.forEach((e) => {
86
178
  const row = document.createElement('button');
87
179
  row.type = 'button';
@@ -89,13 +181,13 @@
89
181
  row.title = e.path;
90
182
  if (e.isDir) {
91
183
  row.innerHTML =
92
- '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-base-200 text-base-content/50">' + FOLDER_ICON + '</span>' +
184
+ '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-base-200 text-base-content/50">' + folderIcon + '</span>' +
93
185
  '<span class="min-w-0 flex-1 truncate font-medium text-base-content/80">' + escapeHtml(e.name) + '</span>' +
94
186
  '<span class="text-xs text-base-content/35">folder</span>';
95
187
  row.addEventListener('click', () => loadFs(e.path));
96
188
  } else {
97
189
  row.innerHTML =
98
- '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-primary/10 text-primary">' + DB_ICON + '</span>' +
190
+ '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-primary/10 text-primary">' + dbIcon + '</span>' +
99
191
  '<span class="min-w-0 flex-1 truncate font-mono text-[13px] text-base-content/85">' + escapeHtml(e.name) + '</span>' +
100
192
  '<span class="text-xs text-base-content/40">' + fmtSize(e.size) + '</span>';
101
193
  row.addEventListener('click', () => openDb(e.path));
@@ -118,8 +210,9 @@
118
210
  }
119
211
 
120
212
  async function openDb(p) {
213
+ const readonly = fsRoInput ? fsRoInput.checked : false;
121
214
  try {
122
- const data = await Api.post('/api/databases/open', { path: p });
215
+ const data = await Api.post('/api/databases/open', { path: p, readonly });
123
216
  UI.showToast(data.message || 'Database opened.', 'success');
124
217
  window.location.href = Api.basePath + '/' + encodeURIComponent(data.id);
125
218
  } catch (e) {
@@ -140,4 +233,3 @@
140
233
  if (fsUpBtn) fsUpBtn.addEventListener('click', goUp);
141
234
  }
142
235
  })();
143
-
@@ -2,7 +2,47 @@
2
2
  * and preview the generated CREATE TABLE live. Create executes; Copy copies. */
3
3
  (function () {
4
4
  'use strict';
5
- const DESIGNER_TYPES = ['TEXT', 'INTEGER', 'REAL', 'BLOB', 'BOOLEAN', 'DATE', 'DATETIME'];
5
+ const SQLITE_TYPES = [
6
+ 'TEXT',
7
+ 'INTEGER',
8
+ 'REAL',
9
+ 'BLOB',
10
+ 'BOOLEAN',
11
+ 'DATE',
12
+ 'DATETIME',
13
+ 'NUMERIC',
14
+ 'VARCHAR(255)',
15
+ 'JSON',
16
+ ];
17
+
18
+ const POSTGRES_TYPES = [
19
+ 'TEXT',
20
+ 'VARCHAR(255)',
21
+ 'INTEGER',
22
+ 'BIGINT',
23
+ 'SMALLINT',
24
+ 'SERIAL',
25
+ 'BIGSERIAL',
26
+ 'REAL',
27
+ 'DECIMAL(10,2)',
28
+ 'NUMERIC',
29
+ 'BOOLEAN',
30
+ 'DATE',
31
+ 'DATETIME',
32
+ 'TIMESTAMP',
33
+ 'TIMESTAMPTZ',
34
+ 'TIME',
35
+ 'INTERVAL',
36
+ 'JSON',
37
+ 'JSONB',
38
+ 'UUID',
39
+ 'BYTEA',
40
+ 'INET',
41
+ ];
42
+
43
+ const isPostgres = window.APP && window.APP.dialect === 'postgres';
44
+ const DESIGNER_TYPES = isPostgres ? POSTGRES_TYPES : SQLITE_TYPES;
45
+
6
46
  const NAME_RE = /^[A-Za-z_][A-Za-z0-9_$]*$/;
7
47
 
8
48
  const columnsEl = document.getElementById('columns');
@@ -67,7 +107,20 @@
67
107
  })
68
108
  .catch(() => {});
69
109
  });
70
- row.querySelector('.remove-col').addEventListener('click', () => row.remove());
110
+ row.querySelector('.remove-col').addEventListener('click', async () => {
111
+ const colName = row.querySelector('.col-name').value.trim();
112
+ if (colName) {
113
+ const confirmed = await UI.confirm({
114
+ title: 'Remove Column',
115
+ message: 'Remove column "' + colName + '" from the table definition?',
116
+ confirmText: 'Remove',
117
+ danger: true,
118
+ });
119
+ if (!confirmed) return;
120
+ }
121
+ row.remove();
122
+ schedulePreview();
123
+ });
71
124
 
72
125
  row.querySelectorAll('input, select').forEach((el) => {
73
126
  el.addEventListener('input', schedulePreview);